blob: 134ce20ad30c84f84715bc25d9753e09f210bb29 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002 * tree.c : implementation of access function for an XML tree.
Owen Taylor3473f882001-02-23 17:55:21 +00003 *
Daniel Veillardd5c2f922002-11-21 14:10:52 +00004 * References:
5 * XHTML 1.0 W3C REC: http://www.w3.org/TR/2002/REC-xhtml1-20020801/
6 *
Owen Taylor3473f882001-02-23 17:55:21 +00007 * See Copyright for the status of this software.
8 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00009 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000010 *
Owen Taylor3473f882001-02-23 17:55:21 +000011 */
12
Daniel Veillard34ce8be2002-03-18 19:37:11 +000013#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000014#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000015
Owen Taylor3473f882001-02-23 17:55:21 +000016#include <string.h> /* for memset() only ! */
17
18#ifdef HAVE_CTYPE_H
19#include <ctype.h>
20#endif
21#ifdef HAVE_STDLIB_H
22#include <stdlib.h>
23#endif
24#ifdef HAVE_ZLIB_H
25#include <zlib.h>
26#endif
27
28#include <libxml/xmlmemory.h>
29#include <libxml/tree.h>
30#include <libxml/parser.h>
Daniel Veillardb8c9be92001-07-09 16:01:19 +000031#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000032#include <libxml/entities.h>
33#include <libxml/valid.h>
34#include <libxml/xmlerror.h>
Daniel Veillardbdb9ba72001-04-11 11:28:06 +000035#include <libxml/parserInternals.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000036#include <libxml/globals.h>
Daniel Veillardd5c2f922002-11-21 14:10:52 +000037#ifdef LIBXML_HTML_ENABLED
38#include <libxml/HTMLtree.h>
39#endif
Owen Taylor3473f882001-02-23 17:55:21 +000040
Daniel Veillarda880b122003-04-21 21:36:41 +000041int __xmlRegisterCallbacks = 0;
42
Daniel Veillard56a4cb82001-03-24 17:00:36 +000043xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
44
45/************************************************************************
46 * *
Daniel Veillard18ec16e2003-10-07 23:16:40 +000047 * Tree memory error handler *
48 * *
49 ************************************************************************/
50/**
51 * xmlTreeErrMemory:
52 * @extra: extra informations
53 *
54 * Handle an out of memory condition
55 */
56static void
57xmlTreeErrMemory(const char *extra)
58{
59 __xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra);
60}
61
62/**
63 * xmlTreeErr:
64 * @code: the error number
65 * @extra: extra informations
66 *
67 * Handle an out of memory condition
68 */
69static void
70xmlTreeErr(int code, xmlNodePtr node, const char *extra)
71{
72 const char *msg = NULL;
73
74 switch(code) {
75 case XML_TREE_INVALID_HEX:
Daniel Veillardac996a12004-07-30 12:02:58 +000076 msg = "invalid hexadecimal character value\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000077 break;
78 case XML_TREE_INVALID_DEC:
Daniel Veillardac996a12004-07-30 12:02:58 +000079 msg = "invalid decimal character value\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000080 break;
81 case XML_TREE_UNTERMINATED_ENTITY:
Daniel Veillardac996a12004-07-30 12:02:58 +000082 msg = "unterminated entity reference %15s\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000083 break;
84 default:
Daniel Veillardac996a12004-07-30 12:02:58 +000085 msg = "unexpected error number\n";
Daniel Veillard18ec16e2003-10-07 23:16:40 +000086 }
87 __xmlSimpleError(XML_FROM_TREE, code, node, msg, extra);
88}
89
90/************************************************************************
91 * *
Daniel Veillard56a4cb82001-03-24 17:00:36 +000092 * A few static variables and macros *
93 * *
94 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +000095/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +000096const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000097/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +000098const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +000099 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +0000100/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +0000101const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
102
Owen Taylor3473f882001-02-23 17:55:21 +0000103static int xmlCompressMode = 0;
104static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000105
Owen Taylor3473f882001-02-23 17:55:21 +0000106#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
107 xmlNodePtr ulccur = (n)->children; \
108 if (ulccur == NULL) { \
109 (n)->last = NULL; \
110 } else { \
111 while (ulccur->next != NULL) { \
112 ulccur->parent = (n); \
113 ulccur = ulccur->next; \
114 } \
115 ulccur->parent = (n); \
116 (n)->last = ulccur; \
117}}
118
119/* #define DEBUG_BUFFER */
120/* #define DEBUG_TREE */
121
122/************************************************************************
123 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000124 * Functions to move to entities.c once the *
125 * API freeze is smoothen and they can be made public. *
126 * *
127 ************************************************************************/
128#include <libxml/hash.h>
129
Daniel Veillard652327a2003-09-29 18:02:38 +0000130#ifdef LIBXML_TREE_ENABLED
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000131/**
132 * xmlGetEntityFromDtd:
133 * @dtd: A pointer to the DTD to search
134 * @name: The entity name
135 *
136 * Do an entity lookup in the DTD entity hash table and
137 * return the corresponding entity, if found.
138 *
139 * Returns A pointer to the entity structure or NULL if not found.
140 */
141static xmlEntityPtr
142xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
143 xmlEntitiesTablePtr table;
144
145 if((dtd != NULL) && (dtd->entities != NULL)) {
146 table = (xmlEntitiesTablePtr) dtd->entities;
147 return((xmlEntityPtr) xmlHashLookup(table, name));
148 /* return(xmlGetEntityFromTable(table, name)); */
149 }
150 return(NULL);
151}
152/**
153 * xmlGetParameterEntityFromDtd:
154 * @dtd: A pointer to the DTD to search
155 * @name: The entity name
156 *
157 * Do an entity lookup in the DTD pararmeter entity hash table and
158 * return the corresponding entity, if found.
159 *
160 * Returns A pointer to the entity structure or NULL if not found.
161 */
162static xmlEntityPtr
163xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
164 xmlEntitiesTablePtr table;
165
166 if ((dtd != NULL) && (dtd->pentities != NULL)) {
167 table = (xmlEntitiesTablePtr) dtd->pentities;
168 return((xmlEntityPtr) xmlHashLookup(table, name));
169 /* return(xmlGetEntityFromTable(table, name)); */
170 }
171 return(NULL);
172}
Daniel Veillard652327a2003-09-29 18:02:38 +0000173#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000174
175/************************************************************************
176 * *
Daniel Veillardc00cda82003-04-07 10:22:39 +0000177 * QName handling helper *
178 * *
179 ************************************************************************/
180
181/**
182 * xmlBuildQName:
183 * @ncname: the Name
184 * @prefix: the prefix
185 * @memory: preallocated memory
186 * @len: preallocated memory length
187 *
188 * Builds the QName @prefix:@ncname in @memory if there is enough space
189 * and prefix is not NULL nor empty, otherwise allocate a new string.
190 * If prefix is NULL or empty it returns ncname.
191 *
192 * Returns the new string which must be freed by the caller if different from
193 * @memory and @ncname or NULL in case of error
194 */
195xmlChar *
196xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix,
197 xmlChar *memory, int len) {
198 int lenn, lenp;
199 xmlChar *ret;
200
Daniel Veillard3b7840c2003-09-11 23:42:01 +0000201 if (ncname == NULL) return(NULL);
202 if (prefix == NULL) return((xmlChar *) ncname);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000203
204 lenn = strlen((char *) ncname);
205 lenp = strlen((char *) prefix);
206
207 if ((memory == NULL) || (len < lenn + lenp + 2)) {
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000208 ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000209 if (ret == NULL) {
210 xmlTreeErrMemory("building QName");
211 return(NULL);
212 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000213 } else {
214 ret = memory;
215 }
216 memcpy(&ret[0], prefix, lenp);
217 ret[lenp] = ':';
218 memcpy(&ret[lenp + 1], ncname, lenn);
219 ret[lenn + lenp + 1] = 0;
220 return(ret);
221}
222
223/**
224 * xmlSplitQName2:
225 * @name: the full QName
226 * @prefix: a xmlChar **
227 *
228 * parse an XML qualified name string
229 *
230 * [NS 5] QName ::= (Prefix ':')? LocalPart
231 *
232 * [NS 6] Prefix ::= NCName
233 *
234 * [NS 7] LocalPart ::= NCName
235 *
236 * Returns NULL if not a QName, otherwise the local part, and prefix
237 * is updated to get the Prefix if any.
238 */
239
240xmlChar *
241xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
242 int len = 0;
243 xmlChar *ret = NULL;
244
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000245 if (prefix == NULL) return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000246 *prefix = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000247 if (name == NULL) return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000248
249#ifndef XML_XML_NAMESPACE
250 /* xml: prefix is not really a namespace */
251 if ((name[0] == 'x') && (name[1] == 'm') &&
252 (name[2] == 'l') && (name[3] == ':'))
253 return(NULL);
254#endif
255
256 /* nasty but valid */
257 if (name[0] == ':')
258 return(NULL);
259
260 /*
261 * we are not trying to validate but just to cut, and yes it will
262 * work even if this is as set of UTF-8 encoded chars
263 */
264 while ((name[len] != 0) && (name[len] != ':'))
265 len++;
266
267 if (name[len] == 0)
268 return(NULL);
269
270 *prefix = xmlStrndup(name, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000271 if (*prefix == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000272 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000273 return(NULL);
274 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000275 ret = xmlStrdup(&name[len + 1]);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000276 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000277 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000278 if (*prefix != NULL) {
279 xmlFree(*prefix);
280 *prefix = NULL;
281 }
282 return(NULL);
283 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000284
285 return(ret);
286}
287
Daniel Veillard8d73bcb2003-08-04 01:06:15 +0000288/**
289 * xmlSplitQName3:
290 * @name: the full QName
291 * @len: an int *
292 *
293 * parse an XML qualified name string,i
294 *
295 * returns NULL if it is not a Qualified Name, otherwise, update len
296 * with the lenght in byte of the prefix and return a pointer
297 */
298
299const xmlChar *
300xmlSplitQName3(const xmlChar *name, int *len) {
301 int l = 0;
302
303 if (name == NULL) return(NULL);
304 if (len == NULL) return(NULL);
305
306 /* nasty but valid */
307 if (name[0] == ':')
308 return(NULL);
309
310 /*
311 * we are not trying to validate but just to cut, and yes it will
312 * work even if this is as set of UTF-8 encoded chars
313 */
314 while ((name[l] != 0) && (name[l] != ':'))
315 l++;
316
317 if (name[l] == 0)
318 return(NULL);
319
320 *len = l;
321
322 return(&name[l+1]);
323}
324
Daniel Veillardc00cda82003-04-07 10:22:39 +0000325/************************************************************************
326 * *
Daniel Veillardd2298792003-02-14 16:54:11 +0000327 * Check Name, NCName and QName strings *
328 * *
329 ************************************************************************/
330
331#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
332
Daniel Veillard03a53c32004-10-26 16:06:51 +0000333#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
Daniel Veillardd2298792003-02-14 16:54:11 +0000334/**
335 * xmlValidateNCName:
336 * @value: the value to check
337 * @space: allow spaces in front and end of the string
338 *
339 * Check that a value conforms to the lexical space of NCName
340 *
341 * Returns 0 if this validates, a positive error code number otherwise
342 * and -1 in case of internal or API error.
343 */
344int
345xmlValidateNCName(const xmlChar *value, int space) {
346 const xmlChar *cur = value;
347 int c,l;
348
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000349 if (value == NULL)
350 return(-1);
351
Daniel Veillardd2298792003-02-14 16:54:11 +0000352 /*
353 * First quick algorithm for ASCII range
354 */
355 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000356 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000357 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
358 (*cur == '_'))
359 cur++;
360 else
361 goto try_complex;
362 while (((*cur >= 'a') && (*cur <= 'z')) ||
363 ((*cur >= 'A') && (*cur <= 'Z')) ||
364 ((*cur >= '0') && (*cur <= '9')) ||
365 (*cur == '_') || (*cur == '-') || (*cur == '.'))
366 cur++;
367 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000368 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000369 if (*cur == 0)
370 return(0);
371
372try_complex:
373 /*
374 * Second check for chars outside the ASCII range
375 */
376 cur = value;
377 c = CUR_SCHAR(cur, l);
378 if (space) {
379 while (IS_BLANK(c)) {
380 cur += l;
381 c = CUR_SCHAR(cur, l);
382 }
383 }
William M. Brack871611b2003-10-18 04:53:14 +0000384 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000385 return(1);
386 cur += l;
387 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000388 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
389 (c == '-') || (c == '_') || IS_COMBINING(c) ||
390 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000391 cur += l;
392 c = CUR_SCHAR(cur, l);
393 }
394 if (space) {
395 while (IS_BLANK(c)) {
396 cur += l;
397 c = CUR_SCHAR(cur, l);
398 }
399 }
400 if (c != 0)
401 return(1);
402
403 return(0);
404}
Daniel Veillard2156d432004-03-04 15:59:36 +0000405#endif
Daniel Veillardd2298792003-02-14 16:54:11 +0000406
Daniel Veillard2156d432004-03-04 15:59:36 +0000407#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Daniel Veillardd2298792003-02-14 16:54:11 +0000408/**
409 * xmlValidateQName:
410 * @value: the value to check
411 * @space: allow spaces in front and end of the string
412 *
413 * Check that a value conforms to the lexical space of QName
414 *
415 * Returns 0 if this validates, a positive error code number otherwise
416 * and -1 in case of internal or API error.
417 */
418int
419xmlValidateQName(const xmlChar *value, int space) {
420 const xmlChar *cur = value;
421 int c,l;
422
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000423 if (value == NULL)
424 return(-1);
Daniel Veillardd2298792003-02-14 16:54:11 +0000425 /*
426 * First quick algorithm for ASCII range
427 */
428 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000429 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000430 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
431 (*cur == '_'))
432 cur++;
433 else
434 goto try_complex;
435 while (((*cur >= 'a') && (*cur <= 'z')) ||
436 ((*cur >= 'A') && (*cur <= 'Z')) ||
437 ((*cur >= '0') && (*cur <= '9')) ||
438 (*cur == '_') || (*cur == '-') || (*cur == '.'))
439 cur++;
440 if (*cur == ':') {
441 cur++;
442 if (((*cur >= 'a') && (*cur <= 'z')) ||
443 ((*cur >= 'A') && (*cur <= 'Z')) ||
444 (*cur == '_'))
445 cur++;
446 else
447 goto try_complex;
448 while (((*cur >= 'a') && (*cur <= 'z')) ||
449 ((*cur >= 'A') && (*cur <= 'Z')) ||
450 ((*cur >= '0') && (*cur <= '9')) ||
451 (*cur == '_') || (*cur == '-') || (*cur == '.'))
452 cur++;
453 }
454 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000455 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000456 if (*cur == 0)
457 return(0);
458
459try_complex:
460 /*
461 * Second check for chars outside the ASCII range
462 */
463 cur = value;
464 c = CUR_SCHAR(cur, l);
465 if (space) {
466 while (IS_BLANK(c)) {
467 cur += l;
468 c = CUR_SCHAR(cur, l);
469 }
470 }
William M. Brack871611b2003-10-18 04:53:14 +0000471 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000472 return(1);
473 cur += l;
474 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000475 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
476 (c == '-') || (c == '_') || IS_COMBINING(c) ||
477 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000478 cur += l;
479 c = CUR_SCHAR(cur, l);
480 }
481 if (c == ':') {
482 cur += l;
483 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000484 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000485 return(1);
486 cur += l;
487 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000488 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
489 (c == '-') || (c == '_') || IS_COMBINING(c) ||
490 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000491 cur += l;
492 c = CUR_SCHAR(cur, l);
493 }
494 }
495 if (space) {
496 while (IS_BLANK(c)) {
497 cur += l;
498 c = CUR_SCHAR(cur, l);
499 }
500 }
501 if (c != 0)
502 return(1);
503 return(0);
504}
505
506/**
507 * xmlValidateName:
508 * @value: the value to check
509 * @space: allow spaces in front and end of the string
510 *
511 * Check that a value conforms to the lexical space of Name
512 *
513 * Returns 0 if this validates, a positive error code number otherwise
514 * and -1 in case of internal or API error.
515 */
516int
517xmlValidateName(const xmlChar *value, int space) {
518 const xmlChar *cur = value;
519 int c,l;
520
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000521 if (value == NULL)
522 return(-1);
Daniel Veillardd2298792003-02-14 16:54:11 +0000523 /*
524 * First quick algorithm for ASCII range
525 */
526 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000527 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000528 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
529 (*cur == '_') || (*cur == ':'))
530 cur++;
531 else
532 goto try_complex;
533 while (((*cur >= 'a') && (*cur <= 'z')) ||
534 ((*cur >= 'A') && (*cur <= 'Z')) ||
535 ((*cur >= '0') && (*cur <= '9')) ||
536 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
537 cur++;
538 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000539 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000540 if (*cur == 0)
541 return(0);
542
543try_complex:
544 /*
545 * Second check for chars outside the ASCII range
546 */
547 cur = value;
548 c = CUR_SCHAR(cur, l);
549 if (space) {
550 while (IS_BLANK(c)) {
551 cur += l;
552 c = CUR_SCHAR(cur, l);
553 }
554 }
William M. Brack871611b2003-10-18 04:53:14 +0000555 if ((!IS_LETTER(c)) && (c != '_') && (c != ':'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000556 return(1);
557 cur += l;
558 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000559 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
560 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000561 cur += l;
562 c = CUR_SCHAR(cur, l);
563 }
564 if (space) {
565 while (IS_BLANK(c)) {
566 cur += l;
567 c = CUR_SCHAR(cur, l);
568 }
569 }
570 if (c != 0)
571 return(1);
572 return(0);
573}
574
Daniel Veillardd4310742003-02-18 21:12:46 +0000575/**
576 * xmlValidateNMToken:
577 * @value: the value to check
578 * @space: allow spaces in front and end of the string
579 *
580 * Check that a value conforms to the lexical space of NMToken
581 *
582 * Returns 0 if this validates, a positive error code number otherwise
583 * and -1 in case of internal or API error.
584 */
585int
586xmlValidateNMToken(const xmlChar *value, int space) {
587 const xmlChar *cur = value;
588 int c,l;
589
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000590 if (value == NULL)
591 return(-1);
Daniel Veillardd4310742003-02-18 21:12:46 +0000592 /*
593 * First quick algorithm for ASCII range
594 */
595 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000596 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000597 if (((*cur >= 'a') && (*cur <= 'z')) ||
598 ((*cur >= 'A') && (*cur <= 'Z')) ||
599 ((*cur >= '0') && (*cur <= '9')) ||
600 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
601 cur++;
602 else
603 goto try_complex;
604 while (((*cur >= 'a') && (*cur <= 'z')) ||
605 ((*cur >= 'A') && (*cur <= 'Z')) ||
606 ((*cur >= '0') && (*cur <= '9')) ||
607 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
608 cur++;
609 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000610 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000611 if (*cur == 0)
612 return(0);
613
614try_complex:
615 /*
616 * Second check for chars outside the ASCII range
617 */
618 cur = value;
619 c = CUR_SCHAR(cur, l);
620 if (space) {
621 while (IS_BLANK(c)) {
622 cur += l;
623 c = CUR_SCHAR(cur, l);
624 }
625 }
William M. Brack871611b2003-10-18 04:53:14 +0000626 if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
627 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)))
Daniel Veillardd4310742003-02-18 21:12:46 +0000628 return(1);
629 cur += l;
630 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000631 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
632 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd4310742003-02-18 21:12:46 +0000633 cur += l;
634 c = CUR_SCHAR(cur, l);
635 }
636 if (space) {
637 while (IS_BLANK(c)) {
638 cur += l;
639 c = CUR_SCHAR(cur, l);
640 }
641 }
642 if (c != 0)
643 return(1);
644 return(0);
645}
Daniel Veillard652327a2003-09-29 18:02:38 +0000646#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardd4310742003-02-18 21:12:46 +0000647
Daniel Veillardd2298792003-02-14 16:54:11 +0000648/************************************************************************
649 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000650 * Allocation and deallocation of basic structures *
651 * *
652 ************************************************************************/
653
654/**
655 * xmlSetBufferAllocationScheme:
656 * @scheme: allocation method to use
657 *
658 * Set the buffer allocation method. Types are
659 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
660 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
661 * improves performance
662 */
663void
664xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
665 xmlBufferAllocScheme = scheme;
666}
667
668/**
669 * xmlGetBufferAllocationScheme:
670 *
671 * Types are
672 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
673 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
674 * improves performance
675 *
676 * Returns the current allocation scheme
677 */
678xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000679xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000680 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000681}
682
683/**
684 * xmlNewNs:
685 * @node: the element carrying the namespace
686 * @href: the URI associated
687 * @prefix: the prefix for the namespace
688 *
689 * Creation of a new Namespace. This function will refuse to create
690 * a namespace with a similar prefix than an existing one present on this
691 * node.
692 * We use href==NULL in the case of an element creation where the namespace
693 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000694 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000695 */
696xmlNsPtr
697xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
698 xmlNsPtr cur;
699
700 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
701 return(NULL);
702
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000703 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
704 return(NULL);
705
Owen Taylor3473f882001-02-23 17:55:21 +0000706 /*
707 * Allocate a new Namespace and fill the fields.
708 */
709 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
710 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000711 xmlTreeErrMemory("building namespace");
Owen Taylor3473f882001-02-23 17:55:21 +0000712 return(NULL);
713 }
714 memset(cur, 0, sizeof(xmlNs));
715 cur->type = XML_LOCAL_NAMESPACE;
716
717 if (href != NULL)
718 cur->href = xmlStrdup(href);
719 if (prefix != NULL)
720 cur->prefix = xmlStrdup(prefix);
721
722 /*
723 * Add it at the end to preserve parsing order ...
724 * and checks for existing use of the prefix
725 */
726 if (node != NULL) {
727 if (node->nsDef == NULL) {
728 node->nsDef = cur;
729 } else {
730 xmlNsPtr prev = node->nsDef;
731
732 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
733 (xmlStrEqual(prev->prefix, cur->prefix))) {
734 xmlFreeNs(cur);
735 return(NULL);
736 }
737 while (prev->next != NULL) {
738 prev = prev->next;
739 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
740 (xmlStrEqual(prev->prefix, cur->prefix))) {
741 xmlFreeNs(cur);
742 return(NULL);
743 }
744 }
745 prev->next = cur;
746 }
747 }
748 return(cur);
749}
750
751/**
752 * xmlSetNs:
753 * @node: a node in the document
754 * @ns: a namespace pointer
755 *
756 * Associate a namespace to a node, a posteriori.
757 */
758void
759xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
760 if (node == NULL) {
761#ifdef DEBUG_TREE
762 xmlGenericError(xmlGenericErrorContext,
763 "xmlSetNs: node == NULL\n");
764#endif
765 return;
766 }
767 node->ns = ns;
768}
769
770/**
771 * xmlFreeNs:
772 * @cur: the namespace pointer
773 *
774 * Free up the structures associated to a namespace
775 */
776void
777xmlFreeNs(xmlNsPtr cur) {
778 if (cur == NULL) {
779#ifdef DEBUG_TREE
780 xmlGenericError(xmlGenericErrorContext,
781 "xmlFreeNs : ns == NULL\n");
782#endif
783 return;
784 }
785 if (cur->href != NULL) xmlFree((char *) cur->href);
786 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000787 xmlFree(cur);
788}
789
790/**
791 * xmlFreeNsList:
792 * @cur: the first namespace pointer
793 *
794 * Free up all the structures associated to the chained namespaces.
795 */
796void
797xmlFreeNsList(xmlNsPtr cur) {
798 xmlNsPtr next;
799 if (cur == NULL) {
800#ifdef DEBUG_TREE
801 xmlGenericError(xmlGenericErrorContext,
802 "xmlFreeNsList : ns == NULL\n");
803#endif
804 return;
805 }
806 while (cur != NULL) {
807 next = cur->next;
808 xmlFreeNs(cur);
809 cur = next;
810 }
811}
812
813/**
814 * xmlNewDtd:
815 * @doc: the document pointer
816 * @name: the DTD name
817 * @ExternalID: the external ID
818 * @SystemID: the system ID
819 *
820 * Creation of a new DTD for the external subset. To create an
821 * internal subset, use xmlCreateIntSubset().
822 *
823 * Returns a pointer to the new DTD structure
824 */
825xmlDtdPtr
826xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
827 const xmlChar *ExternalID, const xmlChar *SystemID) {
828 xmlDtdPtr cur;
829
830 if ((doc != NULL) && (doc->extSubset != NULL)) {
831#ifdef DEBUG_TREE
832 xmlGenericError(xmlGenericErrorContext,
833 "xmlNewDtd(%s): document %s already have a DTD %s\n",
834 /* !!! */ (char *) name, doc->name,
835 /* !!! */ (char *)doc->extSubset->name);
836#endif
837 return(NULL);
838 }
839
840 /*
841 * Allocate a new DTD and fill the fields.
842 */
843 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
844 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000845 xmlTreeErrMemory("building DTD");
Owen Taylor3473f882001-02-23 17:55:21 +0000846 return(NULL);
847 }
848 memset(cur, 0 , sizeof(xmlDtd));
849 cur->type = XML_DTD_NODE;
850
851 if (name != NULL)
852 cur->name = xmlStrdup(name);
853 if (ExternalID != NULL)
854 cur->ExternalID = xmlStrdup(ExternalID);
855 if (SystemID != NULL)
856 cur->SystemID = xmlStrdup(SystemID);
857 if (doc != NULL)
858 doc->extSubset = cur;
859 cur->doc = doc;
860
Daniel Veillarda880b122003-04-21 21:36:41 +0000861 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000862 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000863 return(cur);
864}
865
866/**
867 * xmlGetIntSubset:
868 * @doc: the document pointer
869 *
870 * Get the internal subset of a document
871 * Returns a pointer to the DTD structure or NULL if not found
872 */
873
874xmlDtdPtr
875xmlGetIntSubset(xmlDocPtr doc) {
876 xmlNodePtr cur;
877
878 if (doc == NULL)
879 return(NULL);
880 cur = doc->children;
881 while (cur != NULL) {
882 if (cur->type == XML_DTD_NODE)
883 return((xmlDtdPtr) cur);
884 cur = cur->next;
885 }
886 return((xmlDtdPtr) doc->intSubset);
887}
888
889/**
890 * xmlCreateIntSubset:
891 * @doc: the document pointer
892 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000893 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000894 * @SystemID: the system ID
895 *
896 * Create the internal subset of a document
897 * Returns a pointer to the new DTD structure
898 */
899xmlDtdPtr
900xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
901 const xmlChar *ExternalID, const xmlChar *SystemID) {
902 xmlDtdPtr cur;
903
904 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
905#ifdef DEBUG_TREE
906 xmlGenericError(xmlGenericErrorContext,
907
908 "xmlCreateIntSubset(): document %s already have an internal subset\n",
909 doc->name);
910#endif
911 return(NULL);
912 }
913
914 /*
915 * Allocate a new DTD and fill the fields.
916 */
917 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
918 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000919 xmlTreeErrMemory("building internal subset");
Owen Taylor3473f882001-02-23 17:55:21 +0000920 return(NULL);
921 }
922 memset(cur, 0, sizeof(xmlDtd));
923 cur->type = XML_DTD_NODE;
924
William M. Bracka3215c72004-07-31 16:24:01 +0000925 if (name != NULL) {
926 cur->name = xmlStrdup(name);
927 if (cur->name == NULL) {
928 xmlTreeErrMemory("building internal subset");
929 xmlFree(cur);
930 return(NULL);
931 }
932 }
933 if (ExternalID != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000934 cur->ExternalID = xmlStrdup(ExternalID);
William M. Bracka3215c72004-07-31 16:24:01 +0000935 if (cur->ExternalID == NULL) {
936 xmlTreeErrMemory("building internal subset");
937 if (cur->name != NULL)
938 xmlFree((char *)cur->name);
939 xmlFree(cur);
940 return(NULL);
941 }
942 }
943 if (SystemID != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000944 cur->SystemID = xmlStrdup(SystemID);
William M. Bracka3215c72004-07-31 16:24:01 +0000945 if (cur->SystemID == NULL) {
946 xmlTreeErrMemory("building internal subset");
947 if (cur->name != NULL)
948 xmlFree((char *)cur->name);
949 if (cur->ExternalID != NULL)
950 xmlFree((char *)cur->ExternalID);
951 xmlFree(cur);
952 return(NULL);
953 }
954 }
Owen Taylor3473f882001-02-23 17:55:21 +0000955 if (doc != NULL) {
956 doc->intSubset = cur;
957 cur->parent = doc;
958 cur->doc = doc;
959 if (doc->children == NULL) {
960 doc->children = (xmlNodePtr) cur;
961 doc->last = (xmlNodePtr) cur;
962 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000963 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000964 xmlNodePtr prev;
965
Owen Taylor3473f882001-02-23 17:55:21 +0000966 prev = doc->children;
967 prev->prev = (xmlNodePtr) cur;
968 cur->next = prev;
969 doc->children = (xmlNodePtr) cur;
970 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000971 xmlNodePtr next;
972
973 next = doc->children;
974 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
975 next = next->next;
976 if (next == NULL) {
977 cur->prev = doc->last;
978 cur->prev->next = (xmlNodePtr) cur;
979 cur->next = NULL;
980 doc->last = (xmlNodePtr) cur;
981 } else {
982 cur->next = next;
983 cur->prev = next->prev;
984 if (cur->prev == NULL)
985 doc->children = (xmlNodePtr) cur;
986 else
987 cur->prev->next = (xmlNodePtr) cur;
988 next->prev = (xmlNodePtr) cur;
989 }
Owen Taylor3473f882001-02-23 17:55:21 +0000990 }
991 }
992 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000993
Daniel Veillarda880b122003-04-21 21:36:41 +0000994 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000995 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000996 return(cur);
997}
998
999/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001000 * DICT_FREE:
1001 * @str: a string
1002 *
1003 * Free a string if it is not owned by the "dict" dictionnary in the
1004 * current scope
1005 */
1006#define DICT_FREE(str) \
1007 if ((str) && ((!dict) || \
1008 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
1009 xmlFree((char *)(str));
1010
1011/**
Owen Taylor3473f882001-02-23 17:55:21 +00001012 * xmlFreeDtd:
1013 * @cur: the DTD structure to free up
1014 *
1015 * Free a DTD structure.
1016 */
1017void
1018xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001019 xmlDictPtr dict = NULL;
1020
Owen Taylor3473f882001-02-23 17:55:21 +00001021 if (cur == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001022 return;
1023 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001024 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001025
Daniel Veillarda880b122003-04-21 21:36:41 +00001026 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001027 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1028
Owen Taylor3473f882001-02-23 17:55:21 +00001029 if (cur->children != NULL) {
1030 xmlNodePtr next, c = cur->children;
1031
1032 /*
William M. Brack18a04f22004-08-03 16:42:37 +00001033 * Cleanup all nodes which are not part of the specific lists
1034 * of notations, elements, attributes and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00001035 */
1036 while (c != NULL) {
1037 next = c->next;
William M. Brack18a04f22004-08-03 16:42:37 +00001038 if ((c->type != XML_NOTATION_NODE) &&
1039 (c->type != XML_ELEMENT_DECL) &&
1040 (c->type != XML_ATTRIBUTE_DECL) &&
1041 (c->type != XML_ENTITY_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001042 xmlUnlinkNode(c);
1043 xmlFreeNode(c);
1044 }
1045 c = next;
1046 }
1047 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001048 DICT_FREE(cur->name)
1049 DICT_FREE(cur->SystemID)
1050 DICT_FREE(cur->ExternalID)
Owen Taylor3473f882001-02-23 17:55:21 +00001051 /* TODO !!! */
1052 if (cur->notations != NULL)
1053 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
1054
1055 if (cur->elements != NULL)
1056 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
1057 if (cur->attributes != NULL)
1058 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
1059 if (cur->entities != NULL)
1060 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
1061 if (cur->pentities != NULL)
1062 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
1063
Owen Taylor3473f882001-02-23 17:55:21 +00001064 xmlFree(cur);
1065}
1066
1067/**
1068 * xmlNewDoc:
1069 * @version: xmlChar string giving the version of XML "1.0"
1070 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001071 * Creates a new XML document
1072 *
Owen Taylor3473f882001-02-23 17:55:21 +00001073 * Returns a new document
1074 */
1075xmlDocPtr
1076xmlNewDoc(const xmlChar *version) {
1077 xmlDocPtr cur;
1078
1079 if (version == NULL)
1080 version = (const xmlChar *) "1.0";
1081
1082 /*
1083 * Allocate a new document and fill the fields.
1084 */
1085 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
1086 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001087 xmlTreeErrMemory("building doc");
Owen Taylor3473f882001-02-23 17:55:21 +00001088 return(NULL);
1089 }
1090 memset(cur, 0, sizeof(xmlDoc));
1091 cur->type = XML_DOCUMENT_NODE;
1092
1093 cur->version = xmlStrdup(version);
William M. Bracka3215c72004-07-31 16:24:01 +00001094 if (cur->version == NULL) {
1095 xmlTreeErrMemory("building doc");
1096 xmlFree(cur);
1097 return(NULL);
1098 }
Owen Taylor3473f882001-02-23 17:55:21 +00001099 cur->standalone = -1;
1100 cur->compression = -1; /* not initialized */
1101 cur->doc = cur;
Daniel Veillarda6874ca2003-07-29 16:47:24 +00001102 /*
1103 * The in memory encoding is always UTF8
1104 * This field will never change and would
1105 * be obsolete if not for binary compatibility.
1106 */
Daniel Veillardd2f3ec72001-04-11 07:50:02 +00001107 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001108
Daniel Veillarda880b122003-04-21 21:36:41 +00001109 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001110 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001111 return(cur);
1112}
1113
1114/**
1115 * xmlFreeDoc:
1116 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +00001117 *
1118 * Free up all the structures used by a document, tree included.
1119 */
1120void
1121xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +00001122 xmlDtdPtr extSubset, intSubset;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001123 xmlDictPtr dict = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001124
Owen Taylor3473f882001-02-23 17:55:21 +00001125 if (cur == NULL) {
1126#ifdef DEBUG_TREE
1127 xmlGenericError(xmlGenericErrorContext,
1128 "xmlFreeDoc : document == NULL\n");
1129#endif
1130 return;
1131 }
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001132#ifdef LIBXML_DEBUG_RUNTIME
1133 xmlDebugCheckDocument(stderr, cur);
1134#endif
1135
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001136 if (cur != NULL) dict = cur->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001137
Daniel Veillarda880b122003-04-21 21:36:41 +00001138 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001139 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1140
Daniel Veillard76d66f42001-05-16 21:05:17 +00001141 /*
1142 * Do this before freeing the children list to avoid ID lookups
1143 */
1144 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1145 cur->ids = NULL;
1146 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1147 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001148 extSubset = cur->extSubset;
1149 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +00001150 if (intSubset == extSubset)
1151 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001152 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001153 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001154 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001155 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001156 }
Daniel Veillarda9142e72001-06-19 11:07:54 +00001157 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001158 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001159 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001160 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001161 }
1162
1163 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001164 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001165
1166 DICT_FREE(cur->version)
1167 DICT_FREE(cur->name)
1168 DICT_FREE(cur->encoding)
1169 DICT_FREE(cur->URL)
Owen Taylor3473f882001-02-23 17:55:21 +00001170 xmlFree(cur);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001171 if (dict) xmlDictFree(dict);
Owen Taylor3473f882001-02-23 17:55:21 +00001172}
1173
1174/**
1175 * xmlStringLenGetNodeList:
1176 * @doc: the document
1177 * @value: the value of the text
1178 * @len: the length of the string value
1179 *
1180 * Parse the value string and build the node list associated. Should
1181 * produce a flat tree with only TEXTs and ENTITY_REFs.
1182 * Returns a pointer to the first child
1183 */
1184xmlNodePtr
1185xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1186 xmlNodePtr ret = NULL, last = NULL;
1187 xmlNodePtr node;
1188 xmlChar *val;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001189 const xmlChar *cur = value, *end = cur + len;
Owen Taylor3473f882001-02-23 17:55:21 +00001190 const xmlChar *q;
1191 xmlEntityPtr ent;
1192
1193 if (value == NULL) return(NULL);
1194
1195 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001196 while ((cur < end) && (*cur != 0)) {
1197 if (cur[0] == '&') {
1198 int charval = 0;
1199 xmlChar tmp;
1200
Owen Taylor3473f882001-02-23 17:55:21 +00001201 /*
1202 * Save the current text.
1203 */
1204 if (cur != q) {
1205 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1206 xmlNodeAddContentLen(last, q, cur - q);
1207 } else {
1208 node = xmlNewDocTextLen(doc, q, cur - q);
1209 if (node == NULL) return(ret);
1210 if (last == NULL)
1211 last = ret = node;
1212 else {
1213 last->next = node;
1214 node->prev = last;
1215 last = node;
1216 }
1217 }
1218 }
Owen Taylor3473f882001-02-23 17:55:21 +00001219 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001220 if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
1221 cur += 3;
1222 if (cur < end)
1223 tmp = *cur;
1224 else
1225 tmp = 0;
1226 while (tmp != ';') { /* Non input consuming loop */
1227 if ((tmp >= '0') && (tmp <= '9'))
1228 charval = charval * 16 + (tmp - '0');
1229 else if ((tmp >= 'a') && (tmp <= 'f'))
1230 charval = charval * 16 + (tmp - 'a') + 10;
1231 else if ((tmp >= 'A') && (tmp <= 'F'))
1232 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001233 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001234 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1235 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001236 charval = 0;
1237 break;
1238 }
1239 cur++;
1240 if (cur < end)
1241 tmp = *cur;
1242 else
1243 tmp = 0;
1244 }
1245 if (tmp == ';')
1246 cur++;
1247 q = cur;
1248 } else if ((cur + 1 < end) && (cur[1] == '#')) {
1249 cur += 2;
1250 if (cur < end)
1251 tmp = *cur;
1252 else
1253 tmp = 0;
1254 while (tmp != ';') { /* Non input consuming loops */
1255 if ((tmp >= '0') && (tmp <= '9'))
1256 charval = charval * 10 + (tmp - '0');
1257 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001258 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1259 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001260 charval = 0;
1261 break;
1262 }
1263 cur++;
1264 if (cur < end)
1265 tmp = *cur;
1266 else
1267 tmp = 0;
1268 }
1269 if (tmp == ';')
1270 cur++;
1271 q = cur;
1272 } else {
1273 /*
1274 * Read the entity string
1275 */
1276 cur++;
1277 q = cur;
1278 while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1279 if ((cur >= end) || (*cur == 0)) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001280 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc,
1281 (const char *) q);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001282 return(ret);
1283 }
1284 if (cur != q) {
1285 /*
1286 * Predefined entities don't generate nodes
1287 */
1288 val = xmlStrndup(q, cur - q);
1289 ent = xmlGetDocEntity(doc, val);
1290 if ((ent != NULL) &&
1291 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1292 if (last == NULL) {
1293 node = xmlNewDocText(doc, ent->content);
1294 last = ret = node;
1295 } else if (last->type != XML_TEXT_NODE) {
1296 node = xmlNewDocText(doc, ent->content);
1297 last = xmlAddNextSibling(last, node);
1298 } else
1299 xmlNodeAddContent(last, ent->content);
1300
1301 } else {
1302 /*
1303 * Create a new REFERENCE_REF node
1304 */
1305 node = xmlNewReference(doc, val);
1306 if (node == NULL) {
1307 if (val != NULL) xmlFree(val);
1308 return(ret);
1309 }
1310 else if ((ent != NULL) && (ent->children == NULL)) {
1311 xmlNodePtr temp;
1312
1313 ent->children = xmlStringGetNodeList(doc,
1314 (const xmlChar*)node->content);
1315 ent->owner = 1;
1316 temp = ent->children;
1317 while (temp) {
1318 temp->parent = (xmlNodePtr)ent;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00001319 ent->last = temp;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001320 temp = temp->next;
1321 }
1322 }
1323 if (last == NULL) {
1324 last = ret = node;
1325 } else {
1326 last = xmlAddNextSibling(last, node);
1327 }
1328 }
1329 xmlFree(val);
1330 }
1331 cur++;
1332 q = cur;
1333 }
1334 if (charval != 0) {
1335 xmlChar buf[10];
1336 int l;
1337
1338 l = xmlCopyCharMultiByte(buf, charval);
1339 buf[l] = 0;
1340 node = xmlNewDocText(doc, buf);
1341 if (node != NULL) {
1342 if (last == NULL) {
1343 last = ret = node;
1344 } else {
1345 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001346 }
1347 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001348 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001349 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001350 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001351 cur++;
1352 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001353 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001354 /*
1355 * Handle the last piece of text.
1356 */
1357 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1358 xmlNodeAddContentLen(last, q, cur - q);
1359 } else {
1360 node = xmlNewDocTextLen(doc, q, cur - q);
1361 if (node == NULL) return(ret);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001362 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001363 last = ret = node;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001364 } else {
1365 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001366 }
1367 }
1368 }
1369 return(ret);
1370}
1371
1372/**
1373 * xmlStringGetNodeList:
1374 * @doc: the document
1375 * @value: the value of the attribute
1376 *
1377 * Parse the value string and build the node list associated. Should
1378 * produce a flat tree with only TEXTs and ENTITY_REFs.
1379 * Returns a pointer to the first child
1380 */
1381xmlNodePtr
1382xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1383 xmlNodePtr ret = NULL, last = NULL;
1384 xmlNodePtr node;
1385 xmlChar *val;
1386 const xmlChar *cur = value;
1387 const xmlChar *q;
1388 xmlEntityPtr ent;
1389
1390 if (value == NULL) return(NULL);
1391
1392 q = cur;
1393 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001394 if (cur[0] == '&') {
1395 int charval = 0;
1396 xmlChar tmp;
1397
Owen Taylor3473f882001-02-23 17:55:21 +00001398 /*
1399 * Save the current text.
1400 */
1401 if (cur != q) {
1402 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1403 xmlNodeAddContentLen(last, q, cur - q);
1404 } else {
1405 node = xmlNewDocTextLen(doc, q, cur - q);
1406 if (node == NULL) return(ret);
1407 if (last == NULL)
1408 last = ret = node;
1409 else {
1410 last->next = node;
1411 node->prev = last;
1412 last = node;
1413 }
1414 }
1415 }
Owen Taylor3473f882001-02-23 17:55:21 +00001416 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001417 if ((cur[1] == '#') && (cur[2] == 'x')) {
1418 cur += 3;
1419 tmp = *cur;
1420 while (tmp != ';') { /* Non input consuming loop */
1421 if ((tmp >= '0') && (tmp <= '9'))
1422 charval = charval * 16 + (tmp - '0');
1423 else if ((tmp >= 'a') && (tmp <= 'f'))
1424 charval = charval * 16 + (tmp - 'a') + 10;
1425 else if ((tmp >= 'A') && (tmp <= 'F'))
1426 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001427 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001428 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1429 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001430 charval = 0;
1431 break;
1432 }
1433 cur++;
1434 tmp = *cur;
1435 }
1436 if (tmp == ';')
1437 cur++;
1438 q = cur;
1439 } else if (cur[1] == '#') {
1440 cur += 2;
1441 tmp = *cur;
1442 while (tmp != ';') { /* Non input consuming loops */
1443 if ((tmp >= '0') && (tmp <= '9'))
1444 charval = charval * 10 + (tmp - '0');
1445 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001446 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1447 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001448 charval = 0;
1449 break;
1450 }
1451 cur++;
1452 tmp = *cur;
1453 }
1454 if (tmp == ';')
1455 cur++;
1456 q = cur;
1457 } else {
1458 /*
1459 * Read the entity string
1460 */
1461 cur++;
1462 q = cur;
1463 while ((*cur != 0) && (*cur != ';')) cur++;
1464 if (*cur == 0) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001465 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY,
1466 (xmlNodePtr) doc, (const char *) q);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001467 return(ret);
1468 }
1469 if (cur != q) {
1470 /*
1471 * Predefined entities don't generate nodes
1472 */
1473 val = xmlStrndup(q, cur - q);
1474 ent = xmlGetDocEntity(doc, val);
1475 if ((ent != NULL) &&
1476 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1477 if (last == NULL) {
1478 node = xmlNewDocText(doc, ent->content);
1479 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001480 } else if (last->type != XML_TEXT_NODE) {
1481 node = xmlNewDocText(doc, ent->content);
1482 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001483 } else
1484 xmlNodeAddContent(last, ent->content);
1485
1486 } else {
1487 /*
1488 * Create a new REFERENCE_REF node
1489 */
1490 node = xmlNewReference(doc, val);
1491 if (node == NULL) {
1492 if (val != NULL) xmlFree(val);
1493 return(ret);
1494 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001495 else if ((ent != NULL) && (ent->children == NULL)) {
1496 xmlNodePtr temp;
1497
1498 ent->children = xmlStringGetNodeList(doc,
1499 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001500 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001501 temp = ent->children;
1502 while (temp) {
1503 temp->parent = (xmlNodePtr)ent;
1504 temp = temp->next;
1505 }
1506 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001507 if (last == NULL) {
1508 last = ret = node;
1509 } else {
1510 last = xmlAddNextSibling(last, node);
1511 }
1512 }
1513 xmlFree(val);
1514 }
1515 cur++;
1516 q = cur;
1517 }
1518 if (charval != 0) {
1519 xmlChar buf[10];
1520 int len;
1521
1522 len = xmlCopyCharMultiByte(buf, charval);
1523 buf[len] = 0;
1524 node = xmlNewDocText(doc, buf);
1525 if (node != NULL) {
1526 if (last == NULL) {
1527 last = ret = node;
1528 } else {
1529 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001530 }
1531 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001532
1533 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001534 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001535 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001536 cur++;
1537 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001538 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001539 /*
1540 * Handle the last piece of text.
1541 */
1542 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1543 xmlNodeAddContentLen(last, q, cur - q);
1544 } else {
1545 node = xmlNewDocTextLen(doc, q, cur - q);
1546 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001547 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001548 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001549 } else {
1550 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001551 }
1552 }
1553 }
1554 return(ret);
1555}
1556
1557/**
1558 * xmlNodeListGetString:
1559 * @doc: the document
1560 * @list: a Node list
1561 * @inLine: should we replace entity contents or show their external form
1562 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001563 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001564 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001565 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001566 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001567 */
1568xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001569xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1570{
Owen Taylor3473f882001-02-23 17:55:21 +00001571 xmlNodePtr node = list;
1572 xmlChar *ret = NULL;
1573 xmlEntityPtr ent;
1574
Daniel Veillard7646b182002-04-20 06:41:40 +00001575 if (list == NULL)
1576 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001577
1578 while (node != NULL) {
1579 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001580 (node->type == XML_CDATA_SECTION_NODE)) {
1581 if (inLine) {
1582 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001583 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001584 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001585
Daniel Veillard7646b182002-04-20 06:41:40 +00001586 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1587 if (buffer != NULL) {
1588 ret = xmlStrcat(ret, buffer);
1589 xmlFree(buffer);
1590 }
1591 }
1592 } else if (node->type == XML_ENTITY_REF_NODE) {
1593 if (inLine) {
1594 ent = xmlGetDocEntity(doc, node->name);
1595 if (ent != NULL) {
1596 xmlChar *buffer;
1597
1598 /* an entity content can be any "well balanced chunk",
1599 * i.e. the result of the content [43] production:
1600 * http://www.w3.org/TR/REC-xml#NT-content.
1601 * So it can contain text, CDATA section or nested
1602 * entity reference nodes (among others).
1603 * -> we recursive call xmlNodeListGetString()
1604 * which handles these types */
1605 buffer = xmlNodeListGetString(doc, ent->children, 1);
1606 if (buffer != NULL) {
1607 ret = xmlStrcat(ret, buffer);
1608 xmlFree(buffer);
1609 }
1610 } else {
1611 ret = xmlStrcat(ret, node->content);
1612 }
1613 } else {
1614 xmlChar buf[2];
1615
1616 buf[0] = '&';
1617 buf[1] = 0;
1618 ret = xmlStrncat(ret, buf, 1);
1619 ret = xmlStrcat(ret, node->name);
1620 buf[0] = ';';
1621 buf[1] = 0;
1622 ret = xmlStrncat(ret, buf, 1);
1623 }
1624 }
1625#if 0
1626 else {
1627 xmlGenericError(xmlGenericErrorContext,
1628 "xmlGetNodeListString : invalid node type %d\n",
1629 node->type);
1630 }
1631#endif
1632 node = node->next;
1633 }
1634 return (ret);
1635}
Daniel Veillard652327a2003-09-29 18:02:38 +00001636
1637#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001638/**
1639 * xmlNodeListGetRawString:
1640 * @doc: the document
1641 * @list: a Node list
1642 * @inLine: should we replace entity contents or show their external form
1643 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001644 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001645 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1646 * this function doesn't do any character encoding handling.
1647 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001648 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001649 */
1650xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001651xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1652{
Owen Taylor3473f882001-02-23 17:55:21 +00001653 xmlNodePtr node = list;
1654 xmlChar *ret = NULL;
1655 xmlEntityPtr ent;
1656
Daniel Veillard7646b182002-04-20 06:41:40 +00001657 if (list == NULL)
1658 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001659
1660 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001661 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001662 (node->type == XML_CDATA_SECTION_NODE)) {
1663 if (inLine) {
1664 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001665 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001666 xmlChar *buffer;
1667
1668 buffer = xmlEncodeSpecialChars(doc, node->content);
1669 if (buffer != NULL) {
1670 ret = xmlStrcat(ret, buffer);
1671 xmlFree(buffer);
1672 }
1673 }
1674 } else if (node->type == XML_ENTITY_REF_NODE) {
1675 if (inLine) {
1676 ent = xmlGetDocEntity(doc, node->name);
1677 if (ent != NULL) {
1678 xmlChar *buffer;
1679
1680 /* an entity content can be any "well balanced chunk",
1681 * i.e. the result of the content [43] production:
1682 * http://www.w3.org/TR/REC-xml#NT-content.
1683 * So it can contain text, CDATA section or nested
1684 * entity reference nodes (among others).
1685 * -> we recursive call xmlNodeListGetRawString()
1686 * which handles these types */
1687 buffer =
1688 xmlNodeListGetRawString(doc, ent->children, 1);
1689 if (buffer != NULL) {
1690 ret = xmlStrcat(ret, buffer);
1691 xmlFree(buffer);
1692 }
1693 } else {
1694 ret = xmlStrcat(ret, node->content);
1695 }
1696 } else {
1697 xmlChar buf[2];
1698
1699 buf[0] = '&';
1700 buf[1] = 0;
1701 ret = xmlStrncat(ret, buf, 1);
1702 ret = xmlStrcat(ret, node->name);
1703 buf[0] = ';';
1704 buf[1] = 0;
1705 ret = xmlStrncat(ret, buf, 1);
1706 }
1707 }
Owen Taylor3473f882001-02-23 17:55:21 +00001708#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001709 else {
1710 xmlGenericError(xmlGenericErrorContext,
1711 "xmlGetNodeListString : invalid node type %d\n",
1712 node->type);
1713 }
Owen Taylor3473f882001-02-23 17:55:21 +00001714#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001715 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001716 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001717 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001718}
Daniel Veillard652327a2003-09-29 18:02:38 +00001719#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001720
Daniel Veillard2156d432004-03-04 15:59:36 +00001721#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00001722/**
1723 * xmlNewProp:
1724 * @node: the holding node
1725 * @name: the name of the attribute
1726 * @value: the value of the attribute
1727 *
1728 * Create a new property carried by a node.
1729 * Returns a pointer to the attribute
1730 */
1731xmlAttrPtr
1732xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1733 xmlAttrPtr cur;
1734 xmlDocPtr doc = NULL;
1735
1736 if (name == NULL) {
1737#ifdef DEBUG_TREE
1738 xmlGenericError(xmlGenericErrorContext,
1739 "xmlNewProp : name == NULL\n");
1740#endif
1741 return(NULL);
1742 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00001743 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
1744 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001745
1746 /*
1747 * Allocate a new property and fill the fields.
1748 */
1749 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1750 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001751 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001752 return(NULL);
1753 }
1754 memset(cur, 0, sizeof(xmlAttr));
1755 cur->type = XML_ATTRIBUTE_NODE;
1756
1757 cur->parent = node;
1758 if (node != NULL) {
1759 doc = node->doc;
1760 cur->doc = doc;
1761 }
Daniel Veillard03a53c32004-10-26 16:06:51 +00001762 if ((doc != NULL) && (doc->dict != NULL))
1763 cur->name = (xmlChar *) xmlDictLookup(doc->dict, name, -1);
1764 else
1765 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00001766 if (value != NULL) {
1767 xmlChar *buffer;
1768 xmlNodePtr tmp;
1769
1770 buffer = xmlEncodeEntitiesReentrant(doc, value);
1771 cur->children = xmlStringGetNodeList(doc, buffer);
1772 cur->last = NULL;
1773 tmp = cur->children;
1774 while (tmp != NULL) {
1775 tmp->parent = (xmlNodePtr) cur;
1776 tmp->doc = doc;
1777 if (tmp->next == NULL)
1778 cur->last = tmp;
1779 tmp = tmp->next;
1780 }
1781 xmlFree(buffer);
1782 }
1783
1784 /*
1785 * Add it at the end to preserve parsing order ...
1786 */
1787 if (node != NULL) {
1788 if (node->properties == NULL) {
1789 node->properties = cur;
1790 } else {
1791 xmlAttrPtr prev = node->properties;
1792
1793 while (prev->next != NULL) prev = prev->next;
1794 prev->next = cur;
1795 cur->prev = prev;
1796 }
1797 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001798
Daniel Veillarda880b122003-04-21 21:36:41 +00001799 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001800 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001801 return(cur);
1802}
Daniel Veillard652327a2003-09-29 18:02:38 +00001803#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001804
1805/**
1806 * xmlNewNsProp:
1807 * @node: the holding node
1808 * @ns: the namespace
1809 * @name: the name of the attribute
1810 * @value: the value of the attribute
1811 *
1812 * Create a new property tagged with a namespace and carried by a node.
1813 * Returns a pointer to the attribute
1814 */
1815xmlAttrPtr
1816xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1817 const xmlChar *value) {
1818 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001819 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001820
1821 if (name == NULL) {
1822#ifdef DEBUG_TREE
1823 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001824 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001825#endif
1826 return(NULL);
1827 }
1828
1829 /*
1830 * Allocate a new property and fill the fields.
1831 */
1832 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1833 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001834 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001835 return(NULL);
1836 }
1837 memset(cur, 0, sizeof(xmlAttr));
1838 cur->type = XML_ATTRIBUTE_NODE;
1839
1840 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001841 if (node != NULL) {
1842 doc = node->doc;
1843 cur->doc = doc;
1844 }
Owen Taylor3473f882001-02-23 17:55:21 +00001845 cur->ns = ns;
Daniel Veillard03a53c32004-10-26 16:06:51 +00001846 if ((doc != NULL) && (doc->dict != NULL))
1847 cur->name = xmlDictLookup(doc->dict, name, -1);
1848 else
1849 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00001850 if (value != NULL) {
1851 xmlChar *buffer;
1852 xmlNodePtr tmp;
1853
Daniel Veillarda682b212001-06-07 19:59:42 +00001854 buffer = xmlEncodeEntitiesReentrant(doc, value);
1855 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001856 cur->last = NULL;
1857 tmp = cur->children;
1858 while (tmp != NULL) {
1859 tmp->parent = (xmlNodePtr) cur;
1860 if (tmp->next == NULL)
1861 cur->last = tmp;
1862 tmp = tmp->next;
1863 }
1864 xmlFree(buffer);
1865 }
1866
1867 /*
1868 * Add it at the end to preserve parsing order ...
1869 */
1870 if (node != NULL) {
1871 if (node->properties == NULL) {
1872 node->properties = cur;
1873 } else {
1874 xmlAttrPtr prev = node->properties;
1875
1876 while (prev->next != NULL) prev = prev->next;
1877 prev->next = cur;
1878 cur->prev = prev;
1879 }
1880 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001881
Daniel Veillarda880b122003-04-21 21:36:41 +00001882 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001883 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001884 return(cur);
1885}
1886
1887/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001888 * xmlNewNsPropEatName:
1889 * @node: the holding node
1890 * @ns: the namespace
1891 * @name: the name of the attribute
1892 * @value: the value of the attribute
1893 *
1894 * Create a new property tagged with a namespace and carried by a node.
1895 * Returns a pointer to the attribute
1896 */
1897xmlAttrPtr
1898xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1899 const xmlChar *value) {
1900 xmlAttrPtr cur;
1901 xmlDocPtr doc = NULL;
1902
1903 if (name == NULL) {
1904#ifdef DEBUG_TREE
1905 xmlGenericError(xmlGenericErrorContext,
1906 "xmlNewNsPropEatName : name == NULL\n");
1907#endif
1908 return(NULL);
1909 }
1910
1911 /*
1912 * Allocate a new property and fill the fields.
1913 */
1914 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1915 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001916 xmlTreeErrMemory("building attribute");
Daniel Veillard46de64e2002-05-29 08:21:33 +00001917 return(NULL);
1918 }
1919 memset(cur, 0, sizeof(xmlAttr));
1920 cur->type = XML_ATTRIBUTE_NODE;
1921
1922 cur->parent = node;
1923 if (node != NULL) {
1924 doc = node->doc;
1925 cur->doc = doc;
1926 }
1927 cur->ns = ns;
1928 cur->name = name;
1929 if (value != NULL) {
1930 xmlChar *buffer;
1931 xmlNodePtr tmp;
1932
1933 buffer = xmlEncodeEntitiesReentrant(doc, value);
1934 cur->children = xmlStringGetNodeList(doc, buffer);
1935 cur->last = NULL;
1936 tmp = cur->children;
1937 while (tmp != NULL) {
1938 tmp->parent = (xmlNodePtr) cur;
1939 if (tmp->next == NULL)
1940 cur->last = tmp;
1941 tmp = tmp->next;
1942 }
1943 xmlFree(buffer);
1944 }
1945
1946 /*
1947 * Add it at the end to preserve parsing order ...
1948 */
1949 if (node != NULL) {
1950 if (node->properties == NULL) {
1951 node->properties = cur;
1952 } else {
1953 xmlAttrPtr prev = node->properties;
1954
1955 while (prev->next != NULL) prev = prev->next;
1956 prev->next = cur;
1957 cur->prev = prev;
1958 }
1959 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001960
Daniel Veillarda880b122003-04-21 21:36:41 +00001961 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001962 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001963 return(cur);
1964}
1965
1966/**
Owen Taylor3473f882001-02-23 17:55:21 +00001967 * xmlNewDocProp:
1968 * @doc: the document
1969 * @name: the name of the attribute
1970 * @value: the value of the attribute
1971 *
1972 * Create a new property carried by a document.
1973 * Returns a pointer to the attribute
1974 */
1975xmlAttrPtr
1976xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1977 xmlAttrPtr cur;
1978
1979 if (name == NULL) {
1980#ifdef DEBUG_TREE
1981 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001982 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001983#endif
1984 return(NULL);
1985 }
1986
1987 /*
1988 * Allocate a new property and fill the fields.
1989 */
1990 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1991 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001992 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001993 return(NULL);
1994 }
1995 memset(cur, 0, sizeof(xmlAttr));
1996 cur->type = XML_ATTRIBUTE_NODE;
1997
Daniel Veillard03a53c32004-10-26 16:06:51 +00001998 if ((doc != NULL) && (doc->dict != NULL))
1999 cur->name = xmlDictLookup(doc->dict, name, -1);
2000 else
2001 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00002002 cur->doc = doc;
2003 if (value != NULL) {
2004 xmlNodePtr tmp;
2005
2006 cur->children = xmlStringGetNodeList(doc, value);
2007 cur->last = NULL;
2008
2009 tmp = cur->children;
2010 while (tmp != NULL) {
2011 tmp->parent = (xmlNodePtr) cur;
2012 if (tmp->next == NULL)
2013 cur->last = tmp;
2014 tmp = tmp->next;
2015 }
2016 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002017
Daniel Veillarda880b122003-04-21 21:36:41 +00002018 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002019 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002020 return(cur);
2021}
2022
2023/**
2024 * xmlFreePropList:
2025 * @cur: the first property in the list
2026 *
2027 * Free a property and all its siblings, all the children are freed too.
2028 */
2029void
2030xmlFreePropList(xmlAttrPtr cur) {
2031 xmlAttrPtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002032 if (cur == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002033 while (cur != NULL) {
2034 next = cur->next;
2035 xmlFreeProp(cur);
2036 cur = next;
2037 }
2038}
2039
2040/**
2041 * xmlFreeProp:
2042 * @cur: an attribute
2043 *
2044 * Free one attribute, all the content is freed too
2045 */
2046void
2047xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002048 xmlDictPtr dict = NULL;
2049 if (cur == NULL) return;
2050
2051 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002052
Daniel Veillarda880b122003-04-21 21:36:41 +00002053 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002054 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
2055
Owen Taylor3473f882001-02-23 17:55:21 +00002056 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00002057 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
2058 ((cur->parent->doc->intSubset != NULL) ||
2059 (cur->parent->doc->extSubset != NULL))) {
2060 if (xmlIsID(cur->parent->doc, cur->parent, cur))
2061 xmlRemoveID(cur->parent->doc, cur);
2062 }
Owen Taylor3473f882001-02-23 17:55:21 +00002063 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002064 DICT_FREE(cur->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002065 xmlFree(cur);
2066}
2067
Daniel Veillard652327a2003-09-29 18:02:38 +00002068#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002069/**
2070 * xmlRemoveProp:
2071 * @cur: an attribute
2072 *
2073 * Unlink and free one attribute, all the content is freed too
2074 * Note this doesn't work for namespace definition attributes
2075 *
2076 * Returns 0 if success and -1 in case of error.
2077 */
2078int
2079xmlRemoveProp(xmlAttrPtr cur) {
2080 xmlAttrPtr tmp;
2081 if (cur == NULL) {
2082#ifdef DEBUG_TREE
2083 xmlGenericError(xmlGenericErrorContext,
2084 "xmlRemoveProp : cur == NULL\n");
2085#endif
2086 return(-1);
2087 }
2088 if (cur->parent == NULL) {
2089#ifdef DEBUG_TREE
2090 xmlGenericError(xmlGenericErrorContext,
2091 "xmlRemoveProp : cur->parent == NULL\n");
2092#endif
2093 return(-1);
2094 }
2095 tmp = cur->parent->properties;
2096 if (tmp == cur) {
2097 cur->parent->properties = cur->next;
2098 xmlFreeProp(cur);
2099 return(0);
2100 }
2101 while (tmp != NULL) {
2102 if (tmp->next == cur) {
2103 tmp->next = cur->next;
2104 if (tmp->next != NULL)
2105 tmp->next->prev = tmp;
2106 xmlFreeProp(cur);
2107 return(0);
2108 }
2109 tmp = tmp->next;
2110 }
2111#ifdef DEBUG_TREE
2112 xmlGenericError(xmlGenericErrorContext,
2113 "xmlRemoveProp : attribute not owned by its node\n");
2114#endif
2115 return(-1);
2116}
Daniel Veillard652327a2003-09-29 18:02:38 +00002117#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002118
2119/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002120 * xmlNewDocPI:
2121 * @doc: the target document
Owen Taylor3473f882001-02-23 17:55:21 +00002122 * @name: the processing instruction name
2123 * @content: the PI content
2124 *
2125 * Creation of a processing instruction element.
2126 * Returns a pointer to the new node object.
2127 */
2128xmlNodePtr
Daniel Veillard03a53c32004-10-26 16:06:51 +00002129xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) {
Owen Taylor3473f882001-02-23 17:55:21 +00002130 xmlNodePtr cur;
2131
2132 if (name == NULL) {
2133#ifdef DEBUG_TREE
2134 xmlGenericError(xmlGenericErrorContext,
2135 "xmlNewPI : name == NULL\n");
2136#endif
2137 return(NULL);
2138 }
2139
2140 /*
2141 * Allocate a new node and fill the fields.
2142 */
2143 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2144 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002145 xmlTreeErrMemory("building PI");
Owen Taylor3473f882001-02-23 17:55:21 +00002146 return(NULL);
2147 }
2148 memset(cur, 0, sizeof(xmlNode));
2149 cur->type = XML_PI_NODE;
2150
Daniel Veillard03a53c32004-10-26 16:06:51 +00002151 if ((doc != NULL) && (doc->dict != NULL))
2152 cur->name = xmlDictLookup(doc->dict, name, -1);
2153 else
2154 cur->name = xmlStrdup(name);
Owen Taylor3473f882001-02-23 17:55:21 +00002155 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002156 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002157 }
Daniel Veillarda03e3652004-11-02 18:45:30 +00002158 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002159
Daniel Veillarda880b122003-04-21 21:36:41 +00002160 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002161 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002162 return(cur);
2163}
2164
2165/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00002166 * xmlNewPI:
2167 * @name: the processing instruction name
2168 * @content: the PI content
2169 *
2170 * Creation of a processing instruction element.
2171 * Use xmlDocNewPI preferably to get string interning
2172 *
2173 * Returns a pointer to the new node object.
2174 */
2175xmlNodePtr
2176xmlNewPI(const xmlChar *name, const xmlChar *content) {
2177 return(xmlNewDocPI(NULL, name, content));
2178}
2179
2180/**
Owen Taylor3473f882001-02-23 17:55:21 +00002181 * xmlNewNode:
2182 * @ns: namespace if any
2183 * @name: the node name
2184 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002185 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002186 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002187 * Returns a pointer to the new node object. Uses xmlStrdup() to make
2188 * copy of @name.
Owen Taylor3473f882001-02-23 17:55:21 +00002189 */
2190xmlNodePtr
2191xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2192 xmlNodePtr cur;
2193
2194 if (name == NULL) {
2195#ifdef DEBUG_TREE
2196 xmlGenericError(xmlGenericErrorContext,
2197 "xmlNewNode : name == NULL\n");
2198#endif
2199 return(NULL);
2200 }
2201
2202 /*
2203 * Allocate a new node and fill the fields.
2204 */
2205 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2206 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002207 xmlTreeErrMemory("building node");
Owen Taylor3473f882001-02-23 17:55:21 +00002208 return(NULL);
2209 }
2210 memset(cur, 0, sizeof(xmlNode));
2211 cur->type = XML_ELEMENT_NODE;
2212
2213 cur->name = xmlStrdup(name);
2214 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002215
Daniel Veillarda880b122003-04-21 21:36:41 +00002216 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002217 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002218 return(cur);
2219}
2220
2221/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00002222 * xmlNewNodeEatName:
2223 * @ns: namespace if any
2224 * @name: the node name
2225 *
2226 * Creation of a new node element. @ns is optional (NULL).
2227 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002228 * Returns a pointer to the new node object, with pointer @name as
2229 * new node's name. Use xmlNewNode() if a copy of @name string is
2230 * is needed as new node's name.
Daniel Veillard46de64e2002-05-29 08:21:33 +00002231 */
2232xmlNodePtr
2233xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2234 xmlNodePtr cur;
2235
2236 if (name == NULL) {
2237#ifdef DEBUG_TREE
2238 xmlGenericError(xmlGenericErrorContext,
2239 "xmlNewNode : name == NULL\n");
2240#endif
2241 return(NULL);
2242 }
2243
2244 /*
2245 * Allocate a new node and fill the fields.
2246 */
2247 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2248 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002249 xmlTreeErrMemory("building node");
Daniel Veillard46de64e2002-05-29 08:21:33 +00002250 return(NULL);
2251 }
2252 memset(cur, 0, sizeof(xmlNode));
2253 cur->type = XML_ELEMENT_NODE;
2254
2255 cur->name = name;
2256 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002257
Daniel Veillarda880b122003-04-21 21:36:41 +00002258 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002259 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002260 return(cur);
2261}
2262
2263/**
Owen Taylor3473f882001-02-23 17:55:21 +00002264 * xmlNewDocNode:
2265 * @doc: the document
2266 * @ns: namespace if any
2267 * @name: the node name
2268 * @content: the XML text content if any
2269 *
2270 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002271 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002272 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2273 * references, but XML special chars need to be escaped first by using
2274 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2275 * need entities support.
2276 *
2277 * Returns a pointer to the new node object.
2278 */
2279xmlNodePtr
2280xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2281 const xmlChar *name, const xmlChar *content) {
2282 xmlNodePtr cur;
2283
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002284 if ((doc != NULL) && (doc->dict != NULL))
Daniel Veillard03a53c32004-10-26 16:06:51 +00002285 cur = xmlNewNodeEatName(ns, (xmlChar *)
2286 xmlDictLookup(doc->dict, name, -1));
2287 else
2288 cur = xmlNewNode(ns, name);
Owen Taylor3473f882001-02-23 17:55:21 +00002289 if (cur != NULL) {
2290 cur->doc = doc;
2291 if (content != NULL) {
2292 cur->children = xmlStringGetNodeList(doc, content);
2293 UPDATE_LAST_CHILD_AND_PARENT(cur)
2294 }
2295 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002296
Owen Taylor3473f882001-02-23 17:55:21 +00002297 return(cur);
2298}
2299
Daniel Veillard46de64e2002-05-29 08:21:33 +00002300/**
2301 * xmlNewDocNodeEatName:
2302 * @doc: the document
2303 * @ns: namespace if any
2304 * @name: the node name
2305 * @content: the XML text content if any
2306 *
2307 * Creation of a new node element within a document. @ns and @content
2308 * are optional (NULL).
2309 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2310 * references, but XML special chars need to be escaped first by using
2311 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2312 * need entities support.
2313 *
2314 * Returns a pointer to the new node object.
2315 */
2316xmlNodePtr
2317xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2318 xmlChar *name, const xmlChar *content) {
2319 xmlNodePtr cur;
2320
2321 cur = xmlNewNodeEatName(ns, name);
2322 if (cur != NULL) {
2323 cur->doc = doc;
2324 if (content != NULL) {
2325 cur->children = xmlStringGetNodeList(doc, content);
2326 UPDATE_LAST_CHILD_AND_PARENT(cur)
2327 }
2328 }
2329 return(cur);
2330}
2331
Daniel Veillard652327a2003-09-29 18:02:38 +00002332#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002333/**
2334 * xmlNewDocRawNode:
2335 * @doc: the document
2336 * @ns: namespace if any
2337 * @name: the node name
2338 * @content: the text content if any
2339 *
2340 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002341 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002342 *
2343 * Returns a pointer to the new node object.
2344 */
2345xmlNodePtr
2346xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2347 const xmlChar *name, const xmlChar *content) {
2348 xmlNodePtr cur;
2349
Daniel Veillard95ddcd32004-10-26 21:53:55 +00002350 cur = xmlNewDocNode(doc, ns, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002351 if (cur != NULL) {
2352 cur->doc = doc;
2353 if (content != NULL) {
2354 cur->children = xmlNewDocText(doc, content);
2355 UPDATE_LAST_CHILD_AND_PARENT(cur)
2356 }
2357 }
2358 return(cur);
2359}
2360
2361/**
2362 * xmlNewDocFragment:
2363 * @doc: the document owning the fragment
2364 *
2365 * Creation of a new Fragment node.
2366 * Returns a pointer to the new node object.
2367 */
2368xmlNodePtr
2369xmlNewDocFragment(xmlDocPtr doc) {
2370 xmlNodePtr cur;
2371
2372 /*
2373 * Allocate a new DocumentFragment node and fill the fields.
2374 */
2375 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2376 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002377 xmlTreeErrMemory("building fragment");
Owen Taylor3473f882001-02-23 17:55:21 +00002378 return(NULL);
2379 }
2380 memset(cur, 0, sizeof(xmlNode));
2381 cur->type = XML_DOCUMENT_FRAG_NODE;
2382
2383 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002384
Daniel Veillarda880b122003-04-21 21:36:41 +00002385 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002386 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002387 return(cur);
2388}
Daniel Veillard652327a2003-09-29 18:02:38 +00002389#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002390
2391/**
2392 * xmlNewText:
2393 * @content: the text content
2394 *
2395 * Creation of a new text node.
2396 * Returns a pointer to the new node object.
2397 */
2398xmlNodePtr
2399xmlNewText(const xmlChar *content) {
2400 xmlNodePtr cur;
2401
2402 /*
2403 * Allocate a new node and fill the fields.
2404 */
2405 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2406 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002407 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002408 return(NULL);
2409 }
2410 memset(cur, 0, sizeof(xmlNode));
2411 cur->type = XML_TEXT_NODE;
2412
2413 cur->name = xmlStringText;
2414 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002415 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002416 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002417
Daniel Veillarda880b122003-04-21 21:36:41 +00002418 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002419 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002420 return(cur);
2421}
2422
Daniel Veillard652327a2003-09-29 18:02:38 +00002423#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002424/**
2425 * xmlNewTextChild:
2426 * @parent: the parent node
2427 * @ns: a namespace if any
2428 * @name: the name of the child
2429 * @content: the text content of the child if any.
2430 *
2431 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002432 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2433 * created element inherits the namespace of @parent. If @content is non NULL,
William M. Brackd7cf7f82003-11-14 07:13:16 +00002434 * a child TEXT node will be created containing the string @content.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002435 * NOTE: Use xmlNewChild() if @content will contain entities that need to be
2436 * preserved. Use this function, xmlNewTextChild(), if you need to ensure that
2437 * reserved XML chars that might appear in @content, such as the ampersand,
2438 * greater-than or less-than signs, are automatically replaced by their XML
2439 * escaped entity representations.
Owen Taylor3473f882001-02-23 17:55:21 +00002440 *
2441 * Returns a pointer to the new node object.
2442 */
2443xmlNodePtr
2444xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2445 const xmlChar *name, const xmlChar *content) {
2446 xmlNodePtr cur, prev;
2447
2448 if (parent == NULL) {
2449#ifdef DEBUG_TREE
2450 xmlGenericError(xmlGenericErrorContext,
2451 "xmlNewTextChild : parent == NULL\n");
2452#endif
2453 return(NULL);
2454 }
2455
2456 if (name == NULL) {
2457#ifdef DEBUG_TREE
2458 xmlGenericError(xmlGenericErrorContext,
2459 "xmlNewTextChild : name == NULL\n");
2460#endif
2461 return(NULL);
2462 }
2463
2464 /*
2465 * Allocate a new node
2466 */
Daniel Veillard254b1262003-11-01 17:04:58 +00002467 if (parent->type == XML_ELEMENT_NODE) {
2468 if (ns == NULL)
2469 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2470 else
2471 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2472 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2473 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2474 if (ns == NULL)
2475 cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2476 else
2477 cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2478 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2479 cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2480 } else {
2481 return(NULL);
2482 }
Owen Taylor3473f882001-02-23 17:55:21 +00002483 if (cur == NULL) return(NULL);
2484
2485 /*
2486 * add the new element at the end of the children list.
2487 */
2488 cur->type = XML_ELEMENT_NODE;
2489 cur->parent = parent;
2490 cur->doc = parent->doc;
2491 if (parent->children == NULL) {
2492 parent->children = cur;
2493 parent->last = cur;
2494 } else {
2495 prev = parent->last;
2496 prev->next = cur;
2497 cur->prev = prev;
2498 parent->last = cur;
2499 }
2500
2501 return(cur);
2502}
Daniel Veillard652327a2003-09-29 18:02:38 +00002503#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002504
2505/**
2506 * xmlNewCharRef:
2507 * @doc: the document
2508 * @name: the char ref string, starting with # or "&# ... ;"
2509 *
2510 * Creation of a new character reference node.
2511 * Returns a pointer to the new node object.
2512 */
2513xmlNodePtr
2514xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2515 xmlNodePtr cur;
2516
Daniel Veillard36e5cd52004-11-02 14:52:23 +00002517 if (name == NULL)
2518 return(NULL);
2519
Owen Taylor3473f882001-02-23 17:55:21 +00002520 /*
2521 * Allocate a new node and fill the fields.
2522 */
2523 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2524 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002525 xmlTreeErrMemory("building character reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002526 return(NULL);
2527 }
2528 memset(cur, 0, sizeof(xmlNode));
2529 cur->type = XML_ENTITY_REF_NODE;
2530
2531 cur->doc = doc;
2532 if (name[0] == '&') {
2533 int len;
2534 name++;
2535 len = xmlStrlen(name);
2536 if (name[len - 1] == ';')
2537 cur->name = xmlStrndup(name, len - 1);
2538 else
2539 cur->name = xmlStrndup(name, len);
2540 } else
2541 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002542
Daniel Veillarda880b122003-04-21 21:36:41 +00002543 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002544 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002545 return(cur);
2546}
2547
2548/**
2549 * xmlNewReference:
2550 * @doc: the document
2551 * @name: the reference name, or the reference string with & and ;
2552 *
2553 * Creation of a new reference node.
2554 * Returns a pointer to the new node object.
2555 */
2556xmlNodePtr
2557xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2558 xmlNodePtr cur;
2559 xmlEntityPtr ent;
2560
Daniel Veillard36e5cd52004-11-02 14:52:23 +00002561 if (name == NULL)
2562 return(NULL);
2563
Owen Taylor3473f882001-02-23 17:55:21 +00002564 /*
2565 * Allocate a new node and fill the fields.
2566 */
2567 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2568 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002569 xmlTreeErrMemory("building reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002570 return(NULL);
2571 }
2572 memset(cur, 0, sizeof(xmlNode));
2573 cur->type = XML_ENTITY_REF_NODE;
2574
2575 cur->doc = doc;
2576 if (name[0] == '&') {
2577 int len;
2578 name++;
2579 len = xmlStrlen(name);
2580 if (name[len - 1] == ';')
2581 cur->name = xmlStrndup(name, len - 1);
2582 else
2583 cur->name = xmlStrndup(name, len);
2584 } else
2585 cur->name = xmlStrdup(name);
2586
2587 ent = xmlGetDocEntity(doc, cur->name);
2588 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002589 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002590 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002591 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002592 * updated. Not sure if this is 100% correct.
2593 * -George
2594 */
2595 cur->children = (xmlNodePtr) ent;
2596 cur->last = (xmlNodePtr) ent;
2597 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002598
Daniel Veillarda880b122003-04-21 21:36:41 +00002599 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002600 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002601 return(cur);
2602}
2603
2604/**
2605 * xmlNewDocText:
2606 * @doc: the document
2607 * @content: the text content
2608 *
2609 * Creation of a new text node within a document.
2610 * Returns a pointer to the new node object.
2611 */
2612xmlNodePtr
2613xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2614 xmlNodePtr cur;
2615
2616 cur = xmlNewText(content);
2617 if (cur != NULL) cur->doc = doc;
2618 return(cur);
2619}
2620
2621/**
2622 * xmlNewTextLen:
2623 * @content: the text content
2624 * @len: the text len.
2625 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002626 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002627 * Returns a pointer to the new node object.
2628 */
2629xmlNodePtr
2630xmlNewTextLen(const xmlChar *content, int len) {
2631 xmlNodePtr cur;
2632
2633 /*
2634 * Allocate a new node and fill the fields.
2635 */
2636 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2637 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002638 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002639 return(NULL);
2640 }
2641 memset(cur, 0, sizeof(xmlNode));
2642 cur->type = XML_TEXT_NODE;
2643
2644 cur->name = xmlStringText;
2645 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002646 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002647 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002648
Daniel Veillarda880b122003-04-21 21:36:41 +00002649 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002650 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002651 return(cur);
2652}
2653
2654/**
2655 * xmlNewDocTextLen:
2656 * @doc: the document
2657 * @content: the text content
2658 * @len: the text len.
2659 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002660 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002661 * text node pertain to a given document.
2662 * Returns a pointer to the new node object.
2663 */
2664xmlNodePtr
2665xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2666 xmlNodePtr cur;
2667
2668 cur = xmlNewTextLen(content, len);
2669 if (cur != NULL) cur->doc = doc;
2670 return(cur);
2671}
2672
2673/**
2674 * xmlNewComment:
2675 * @content: the comment content
2676 *
2677 * Creation of a new node containing a comment.
2678 * Returns a pointer to the new node object.
2679 */
2680xmlNodePtr
2681xmlNewComment(const xmlChar *content) {
2682 xmlNodePtr cur;
2683
2684 /*
2685 * Allocate a new node and fill the fields.
2686 */
2687 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2688 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002689 xmlTreeErrMemory("building comment");
Owen Taylor3473f882001-02-23 17:55:21 +00002690 return(NULL);
2691 }
2692 memset(cur, 0, sizeof(xmlNode));
2693 cur->type = XML_COMMENT_NODE;
2694
2695 cur->name = xmlStringComment;
2696 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002697 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002698 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002699
Daniel Veillarda880b122003-04-21 21:36:41 +00002700 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002701 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002702 return(cur);
2703}
2704
2705/**
2706 * xmlNewCDataBlock:
2707 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002708 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002709 * @len: the length of the block
2710 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002711 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002712 * Returns a pointer to the new node object.
2713 */
2714xmlNodePtr
2715xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2716 xmlNodePtr cur;
2717
2718 /*
2719 * Allocate a new node and fill the fields.
2720 */
2721 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2722 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002723 xmlTreeErrMemory("building CDATA");
Owen Taylor3473f882001-02-23 17:55:21 +00002724 return(NULL);
2725 }
2726 memset(cur, 0, sizeof(xmlNode));
2727 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002728 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002729
2730 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002731 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002732 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002733
Daniel Veillarda880b122003-04-21 21:36:41 +00002734 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002735 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002736 return(cur);
2737}
2738
2739/**
2740 * xmlNewDocComment:
2741 * @doc: the document
2742 * @content: the comment content
2743 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002744 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002745 * Returns a pointer to the new node object.
2746 */
2747xmlNodePtr
2748xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2749 xmlNodePtr cur;
2750
2751 cur = xmlNewComment(content);
2752 if (cur != NULL) cur->doc = doc;
2753 return(cur);
2754}
2755
2756/**
2757 * xmlSetTreeDoc:
2758 * @tree: the top element
2759 * @doc: the document
2760 *
2761 * update all nodes under the tree to point to the right document
2762 */
2763void
2764xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002765 xmlAttrPtr prop;
2766
Owen Taylor3473f882001-02-23 17:55:21 +00002767 if (tree == NULL)
2768 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002769 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002770 if(tree->type == XML_ELEMENT_NODE) {
2771 prop = tree->properties;
2772 while (prop != NULL) {
2773 prop->doc = doc;
2774 xmlSetListDoc(prop->children, doc);
2775 prop = prop->next;
2776 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002777 }
Owen Taylor3473f882001-02-23 17:55:21 +00002778 if (tree->children != NULL)
2779 xmlSetListDoc(tree->children, doc);
2780 tree->doc = doc;
2781 }
2782}
2783
2784/**
2785 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002786 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002787 * @doc: the document
2788 *
2789 * update all nodes in the list to point to the right document
2790 */
2791void
2792xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2793 xmlNodePtr cur;
2794
2795 if (list == NULL)
2796 return;
2797 cur = list;
2798 while (cur != NULL) {
2799 if (cur->doc != doc)
2800 xmlSetTreeDoc(cur, doc);
2801 cur = cur->next;
2802 }
2803}
2804
Daniel Veillard2156d432004-03-04 15:59:36 +00002805#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002806/**
2807 * xmlNewChild:
2808 * @parent: the parent node
2809 * @ns: a namespace if any
2810 * @name: the name of the child
2811 * @content: the XML content of the child if any.
2812 *
2813 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002814 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2815 * created element inherits the namespace of @parent. If @content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002816 * a child list containing the TEXTs and ENTITY_REFs node will be created.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002817 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
2818 * references. XML special chars must be escaped first by using
2819 * xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used.
Owen Taylor3473f882001-02-23 17:55:21 +00002820 *
2821 * Returns a pointer to the new node object.
2822 */
2823xmlNodePtr
2824xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2825 const xmlChar *name, const xmlChar *content) {
2826 xmlNodePtr cur, prev;
2827
2828 if (parent == NULL) {
2829#ifdef DEBUG_TREE
2830 xmlGenericError(xmlGenericErrorContext,
2831 "xmlNewChild : parent == NULL\n");
2832#endif
2833 return(NULL);
2834 }
2835
2836 if (name == NULL) {
2837#ifdef DEBUG_TREE
2838 xmlGenericError(xmlGenericErrorContext,
2839 "xmlNewChild : name == NULL\n");
2840#endif
2841 return(NULL);
2842 }
2843
2844 /*
2845 * Allocate a new node
2846 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002847 if (parent->type == XML_ELEMENT_NODE) {
2848 if (ns == NULL)
2849 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2850 else
2851 cur = xmlNewDocNode(parent->doc, ns, name, content);
2852 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2853 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2854 if (ns == NULL)
2855 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2856 else
2857 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002858 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2859 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002860 } else {
2861 return(NULL);
2862 }
Owen Taylor3473f882001-02-23 17:55:21 +00002863 if (cur == NULL) return(NULL);
2864
2865 /*
2866 * add the new element at the end of the children list.
2867 */
2868 cur->type = XML_ELEMENT_NODE;
2869 cur->parent = parent;
2870 cur->doc = parent->doc;
2871 if (parent->children == NULL) {
2872 parent->children = cur;
2873 parent->last = cur;
2874 } else {
2875 prev = parent->last;
2876 prev->next = cur;
2877 cur->prev = prev;
2878 parent->last = cur;
2879 }
2880
2881 return(cur);
2882}
Daniel Veillard652327a2003-09-29 18:02:38 +00002883#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002884
2885/**
2886 * xmlAddNextSibling:
2887 * @cur: the child node
2888 * @elem: the new node
2889 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002890 * Add a new node @elem as the next sibling of @cur
2891 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002892 * first unlinked from its existing context.
2893 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002894 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2895 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002896 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002897 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002898 */
2899xmlNodePtr
2900xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2901 if (cur == NULL) {
2902#ifdef DEBUG_TREE
2903 xmlGenericError(xmlGenericErrorContext,
2904 "xmlAddNextSibling : cur == NULL\n");
2905#endif
2906 return(NULL);
2907 }
2908 if (elem == NULL) {
2909#ifdef DEBUG_TREE
2910 xmlGenericError(xmlGenericErrorContext,
2911 "xmlAddNextSibling : elem == NULL\n");
2912#endif
2913 return(NULL);
2914 }
2915
2916 xmlUnlinkNode(elem);
2917
2918 if (elem->type == XML_TEXT_NODE) {
2919 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002920 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002921 xmlFreeNode(elem);
2922 return(cur);
2923 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002924 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2925 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002926 xmlChar *tmp;
2927
2928 tmp = xmlStrdup(elem->content);
2929 tmp = xmlStrcat(tmp, cur->next->content);
2930 xmlNodeSetContent(cur->next, tmp);
2931 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002932 xmlFreeNode(elem);
2933 return(cur->next);
2934 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002935 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2936 /* check if an attribute with the same name exists */
2937 xmlAttrPtr attr;
2938
2939 if (elem->ns == NULL)
2940 attr = xmlHasProp(cur->parent, elem->name);
2941 else
2942 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2943 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2944 /* different instance, destroy it (attributes must be unique) */
2945 xmlFreeProp(attr);
2946 }
Owen Taylor3473f882001-02-23 17:55:21 +00002947 }
2948
2949 if (elem->doc != cur->doc) {
2950 xmlSetTreeDoc(elem, cur->doc);
2951 }
2952 elem->parent = cur->parent;
2953 elem->prev = cur;
2954 elem->next = cur->next;
2955 cur->next = elem;
2956 if (elem->next != NULL)
2957 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002958 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002959 elem->parent->last = elem;
2960 return(elem);
2961}
2962
Daniel Veillard2156d432004-03-04 15:59:36 +00002963#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00002964/**
2965 * xmlAddPrevSibling:
2966 * @cur: the child node
2967 * @elem: the new node
2968 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002969 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002970 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002971 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002972 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002973 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2974 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002975 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002976 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002977 */
2978xmlNodePtr
2979xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2980 if (cur == NULL) {
2981#ifdef DEBUG_TREE
2982 xmlGenericError(xmlGenericErrorContext,
2983 "xmlAddPrevSibling : cur == NULL\n");
2984#endif
2985 return(NULL);
2986 }
2987 if (elem == NULL) {
2988#ifdef DEBUG_TREE
2989 xmlGenericError(xmlGenericErrorContext,
2990 "xmlAddPrevSibling : elem == NULL\n");
2991#endif
2992 return(NULL);
2993 }
2994
2995 xmlUnlinkNode(elem);
2996
2997 if (elem->type == XML_TEXT_NODE) {
2998 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002999 xmlChar *tmp;
3000
3001 tmp = xmlStrdup(elem->content);
3002 tmp = xmlStrcat(tmp, cur->content);
3003 xmlNodeSetContent(cur, tmp);
3004 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00003005 xmlFreeNode(elem);
3006 return(cur);
3007 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00003008 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
3009 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003010 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003011 xmlFreeNode(elem);
3012 return(cur->prev);
3013 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003014 } else if (elem->type == XML_ATTRIBUTE_NODE) {
3015 /* check if an attribute with the same name exists */
3016 xmlAttrPtr attr;
3017
3018 if (elem->ns == NULL)
3019 attr = xmlHasProp(cur->parent, elem->name);
3020 else
3021 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
3022 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
3023 /* different instance, destroy it (attributes must be unique) */
3024 xmlFreeProp(attr);
3025 }
Owen Taylor3473f882001-02-23 17:55:21 +00003026 }
3027
3028 if (elem->doc != cur->doc) {
3029 xmlSetTreeDoc(elem, cur->doc);
3030 }
3031 elem->parent = cur->parent;
3032 elem->next = cur;
3033 elem->prev = cur->prev;
3034 cur->prev = elem;
3035 if (elem->prev != NULL)
3036 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003037 if (elem->parent != NULL) {
3038 if (elem->type == XML_ATTRIBUTE_NODE) {
3039 if (elem->parent->properties == (xmlAttrPtr) cur) {
3040 elem->parent->properties = (xmlAttrPtr) elem;
3041 }
3042 } else {
3043 if (elem->parent->children == cur) {
3044 elem->parent->children = elem;
3045 }
3046 }
3047 }
Owen Taylor3473f882001-02-23 17:55:21 +00003048 return(elem);
3049}
Daniel Veillard652327a2003-09-29 18:02:38 +00003050#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003051
3052/**
3053 * xmlAddSibling:
3054 * @cur: the child node
3055 * @elem: the new node
3056 *
3057 * Add a new element @elem to the list of siblings of @cur
3058 * merging adjacent TEXT nodes (@elem may be freed)
3059 * If the new element was already inserted in a document it is
3060 * first unlinked from its existing context.
3061 *
3062 * Returns the new element or NULL in case of error.
3063 */
3064xmlNodePtr
3065xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
3066 xmlNodePtr parent;
3067
3068 if (cur == NULL) {
3069#ifdef DEBUG_TREE
3070 xmlGenericError(xmlGenericErrorContext,
3071 "xmlAddSibling : cur == NULL\n");
3072#endif
3073 return(NULL);
3074 }
3075
3076 if (elem == NULL) {
3077#ifdef DEBUG_TREE
3078 xmlGenericError(xmlGenericErrorContext,
3079 "xmlAddSibling : elem == NULL\n");
3080#endif
3081 return(NULL);
3082 }
3083
3084 /*
3085 * Constant time is we can rely on the ->parent->last to find
3086 * the last sibling.
3087 */
3088 if ((cur->parent != NULL) &&
3089 (cur->parent->children != NULL) &&
3090 (cur->parent->last != NULL) &&
3091 (cur->parent->last->next == NULL)) {
3092 cur = cur->parent->last;
3093 } else {
3094 while (cur->next != NULL) cur = cur->next;
3095 }
3096
3097 xmlUnlinkNode(elem);
3098
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003099 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3100 (cur->name == elem->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003101 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003102 xmlFreeNode(elem);
3103 return(cur);
3104 }
3105
3106 if (elem->doc != cur->doc) {
3107 xmlSetTreeDoc(elem, cur->doc);
3108 }
3109 parent = cur->parent;
3110 elem->prev = cur;
3111 elem->next = NULL;
3112 elem->parent = parent;
3113 cur->next = elem;
3114 if (parent != NULL)
3115 parent->last = elem;
3116
3117 return(elem);
3118}
3119
3120/**
3121 * xmlAddChildList:
3122 * @parent: the parent node
3123 * @cur: the first node in the list
3124 *
3125 * Add a list of node at the end of the child list of the parent
3126 * merging adjacent TEXT nodes (@cur may be freed)
3127 *
3128 * Returns the last child or NULL in case of error.
3129 */
3130xmlNodePtr
3131xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3132 xmlNodePtr prev;
3133
3134 if (parent == NULL) {
3135#ifdef DEBUG_TREE
3136 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003137 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003138#endif
3139 return(NULL);
3140 }
3141
3142 if (cur == NULL) {
3143#ifdef DEBUG_TREE
3144 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003145 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003146#endif
3147 return(NULL);
3148 }
3149
3150 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3151 (cur->doc != parent->doc)) {
3152#ifdef DEBUG_TREE
3153 xmlGenericError(xmlGenericErrorContext,
3154 "Elements moved to a different document\n");
3155#endif
3156 }
3157
3158 /*
3159 * add the first element at the end of the children list.
3160 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003161
Owen Taylor3473f882001-02-23 17:55:21 +00003162 if (parent->children == NULL) {
3163 parent->children = cur;
3164 } else {
3165 /*
3166 * If cur and parent->last both are TEXT nodes, then merge them.
3167 */
3168 if ((cur->type == XML_TEXT_NODE) &&
3169 (parent->last->type == XML_TEXT_NODE) &&
3170 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003171 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003172 /*
3173 * if it's the only child, nothing more to be done.
3174 */
3175 if (cur->next == NULL) {
3176 xmlFreeNode(cur);
3177 return(parent->last);
3178 }
3179 prev = cur;
3180 cur = cur->next;
3181 xmlFreeNode(prev);
3182 }
3183 prev = parent->last;
3184 prev->next = cur;
3185 cur->prev = prev;
3186 }
3187 while (cur->next != NULL) {
3188 cur->parent = parent;
3189 if (cur->doc != parent->doc) {
3190 xmlSetTreeDoc(cur, parent->doc);
3191 }
3192 cur = cur->next;
3193 }
3194 cur->parent = parent;
3195 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
3196 parent->last = cur;
3197
3198 return(cur);
3199}
3200
3201/**
3202 * xmlAddChild:
3203 * @parent: the parent node
3204 * @cur: the child node
3205 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003206 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003207 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003208 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3209 * If there is an attribute with equal name, it is first destroyed.
3210 *
Owen Taylor3473f882001-02-23 17:55:21 +00003211 * Returns the child or NULL in case of error.
3212 */
3213xmlNodePtr
3214xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3215 xmlNodePtr prev;
3216
3217 if (parent == NULL) {
3218#ifdef DEBUG_TREE
3219 xmlGenericError(xmlGenericErrorContext,
3220 "xmlAddChild : parent == NULL\n");
3221#endif
3222 return(NULL);
3223 }
3224
3225 if (cur == NULL) {
3226#ifdef DEBUG_TREE
3227 xmlGenericError(xmlGenericErrorContext,
3228 "xmlAddChild : child == NULL\n");
3229#endif
3230 return(NULL);
3231 }
3232
Owen Taylor3473f882001-02-23 17:55:21 +00003233 /*
3234 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003235 * cur is then freed.
3236 */
3237 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003238 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003239 (parent->content != NULL) &&
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003240 (parent->name == cur->name) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003241 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003242 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003243 xmlFreeNode(cur);
3244 return(parent);
3245 }
3246 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003247 (parent->last->name == cur->name) &&
3248 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003249 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003250 xmlFreeNode(cur);
3251 return(parent->last);
3252 }
3253 }
3254
3255 /*
3256 * add the new element at the end of the children list.
3257 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003258 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003259 cur->parent = parent;
3260 if (cur->doc != parent->doc) {
3261 xmlSetTreeDoc(cur, parent->doc);
3262 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003263 /* this check prevents a loop on tree-traversions if a developer
3264 * tries to add a node to its parent multiple times
3265 */
3266 if (prev == parent)
3267 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003268
3269 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003270 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003271 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003272 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003273 (parent->content != NULL) &&
3274 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003275 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003276 xmlFreeNode(cur);
3277 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003278 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003279 if (cur->type == XML_ATTRIBUTE_NODE) {
3280 if (parent->properties == NULL) {
3281 parent->properties = (xmlAttrPtr) cur;
3282 } else {
3283 /* check if an attribute with the same name exists */
3284 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003285
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003286 if (cur->ns == NULL)
3287 lastattr = xmlHasProp(parent, cur->name);
3288 else
3289 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3290 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
3291 /* different instance, destroy it (attributes must be unique) */
3292 xmlFreeProp(lastattr);
3293 }
3294 /* find the end */
3295 lastattr = parent->properties;
3296 while (lastattr->next != NULL) {
3297 lastattr = lastattr->next;
3298 }
3299 lastattr->next = (xmlAttrPtr) cur;
3300 ((xmlAttrPtr) cur)->prev = lastattr;
3301 }
3302 } else {
3303 if (parent->children == NULL) {
3304 parent->children = cur;
3305 parent->last = cur;
3306 } else {
3307 prev = parent->last;
3308 prev->next = cur;
3309 cur->prev = prev;
3310 parent->last = cur;
3311 }
3312 }
Owen Taylor3473f882001-02-23 17:55:21 +00003313 return(cur);
3314}
3315
3316/**
3317 * xmlGetLastChild:
3318 * @parent: the parent node
3319 *
3320 * Search the last child of a node.
3321 * Returns the last child or NULL if none.
3322 */
3323xmlNodePtr
3324xmlGetLastChild(xmlNodePtr parent) {
3325 if (parent == NULL) {
3326#ifdef DEBUG_TREE
3327 xmlGenericError(xmlGenericErrorContext,
3328 "xmlGetLastChild : parent == NULL\n");
3329#endif
3330 return(NULL);
3331 }
3332 return(parent->last);
3333}
3334
3335/**
3336 * xmlFreeNodeList:
3337 * @cur: the first node in the list
3338 *
3339 * Free a node and all its siblings, this is a recursive behaviour, all
3340 * the children are freed too.
3341 */
3342void
3343xmlFreeNodeList(xmlNodePtr cur) {
3344 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003345 xmlDictPtr dict = NULL;
3346
3347 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003348 if (cur->type == XML_NAMESPACE_DECL) {
3349 xmlFreeNsList((xmlNsPtr) cur);
3350 return;
3351 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003352 if ((cur->type == XML_DOCUMENT_NODE) ||
3353#ifdef LIBXML_DOCB_ENABLED
3354 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003355#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003356 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003357 xmlFreeDoc((xmlDocPtr) cur);
3358 return;
3359 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003360 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003361 while (cur != NULL) {
3362 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003363 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003364
Daniel Veillarda880b122003-04-21 21:36:41 +00003365 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003366 xmlDeregisterNodeDefaultValue(cur);
3367
Daniel Veillard02141ea2001-04-30 11:46:40 +00003368 if ((cur->children != NULL) &&
3369 (cur->type != XML_ENTITY_REF_NODE))
3370 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003371 if (((cur->type == XML_ELEMENT_NODE) ||
3372 (cur->type == XML_XINCLUDE_START) ||
3373 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003374 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003375 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003376 if ((cur->type != XML_ELEMENT_NODE) &&
3377 (cur->type != XML_XINCLUDE_START) &&
3378 (cur->type != XML_XINCLUDE_END) &&
3379 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003380 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003381 }
3382 if (((cur->type == XML_ELEMENT_NODE) ||
3383 (cur->type == XML_XINCLUDE_START) ||
3384 (cur->type == XML_XINCLUDE_END)) &&
3385 (cur->nsDef != NULL))
3386 xmlFreeNsList(cur->nsDef);
3387
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003388 /*
3389 * When a node is a text node or a comment, it uses a global static
3390 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003391 * Otherwise the node name might come from the document's
3392 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003393 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003394 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003395 (cur->type != XML_TEXT_NODE) &&
3396 (cur->type != XML_COMMENT_NODE))
3397 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003398 xmlFree(cur);
3399 }
Owen Taylor3473f882001-02-23 17:55:21 +00003400 cur = next;
3401 }
3402}
3403
3404/**
3405 * xmlFreeNode:
3406 * @cur: the node
3407 *
3408 * Free a node, this is a recursive behaviour, all the children are freed too.
3409 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3410 */
3411void
3412xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003413 xmlDictPtr dict = NULL;
3414
3415 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003416
Daniel Veillard02141ea2001-04-30 11:46:40 +00003417 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003418 if (cur->type == XML_DTD_NODE) {
3419 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003420 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003421 }
3422 if (cur->type == XML_NAMESPACE_DECL) {
3423 xmlFreeNs((xmlNsPtr) cur);
3424 return;
3425 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003426 if (cur->type == XML_ATTRIBUTE_NODE) {
3427 xmlFreeProp((xmlAttrPtr) cur);
3428 return;
3429 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003430
Daniel Veillarda880b122003-04-21 21:36:41 +00003431 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003432 xmlDeregisterNodeDefaultValue(cur);
3433
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003434 if (cur->doc != NULL) dict = cur->doc->dict;
3435
Owen Taylor3473f882001-02-23 17:55:21 +00003436 if ((cur->children != NULL) &&
3437 (cur->type != XML_ENTITY_REF_NODE))
3438 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003439 if (((cur->type == XML_ELEMENT_NODE) ||
3440 (cur->type == XML_XINCLUDE_START) ||
3441 (cur->type == XML_XINCLUDE_END)) &&
3442 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003443 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003444 if ((cur->type != XML_ELEMENT_NODE) &&
3445 (cur->content != NULL) &&
3446 (cur->type != XML_ENTITY_REF_NODE) &&
3447 (cur->type != XML_XINCLUDE_END) &&
3448 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003449 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003450 }
3451
Daniel Veillardacd370f2001-06-09 17:17:51 +00003452 /*
3453 * When a node is a text node or a comment, it uses a global static
3454 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003455 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003456 */
Owen Taylor3473f882001-02-23 17:55:21 +00003457 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003458 (cur->type != XML_TEXT_NODE) &&
3459 (cur->type != XML_COMMENT_NODE))
3460 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003461
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003462 if (((cur->type == XML_ELEMENT_NODE) ||
3463 (cur->type == XML_XINCLUDE_START) ||
3464 (cur->type == XML_XINCLUDE_END)) &&
3465 (cur->nsDef != NULL))
3466 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003467 xmlFree(cur);
3468}
3469
3470/**
3471 * xmlUnlinkNode:
3472 * @cur: the node
3473 *
3474 * Unlink a node from it's current context, the node is not freed
3475 */
3476void
3477xmlUnlinkNode(xmlNodePtr cur) {
3478 if (cur == NULL) {
3479#ifdef DEBUG_TREE
3480 xmlGenericError(xmlGenericErrorContext,
3481 "xmlUnlinkNode : node == NULL\n");
3482#endif
3483 return;
3484 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003485 if (cur->type == XML_DTD_NODE) {
3486 xmlDocPtr doc;
3487 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003488 if (doc != NULL) {
3489 if (doc->intSubset == (xmlDtdPtr) cur)
3490 doc->intSubset = NULL;
3491 if (doc->extSubset == (xmlDtdPtr) cur)
3492 doc->extSubset = NULL;
3493 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003494 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003495 if (cur->parent != NULL) {
3496 xmlNodePtr parent;
3497 parent = cur->parent;
3498 if (cur->type == XML_ATTRIBUTE_NODE) {
3499 if (parent->properties == (xmlAttrPtr) cur)
3500 parent->properties = ((xmlAttrPtr) cur)->next;
3501 } else {
3502 if (parent->children == cur)
3503 parent->children = cur->next;
3504 if (parent->last == cur)
3505 parent->last = cur->prev;
3506 }
3507 cur->parent = NULL;
3508 }
Owen Taylor3473f882001-02-23 17:55:21 +00003509 if (cur->next != NULL)
3510 cur->next->prev = cur->prev;
3511 if (cur->prev != NULL)
3512 cur->prev->next = cur->next;
3513 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003514}
3515
Daniel Veillard2156d432004-03-04 15:59:36 +00003516#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003517/**
3518 * xmlReplaceNode:
3519 * @old: the old node
3520 * @cur: the node
3521 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00003522 * Unlink the old node from its current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003523 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003524 * first unlinked from its existing context.
3525 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003526 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003527 */
3528xmlNodePtr
3529xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00003530 if (old == cur) return(NULL);
Daniel Veillarda03e3652004-11-02 18:45:30 +00003531 if ((old == NULL) || (old->parent == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003532#ifdef DEBUG_TREE
3533 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda03e3652004-11-02 18:45:30 +00003534 "xmlReplaceNode : old == NULL or without parent\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003535#endif
3536 return(NULL);
3537 }
3538 if (cur == NULL) {
3539 xmlUnlinkNode(old);
3540 return(old);
3541 }
3542 if (cur == old) {
3543 return(old);
3544 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003545 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3546#ifdef DEBUG_TREE
3547 xmlGenericError(xmlGenericErrorContext,
3548 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3549#endif
3550 return(old);
3551 }
3552 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3553#ifdef DEBUG_TREE
3554 xmlGenericError(xmlGenericErrorContext,
3555 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3556#endif
3557 return(old);
3558 }
Owen Taylor3473f882001-02-23 17:55:21 +00003559 xmlUnlinkNode(cur);
3560 cur->doc = old->doc;
3561 cur->parent = old->parent;
3562 cur->next = old->next;
3563 if (cur->next != NULL)
3564 cur->next->prev = cur;
3565 cur->prev = old->prev;
3566 if (cur->prev != NULL)
3567 cur->prev->next = cur;
3568 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003569 if (cur->type == XML_ATTRIBUTE_NODE) {
3570 if (cur->parent->properties == (xmlAttrPtr)old)
3571 cur->parent->properties = ((xmlAttrPtr) cur);
3572 } else {
3573 if (cur->parent->children == old)
3574 cur->parent->children = cur;
3575 if (cur->parent->last == old)
3576 cur->parent->last = cur;
3577 }
Owen Taylor3473f882001-02-23 17:55:21 +00003578 }
3579 old->next = old->prev = NULL;
3580 old->parent = NULL;
3581 return(old);
3582}
Daniel Veillard652327a2003-09-29 18:02:38 +00003583#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003584
3585/************************************************************************
3586 * *
3587 * Copy operations *
3588 * *
3589 ************************************************************************/
3590
3591/**
3592 * xmlCopyNamespace:
3593 * @cur: the namespace
3594 *
3595 * Do a copy of the namespace.
3596 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003597 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003598 */
3599xmlNsPtr
3600xmlCopyNamespace(xmlNsPtr cur) {
3601 xmlNsPtr ret;
3602
3603 if (cur == NULL) return(NULL);
3604 switch (cur->type) {
3605 case XML_LOCAL_NAMESPACE:
3606 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3607 break;
3608 default:
3609#ifdef DEBUG_TREE
3610 xmlGenericError(xmlGenericErrorContext,
3611 "xmlCopyNamespace: invalid type %d\n", cur->type);
3612#endif
3613 return(NULL);
3614 }
3615 return(ret);
3616}
3617
3618/**
3619 * xmlCopyNamespaceList:
3620 * @cur: the first namespace
3621 *
3622 * Do a copy of an namespace list.
3623 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003624 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003625 */
3626xmlNsPtr
3627xmlCopyNamespaceList(xmlNsPtr cur) {
3628 xmlNsPtr ret = NULL;
3629 xmlNsPtr p = NULL,q;
3630
3631 while (cur != NULL) {
3632 q = xmlCopyNamespace(cur);
3633 if (p == NULL) {
3634 ret = p = q;
3635 } else {
3636 p->next = q;
3637 p = q;
3638 }
3639 cur = cur->next;
3640 }
3641 return(ret);
3642}
3643
3644static xmlNodePtr
3645xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3646/**
3647 * xmlCopyProp:
3648 * @target: the element where the attribute will be grafted
3649 * @cur: the attribute
3650 *
3651 * Do a copy of the attribute.
3652 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003653 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003654 */
3655xmlAttrPtr
3656xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3657 xmlAttrPtr ret;
3658
3659 if (cur == NULL) return(NULL);
3660 if (target != NULL)
3661 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3662 else if (cur->parent != NULL)
3663 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3664 else if (cur->children != NULL)
3665 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3666 else
3667 ret = xmlNewDocProp(NULL, cur->name, NULL);
3668 if (ret == NULL) return(NULL);
3669 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003670
Owen Taylor3473f882001-02-23 17:55:21 +00003671 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003672 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003673
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003674 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3675 if (ns == NULL) {
3676 /*
3677 * Humm, we are copying an element whose namespace is defined
3678 * out of the new tree scope. Search it in the original tree
3679 * and add it at the top of the new tree
3680 */
3681 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3682 if (ns != NULL) {
3683 xmlNodePtr root = target;
3684 xmlNodePtr pred = NULL;
3685
3686 while (root->parent != NULL) {
3687 pred = root;
3688 root = root->parent;
3689 }
3690 if (root == (xmlNodePtr) target->doc) {
3691 /* correct possibly cycling above the document elt */
3692 root = pred;
3693 }
3694 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3695 }
3696 } else {
3697 /*
3698 * we have to find something appropriate here since
3699 * we cant be sure, that the namespce we found is identified
3700 * by the prefix
3701 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003702 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003703 /* this is the nice case */
3704 ret->ns = ns;
3705 } else {
3706 /*
3707 * we are in trouble: we need a new reconcilied namespace.
3708 * This is expensive
3709 */
3710 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3711 }
3712 }
3713
Owen Taylor3473f882001-02-23 17:55:21 +00003714 } else
3715 ret->ns = NULL;
3716
3717 if (cur->children != NULL) {
3718 xmlNodePtr tmp;
3719
3720 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3721 ret->last = NULL;
3722 tmp = ret->children;
3723 while (tmp != NULL) {
3724 /* tmp->parent = (xmlNodePtr)ret; */
3725 if (tmp->next == NULL)
3726 ret->last = tmp;
3727 tmp = tmp->next;
3728 }
3729 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003730 /*
3731 * Try to handle IDs
3732 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003733 if ((target!= NULL) && (cur!= NULL) &&
3734 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003735 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3736 if (xmlIsID(cur->doc, cur->parent, cur)) {
3737 xmlChar *id;
3738
3739 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3740 if (id != NULL) {
3741 xmlAddID(NULL, target->doc, id, ret);
3742 xmlFree(id);
3743 }
3744 }
3745 }
Owen Taylor3473f882001-02-23 17:55:21 +00003746 return(ret);
3747}
3748
3749/**
3750 * xmlCopyPropList:
3751 * @target: the element where the attributes will be grafted
3752 * @cur: the first attribute
3753 *
3754 * Do a copy of an attribute list.
3755 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003756 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003757 */
3758xmlAttrPtr
3759xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3760 xmlAttrPtr ret = NULL;
3761 xmlAttrPtr p = NULL,q;
3762
3763 while (cur != NULL) {
3764 q = xmlCopyProp(target, cur);
William M. Brack13dfa872004-09-18 04:52:08 +00003765 if (q == NULL)
3766 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003767 if (p == NULL) {
3768 ret = p = q;
3769 } else {
3770 p->next = q;
3771 q->prev = p;
3772 p = q;
3773 }
3774 cur = cur->next;
3775 }
3776 return(ret);
3777}
3778
3779/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003780 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003781 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003782 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003783 * tricky reason: namespaces. Doing a direct copy of a node
3784 * say RPM:Copyright without changing the namespace pointer to
3785 * something else can produce stale links. One way to do it is
3786 * to keep a reference counter but this doesn't work as soon
3787 * as one move the element or the subtree out of the scope of
3788 * the existing namespace. The actual solution seems to add
3789 * a copy of the namespace at the top of the copied tree if
3790 * not available in the subtree.
3791 * Hence two functions, the public front-end call the inner ones
William M. Brack57e9e912004-03-09 16:19:02 +00003792 * The argument "recursive" normally indicates a recursive copy
3793 * of the node with values 0 (no) and 1 (yes). For XInclude,
3794 * however, we allow a value of 2 to indicate copy properties and
3795 * namespace info, but don't recurse on children.
Owen Taylor3473f882001-02-23 17:55:21 +00003796 */
3797
3798static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003799xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
William M. Brack57e9e912004-03-09 16:19:02 +00003800 int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003801 xmlNodePtr ret;
3802
3803 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003804 switch (node->type) {
3805 case XML_TEXT_NODE:
3806 case XML_CDATA_SECTION_NODE:
3807 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003808 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003809 case XML_ENTITY_REF_NODE:
3810 case XML_ENTITY_NODE:
3811 case XML_PI_NODE:
3812 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003813 case XML_XINCLUDE_START:
3814 case XML_XINCLUDE_END:
3815 break;
3816 case XML_ATTRIBUTE_NODE:
3817 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3818 case XML_NAMESPACE_DECL:
3819 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3820
Daniel Veillard39196eb2001-06-19 18:09:42 +00003821 case XML_DOCUMENT_NODE:
3822 case XML_HTML_DOCUMENT_NODE:
3823#ifdef LIBXML_DOCB_ENABLED
3824 case XML_DOCB_DOCUMENT_NODE:
3825#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00003826#ifdef LIBXML_TREE_ENABLED
William M. Brack57e9e912004-03-09 16:19:02 +00003827 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
Daniel Veillard652327a2003-09-29 18:02:38 +00003828#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00003829 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003830 case XML_NOTATION_NODE:
3831 case XML_DTD_NODE:
3832 case XML_ELEMENT_DECL:
3833 case XML_ATTRIBUTE_DECL:
3834 case XML_ENTITY_DECL:
3835 return(NULL);
3836 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003837
Owen Taylor3473f882001-02-23 17:55:21 +00003838 /*
3839 * Allocate a new node and fill the fields.
3840 */
3841 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3842 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00003843 xmlTreeErrMemory("copying node");
Owen Taylor3473f882001-02-23 17:55:21 +00003844 return(NULL);
3845 }
3846 memset(ret, 0, sizeof(xmlNode));
3847 ret->type = node->type;
3848
3849 ret->doc = doc;
3850 ret->parent = parent;
3851 if (node->name == xmlStringText)
3852 ret->name = xmlStringText;
3853 else if (node->name == xmlStringTextNoenc)
3854 ret->name = xmlStringTextNoenc;
3855 else if (node->name == xmlStringComment)
3856 ret->name = xmlStringComment;
Daniel Veillard03a53c32004-10-26 16:06:51 +00003857 else if (node->name != NULL) {
3858 if ((doc != NULL) && (doc->dict != NULL))
3859 ret->name = xmlDictLookup(doc->dict, node->name, -1);
3860 else
3861 ret->name = xmlStrdup(node->name);
3862 }
Daniel Veillard7db37732001-07-12 01:20:08 +00003863 if ((node->type != XML_ELEMENT_NODE) &&
3864 (node->content != NULL) &&
3865 (node->type != XML_ENTITY_REF_NODE) &&
3866 (node->type != XML_XINCLUDE_END) &&
3867 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003868 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003869 }else{
3870 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00003871 ret->line = node->line;
Owen Taylor3473f882001-02-23 17:55:21 +00003872 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003873 if (parent != NULL) {
3874 xmlNodePtr tmp;
3875
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003876 /*
3877 * this is a tricky part for the node register thing:
3878 * in case ret does get coalesced in xmlAddChild
3879 * the deregister-node callback is called; so we register ret now already
3880 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003881 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003882 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3883
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003884 tmp = xmlAddChild(parent, ret);
3885 /* node could have coalesced */
3886 if (tmp != ret)
3887 return(tmp);
3888 }
Owen Taylor3473f882001-02-23 17:55:21 +00003889
William M. Brack57e9e912004-03-09 16:19:02 +00003890 if (!extended)
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003891 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003892 if (node->nsDef != NULL)
3893 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3894
3895 if (node->ns != NULL) {
3896 xmlNsPtr ns;
3897
3898 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3899 if (ns == NULL) {
3900 /*
3901 * Humm, we are copying an element whose namespace is defined
3902 * out of the new tree scope. Search it in the original tree
3903 * and add it at the top of the new tree
3904 */
3905 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3906 if (ns != NULL) {
3907 xmlNodePtr root = ret;
3908
3909 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003910 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003911 }
3912 } else {
3913 /*
3914 * reference the existing namespace definition in our own tree.
3915 */
3916 ret->ns = ns;
3917 }
3918 }
3919 if (node->properties != NULL)
3920 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003921 if (node->type == XML_ENTITY_REF_NODE) {
3922 if ((doc == NULL) || (node->doc != doc)) {
3923 /*
3924 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003925 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003926 * we cannot keep the reference. Try to find it in the
3927 * target document.
3928 */
3929 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3930 } else {
3931 ret->children = node->children;
3932 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003933 ret->last = ret->children;
William M. Brack57e9e912004-03-09 16:19:02 +00003934 } else if ((node->children != NULL) && (extended != 2)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003935 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003936 UPDATE_LAST_CHILD_AND_PARENT(ret)
3937 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003938
3939out:
3940 /* if parent != NULL we already registered the node above */
Daniel Veillardac996a12004-07-30 12:02:58 +00003941 if ((parent == NULL) &&
3942 ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003943 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003944 return(ret);
3945}
3946
3947static xmlNodePtr
3948xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3949 xmlNodePtr ret = NULL;
3950 xmlNodePtr p = NULL,q;
3951
3952 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00003953#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003954 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003955 if (doc == NULL) {
3956 node = node->next;
3957 continue;
3958 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003959 if (doc->intSubset == NULL) {
3960 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3961 q->doc = doc;
3962 q->parent = parent;
3963 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003964 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003965 } else {
3966 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003967 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003968 }
3969 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00003970#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00003971 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003972 if (ret == NULL) {
3973 q->prev = NULL;
3974 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003975 } else if (p != q) {
3976 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003977 p->next = q;
3978 q->prev = p;
3979 p = q;
3980 }
3981 node = node->next;
3982 }
3983 return(ret);
3984}
3985
3986/**
3987 * xmlCopyNode:
3988 * @node: the node
William M. Brack57e9e912004-03-09 16:19:02 +00003989 * @extended: if 1 do a recursive copy (properties, namespaces and children
3990 * when applicable)
3991 * if 2 copy properties and namespaces (when applicable)
Owen Taylor3473f882001-02-23 17:55:21 +00003992 *
3993 * Do a copy of the node.
3994 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003995 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003996 */
3997xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00003998xmlCopyNode(const xmlNodePtr node, int extended) {
Owen Taylor3473f882001-02-23 17:55:21 +00003999 xmlNodePtr ret;
4000
William M. Brack57e9e912004-03-09 16:19:02 +00004001 ret = xmlStaticCopyNode(node, NULL, NULL, extended);
Owen Taylor3473f882001-02-23 17:55:21 +00004002 return(ret);
4003}
4004
4005/**
Daniel Veillard82daa812001-04-12 08:55:36 +00004006 * xmlDocCopyNode:
4007 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00004008 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004009 * @extended: if 1 do a recursive copy (properties, namespaces and children
4010 * when applicable)
4011 * if 2 copy properties and namespaces (when applicable)
Daniel Veillard82daa812001-04-12 08:55:36 +00004012 *
4013 * Do a copy of the node to a given document.
4014 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004015 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00004016 */
4017xmlNodePtr
William M. Brack57e9e912004-03-09 16:19:02 +00004018xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int extended) {
Daniel Veillard82daa812001-04-12 08:55:36 +00004019 xmlNodePtr ret;
4020
William M. Brack57e9e912004-03-09 16:19:02 +00004021 ret = xmlStaticCopyNode(node, doc, NULL, extended);
Daniel Veillard82daa812001-04-12 08:55:36 +00004022 return(ret);
4023}
4024
4025/**
Daniel Veillard03a53c32004-10-26 16:06:51 +00004026 * xmlDocCopyNodeList:
4027 * @doc: the target document
4028 * @node: the first node in the list.
4029 *
4030 * Do a recursive copy of the node list.
4031 *
4032 * Returns: a new #xmlNodePtr, or NULL in case of error.
4033 */
4034xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, const xmlNodePtr node) {
4035 xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL);
4036 return(ret);
4037}
4038
4039/**
Owen Taylor3473f882001-02-23 17:55:21 +00004040 * xmlCopyNodeList:
4041 * @node: the first node in the list.
4042 *
4043 * Do a recursive copy of the node list.
Daniel Veillard03a53c32004-10-26 16:06:51 +00004044 * Use xmlDocCopyNodeList() if possible to ensure string interning.
Owen Taylor3473f882001-02-23 17:55:21 +00004045 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004046 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004047 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00004048xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00004049 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
4050 return(ret);
4051}
4052
Daniel Veillard2156d432004-03-04 15:59:36 +00004053#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004054/**
Owen Taylor3473f882001-02-23 17:55:21 +00004055 * xmlCopyDtd:
4056 * @dtd: the dtd
4057 *
4058 * Do a copy of the dtd.
4059 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004060 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004061 */
4062xmlDtdPtr
4063xmlCopyDtd(xmlDtdPtr dtd) {
4064 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004065 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00004066
4067 if (dtd == NULL) return(NULL);
4068 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
4069 if (ret == NULL) return(NULL);
4070 if (dtd->entities != NULL)
4071 ret->entities = (void *) xmlCopyEntitiesTable(
4072 (xmlEntitiesTablePtr) dtd->entities);
4073 if (dtd->notations != NULL)
4074 ret->notations = (void *) xmlCopyNotationTable(
4075 (xmlNotationTablePtr) dtd->notations);
4076 if (dtd->elements != NULL)
4077 ret->elements = (void *) xmlCopyElementTable(
4078 (xmlElementTablePtr) dtd->elements);
4079 if (dtd->attributes != NULL)
4080 ret->attributes = (void *) xmlCopyAttributeTable(
4081 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004082 if (dtd->pentities != NULL)
4083 ret->pentities = (void *) xmlCopyEntitiesTable(
4084 (xmlEntitiesTablePtr) dtd->pentities);
4085
4086 cur = dtd->children;
4087 while (cur != NULL) {
4088 q = NULL;
4089
4090 if (cur->type == XML_ENTITY_DECL) {
4091 xmlEntityPtr tmp = (xmlEntityPtr) cur;
4092 switch (tmp->etype) {
4093 case XML_INTERNAL_GENERAL_ENTITY:
4094 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
4095 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
4096 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4097 break;
4098 case XML_INTERNAL_PARAMETER_ENTITY:
4099 case XML_EXTERNAL_PARAMETER_ENTITY:
4100 q = (xmlNodePtr)
4101 xmlGetParameterEntityFromDtd(ret, tmp->name);
4102 break;
4103 case XML_INTERNAL_PREDEFINED_ENTITY:
4104 break;
4105 }
4106 } else if (cur->type == XML_ELEMENT_DECL) {
4107 xmlElementPtr tmp = (xmlElementPtr) cur;
4108 q = (xmlNodePtr)
4109 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4110 } else if (cur->type == XML_ATTRIBUTE_DECL) {
4111 xmlAttributePtr tmp = (xmlAttributePtr) cur;
4112 q = (xmlNodePtr)
4113 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4114 } else if (cur->type == XML_COMMENT_NODE) {
4115 q = xmlCopyNode(cur, 0);
4116 }
4117
4118 if (q == NULL) {
4119 cur = cur->next;
4120 continue;
4121 }
4122
4123 if (p == NULL)
4124 ret->children = q;
4125 else
4126 p->next = q;
4127
4128 q->prev = p;
4129 q->parent = (xmlNodePtr) ret;
4130 q->next = NULL;
4131 ret->last = q;
4132 p = q;
4133 cur = cur->next;
4134 }
4135
Owen Taylor3473f882001-02-23 17:55:21 +00004136 return(ret);
4137}
Daniel Veillard2156d432004-03-04 15:59:36 +00004138#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004139
Daniel Veillard2156d432004-03-04 15:59:36 +00004140#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004141/**
4142 * xmlCopyDoc:
4143 * @doc: the document
William M. Brack57e9e912004-03-09 16:19:02 +00004144 * @recursive: if not zero do a recursive copy.
Owen Taylor3473f882001-02-23 17:55:21 +00004145 *
4146 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004147 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004148 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004149 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004150 */
4151xmlDocPtr
4152xmlCopyDoc(xmlDocPtr doc, int recursive) {
4153 xmlDocPtr ret;
4154
4155 if (doc == NULL) return(NULL);
4156 ret = xmlNewDoc(doc->version);
4157 if (ret == NULL) return(NULL);
4158 if (doc->name != NULL)
4159 ret->name = xmlMemStrdup(doc->name);
4160 if (doc->encoding != NULL)
4161 ret->encoding = xmlStrdup(doc->encoding);
4162 ret->charset = doc->charset;
4163 ret->compression = doc->compression;
4164 ret->standalone = doc->standalone;
4165 if (!recursive) return(ret);
4166
Daniel Veillardb33c2012001-04-25 12:59:04 +00004167 ret->last = NULL;
4168 ret->children = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00004169#ifdef LIBXML_TREE_ENABLED
Daniel Veillardb33c2012001-04-25 12:59:04 +00004170 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004171 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004172 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004173 ret->intSubset->parent = ret;
4174 }
Daniel Veillard2156d432004-03-04 15:59:36 +00004175#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004176 if (doc->oldNs != NULL)
4177 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4178 if (doc->children != NULL) {
4179 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00004180
4181 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4182 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004183 ret->last = NULL;
4184 tmp = ret->children;
4185 while (tmp != NULL) {
4186 if (tmp->next == NULL)
4187 ret->last = tmp;
4188 tmp = tmp->next;
4189 }
4190 }
4191 return(ret);
4192}
Daniel Veillard652327a2003-09-29 18:02:38 +00004193#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004194
4195/************************************************************************
4196 * *
4197 * Content access functions *
4198 * *
4199 ************************************************************************/
4200
4201/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004202 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004203 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004204 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00004205 * Get line number of @node. This requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004206 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004207 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004208 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004209 */
4210long
4211xmlGetLineNo(xmlNodePtr node)
4212{
4213 long result = -1;
4214
4215 if (!node)
4216 return result;
4217 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004218 result = (long) node->line;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004219 else if ((node->prev != NULL) &&
4220 ((node->prev->type == XML_ELEMENT_NODE) ||
4221 (node->prev->type == XML_TEXT_NODE)))
4222 result = xmlGetLineNo(node->prev);
4223 else if ((node->parent != NULL) &&
4224 ((node->parent->type == XML_ELEMENT_NODE) ||
4225 (node->parent->type == XML_TEXT_NODE)))
4226 result = xmlGetLineNo(node->parent);
4227
4228 return result;
4229}
4230
Daniel Veillard2156d432004-03-04 15:59:36 +00004231#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004232/**
4233 * xmlGetNodePath:
4234 * @node: a node
4235 *
4236 * Build a structure based Path for the given node
4237 *
4238 * Returns the new path or NULL in case of error. The caller must free
4239 * the returned string
4240 */
4241xmlChar *
4242xmlGetNodePath(xmlNodePtr node)
4243{
4244 xmlNodePtr cur, tmp, next;
4245 xmlChar *buffer = NULL, *temp;
4246 size_t buf_len;
4247 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004248 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004249 const char *name;
4250 char nametemp[100];
4251 int occur = 0;
4252
4253 if (node == NULL)
4254 return (NULL);
4255
4256 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004257 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004258 if (buffer == NULL) {
4259 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004260 return (NULL);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004261 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004262 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004263 if (buf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004264 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004265 xmlFree(buffer);
4266 return (NULL);
4267 }
4268
4269 buffer[0] = 0;
4270 cur = node;
4271 do {
4272 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004273 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004274 occur = 0;
4275 if ((cur->type == XML_DOCUMENT_NODE) ||
4276 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4277 if (buffer[0] == '/')
4278 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004279 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004280 next = NULL;
4281 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004282 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004283 name = (const char *) cur->name;
4284 if (cur->ns) {
William M. Brack84d83e32003-12-23 03:45:17 +00004285 if (cur->ns->prefix != NULL)
William M. Brack13dfa872004-09-18 04:52:08 +00004286 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4287 (char *)cur->ns->prefix, (char *)cur->name);
William M. Brack84d83e32003-12-23 03:45:17 +00004288 else
William M. Brack13dfa872004-09-18 04:52:08 +00004289 snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4290 (char *)cur->name);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004291 nametemp[sizeof(nametemp) - 1] = 0;
4292 name = nametemp;
4293 }
4294 next = cur->parent;
4295
4296 /*
4297 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004298 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004299 */
4300 tmp = cur->prev;
4301 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004302 if ((tmp->type == XML_ELEMENT_NODE) &&
4303 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004304 occur++;
4305 tmp = tmp->prev;
4306 }
4307 if (occur == 0) {
4308 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004309 while (tmp != NULL && occur == 0) {
4310 if ((tmp->type == XML_ELEMENT_NODE) &&
4311 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004312 occur++;
4313 tmp = tmp->next;
4314 }
4315 if (occur != 0)
4316 occur = 1;
4317 } else
4318 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004319 } else if (cur->type == XML_COMMENT_NODE) {
4320 sep = "/";
4321 name = "comment()";
4322 next = cur->parent;
4323
4324 /*
4325 * Thumbler index computation
4326 */
4327 tmp = cur->prev;
4328 while (tmp != NULL) {
4329 if (tmp->type == XML_COMMENT_NODE)
4330 occur++;
4331 tmp = tmp->prev;
4332 }
4333 if (occur == 0) {
4334 tmp = cur->next;
4335 while (tmp != NULL && occur == 0) {
4336 if (tmp->type == XML_COMMENT_NODE)
4337 occur++;
4338 tmp = tmp->next;
4339 }
4340 if (occur != 0)
4341 occur = 1;
4342 } else
4343 occur++;
4344 } else if ((cur->type == XML_TEXT_NODE) ||
4345 (cur->type == XML_CDATA_SECTION_NODE)) {
4346 sep = "/";
4347 name = "text()";
4348 next = cur->parent;
4349
4350 /*
4351 * Thumbler index computation
4352 */
4353 tmp = cur->prev;
4354 while (tmp != NULL) {
4355 if ((cur->type == XML_TEXT_NODE) ||
4356 (cur->type == XML_CDATA_SECTION_NODE))
4357 occur++;
4358 tmp = tmp->prev;
4359 }
4360 if (occur == 0) {
4361 tmp = cur->next;
4362 while (tmp != NULL && occur == 0) {
Daniel Veillard1f8658a2004-08-14 21:46:31 +00004363 if ((tmp->type == XML_TEXT_NODE) ||
4364 (tmp->type == XML_CDATA_SECTION_NODE))
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004365 occur++;
4366 tmp = tmp->next;
4367 }
4368 if (occur != 0)
4369 occur = 1;
4370 } else
4371 occur++;
4372 } else if (cur->type == XML_PI_NODE) {
4373 sep = "/";
4374 snprintf(nametemp, sizeof(nametemp) - 1,
William M. Brack13dfa872004-09-18 04:52:08 +00004375 "processing-instruction('%s')", (char *)cur->name);
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004376 nametemp[sizeof(nametemp) - 1] = 0;
4377 name = nametemp;
4378
4379 next = cur->parent;
4380
4381 /*
4382 * Thumbler index computation
4383 */
4384 tmp = cur->prev;
4385 while (tmp != NULL) {
4386 if ((tmp->type == XML_PI_NODE) &&
4387 (xmlStrEqual(cur->name, tmp->name)))
4388 occur++;
4389 tmp = tmp->prev;
4390 }
4391 if (occur == 0) {
4392 tmp = cur->next;
4393 while (tmp != NULL && occur == 0) {
4394 if ((tmp->type == XML_PI_NODE) &&
4395 (xmlStrEqual(cur->name, tmp->name)))
4396 occur++;
4397 tmp = tmp->next;
4398 }
4399 if (occur != 0)
4400 occur = 1;
4401 } else
4402 occur++;
4403
Daniel Veillard8faa7832001-11-26 15:58:08 +00004404 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004405 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004406 name = (const char *) (((xmlAttrPtr) cur)->name);
4407 next = ((xmlAttrPtr) cur)->parent;
4408 } else {
4409 next = cur->parent;
4410 }
4411
4412 /*
4413 * Make sure there is enough room
4414 */
4415 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4416 buf_len =
4417 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4418 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4419 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004420 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004421 xmlFree(buf);
4422 xmlFree(buffer);
4423 return (NULL);
4424 }
4425 buffer = temp;
4426 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4427 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004428 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004429 xmlFree(buf);
4430 xmlFree(buffer);
4431 return (NULL);
4432 }
4433 buf = temp;
4434 }
4435 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004436 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004437 sep, name, (char *) buffer);
4438 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004439 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004440 sep, name, occur, (char *) buffer);
William M. Brack13dfa872004-09-18 04:52:08 +00004441 snprintf((char *) buffer, buf_len, "%s", (char *)buf);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004442 cur = next;
4443 } while (cur != NULL);
4444 xmlFree(buf);
4445 return (buffer);
4446}
Daniel Veillard652327a2003-09-29 18:02:38 +00004447#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004448
4449/**
Owen Taylor3473f882001-02-23 17:55:21 +00004450 * xmlDocGetRootElement:
4451 * @doc: the document
4452 *
4453 * Get the root element of the document (doc->children is a list
4454 * containing possibly comments, PIs, etc ...).
4455 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004456 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004457 */
4458xmlNodePtr
4459xmlDocGetRootElement(xmlDocPtr doc) {
4460 xmlNodePtr ret;
4461
4462 if (doc == NULL) return(NULL);
4463 ret = doc->children;
4464 while (ret != NULL) {
4465 if (ret->type == XML_ELEMENT_NODE)
4466 return(ret);
4467 ret = ret->next;
4468 }
4469 return(ret);
4470}
4471
Daniel Veillard2156d432004-03-04 15:59:36 +00004472#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004473/**
4474 * xmlDocSetRootElement:
4475 * @doc: the document
4476 * @root: the new document root element
4477 *
4478 * Set the root element of the document (doc->children is a list
4479 * containing possibly comments, PIs, etc ...).
4480 *
4481 * Returns the old root element if any was found
4482 */
4483xmlNodePtr
4484xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4485 xmlNodePtr old = NULL;
4486
4487 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004488 if (root == NULL)
4489 return(NULL);
4490 xmlUnlinkNode(root);
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00004491 xmlSetTreeDoc(root, doc);
Daniel Veillardc575b992002-02-08 13:28:40 +00004492 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004493 old = doc->children;
4494 while (old != NULL) {
4495 if (old->type == XML_ELEMENT_NODE)
4496 break;
4497 old = old->next;
4498 }
4499 if (old == NULL) {
4500 if (doc->children == NULL) {
4501 doc->children = root;
4502 doc->last = root;
4503 } else {
4504 xmlAddSibling(doc->children, root);
4505 }
4506 } else {
4507 xmlReplaceNode(old, root);
4508 }
4509 return(old);
4510}
Daniel Veillard2156d432004-03-04 15:59:36 +00004511#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004512
Daniel Veillard2156d432004-03-04 15:59:36 +00004513#if defined(LIBXML_TREE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004514/**
4515 * xmlNodeSetLang:
4516 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004517 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004518 *
4519 * Set the language of a node, i.e. the values of the xml:lang
4520 * attribute.
4521 */
4522void
4523xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004524 xmlNsPtr ns;
4525
Owen Taylor3473f882001-02-23 17:55:21 +00004526 if (cur == NULL) return;
4527 switch(cur->type) {
4528 case XML_TEXT_NODE:
4529 case XML_CDATA_SECTION_NODE:
4530 case XML_COMMENT_NODE:
4531 case XML_DOCUMENT_NODE:
4532 case XML_DOCUMENT_TYPE_NODE:
4533 case XML_DOCUMENT_FRAG_NODE:
4534 case XML_NOTATION_NODE:
4535 case XML_HTML_DOCUMENT_NODE:
4536 case XML_DTD_NODE:
4537 case XML_ELEMENT_DECL:
4538 case XML_ATTRIBUTE_DECL:
4539 case XML_ENTITY_DECL:
4540 case XML_PI_NODE:
4541 case XML_ENTITY_REF_NODE:
4542 case XML_ENTITY_NODE:
4543 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004544#ifdef LIBXML_DOCB_ENABLED
4545 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004546#endif
4547 case XML_XINCLUDE_START:
4548 case XML_XINCLUDE_END:
4549 return;
4550 case XML_ELEMENT_NODE:
4551 case XML_ATTRIBUTE_NODE:
4552 break;
4553 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004554 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4555 if (ns == NULL)
4556 return;
4557 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004558}
Daniel Veillard652327a2003-09-29 18:02:38 +00004559#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004560
4561/**
4562 * xmlNodeGetLang:
4563 * @cur: the node being checked
4564 *
4565 * Searches the language of a node, i.e. the values of the xml:lang
4566 * attribute or the one carried by the nearest ancestor.
4567 *
4568 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004569 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004570 */
4571xmlChar *
4572xmlNodeGetLang(xmlNodePtr cur) {
4573 xmlChar *lang;
4574
4575 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004576 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004577 if (lang != NULL)
4578 return(lang);
4579 cur = cur->parent;
4580 }
4581 return(NULL);
4582}
4583
4584
Daniel Veillard652327a2003-09-29 18:02:38 +00004585#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004586/**
4587 * xmlNodeSetSpacePreserve:
4588 * @cur: the node being changed
4589 * @val: the xml:space value ("0": default, 1: "preserve")
4590 *
4591 * Set (or reset) the space preserving behaviour of a node, i.e. the
4592 * value of the xml:space attribute.
4593 */
4594void
4595xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004596 xmlNsPtr ns;
4597
Owen Taylor3473f882001-02-23 17:55:21 +00004598 if (cur == NULL) return;
4599 switch(cur->type) {
4600 case XML_TEXT_NODE:
4601 case XML_CDATA_SECTION_NODE:
4602 case XML_COMMENT_NODE:
4603 case XML_DOCUMENT_NODE:
4604 case XML_DOCUMENT_TYPE_NODE:
4605 case XML_DOCUMENT_FRAG_NODE:
4606 case XML_NOTATION_NODE:
4607 case XML_HTML_DOCUMENT_NODE:
4608 case XML_DTD_NODE:
4609 case XML_ELEMENT_DECL:
4610 case XML_ATTRIBUTE_DECL:
4611 case XML_ENTITY_DECL:
4612 case XML_PI_NODE:
4613 case XML_ENTITY_REF_NODE:
4614 case XML_ENTITY_NODE:
4615 case XML_NAMESPACE_DECL:
4616 case XML_XINCLUDE_START:
4617 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004618#ifdef LIBXML_DOCB_ENABLED
4619 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004620#endif
4621 return;
4622 case XML_ELEMENT_NODE:
4623 case XML_ATTRIBUTE_NODE:
4624 break;
4625 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004626 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4627 if (ns == NULL)
4628 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004629 switch (val) {
4630 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004631 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004632 break;
4633 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004634 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004635 break;
4636 }
4637}
Daniel Veillard652327a2003-09-29 18:02:38 +00004638#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004639
4640/**
4641 * xmlNodeGetSpacePreserve:
4642 * @cur: the node being checked
4643 *
4644 * Searches the space preserving behaviour of a node, i.e. the values
4645 * of the xml:space attribute or the one carried by the nearest
4646 * ancestor.
4647 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004648 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004649 */
4650int
4651xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4652 xmlChar *space;
4653
4654 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004655 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004656 if (space != NULL) {
4657 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4658 xmlFree(space);
4659 return(1);
4660 }
4661 if (xmlStrEqual(space, BAD_CAST "default")) {
4662 xmlFree(space);
4663 return(0);
4664 }
4665 xmlFree(space);
4666 }
4667 cur = cur->parent;
4668 }
4669 return(-1);
4670}
4671
Daniel Veillard652327a2003-09-29 18:02:38 +00004672#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004673/**
4674 * xmlNodeSetName:
4675 * @cur: the node being changed
4676 * @name: the new tag name
4677 *
4678 * Set (or reset) the name of a node.
4679 */
4680void
4681xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00004682 xmlDocPtr doc;
4683 xmlDictPtr dict;
4684
Owen Taylor3473f882001-02-23 17:55:21 +00004685 if (cur == NULL) return;
4686 if (name == NULL) return;
4687 switch(cur->type) {
4688 case XML_TEXT_NODE:
4689 case XML_CDATA_SECTION_NODE:
4690 case XML_COMMENT_NODE:
4691 case XML_DOCUMENT_TYPE_NODE:
4692 case XML_DOCUMENT_FRAG_NODE:
4693 case XML_NOTATION_NODE:
4694 case XML_HTML_DOCUMENT_NODE:
4695 case XML_NAMESPACE_DECL:
4696 case XML_XINCLUDE_START:
4697 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004698#ifdef LIBXML_DOCB_ENABLED
4699 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004700#endif
4701 return;
4702 case XML_ELEMENT_NODE:
4703 case XML_ATTRIBUTE_NODE:
4704 case XML_PI_NODE:
4705 case XML_ENTITY_REF_NODE:
4706 case XML_ENTITY_NODE:
4707 case XML_DTD_NODE:
4708 case XML_DOCUMENT_NODE:
4709 case XML_ELEMENT_DECL:
4710 case XML_ATTRIBUTE_DECL:
4711 case XML_ENTITY_DECL:
4712 break;
4713 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00004714 doc = cur->doc;
4715 if (doc != NULL)
4716 dict = doc->dict;
4717 else
4718 dict = NULL;
4719 if (dict != NULL) {
4720 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
4721 xmlFree((xmlChar *) cur->name);
4722 cur->name = xmlDictLookup(dict, name, -1);
4723 } else {
4724 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4725 cur->name = xmlStrdup(name);
4726 }
Owen Taylor3473f882001-02-23 17:55:21 +00004727}
Daniel Veillard2156d432004-03-04 15:59:36 +00004728#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004729
Daniel Veillard2156d432004-03-04 15:59:36 +00004730#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00004731/**
4732 * xmlNodeSetBase:
4733 * @cur: the node being changed
4734 * @uri: the new base URI
4735 *
4736 * Set (or reset) the base URI of a node, i.e. the value of the
4737 * xml:base attribute.
4738 */
4739void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00004740xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004741 xmlNsPtr ns;
4742
Owen Taylor3473f882001-02-23 17:55:21 +00004743 if (cur == NULL) return;
4744 switch(cur->type) {
4745 case XML_TEXT_NODE:
4746 case XML_CDATA_SECTION_NODE:
4747 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004748 case XML_DOCUMENT_TYPE_NODE:
4749 case XML_DOCUMENT_FRAG_NODE:
4750 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004751 case XML_DTD_NODE:
4752 case XML_ELEMENT_DECL:
4753 case XML_ATTRIBUTE_DECL:
4754 case XML_ENTITY_DECL:
4755 case XML_PI_NODE:
4756 case XML_ENTITY_REF_NODE:
4757 case XML_ENTITY_NODE:
4758 case XML_NAMESPACE_DECL:
4759 case XML_XINCLUDE_START:
4760 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004761 return;
4762 case XML_ELEMENT_NODE:
4763 case XML_ATTRIBUTE_NODE:
4764 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004765 case XML_DOCUMENT_NODE:
4766#ifdef LIBXML_DOCB_ENABLED
4767 case XML_DOCB_DOCUMENT_NODE:
4768#endif
4769 case XML_HTML_DOCUMENT_NODE: {
4770 xmlDocPtr doc = (xmlDocPtr) cur;
4771
4772 if (doc->URL != NULL)
4773 xmlFree((xmlChar *) doc->URL);
4774 if (uri == NULL)
4775 doc->URL = NULL;
4776 else
4777 doc->URL = xmlStrdup(uri);
4778 return;
4779 }
Owen Taylor3473f882001-02-23 17:55:21 +00004780 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004781
4782 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4783 if (ns == NULL)
4784 return;
4785 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004786}
Daniel Veillard652327a2003-09-29 18:02:38 +00004787#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004788
4789/**
Owen Taylor3473f882001-02-23 17:55:21 +00004790 * xmlNodeGetBase:
4791 * @doc: the document the node pertains to
4792 * @cur: the node being checked
4793 *
4794 * Searches for the BASE URL. The code should work on both XML
4795 * and HTML document even if base mechanisms are completely different.
4796 * It returns the base as defined in RFC 2396 sections
4797 * 5.1.1. Base URI within Document Content
4798 * and
4799 * 5.1.2. Base URI from the Encapsulating Entity
4800 * However it does not return the document base (5.1.3), use
4801 * xmlDocumentGetBase() for this
4802 *
4803 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004804 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004805 */
4806xmlChar *
4807xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004808 xmlChar *oldbase = NULL;
4809 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004810
4811 if ((cur == NULL) && (doc == NULL))
4812 return(NULL);
4813 if (doc == NULL) doc = cur->doc;
4814 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4815 cur = doc->children;
4816 while ((cur != NULL) && (cur->name != NULL)) {
4817 if (cur->type != XML_ELEMENT_NODE) {
4818 cur = cur->next;
4819 continue;
4820 }
4821 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4822 cur = cur->children;
4823 continue;
4824 }
4825 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4826 cur = cur->children;
4827 continue;
4828 }
4829 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4830 return(xmlGetProp(cur, BAD_CAST "href"));
4831 }
4832 cur = cur->next;
4833 }
4834 return(NULL);
4835 }
4836 while (cur != NULL) {
4837 if (cur->type == XML_ENTITY_DECL) {
4838 xmlEntityPtr ent = (xmlEntityPtr) cur;
4839 return(xmlStrdup(ent->URI));
4840 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004841 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004842 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004843 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004844 if (oldbase != NULL) {
4845 newbase = xmlBuildURI(oldbase, base);
4846 if (newbase != NULL) {
4847 xmlFree(oldbase);
4848 xmlFree(base);
4849 oldbase = newbase;
4850 } else {
4851 xmlFree(oldbase);
4852 xmlFree(base);
4853 return(NULL);
4854 }
4855 } else {
4856 oldbase = base;
4857 }
4858 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4859 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4860 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4861 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004862 }
4863 }
Owen Taylor3473f882001-02-23 17:55:21 +00004864 cur = cur->parent;
4865 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004866 if ((doc != NULL) && (doc->URL != NULL)) {
4867 if (oldbase == NULL)
4868 return(xmlStrdup(doc->URL));
4869 newbase = xmlBuildURI(oldbase, doc->URL);
4870 xmlFree(oldbase);
4871 return(newbase);
4872 }
4873 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004874}
4875
4876/**
Daniel Veillard78697292003-10-19 20:44:43 +00004877 * xmlNodeBufGetContent:
4878 * @buffer: a buffer
4879 * @cur: the node being read
4880 *
4881 * Read the value of a node @cur, this can be either the text carried
4882 * directly by this node if it's a TEXT node or the aggregate string
4883 * of the values carried by this node child's (TEXT and ENTITY_REF).
4884 * Entity references are substituted.
4885 * Fills up the buffer @buffer with this value
4886 *
4887 * Returns 0 in case of success and -1 in case of error.
4888 */
4889int
4890xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
4891{
4892 if ((cur == NULL) || (buffer == NULL)) return(-1);
4893 switch (cur->type) {
4894 case XML_CDATA_SECTION_NODE:
4895 case XML_TEXT_NODE:
4896 xmlBufferCat(buffer, cur->content);
4897 break;
4898 case XML_DOCUMENT_FRAG_NODE:
4899 case XML_ELEMENT_NODE:{
4900 xmlNodePtr tmp = cur;
4901
4902 while (tmp != NULL) {
4903 switch (tmp->type) {
4904 case XML_CDATA_SECTION_NODE:
4905 case XML_TEXT_NODE:
4906 if (tmp->content != NULL)
4907 xmlBufferCat(buffer, tmp->content);
4908 break;
4909 case XML_ENTITY_REF_NODE:
4910 xmlNodeBufGetContent(buffer, tmp->children);
4911 break;
4912 default:
4913 break;
4914 }
4915 /*
4916 * Skip to next node
4917 */
4918 if (tmp->children != NULL) {
4919 if (tmp->children->type != XML_ENTITY_DECL) {
4920 tmp = tmp->children;
4921 continue;
4922 }
4923 }
4924 if (tmp == cur)
4925 break;
4926
4927 if (tmp->next != NULL) {
4928 tmp = tmp->next;
4929 continue;
4930 }
4931
4932 do {
4933 tmp = tmp->parent;
4934 if (tmp == NULL)
4935 break;
4936 if (tmp == cur) {
4937 tmp = NULL;
4938 break;
4939 }
4940 if (tmp->next != NULL) {
4941 tmp = tmp->next;
4942 break;
4943 }
4944 } while (tmp != NULL);
4945 }
4946 break;
4947 }
4948 case XML_ATTRIBUTE_NODE:{
4949 xmlAttrPtr attr = (xmlAttrPtr) cur;
4950 xmlNodePtr tmp = attr->children;
4951
4952 while (tmp != NULL) {
4953 if (tmp->type == XML_TEXT_NODE)
4954 xmlBufferCat(buffer, tmp->content);
4955 else
4956 xmlNodeBufGetContent(buffer, tmp);
4957 tmp = tmp->next;
4958 }
4959 break;
4960 }
4961 case XML_COMMENT_NODE:
4962 case XML_PI_NODE:
4963 xmlBufferCat(buffer, cur->content);
4964 break;
4965 case XML_ENTITY_REF_NODE:{
4966 xmlEntityPtr ent;
4967 xmlNodePtr tmp;
4968
4969 /* lookup entity declaration */
4970 ent = xmlGetDocEntity(cur->doc, cur->name);
4971 if (ent == NULL)
4972 return(-1);
4973
4974 /* an entity content can be any "well balanced chunk",
4975 * i.e. the result of the content [43] production:
4976 * http://www.w3.org/TR/REC-xml#NT-content
4977 * -> we iterate through child nodes and recursive call
4978 * xmlNodeGetContent() which handles all possible node types */
4979 tmp = ent->children;
4980 while (tmp) {
4981 xmlNodeBufGetContent(buffer, tmp);
4982 tmp = tmp->next;
4983 }
4984 break;
4985 }
4986 case XML_ENTITY_NODE:
4987 case XML_DOCUMENT_TYPE_NODE:
4988 case XML_NOTATION_NODE:
4989 case XML_DTD_NODE:
4990 case XML_XINCLUDE_START:
4991 case XML_XINCLUDE_END:
4992 break;
4993 case XML_DOCUMENT_NODE:
4994#ifdef LIBXML_DOCB_ENABLED
4995 case XML_DOCB_DOCUMENT_NODE:
4996#endif
4997 case XML_HTML_DOCUMENT_NODE:
4998 cur = cur->children;
4999 while (cur!= NULL) {
5000 if ((cur->type == XML_ELEMENT_NODE) ||
5001 (cur->type == XML_TEXT_NODE) ||
5002 (cur->type == XML_CDATA_SECTION_NODE)) {
5003 xmlNodeBufGetContent(buffer, cur);
5004 }
5005 cur = cur->next;
5006 }
5007 break;
5008 case XML_NAMESPACE_DECL:
5009 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
5010 break;
5011 case XML_ELEMENT_DECL:
5012 case XML_ATTRIBUTE_DECL:
5013 case XML_ENTITY_DECL:
5014 break;
5015 }
5016 return(0);
5017}
5018/**
Owen Taylor3473f882001-02-23 17:55:21 +00005019 * xmlNodeGetContent:
5020 * @cur: the node being read
5021 *
5022 * Read the value of a node, this can be either the text carried
5023 * directly by this node if it's a TEXT node or the aggregate string
5024 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00005025 * Entity references are substituted.
5026 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005027 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005028 */
5029xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00005030xmlNodeGetContent(xmlNodePtr cur)
5031{
5032 if (cur == NULL)
5033 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005034 switch (cur->type) {
5035 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005036 case XML_ELEMENT_NODE:{
Daniel Veillard7646b182002-04-20 06:41:40 +00005037 xmlBufferPtr buffer;
5038 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00005039
Daniel Veillard814a76d2003-01-23 18:24:20 +00005040 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00005041 if (buffer == NULL)
5042 return (NULL);
Daniel Veillardc4696922003-10-19 21:47:14 +00005043 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005044 ret = buffer->content;
5045 buffer->content = NULL;
5046 xmlBufferFree(buffer);
5047 return (ret);
5048 }
5049 case XML_ATTRIBUTE_NODE:{
5050 xmlAttrPtr attr = (xmlAttrPtr) cur;
5051
5052 if (attr->parent != NULL)
5053 return (xmlNodeListGetString
5054 (attr->parent->doc, attr->children, 1));
5055 else
5056 return (xmlNodeListGetString(NULL, attr->children, 1));
5057 break;
5058 }
Owen Taylor3473f882001-02-23 17:55:21 +00005059 case XML_COMMENT_NODE:
5060 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005061 if (cur->content != NULL)
5062 return (xmlStrdup(cur->content));
5063 return (NULL);
5064 case XML_ENTITY_REF_NODE:{
5065 xmlEntityPtr ent;
Daniel Veillard7646b182002-04-20 06:41:40 +00005066 xmlBufferPtr buffer;
5067 xmlChar *ret;
5068
5069 /* lookup entity declaration */
5070 ent = xmlGetDocEntity(cur->doc, cur->name);
5071 if (ent == NULL)
5072 return (NULL);
5073
5074 buffer = xmlBufferCreate();
5075 if (buffer == NULL)
5076 return (NULL);
5077
Daniel Veillardc4696922003-10-19 21:47:14 +00005078 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00005079
5080 ret = buffer->content;
5081 buffer->content = NULL;
5082 xmlBufferFree(buffer);
5083 return (ret);
5084 }
Owen Taylor3473f882001-02-23 17:55:21 +00005085 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005086 case XML_DOCUMENT_TYPE_NODE:
5087 case XML_NOTATION_NODE:
5088 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005089 case XML_XINCLUDE_START:
5090 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00005091 return (NULL);
5092 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005093#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00005094 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005095#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00005096 case XML_HTML_DOCUMENT_NODE: {
Daniel Veillardc4696922003-10-19 21:47:14 +00005097 xmlBufferPtr buffer;
5098 xmlChar *ret;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005099
Daniel Veillardc4696922003-10-19 21:47:14 +00005100 buffer = xmlBufferCreate();
5101 if (buffer == NULL)
5102 return (NULL);
5103
5104 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
5105
5106 ret = buffer->content;
5107 buffer->content = NULL;
5108 xmlBufferFree(buffer);
5109 return (ret);
Daniel Veillard9adc0462003-03-24 18:39:54 +00005110 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00005111 case XML_NAMESPACE_DECL: {
5112 xmlChar *tmp;
5113
5114 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
5115 return (tmp);
5116 }
Owen Taylor3473f882001-02-23 17:55:21 +00005117 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005118 /* TODO !!! */
5119 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005120 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005121 /* TODO !!! */
5122 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005123 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005124 /* TODO !!! */
5125 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005126 case XML_CDATA_SECTION_NODE:
5127 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005128 if (cur->content != NULL)
5129 return (xmlStrdup(cur->content));
5130 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005131 }
Daniel Veillard7646b182002-04-20 06:41:40 +00005132 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005133}
Daniel Veillard652327a2003-09-29 18:02:38 +00005134
Owen Taylor3473f882001-02-23 17:55:21 +00005135/**
5136 * xmlNodeSetContent:
5137 * @cur: the node being modified
5138 * @content: the new value of the content
5139 *
5140 * Replace the content of a node.
5141 */
5142void
5143xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5144 if (cur == NULL) {
5145#ifdef DEBUG_TREE
5146 xmlGenericError(xmlGenericErrorContext,
5147 "xmlNodeSetContent : node == NULL\n");
5148#endif
5149 return;
5150 }
5151 switch (cur->type) {
5152 case XML_DOCUMENT_FRAG_NODE:
5153 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005154 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005155 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5156 cur->children = xmlStringGetNodeList(cur->doc, content);
5157 UPDATE_LAST_CHILD_AND_PARENT(cur)
5158 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005159 case XML_TEXT_NODE:
5160 case XML_CDATA_SECTION_NODE:
5161 case XML_ENTITY_REF_NODE:
5162 case XML_ENTITY_NODE:
5163 case XML_PI_NODE:
5164 case XML_COMMENT_NODE:
5165 if (cur->content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005166 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
Daniel Veillard370ba3d2004-10-25 16:23:56 +00005167 (!xmlDictOwns(cur->doc->dict, cur->content))))
William M. Brack7762bb12004-01-04 14:49:01 +00005168 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005169 }
5170 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5171 cur->last = cur->children = NULL;
5172 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005173 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00005174 } else
5175 cur->content = NULL;
5176 break;
5177 case XML_DOCUMENT_NODE:
5178 case XML_HTML_DOCUMENT_NODE:
5179 case XML_DOCUMENT_TYPE_NODE:
5180 case XML_XINCLUDE_START:
5181 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005182#ifdef LIBXML_DOCB_ENABLED
5183 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005184#endif
5185 break;
5186 case XML_NOTATION_NODE:
5187 break;
5188 case XML_DTD_NODE:
5189 break;
5190 case XML_NAMESPACE_DECL:
5191 break;
5192 case XML_ELEMENT_DECL:
5193 /* TODO !!! */
5194 break;
5195 case XML_ATTRIBUTE_DECL:
5196 /* TODO !!! */
5197 break;
5198 case XML_ENTITY_DECL:
5199 /* TODO !!! */
5200 break;
5201 }
5202}
5203
Daniel Veillard652327a2003-09-29 18:02:38 +00005204#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005205/**
5206 * xmlNodeSetContentLen:
5207 * @cur: the node being modified
5208 * @content: the new value of the content
5209 * @len: the size of @content
5210 *
5211 * Replace the content of a node.
5212 */
5213void
5214xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5215 if (cur == NULL) {
5216#ifdef DEBUG_TREE
5217 xmlGenericError(xmlGenericErrorContext,
5218 "xmlNodeSetContentLen : node == NULL\n");
5219#endif
5220 return;
5221 }
5222 switch (cur->type) {
5223 case XML_DOCUMENT_FRAG_NODE:
5224 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005225 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005226 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5227 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5228 UPDATE_LAST_CHILD_AND_PARENT(cur)
5229 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005230 case XML_TEXT_NODE:
5231 case XML_CDATA_SECTION_NODE:
5232 case XML_ENTITY_REF_NODE:
5233 case XML_ENTITY_NODE:
5234 case XML_PI_NODE:
5235 case XML_COMMENT_NODE:
5236 case XML_NOTATION_NODE:
5237 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005238 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005239 }
5240 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5241 cur->children = cur->last = NULL;
5242 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005243 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005244 } else
5245 cur->content = NULL;
5246 break;
5247 case XML_DOCUMENT_NODE:
5248 case XML_DTD_NODE:
5249 case XML_HTML_DOCUMENT_NODE:
5250 case XML_DOCUMENT_TYPE_NODE:
5251 case XML_NAMESPACE_DECL:
5252 case XML_XINCLUDE_START:
5253 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005254#ifdef LIBXML_DOCB_ENABLED
5255 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005256#endif
5257 break;
5258 case XML_ELEMENT_DECL:
5259 /* TODO !!! */
5260 break;
5261 case XML_ATTRIBUTE_DECL:
5262 /* TODO !!! */
5263 break;
5264 case XML_ENTITY_DECL:
5265 /* TODO !!! */
5266 break;
5267 }
5268}
Daniel Veillard652327a2003-09-29 18:02:38 +00005269#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005270
5271/**
5272 * xmlNodeAddContentLen:
5273 * @cur: the node being modified
5274 * @content: extra content
5275 * @len: the size of @content
5276 *
5277 * Append the extra substring to the node content.
5278 */
5279void
5280xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5281 if (cur == NULL) {
5282#ifdef DEBUG_TREE
5283 xmlGenericError(xmlGenericErrorContext,
5284 "xmlNodeAddContentLen : node == NULL\n");
5285#endif
5286 return;
5287 }
5288 if (len <= 0) return;
5289 switch (cur->type) {
5290 case XML_DOCUMENT_FRAG_NODE:
5291 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005292 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005293
Daniel Veillard7db37732001-07-12 01:20:08 +00005294 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005295 newNode = xmlNewTextLen(content, len);
5296 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005297 tmp = xmlAddChild(cur, newNode);
5298 if (tmp != newNode)
5299 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005300 if ((last != NULL) && (last->next == newNode)) {
5301 xmlTextMerge(last, newNode);
5302 }
5303 }
5304 break;
5305 }
5306 case XML_ATTRIBUTE_NODE:
5307 break;
5308 case XML_TEXT_NODE:
5309 case XML_CDATA_SECTION_NODE:
5310 case XML_ENTITY_REF_NODE:
5311 case XML_ENTITY_NODE:
5312 case XML_PI_NODE:
5313 case XML_COMMENT_NODE:
5314 case XML_NOTATION_NODE:
5315 if (content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005316 if ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5317 xmlDictOwns(cur->doc->dict, cur->content)) {
5318 cur->content =
5319 xmlStrncatNew(cur->content, content, len);
5320 break;
5321 }
Owen Taylor3473f882001-02-23 17:55:21 +00005322 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005323 }
5324 case XML_DOCUMENT_NODE:
5325 case XML_DTD_NODE:
5326 case XML_HTML_DOCUMENT_NODE:
5327 case XML_DOCUMENT_TYPE_NODE:
5328 case XML_NAMESPACE_DECL:
5329 case XML_XINCLUDE_START:
5330 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005331#ifdef LIBXML_DOCB_ENABLED
5332 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005333#endif
5334 break;
5335 case XML_ELEMENT_DECL:
5336 case XML_ATTRIBUTE_DECL:
5337 case XML_ENTITY_DECL:
5338 break;
5339 }
5340}
5341
5342/**
5343 * xmlNodeAddContent:
5344 * @cur: the node being modified
5345 * @content: extra content
5346 *
5347 * Append the extra substring to the node content.
5348 */
5349void
5350xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5351 int len;
5352
5353 if (cur == NULL) {
5354#ifdef DEBUG_TREE
5355 xmlGenericError(xmlGenericErrorContext,
5356 "xmlNodeAddContent : node == NULL\n");
5357#endif
5358 return;
5359 }
5360 if (content == NULL) return;
5361 len = xmlStrlen(content);
5362 xmlNodeAddContentLen(cur, content, len);
5363}
5364
5365/**
5366 * xmlTextMerge:
5367 * @first: the first text node
5368 * @second: the second text node being merged
5369 *
5370 * Merge two text nodes into one
5371 * Returns the first text node augmented
5372 */
5373xmlNodePtr
5374xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5375 if (first == NULL) return(second);
5376 if (second == NULL) return(first);
5377 if (first->type != XML_TEXT_NODE) return(first);
5378 if (second->type != XML_TEXT_NODE) return(first);
5379 if (second->name != first->name)
5380 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005381 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005382 xmlUnlinkNode(second);
5383 xmlFreeNode(second);
5384 return(first);
5385}
5386
Daniel Veillard2156d432004-03-04 15:59:36 +00005387#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00005388/**
5389 * xmlGetNsList:
5390 * @doc: the document
5391 * @node: the current node
5392 *
5393 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005394 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005395 * that need to be freed by the caller or NULL if no
5396 * namespace if defined
5397 */
5398xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005399xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5400{
Owen Taylor3473f882001-02-23 17:55:21 +00005401 xmlNsPtr cur;
5402 xmlNsPtr *ret = NULL;
5403 int nbns = 0;
5404 int maxns = 10;
5405 int i;
5406
5407 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005408 if (node->type == XML_ELEMENT_NODE) {
5409 cur = node->nsDef;
5410 while (cur != NULL) {
5411 if (ret == NULL) {
5412 ret =
5413 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5414 sizeof(xmlNsPtr));
5415 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005416 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005417 return (NULL);
5418 }
5419 ret[nbns] = NULL;
5420 }
5421 for (i = 0; i < nbns; i++) {
5422 if ((cur->prefix == ret[i]->prefix) ||
5423 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5424 break;
5425 }
5426 if (i >= nbns) {
5427 if (nbns >= maxns) {
5428 maxns *= 2;
5429 ret = (xmlNsPtr *) xmlRealloc(ret,
5430 (maxns +
5431 1) *
5432 sizeof(xmlNsPtr));
5433 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005434 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005435 return (NULL);
5436 }
5437 }
5438 ret[nbns++] = cur;
5439 ret[nbns] = NULL;
5440 }
Owen Taylor3473f882001-02-23 17:55:21 +00005441
Daniel Veillard77044732001-06-29 21:31:07 +00005442 cur = cur->next;
5443 }
5444 }
5445 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005446 }
Daniel Veillard77044732001-06-29 21:31:07 +00005447 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005448}
Daniel Veillard652327a2003-09-29 18:02:38 +00005449#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005450
5451/**
5452 * xmlSearchNs:
5453 * @doc: the document
5454 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005455 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005456 *
5457 * Search a Ns registered under a given name space for a document.
5458 * recurse on the parents until it finds the defined namespace
5459 * or return NULL otherwise.
5460 * @nameSpace can be NULL, this is a search for the default namespace.
5461 * We don't allow to cross entities boundaries. If you don't declare
5462 * the namespace within those you will be in troubles !!! A warning
5463 * is generated to cover this case.
5464 *
5465 * Returns the namespace pointer or NULL.
5466 */
5467xmlNsPtr
5468xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillardf4e56292003-10-28 14:27:41 +00005469
Owen Taylor3473f882001-02-23 17:55:21 +00005470 xmlNsPtr cur;
Daniel Veillardf4e56292003-10-28 14:27:41 +00005471 xmlNodePtr orig = node;
Owen Taylor3473f882001-02-23 17:55:21 +00005472
5473 if (node == NULL) return(NULL);
5474 if ((nameSpace != NULL) &&
5475 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005476 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5477 /*
5478 * The XML-1.0 namespace is normally held on the root
5479 * element. In this case exceptionally create it on the
5480 * node element.
5481 */
5482 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5483 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005484 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005485 return(NULL);
5486 }
5487 memset(cur, 0, sizeof(xmlNs));
5488 cur->type = XML_LOCAL_NAMESPACE;
5489 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5490 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5491 cur->next = node->nsDef;
5492 node->nsDef = cur;
5493 return(cur);
5494 }
Owen Taylor3473f882001-02-23 17:55:21 +00005495 if (doc->oldNs == NULL) {
5496 /*
5497 * Allocate a new Namespace and fill the fields.
5498 */
5499 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5500 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005501 xmlTreeErrMemory("searching namespace");
Owen Taylor3473f882001-02-23 17:55:21 +00005502 return(NULL);
5503 }
5504 memset(doc->oldNs, 0, sizeof(xmlNs));
5505 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5506
5507 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5508 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5509 }
5510 return(doc->oldNs);
5511 }
5512 while (node != NULL) {
5513 if ((node->type == XML_ENTITY_REF_NODE) ||
5514 (node->type == XML_ENTITY_NODE) ||
5515 (node->type == XML_ENTITY_DECL))
5516 return(NULL);
5517 if (node->type == XML_ELEMENT_NODE) {
5518 cur = node->nsDef;
5519 while (cur != NULL) {
5520 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5521 (cur->href != NULL))
5522 return(cur);
5523 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5524 (cur->href != NULL) &&
5525 (xmlStrEqual(cur->prefix, nameSpace)))
5526 return(cur);
5527 cur = cur->next;
5528 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005529 if (orig != node) {
5530 cur = node->ns;
5531 if (cur != NULL) {
5532 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5533 (cur->href != NULL))
5534 return(cur);
5535 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5536 (cur->href != NULL) &&
5537 (xmlStrEqual(cur->prefix, nameSpace)))
5538 return(cur);
5539 }
5540 }
Owen Taylor3473f882001-02-23 17:55:21 +00005541 }
5542 node = node->parent;
5543 }
5544 return(NULL);
5545}
5546
5547/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005548 * xmlNsInScope:
5549 * @doc: the document
5550 * @node: the current node
5551 * @ancestor: the ancestor carrying the namespace
5552 * @prefix: the namespace prefix
5553 *
5554 * Verify that the given namespace held on @ancestor is still in scope
5555 * on node.
5556 *
5557 * Returns 1 if true, 0 if false and -1 in case of error.
5558 */
5559static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005560xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5561 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005562{
5563 xmlNsPtr tst;
5564
5565 while ((node != NULL) && (node != ancestor)) {
5566 if ((node->type == XML_ENTITY_REF_NODE) ||
5567 (node->type == XML_ENTITY_NODE) ||
5568 (node->type == XML_ENTITY_DECL))
5569 return (-1);
5570 if (node->type == XML_ELEMENT_NODE) {
5571 tst = node->nsDef;
5572 while (tst != NULL) {
5573 if ((tst->prefix == NULL)
5574 && (prefix == NULL))
5575 return (0);
5576 if ((tst->prefix != NULL)
5577 && (prefix != NULL)
5578 && (xmlStrEqual(tst->prefix, prefix)))
5579 return (0);
5580 tst = tst->next;
5581 }
5582 }
5583 node = node->parent;
5584 }
5585 if (node != ancestor)
5586 return (-1);
5587 return (1);
5588}
5589
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005590/**
Owen Taylor3473f882001-02-23 17:55:21 +00005591 * xmlSearchNsByHref:
5592 * @doc: the document
5593 * @node: the current node
5594 * @href: the namespace value
5595 *
5596 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5597 * the defined namespace or return NULL otherwise.
5598 * Returns the namespace pointer or NULL.
5599 */
5600xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005601xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5602{
Owen Taylor3473f882001-02-23 17:55:21 +00005603 xmlNsPtr cur;
5604 xmlNodePtr orig = node;
Daniel Veillard62040be2004-05-17 03:17:26 +00005605 int is_attr;
Owen Taylor3473f882001-02-23 17:55:21 +00005606
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005607 if ((node == NULL) || (href == NULL))
5608 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005609 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005610 /*
5611 * Only the document can hold the XML spec namespace.
5612 */
5613 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5614 /*
5615 * The XML-1.0 namespace is normally held on the root
5616 * element. In this case exceptionally create it on the
5617 * node element.
5618 */
5619 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5620 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005621 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005622 return (NULL);
5623 }
5624 memset(cur, 0, sizeof(xmlNs));
5625 cur->type = XML_LOCAL_NAMESPACE;
5626 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5627 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5628 cur->next = node->nsDef;
5629 node->nsDef = cur;
5630 return (cur);
5631 }
5632 if (doc->oldNs == NULL) {
5633 /*
5634 * Allocate a new Namespace and fill the fields.
5635 */
5636 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5637 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005638 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005639 return (NULL);
5640 }
5641 memset(doc->oldNs, 0, sizeof(xmlNs));
5642 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005643
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005644 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5645 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5646 }
5647 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005648 }
Daniel Veillard62040be2004-05-17 03:17:26 +00005649 is_attr = (node->type == XML_ATTRIBUTE_NODE);
Owen Taylor3473f882001-02-23 17:55:21 +00005650 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005651 if ((node->type == XML_ENTITY_REF_NODE) ||
5652 (node->type == XML_ENTITY_NODE) ||
5653 (node->type == XML_ENTITY_DECL))
5654 return (NULL);
5655 if (node->type == XML_ELEMENT_NODE) {
5656 cur = node->nsDef;
5657 while (cur != NULL) {
5658 if ((cur->href != NULL) && (href != NULL) &&
5659 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005660 if (((!is_attr) || (cur->prefix != NULL)) &&
5661 (xmlNsInScope(doc, orig, node, cur->href) == 1))
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005662 return (cur);
5663 }
5664 cur = cur->next;
5665 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005666 if (orig != node) {
5667 cur = node->ns;
5668 if (cur != NULL) {
5669 if ((cur->href != NULL) && (href != NULL) &&
5670 (xmlStrEqual(cur->href, href))) {
Daniel Veillard62040be2004-05-17 03:17:26 +00005671 if (((!is_attr) || (cur->prefix != NULL)) &&
5672 (xmlNsInScope(doc, orig, node, cur->href) == 1))
Daniel Veillardf4e56292003-10-28 14:27:41 +00005673 return (cur);
5674 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005675 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005676 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005677 }
5678 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005679 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005680 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005681}
5682
5683/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005684 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005685 * @doc: the document
5686 * @tree: a node expected to hold the new namespace
5687 * @ns: the original namespace
5688 *
5689 * This function tries to locate a namespace definition in a tree
5690 * ancestors, or create a new namespace definition node similar to
5691 * @ns trying to reuse the same prefix. However if the given prefix is
5692 * null (default namespace) or reused within the subtree defined by
5693 * @tree or on one of its ancestors then a new prefix is generated.
5694 * Returns the (new) namespace definition or NULL in case of error
5695 */
5696xmlNsPtr
5697xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5698 xmlNsPtr def;
5699 xmlChar prefix[50];
5700 int counter = 1;
5701
5702 if (tree == NULL) {
5703#ifdef DEBUG_TREE
5704 xmlGenericError(xmlGenericErrorContext,
5705 "xmlNewReconciliedNs : tree == NULL\n");
5706#endif
5707 return(NULL);
5708 }
Daniel Veillardce244ad2004-11-05 10:03:46 +00005709 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005710#ifdef DEBUG_TREE
5711 xmlGenericError(xmlGenericErrorContext,
5712 "xmlNewReconciliedNs : ns == NULL\n");
5713#endif
5714 return(NULL);
5715 }
5716 /*
5717 * Search an existing namespace definition inherited.
5718 */
5719 def = xmlSearchNsByHref(doc, tree, ns->href);
5720 if (def != NULL)
5721 return(def);
5722
5723 /*
5724 * Find a close prefix which is not already in use.
5725 * Let's strip namespace prefixes longer than 20 chars !
5726 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005727 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005728 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005729 else
William M. Brack13dfa872004-09-18 04:52:08 +00005730 snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005731
Owen Taylor3473f882001-02-23 17:55:21 +00005732 def = xmlSearchNs(doc, tree, prefix);
5733 while (def != NULL) {
5734 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005735 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005736 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005737 else
William M. Brack13dfa872004-09-18 04:52:08 +00005738 snprintf((char *) prefix, sizeof(prefix), "%.20s%d",
5739 (char *)ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005740 def = xmlSearchNs(doc, tree, prefix);
5741 }
5742
5743 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005744 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005745 */
5746 def = xmlNewNs(tree, ns->href, prefix);
5747 return(def);
5748}
5749
Daniel Veillard652327a2003-09-29 18:02:38 +00005750#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005751/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005752 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005753 * @doc: the document
5754 * @tree: a node defining the subtree to reconciliate
5755 *
5756 * This function checks that all the namespaces declared within the given
5757 * tree are properly declared. This is needed for example after Copy or Cut
5758 * and then paste operations. The subtree may still hold pointers to
5759 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005760 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005761 * the new environment. If not possible the new namespaces are redeclared
5762 * on @tree at the top of the given subtree.
5763 * Returns the number of namespace declarations created or -1 in case of error.
5764 */
5765int
5766xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5767 xmlNsPtr *oldNs = NULL;
5768 xmlNsPtr *newNs = NULL;
5769 int sizeCache = 0;
5770 int nbCache = 0;
5771
5772 xmlNsPtr n;
5773 xmlNodePtr node = tree;
5774 xmlAttrPtr attr;
5775 int ret = 0, i;
5776
Daniel Veillardce244ad2004-11-05 10:03:46 +00005777 if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1);
5778 if ((doc == NULL) || (doc->type != XML_DOCUMENT_NODE)) return(-1);
5779 if (node->doc != doc) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005780 while (node != NULL) {
5781 /*
5782 * Reconciliate the node namespace
5783 */
5784 if (node->ns != NULL) {
5785 /*
5786 * initialize the cache if needed
5787 */
5788 if (sizeCache == 0) {
5789 sizeCache = 10;
5790 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5791 sizeof(xmlNsPtr));
5792 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005793 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005794 return(-1);
5795 }
5796 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5797 sizeof(xmlNsPtr));
5798 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005799 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005800 xmlFree(oldNs);
5801 return(-1);
5802 }
5803 }
5804 for (i = 0;i < nbCache;i++) {
5805 if (oldNs[i] == node->ns) {
5806 node->ns = newNs[i];
5807 break;
5808 }
5809 }
5810 if (i == nbCache) {
5811 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005812 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005813 */
5814 n = xmlNewReconciliedNs(doc, tree, node->ns);
5815 if (n != NULL) { /* :-( what if else ??? */
5816 /*
5817 * check if we need to grow the cache buffers.
5818 */
5819 if (sizeCache <= nbCache) {
5820 sizeCache *= 2;
5821 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5822 sizeof(xmlNsPtr));
5823 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005824 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005825 xmlFree(newNs);
5826 return(-1);
5827 }
5828 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5829 sizeof(xmlNsPtr));
5830 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005831 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005832 xmlFree(oldNs);
5833 return(-1);
5834 }
5835 }
5836 newNs[nbCache] = n;
5837 oldNs[nbCache++] = node->ns;
5838 node->ns = n;
5839 }
5840 }
5841 }
5842 /*
5843 * now check for namespace hold by attributes on the node.
5844 */
5845 attr = node->properties;
5846 while (attr != NULL) {
5847 if (attr->ns != NULL) {
5848 /*
5849 * initialize the cache if needed
5850 */
5851 if (sizeCache == 0) {
5852 sizeCache = 10;
5853 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5854 sizeof(xmlNsPtr));
5855 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005856 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005857 return(-1);
5858 }
5859 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5860 sizeof(xmlNsPtr));
5861 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005862 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005863 xmlFree(oldNs);
5864 return(-1);
5865 }
5866 }
5867 for (i = 0;i < nbCache;i++) {
5868 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005869 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005870 break;
5871 }
5872 }
5873 if (i == nbCache) {
5874 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005875 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005876 */
5877 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5878 if (n != NULL) { /* :-( what if else ??? */
5879 /*
5880 * check if we need to grow the cache buffers.
5881 */
5882 if (sizeCache <= nbCache) {
5883 sizeCache *= 2;
5884 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5885 sizeof(xmlNsPtr));
5886 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005887 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005888 xmlFree(newNs);
5889 return(-1);
5890 }
5891 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5892 sizeof(xmlNsPtr));
5893 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005894 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005895 xmlFree(oldNs);
5896 return(-1);
5897 }
5898 }
5899 newNs[nbCache] = n;
5900 oldNs[nbCache++] = attr->ns;
5901 attr->ns = n;
5902 }
5903 }
5904 }
5905 attr = attr->next;
5906 }
5907
5908 /*
5909 * Browse the full subtree, deep first
5910 */
Daniel Veillardac996a12004-07-30 12:02:58 +00005911 if (node->children != NULL && node->type != XML_ENTITY_REF_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00005912 /* deep first */
5913 node = node->children;
5914 } else if ((node != tree) && (node->next != NULL)) {
5915 /* then siblings */
5916 node = node->next;
5917 } else if (node != tree) {
5918 /* go up to parents->next if needed */
5919 while (node != tree) {
5920 if (node->parent != NULL)
5921 node = node->parent;
5922 if ((node != tree) && (node->next != NULL)) {
5923 node = node->next;
5924 break;
5925 }
5926 if (node->parent == NULL) {
5927 node = NULL;
5928 break;
5929 }
5930 }
5931 /* exit condition */
5932 if (node == tree)
5933 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005934 } else
5935 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005936 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005937 if (oldNs != NULL)
5938 xmlFree(oldNs);
5939 if (newNs != NULL)
5940 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005941 return(ret);
5942}
Daniel Veillard652327a2003-09-29 18:02:38 +00005943#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005944
5945/**
5946 * xmlHasProp:
5947 * @node: the node
5948 * @name: the attribute name
5949 *
5950 * Search an attribute associated to a node
5951 * This function also looks in DTD attribute declaration for #FIXED or
5952 * default declaration values unless DTD use has been turned off.
5953 *
5954 * Returns the attribute or the attribute declaration or NULL if
5955 * neither was found.
5956 */
5957xmlAttrPtr
5958xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5959 xmlAttrPtr prop;
5960 xmlDocPtr doc;
5961
5962 if ((node == NULL) || (name == NULL)) return(NULL);
5963 /*
5964 * Check on the properties attached to the node
5965 */
5966 prop = node->properties;
5967 while (prop != NULL) {
5968 if (xmlStrEqual(prop->name, name)) {
5969 return(prop);
5970 }
5971 prop = prop->next;
5972 }
5973 if (!xmlCheckDTD) return(NULL);
5974
5975 /*
5976 * Check if there is a default declaration in the internal
5977 * or external subsets
5978 */
5979 doc = node->doc;
5980 if (doc != NULL) {
5981 xmlAttributePtr attrDecl;
5982 if (doc->intSubset != NULL) {
5983 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5984 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5985 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005986 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5987 /* return attribute declaration only if a default value is given
5988 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005989 return((xmlAttrPtr) attrDecl);
5990 }
5991 }
5992 return(NULL);
5993}
5994
5995/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005996 * xmlHasNsProp:
5997 * @node: the node
5998 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005999 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00006000 *
6001 * Search for an attribute associated to a node
6002 * This attribute has to be anchored in the namespace specified.
6003 * This does the entity substitution.
6004 * This function looks in DTD attribute declaration for #FIXED or
6005 * default declaration values unless DTD use has been turned off.
William M. Brack2c228442004-10-03 04:10:00 +00006006 * Note that a namespace of NULL indicates to use the default namespace.
Daniel Veillarde95e2392001-06-06 10:46:28 +00006007 *
6008 * Returns the attribute or the attribute declaration or NULL
6009 * if neither was found.
6010 */
6011xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00006012xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00006013 xmlAttrPtr prop;
Daniel Veillard652327a2003-09-29 18:02:38 +00006014#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00006015 xmlDocPtr doc;
Daniel Veillard652327a2003-09-29 18:02:38 +00006016#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00006017
6018 if (node == NULL)
6019 return(NULL);
6020
6021 prop = node->properties;
Daniel Veillarde95e2392001-06-06 10:46:28 +00006022 while (prop != NULL) {
6023 /*
6024 * One need to have
6025 * - same attribute names
6026 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00006027 */
William M. Brack2c228442004-10-03 04:10:00 +00006028 if (xmlStrEqual(prop->name, name)) {
6029 if (((prop->ns != NULL) &&
6030 (xmlStrEqual(prop->ns->href, nameSpace))) ||
6031 ((prop->ns == NULL) && (nameSpace == NULL))) {
6032 return(prop);
6033 }
Daniel Veillarde95e2392001-06-06 10:46:28 +00006034 }
6035 prop = prop->next;
6036 }
6037 if (!xmlCheckDTD) return(NULL);
6038
Daniel Veillard652327a2003-09-29 18:02:38 +00006039#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00006040 /*
6041 * Check if there is a default declaration in the internal
6042 * or external subsets
6043 */
6044 doc = node->doc;
6045 if (doc != NULL) {
6046 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006047 xmlAttributePtr attrDecl = NULL;
6048 xmlNsPtr *nsList, *cur;
6049 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00006050
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006051 nsList = xmlGetNsList(node->doc, node);
6052 if (nsList == NULL)
6053 return(NULL);
6054 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
6055 ename = xmlStrdup(node->ns->prefix);
6056 ename = xmlStrcat(ename, BAD_CAST ":");
6057 ename = xmlStrcat(ename, node->name);
6058 } else {
6059 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00006060 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006061 if (ename == NULL) {
6062 xmlFree(nsList);
6063 return(NULL);
6064 }
6065
William M. Brack2c228442004-10-03 04:10:00 +00006066 if (nameSpace == NULL) {
6067 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
6068 name, NULL);
6069 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
6070 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
6071 name, NULL);
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006072 }
William M. Brack2c228442004-10-03 04:10:00 +00006073 } else {
6074 cur = nsList;
6075 while (*cur != NULL) {
6076 if (xmlStrEqual((*cur)->href, nameSpace)) {
6077 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
6078 name, (*cur)->prefix);
6079 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6080 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
6081 name, (*cur)->prefix);
6082 }
6083 cur++;
6084 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00006085 }
6086 xmlFree(nsList);
6087 xmlFree(ename);
6088 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00006089 }
6090 }
Daniel Veillard652327a2003-09-29 18:02:38 +00006091#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00006092 return(NULL);
6093}
6094
6095/**
Owen Taylor3473f882001-02-23 17:55:21 +00006096 * xmlGetProp:
6097 * @node: the node
6098 * @name: the attribute name
6099 *
6100 * Search and get the value of an attribute associated to a node
6101 * This does the entity substitution.
6102 * This function looks in DTD attribute declaration for #FIXED or
6103 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00006104 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00006105 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
6106 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00006107 *
6108 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006109 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006110 */
6111xmlChar *
6112xmlGetProp(xmlNodePtr node, const xmlChar *name) {
6113 xmlAttrPtr prop;
6114 xmlDocPtr doc;
6115
6116 if ((node == NULL) || (name == NULL)) return(NULL);
6117 /*
6118 * Check on the properties attached to the node
6119 */
6120 prop = node->properties;
6121 while (prop != NULL) {
6122 if (xmlStrEqual(prop->name, name)) {
6123 xmlChar *ret;
6124
6125 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6126 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6127 return(ret);
6128 }
6129 prop = prop->next;
6130 }
6131 if (!xmlCheckDTD) return(NULL);
6132
6133 /*
6134 * Check if there is a default declaration in the internal
6135 * or external subsets
6136 */
6137 doc = node->doc;
6138 if (doc != NULL) {
6139 xmlAttributePtr attrDecl;
6140 if (doc->intSubset != NULL) {
6141 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6142 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6143 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006144 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6145 /* return attribute declaration only if a default value is given
6146 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00006147 return(xmlStrdup(attrDecl->defaultValue));
6148 }
6149 }
6150 return(NULL);
6151}
6152
6153/**
Daniel Veillard71531f32003-02-05 13:19:53 +00006154 * xmlGetNoNsProp:
6155 * @node: the node
6156 * @name: the attribute name
6157 *
6158 * Search and get the value of an attribute associated to a node
6159 * This does the entity substitution.
6160 * This function looks in DTD attribute declaration for #FIXED or
6161 * default declaration values unless DTD use has been turned off.
6162 * This function is similar to xmlGetProp except it will accept only
6163 * an attribute in no namespace.
6164 *
6165 * Returns the attribute value or NULL if not found.
6166 * It's up to the caller to free the memory with xmlFree().
6167 */
6168xmlChar *
6169xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
6170 xmlAttrPtr prop;
6171 xmlDocPtr doc;
6172
6173 if ((node == NULL) || (name == NULL)) return(NULL);
6174 /*
6175 * Check on the properties attached to the node
6176 */
6177 prop = node->properties;
6178 while (prop != NULL) {
6179 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
6180 xmlChar *ret;
6181
6182 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6183 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6184 return(ret);
6185 }
6186 prop = prop->next;
6187 }
6188 if (!xmlCheckDTD) return(NULL);
6189
6190 /*
6191 * Check if there is a default declaration in the internal
6192 * or external subsets
6193 */
6194 doc = node->doc;
6195 if (doc != NULL) {
6196 xmlAttributePtr attrDecl;
6197 if (doc->intSubset != NULL) {
6198 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6199 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6200 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006201 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6202 /* return attribute declaration only if a default value is given
6203 (that includes #FIXED declarations) */
Daniel Veillard71531f32003-02-05 13:19:53 +00006204 return(xmlStrdup(attrDecl->defaultValue));
6205 }
6206 }
6207 return(NULL);
6208}
6209
6210/**
Owen Taylor3473f882001-02-23 17:55:21 +00006211 * xmlGetNsProp:
6212 * @node: the node
6213 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006214 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006215 *
6216 * Search and get the value of an attribute associated to a node
6217 * This attribute has to be anchored in the namespace specified.
6218 * This does the entity substitution.
6219 * This function looks in DTD attribute declaration for #FIXED or
6220 * default declaration values unless DTD use has been turned off.
6221 *
6222 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006223 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006224 */
6225xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006226xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006227 xmlAttrPtr prop;
6228 xmlDocPtr doc;
6229 xmlNsPtr ns;
6230
6231 if (node == NULL)
6232 return(NULL);
6233
6234 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00006235 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00006236 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00006237 while (prop != NULL) {
6238 /*
6239 * One need to have
6240 * - same attribute names
6241 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006242 */
6243 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00006244 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00006245 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006246 xmlChar *ret;
6247
6248 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6249 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6250 return(ret);
6251 }
6252 prop = prop->next;
6253 }
6254 if (!xmlCheckDTD) return(NULL);
6255
6256 /*
6257 * Check if there is a default declaration in the internal
6258 * or external subsets
6259 */
6260 doc = node->doc;
6261 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006262 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00006263 xmlAttributePtr attrDecl;
6264
Owen Taylor3473f882001-02-23 17:55:21 +00006265 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6266 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6267 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
6268
6269 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
6270 /*
6271 * The DTD declaration only allows a prefix search
6272 */
6273 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00006274 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00006275 return(xmlStrdup(attrDecl->defaultValue));
6276 }
6277 }
6278 }
6279 return(NULL);
6280}
6281
Daniel Veillard2156d432004-03-04 15:59:36 +00006282#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
6283/**
6284 * xmlUnsetProp:
6285 * @node: the node
6286 * @name: the attribute name
6287 *
6288 * Remove an attribute carried by a node.
6289 * Returns 0 if successful, -1 if not found
6290 */
6291int
6292xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
6293 xmlAttrPtr prop, prev = NULL;;
6294
6295 if ((node == NULL) || (name == NULL))
6296 return(-1);
6297 prop = node->properties;
6298 while (prop != NULL) {
6299 if ((xmlStrEqual(prop->name, name)) &&
6300 (prop->ns == NULL)) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006301 if (prev == NULL) {
Daniel Veillard2156d432004-03-04 15:59:36 +00006302 node->properties = prop->next;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006303 if (prop->next != NULL)
6304 prop->next->prev = NULL;
6305 } else {
Daniel Veillard2156d432004-03-04 15:59:36 +00006306 prev->next = prop->next;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006307 if (prop->next != NULL)
6308 prop->next->prev = NULL;
6309 }
6310 prop->next = NULL;
6311 prop->prev = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00006312 xmlFreeProp(prop);
6313 return(0);
6314 }
6315 prev = prop;
6316 prop = prop->next;
6317 }
6318 return(-1);
6319}
6320
6321/**
6322 * xmlUnsetNsProp:
6323 * @node: the node
6324 * @ns: the namespace definition
6325 * @name: the attribute name
6326 *
6327 * Remove an attribute carried by a node.
6328 * Returns 0 if successful, -1 if not found
6329 */
6330int
6331xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
Daniel Veillard27f20102004-11-05 11:50:11 +00006332 xmlAttrPtr prop, prev = NULL;;
Daniel Veillard2156d432004-03-04 15:59:36 +00006333
6334 if ((node == NULL) || (name == NULL))
6335 return(-1);
Daniel Veillard27f20102004-11-05 11:50:11 +00006336 prop = node->properties;
Daniel Veillard2156d432004-03-04 15:59:36 +00006337 if (ns == NULL)
6338 return(xmlUnsetProp(node, name));
6339 if (ns->href == NULL)
6340 return(-1);
6341 while (prop != NULL) {
6342 if ((xmlStrEqual(prop->name, name)) &&
6343 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006344 if (prev == NULL) {
Daniel Veillard2156d432004-03-04 15:59:36 +00006345 node->properties = prop->next;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006346 if (prop->next != NULL)
6347 prop->next->prev = NULL;
6348 } else {
Daniel Veillard2156d432004-03-04 15:59:36 +00006349 prev->next = prop->next;
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006350 if (prop->next != NULL)
6351 prop->next->prev = NULL;
6352 }
6353 prop->next = NULL;
6354 prop->prev = NULL;
Daniel Veillard2156d432004-03-04 15:59:36 +00006355 xmlFreeProp(prop);
6356 return(0);
6357 }
6358 prev = prop;
6359 prop = prop->next;
6360 }
6361 return(-1);
6362}
6363#endif
6364
6365#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00006366/**
6367 * xmlSetProp:
6368 * @node: the node
6369 * @name: the attribute name
6370 * @value: the attribute value
6371 *
6372 * Set (or reset) an attribute carried by a node.
6373 * Returns the attribute pointer.
6374 */
6375xmlAttrPtr
6376xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006377 xmlAttrPtr prop;
6378 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00006379
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006380 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006381 return(NULL);
6382 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006383 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00006384 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006385 if ((xmlStrEqual(prop->name, name)) &&
6386 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006387 xmlNodePtr oldprop = prop->children;
6388
Owen Taylor3473f882001-02-23 17:55:21 +00006389 prop->children = NULL;
6390 prop->last = NULL;
6391 if (value != NULL) {
6392 xmlChar *buffer;
6393 xmlNodePtr tmp;
6394
6395 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6396 prop->children = xmlStringGetNodeList(node->doc, buffer);
6397 prop->last = NULL;
6398 prop->doc = doc;
6399 tmp = prop->children;
6400 while (tmp != NULL) {
6401 tmp->parent = (xmlNodePtr) prop;
6402 tmp->doc = doc;
6403 if (tmp->next == NULL)
6404 prop->last = tmp;
6405 tmp = tmp->next;
6406 }
6407 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00006408 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006409 if (oldprop != NULL)
6410 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00006411 return(prop);
6412 }
6413 prop = prop->next;
6414 }
6415 prop = xmlNewProp(node, name, value);
6416 return(prop);
6417}
6418
6419/**
6420 * xmlSetNsProp:
6421 * @node: the node
6422 * @ns: the namespace definition
6423 * @name: the attribute name
6424 * @value: the attribute value
6425 *
6426 * Set (or reset) an attribute carried by a node.
6427 * The ns structure must be in scope, this is not checked.
6428 *
6429 * Returns the attribute pointer.
6430 */
6431xmlAttrPtr
6432xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
6433 const xmlChar *value) {
6434 xmlAttrPtr prop;
6435
6436 if ((node == NULL) || (name == NULL))
6437 return(NULL);
6438
6439 if (ns == NULL)
6440 return(xmlSetProp(node, name, value));
6441 if (ns->href == NULL)
6442 return(NULL);
6443 prop = node->properties;
6444
6445 while (prop != NULL) {
6446 /*
6447 * One need to have
6448 * - same attribute names
6449 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006450 */
6451 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00006452 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006453 if (prop->children != NULL)
6454 xmlFreeNodeList(prop->children);
6455 prop->children = NULL;
6456 prop->last = NULL;
6457 prop->ns = ns;
6458 if (value != NULL) {
6459 xmlChar *buffer;
6460 xmlNodePtr tmp;
6461
6462 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6463 prop->children = xmlStringGetNodeList(node->doc, buffer);
6464 prop->last = NULL;
6465 tmp = prop->children;
6466 while (tmp != NULL) {
6467 tmp->parent = (xmlNodePtr) prop;
6468 if (tmp->next == NULL)
6469 prop->last = tmp;
6470 tmp = tmp->next;
6471 }
6472 xmlFree(buffer);
6473 }
6474 return(prop);
6475 }
6476 prop = prop->next;
6477 }
6478 prop = xmlNewNsProp(node, ns, name, value);
6479 return(prop);
6480}
6481
Daniel Veillard652327a2003-09-29 18:02:38 +00006482#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006483
6484/**
Owen Taylor3473f882001-02-23 17:55:21 +00006485 * xmlNodeIsText:
6486 * @node: the node
6487 *
6488 * Is this node a Text node ?
6489 * Returns 1 yes, 0 no
6490 */
6491int
6492xmlNodeIsText(xmlNodePtr node) {
6493 if (node == NULL) return(0);
6494
6495 if (node->type == XML_TEXT_NODE) return(1);
6496 return(0);
6497}
6498
6499/**
6500 * xmlIsBlankNode:
6501 * @node: the node
6502 *
6503 * Checks whether this node is an empty or whitespace only
6504 * (and possibly ignorable) text-node.
6505 *
6506 * Returns 1 yes, 0 no
6507 */
6508int
6509xmlIsBlankNode(xmlNodePtr node) {
6510 const xmlChar *cur;
6511 if (node == NULL) return(0);
6512
Daniel Veillard7db37732001-07-12 01:20:08 +00006513 if ((node->type != XML_TEXT_NODE) &&
6514 (node->type != XML_CDATA_SECTION_NODE))
6515 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006516 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006517 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006518 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006519 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006520 cur++;
6521 }
6522
6523 return(1);
6524}
6525
6526/**
6527 * xmlTextConcat:
6528 * @node: the node
6529 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006530 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006531 *
6532 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006533 *
6534 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006535 */
6536
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006537int
Owen Taylor3473f882001-02-23 17:55:21 +00006538xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006539 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006540
6541 if ((node->type != XML_TEXT_NODE) &&
6542 (node->type != XML_CDATA_SECTION_NODE)) {
6543#ifdef DEBUG_TREE
6544 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006545 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006546#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006547 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006548 }
William M. Brack7762bb12004-01-04 14:49:01 +00006549 /* need to check if content is currently in the dictionary */
6550 if ((node->doc != NULL) && (node->doc->dict != NULL) &&
6551 xmlDictOwns(node->doc->dict, node->content)) {
6552 node->content = xmlStrncatNew(node->content, content, len);
6553 } else {
6554 node->content = xmlStrncat(node->content, content, len);
6555 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006556 if (node->content == NULL)
6557 return(-1);
6558 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006559}
6560
6561/************************************************************************
6562 * *
6563 * Output : to a FILE or in memory *
6564 * *
6565 ************************************************************************/
6566
Owen Taylor3473f882001-02-23 17:55:21 +00006567/**
6568 * xmlBufferCreate:
6569 *
6570 * routine to create an XML buffer.
6571 * returns the new structure.
6572 */
6573xmlBufferPtr
6574xmlBufferCreate(void) {
6575 xmlBufferPtr ret;
6576
6577 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6578 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006579 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006580 return(NULL);
6581 }
6582 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006583 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006584 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006585 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006586 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006587 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006588 xmlFree(ret);
6589 return(NULL);
6590 }
6591 ret->content[0] = 0;
6592 return(ret);
6593}
6594
6595/**
6596 * xmlBufferCreateSize:
6597 * @size: initial size of buffer
6598 *
6599 * routine to create an XML buffer.
6600 * returns the new structure.
6601 */
6602xmlBufferPtr
6603xmlBufferCreateSize(size_t size) {
6604 xmlBufferPtr ret;
6605
6606 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6607 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006608 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006609 return(NULL);
6610 }
6611 ret->use = 0;
6612 ret->alloc = xmlBufferAllocScheme;
6613 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6614 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006615 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006616 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006617 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006618 xmlFree(ret);
6619 return(NULL);
6620 }
6621 ret->content[0] = 0;
6622 } else
6623 ret->content = NULL;
6624 return(ret);
6625}
6626
6627/**
Daniel Veillard53350552003-09-18 13:35:51 +00006628 * xmlBufferCreateStatic:
6629 * @mem: the memory area
6630 * @size: the size in byte
6631 *
MST 2003 John Flecka0e7e932003-12-19 03:13:47 +00006632 * routine to create an XML buffer from an immutable memory area.
6633 * The area won't be modified nor copied, and is expected to be
Daniel Veillard53350552003-09-18 13:35:51 +00006634 * present until the end of the buffer lifetime.
6635 *
6636 * returns the new structure.
6637 */
6638xmlBufferPtr
6639xmlBufferCreateStatic(void *mem, size_t size) {
6640 xmlBufferPtr ret;
6641
6642 if ((mem == NULL) || (size == 0))
6643 return(NULL);
6644
6645 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6646 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006647 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00006648 return(NULL);
6649 }
6650 ret->use = size;
6651 ret->size = size;
6652 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6653 ret->content = (xmlChar *) mem;
6654 return(ret);
6655}
6656
6657/**
Owen Taylor3473f882001-02-23 17:55:21 +00006658 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006659 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006660 * @scheme: allocation scheme to use
6661 *
6662 * Sets the allocation scheme for this buffer
6663 */
6664void
6665xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6666 xmlBufferAllocationScheme scheme) {
6667 if (buf == NULL) {
6668#ifdef DEBUG_BUFFER
6669 xmlGenericError(xmlGenericErrorContext,
6670 "xmlBufferSetAllocationScheme: buf == NULL\n");
6671#endif
6672 return;
6673 }
Daniel Veillard53350552003-09-18 13:35:51 +00006674 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006675
6676 buf->alloc = scheme;
6677}
6678
6679/**
6680 * xmlBufferFree:
6681 * @buf: the buffer to free
6682 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006683 * Frees an XML buffer. It frees both the content and the structure which
6684 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006685 */
6686void
6687xmlBufferFree(xmlBufferPtr buf) {
6688 if (buf == NULL) {
6689#ifdef DEBUG_BUFFER
6690 xmlGenericError(xmlGenericErrorContext,
6691 "xmlBufferFree: buf == NULL\n");
6692#endif
6693 return;
6694 }
Daniel Veillard53350552003-09-18 13:35:51 +00006695
6696 if ((buf->content != NULL) &&
6697 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006698 xmlFree(buf->content);
6699 }
Owen Taylor3473f882001-02-23 17:55:21 +00006700 xmlFree(buf);
6701}
6702
6703/**
6704 * xmlBufferEmpty:
6705 * @buf: the buffer
6706 *
6707 * empty a buffer.
6708 */
6709void
6710xmlBufferEmpty(xmlBufferPtr buf) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006711 if (buf == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006712 if (buf->content == NULL) return;
6713 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006714 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00006715 buf->content = BAD_CAST "";
Daniel Veillard53350552003-09-18 13:35:51 +00006716 } else {
6717 memset(buf->content, 0, buf->size);
6718 }
Owen Taylor3473f882001-02-23 17:55:21 +00006719}
6720
6721/**
6722 * xmlBufferShrink:
6723 * @buf: the buffer to dump
6724 * @len: the number of xmlChar to remove
6725 *
6726 * Remove the beginning of an XML buffer.
6727 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006728 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006729 */
6730int
6731xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
Daniel Veillard3d97e662004-11-04 10:49:00 +00006732 if (buf == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006733 if (len == 0) return(0);
6734 if (len > buf->use) return(-1);
6735
6736 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006737 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6738 buf->content += len;
6739 } else {
6740 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6741 buf->content[buf->use] = 0;
6742 }
Owen Taylor3473f882001-02-23 17:55:21 +00006743 return(len);
6744}
6745
6746/**
6747 * xmlBufferGrow:
6748 * @buf: the buffer
6749 * @len: the minimum free size to allocate
6750 *
6751 * Grow the available space of an XML buffer.
6752 *
6753 * Returns the new available space or -1 in case of error
6754 */
6755int
6756xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6757 int size;
6758 xmlChar *newbuf;
6759
Daniel Veillard3d97e662004-11-04 10:49:00 +00006760 if (buf == NULL) return(-1);
6761
Daniel Veillard53350552003-09-18 13:35:51 +00006762 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006763 if (len + buf->use < buf->size) return(0);
6764
William M. Brack30fe43f2004-07-26 18:00:58 +00006765/*
6766 * Windows has a BIG problem on realloc timing, so we try to double
6767 * the buffer size (if that's enough) (bug 146697)
6768 */
6769#ifdef WIN32
6770 if (buf->size > len)
6771 size = buf->size * 2;
6772 else
6773 size = buf->use + len + 100;
6774#else
Owen Taylor3473f882001-02-23 17:55:21 +00006775 size = buf->use + len + 100;
William M. Brack30fe43f2004-07-26 18:00:58 +00006776#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006777
6778 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006779 if (newbuf == NULL) {
6780 xmlTreeErrMemory("growing buffer");
6781 return(-1);
6782 }
Owen Taylor3473f882001-02-23 17:55:21 +00006783 buf->content = newbuf;
6784 buf->size = size;
6785 return(buf->size - buf->use);
6786}
6787
6788/**
6789 * xmlBufferDump:
6790 * @file: the file output
6791 * @buf: the buffer to dump
6792 *
6793 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006794 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006795 */
6796int
6797xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6798 int ret;
6799
6800 if (buf == NULL) {
6801#ifdef DEBUG_BUFFER
6802 xmlGenericError(xmlGenericErrorContext,
6803 "xmlBufferDump: buf == NULL\n");
6804#endif
6805 return(0);
6806 }
6807 if (buf->content == NULL) {
6808#ifdef DEBUG_BUFFER
6809 xmlGenericError(xmlGenericErrorContext,
6810 "xmlBufferDump: buf->content == NULL\n");
6811#endif
6812 return(0);
6813 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006814 if (file == NULL)
6815 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006816 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6817 return(ret);
6818}
6819
6820/**
6821 * xmlBufferContent:
6822 * @buf: the buffer
6823 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006824 * Function to extract the content of a buffer
6825 *
Owen Taylor3473f882001-02-23 17:55:21 +00006826 * Returns the internal content
6827 */
6828
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006829const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006830xmlBufferContent(const xmlBufferPtr buf)
6831{
6832 if(!buf)
6833 return NULL;
6834
6835 return buf->content;
6836}
6837
6838/**
6839 * xmlBufferLength:
6840 * @buf: the buffer
6841 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006842 * Function to get the length of a buffer
6843 *
Owen Taylor3473f882001-02-23 17:55:21 +00006844 * Returns the length of data in the internal content
6845 */
6846
6847int
6848xmlBufferLength(const xmlBufferPtr buf)
6849{
6850 if(!buf)
6851 return 0;
6852
6853 return buf->use;
6854}
6855
6856/**
6857 * xmlBufferResize:
6858 * @buf: the buffer to resize
6859 * @size: the desired size
6860 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006861 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006862 *
6863 * Returns 0 in case of problems, 1 otherwise
6864 */
6865int
6866xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6867{
6868 unsigned int newSize;
6869 xmlChar* rebuf = NULL;
6870
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006871 if (buf == NULL)
6872 return(0);
6873
Daniel Veillard53350552003-09-18 13:35:51 +00006874 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6875
Owen Taylor3473f882001-02-23 17:55:21 +00006876 /* Don't resize if we don't have to */
6877 if (size < buf->size)
6878 return 1;
6879
6880 /* figure out new size */
6881 switch (buf->alloc){
6882 case XML_BUFFER_ALLOC_DOUBLEIT:
Daniel Veillardbf629492004-04-20 22:20:59 +00006883 /*take care of empty case*/
6884 newSize = (buf->size ? buf->size*2 : size + 10);
Owen Taylor3473f882001-02-23 17:55:21 +00006885 while (size > newSize) newSize *= 2;
6886 break;
6887 case XML_BUFFER_ALLOC_EXACT:
6888 newSize = size+10;
6889 break;
6890 default:
6891 newSize = size+10;
6892 break;
6893 }
6894
6895 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006896 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006897 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006898 rebuf = (xmlChar *) xmlRealloc(buf->content,
6899 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006900 } else {
6901 /*
6902 * if we are reallocating a buffer far from being full, it's
6903 * better to make a new allocation and copy only the used range
6904 * and free the old one.
6905 */
6906 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6907 if (rebuf != NULL) {
6908 memcpy(rebuf, buf->content, buf->use);
6909 xmlFree(buf->content);
William M. Brack42331a92004-07-29 07:07:16 +00006910 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006911 }
6912 }
Owen Taylor3473f882001-02-23 17:55:21 +00006913 if (rebuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006914 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006915 return 0;
6916 }
6917 buf->content = rebuf;
6918 buf->size = newSize;
6919
6920 return 1;
6921}
6922
6923/**
6924 * xmlBufferAdd:
6925 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006926 * @str: the #xmlChar string
6927 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006928 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006929 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006930 * str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006931 *
6932 * Returns 0 successful, a positive error code number otherwise
6933 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006934 */
William M. Bracka3215c72004-07-31 16:24:01 +00006935int
Owen Taylor3473f882001-02-23 17:55:21 +00006936xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6937 unsigned int needSize;
6938
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006939 if ((str == NULL) || (buf == NULL)) {
William M. Bracka3215c72004-07-31 16:24:01 +00006940 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006941 }
William M. Bracka3215c72004-07-31 16:24:01 +00006942 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006943 if (len < -1) {
6944#ifdef DEBUG_BUFFER
6945 xmlGenericError(xmlGenericErrorContext,
6946 "xmlBufferAdd: len < 0\n");
6947#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006948 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006949 }
William M. Bracka3215c72004-07-31 16:24:01 +00006950 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006951
6952 if (len < 0)
6953 len = xmlStrlen(str);
6954
William M. Bracka3215c72004-07-31 16:24:01 +00006955 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006956
6957 needSize = buf->use + len + 2;
6958 if (needSize > buf->size){
6959 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006960 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00006961 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00006962 }
6963 }
6964
6965 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6966 buf->use += len;
6967 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00006968 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006969}
6970
6971/**
6972 * xmlBufferAddHead:
6973 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006974 * @str: the #xmlChar string
6975 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006976 *
6977 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006978 * if len == -1, the length of @str is recomputed.
William M. Bracka3215c72004-07-31 16:24:01 +00006979 *
6980 * Returns 0 successful, a positive error code number otherwise
6981 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00006982 */
William M. Bracka3215c72004-07-31 16:24:01 +00006983int
Owen Taylor3473f882001-02-23 17:55:21 +00006984xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6985 unsigned int needSize;
6986
Daniel Veillardd005b9e2004-11-03 17:07:05 +00006987 if (buf == NULL)
6988 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00006989 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006990 if (str == NULL) {
6991#ifdef DEBUG_BUFFER
6992 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006993 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006994#endif
William M. Bracka3215c72004-07-31 16:24:01 +00006995 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006996 }
6997 if (len < -1) {
6998#ifdef DEBUG_BUFFER
6999 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007000 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007001#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007002 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007003 }
William M. Bracka3215c72004-07-31 16:24:01 +00007004 if (len == 0) return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007005
7006 if (len < 0)
7007 len = xmlStrlen(str);
7008
William M. Bracka3215c72004-07-31 16:24:01 +00007009 if (len <= 0) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007010
7011 needSize = buf->use + len + 2;
7012 if (needSize > buf->size){
7013 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007014 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00007015 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00007016 }
7017 }
7018
7019 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
7020 memmove(&buf->content[0], str, len * sizeof(xmlChar));
7021 buf->use += len;
7022 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00007023 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007024}
7025
7026/**
7027 * xmlBufferCat:
William M. Bracka3215c72004-07-31 16:24:01 +00007028 * @buf: the buffer to add to
Daniel Veillardd1640922001-12-17 15:30:10 +00007029 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00007030 *
7031 * Append a zero terminated string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00007032 *
7033 * Returns 0 successful, a positive error code number otherwise
7034 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007035 */
William M. Bracka3215c72004-07-31 16:24:01 +00007036int
Owen Taylor3473f882001-02-23 17:55:21 +00007037xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007038 if (buf == NULL)
7039 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00007040 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
7041 if (str == NULL) return -1;
7042 return xmlBufferAdd(buf, str, -1);
Owen Taylor3473f882001-02-23 17:55:21 +00007043}
7044
7045/**
7046 * xmlBufferCCat:
7047 * @buf: the buffer to dump
7048 * @str: the C char string
7049 *
7050 * Append a zero terminated C string to an XML buffer.
William M. Bracka3215c72004-07-31 16:24:01 +00007051 *
7052 * Returns 0 successful, a positive error code number otherwise
7053 * and -1 in case of internal or API error.
Owen Taylor3473f882001-02-23 17:55:21 +00007054 */
William M. Bracka3215c72004-07-31 16:24:01 +00007055int
Owen Taylor3473f882001-02-23 17:55:21 +00007056xmlBufferCCat(xmlBufferPtr buf, const char *str) {
7057 const char *cur;
7058
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007059 if (buf == NULL)
7060 return(-1);
William M. Bracka3215c72004-07-31 16:24:01 +00007061 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007062 if (str == NULL) {
7063#ifdef DEBUG_BUFFER
7064 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007065 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007066#endif
William M. Bracka3215c72004-07-31 16:24:01 +00007067 return -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007068 }
7069 for (cur = str;*cur != 0;cur++) {
7070 if (buf->use + 10 >= buf->size) {
7071 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007072 xmlTreeErrMemory("growing buffer");
William M. Bracka3215c72004-07-31 16:24:01 +00007073 return XML_ERR_NO_MEMORY;
Owen Taylor3473f882001-02-23 17:55:21 +00007074 }
7075 }
7076 buf->content[buf->use++] = *cur;
7077 }
7078 buf->content[buf->use] = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00007079 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007080}
7081
7082/**
7083 * xmlBufferWriteCHAR:
7084 * @buf: the XML buffer
7085 * @string: the string to add
7086 *
7087 * routine which manages and grows an output buffer. This one adds
7088 * xmlChars at the end of the buffer.
7089 */
7090void
Daniel Veillard53350552003-09-18 13:35:51 +00007091xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007092 if (buf == NULL)
7093 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007094 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007095 xmlBufferCat(buf, string);
7096}
7097
7098/**
7099 * xmlBufferWriteChar:
7100 * @buf: the XML buffer output
7101 * @string: the string to add
7102 *
7103 * routine which manage and grows an output buffer. This one add
7104 * C chars at the end of the array.
7105 */
7106void
7107xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007108 if (buf == NULL)
7109 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007110 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007111 xmlBufferCCat(buf, string);
7112}
7113
7114
7115/**
7116 * xmlBufferWriteQuotedString:
7117 * @buf: the XML buffer output
7118 * @string: the string to add
7119 *
7120 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00007121 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00007122 * quote or double-quotes internally
7123 */
7124void
7125xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00007126 const xmlChar *cur, *base;
Daniel Veillardd005b9e2004-11-03 17:07:05 +00007127 if (buf == NULL)
7128 return;
Daniel Veillard53350552003-09-18 13:35:51 +00007129 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00007130 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00007131 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00007132#ifdef DEBUG_BUFFER
7133 xmlGenericError(xmlGenericErrorContext,
7134 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
7135#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00007136 xmlBufferCCat(buf, "\"");
7137 base = cur = string;
7138 while(*cur != 0){
7139 if(*cur == '"'){
7140 if (base != cur)
7141 xmlBufferAdd(buf, base, cur - base);
7142 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7143 cur++;
7144 base = cur;
7145 }
7146 else {
7147 cur++;
7148 }
7149 }
7150 if (base != cur)
7151 xmlBufferAdd(buf, base, cur - base);
7152 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007153 }
Daniel Veillard39057f42003-08-04 01:33:43 +00007154 else{
7155 xmlBufferCCat(buf, "\'");
7156 xmlBufferCat(buf, string);
7157 xmlBufferCCat(buf, "\'");
7158 }
Owen Taylor3473f882001-02-23 17:55:21 +00007159 } else {
7160 xmlBufferCCat(buf, "\"");
7161 xmlBufferCat(buf, string);
7162 xmlBufferCCat(buf, "\"");
7163 }
7164}
7165
7166
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007167/**
7168 * xmlGetDocCompressMode:
7169 * @doc: the document
7170 *
7171 * get the compression ratio for a document, ZLIB based
7172 * Returns 0 (uncompressed) to 9 (max compression)
7173 */
7174int
7175xmlGetDocCompressMode (xmlDocPtr doc) {
7176 if (doc == NULL) return(-1);
7177 return(doc->compression);
7178}
7179
7180/**
7181 * xmlSetDocCompressMode:
7182 * @doc: the document
7183 * @mode: the compression ratio
7184 *
7185 * set the compression ratio for a document, ZLIB based
7186 * Correct values: 0 (uncompressed) to 9 (max compression)
7187 */
7188void
7189xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7190 if (doc == NULL) return;
7191 if (mode < 0) doc->compression = 0;
7192 else if (mode > 9) doc->compression = 9;
7193 else doc->compression = mode;
7194}
7195
7196/**
7197 * xmlGetCompressMode:
7198 *
7199 * get the default compression mode used, ZLIB based.
7200 * Returns 0 (uncompressed) to 9 (max compression)
7201 */
7202int
7203xmlGetCompressMode(void)
7204{
7205 return (xmlCompressMode);
7206}
7207
7208/**
7209 * xmlSetCompressMode:
7210 * @mode: the compression ratio
7211 *
7212 * set the default compression mode used, ZLIB based
7213 * Correct values: 0 (uncompressed) to 9 (max compression)
7214 */
7215void
7216xmlSetCompressMode(int mode) {
7217 if (mode < 0) xmlCompressMode = 0;
7218 else if (mode > 9) xmlCompressMode = 9;
7219 else xmlCompressMode = mode;
7220}
7221