blob: d7d4144946730bb86fcc3eda92dd14c470e8c12f [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002 * tree.c : implementation of access function for an XML tree.
Owen Taylor3473f882001-02-23 17:55:21 +00003 *
Daniel Veillardd5c2f922002-11-21 14:10:52 +00004 * References:
5 * XHTML 1.0 W3C REC: http://www.w3.org/TR/2002/REC-xhtml1-20020801/
6 *
Owen Taylor3473f882001-02-23 17:55:21 +00007 * See Copyright for the status of this software.
8 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00009 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000010 *
Owen Taylor3473f882001-02-23 17:55:21 +000011 */
12
Daniel Veillard34ce8be2002-03-18 19:37:11 +000013#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000014#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000015
Owen Taylor3473f882001-02-23 17:55:21 +000016#include <string.h> /* for memset() only ! */
17
18#ifdef HAVE_CTYPE_H
19#include <ctype.h>
20#endif
21#ifdef HAVE_STDLIB_H
22#include <stdlib.h>
23#endif
24#ifdef HAVE_ZLIB_H
25#include <zlib.h>
26#endif
27
28#include <libxml/xmlmemory.h>
29#include <libxml/tree.h>
30#include <libxml/parser.h>
Daniel Veillardb8c9be92001-07-09 16:01:19 +000031#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000032#include <libxml/entities.h>
33#include <libxml/valid.h>
34#include <libxml/xmlerror.h>
Daniel Veillardbdb9ba72001-04-11 11:28:06 +000035#include <libxml/parserInternals.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000036#include <libxml/globals.h>
Daniel Veillardd5c2f922002-11-21 14:10:52 +000037#ifdef LIBXML_HTML_ENABLED
38#include <libxml/HTMLtree.h>
39#endif
Owen Taylor3473f882001-02-23 17:55:21 +000040
Daniel Veillarda880b122003-04-21 21:36:41 +000041int __xmlRegisterCallbacks = 0;
42
Daniel Veillard56a4cb82001-03-24 17:00:36 +000043xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
44
45/************************************************************************
46 * *
Daniel Veillard18ec16e2003-10-07 23:16:40 +000047 * Tree memory error handler *
48 * *
49 ************************************************************************/
50/**
51 * xmlTreeErrMemory:
52 * @extra: extra informations
53 *
54 * Handle an out of memory condition
55 */
56static void
57xmlTreeErrMemory(const char *extra)
58{
59 __xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra);
60}
61
62/**
63 * xmlTreeErr:
64 * @code: the error number
65 * @extra: extra informations
66 *
67 * Handle an out of memory condition
68 */
69static void
70xmlTreeErr(int code, xmlNodePtr node, const char *extra)
71{
72 const char *msg = NULL;
73
74 switch(code) {
75 case XML_TREE_INVALID_HEX:
76 msg = "invalid hexadecimal character value";
77 break;
78 case XML_TREE_INVALID_DEC:
79 msg = "invalid decimal character value";
80 break;
81 case XML_TREE_UNTERMINATED_ENTITY:
82 msg = "unterminated entity reference %15s";
83 break;
84 default:
85 msg = "unexpected error number";
86 }
87 __xmlSimpleError(XML_FROM_TREE, code, node, msg, extra);
88}
89
90/************************************************************************
91 * *
Daniel Veillard56a4cb82001-03-24 17:00:36 +000092 * A few static variables and macros *
93 * *
94 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +000095/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +000096const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000097/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +000098const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +000099 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +0000100/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +0000101const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
102
Owen Taylor3473f882001-02-23 17:55:21 +0000103static int xmlCompressMode = 0;
104static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000105
Owen Taylor3473f882001-02-23 17:55:21 +0000106#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
107 xmlNodePtr ulccur = (n)->children; \
108 if (ulccur == NULL) { \
109 (n)->last = NULL; \
110 } else { \
111 while (ulccur->next != NULL) { \
112 ulccur->parent = (n); \
113 ulccur = ulccur->next; \
114 } \
115 ulccur->parent = (n); \
116 (n)->last = ulccur; \
117}}
118
119/* #define DEBUG_BUFFER */
120/* #define DEBUG_TREE */
121
122/************************************************************************
123 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000124 * Functions to move to entities.c once the *
125 * API freeze is smoothen and they can be made public. *
126 * *
127 ************************************************************************/
128#include <libxml/hash.h>
129
Daniel Veillard652327a2003-09-29 18:02:38 +0000130#ifdef LIBXML_TREE_ENABLED
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000131/**
132 * xmlGetEntityFromDtd:
133 * @dtd: A pointer to the DTD to search
134 * @name: The entity name
135 *
136 * Do an entity lookup in the DTD entity hash table and
137 * return the corresponding entity, if found.
138 *
139 * Returns A pointer to the entity structure or NULL if not found.
140 */
141static xmlEntityPtr
142xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
143 xmlEntitiesTablePtr table;
144
145 if((dtd != NULL) && (dtd->entities != NULL)) {
146 table = (xmlEntitiesTablePtr) dtd->entities;
147 return((xmlEntityPtr) xmlHashLookup(table, name));
148 /* return(xmlGetEntityFromTable(table, name)); */
149 }
150 return(NULL);
151}
152/**
153 * xmlGetParameterEntityFromDtd:
154 * @dtd: A pointer to the DTD to search
155 * @name: The entity name
156 *
157 * Do an entity lookup in the DTD pararmeter entity hash table and
158 * return the corresponding entity, if found.
159 *
160 * Returns A pointer to the entity structure or NULL if not found.
161 */
162static xmlEntityPtr
163xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
164 xmlEntitiesTablePtr table;
165
166 if ((dtd != NULL) && (dtd->pentities != NULL)) {
167 table = (xmlEntitiesTablePtr) dtd->pentities;
168 return((xmlEntityPtr) xmlHashLookup(table, name));
169 /* return(xmlGetEntityFromTable(table, name)); */
170 }
171 return(NULL);
172}
Daniel Veillard652327a2003-09-29 18:02:38 +0000173#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000174
175/************************************************************************
176 * *
Daniel Veillardc00cda82003-04-07 10:22:39 +0000177 * QName handling helper *
178 * *
179 ************************************************************************/
180
181/**
182 * xmlBuildQName:
183 * @ncname: the Name
184 * @prefix: the prefix
185 * @memory: preallocated memory
186 * @len: preallocated memory length
187 *
188 * Builds the QName @prefix:@ncname in @memory if there is enough space
189 * and prefix is not NULL nor empty, otherwise allocate a new string.
190 * If prefix is NULL or empty it returns ncname.
191 *
192 * Returns the new string which must be freed by the caller if different from
193 * @memory and @ncname or NULL in case of error
194 */
195xmlChar *
196xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix,
197 xmlChar *memory, int len) {
198 int lenn, lenp;
199 xmlChar *ret;
200
Daniel Veillard3b7840c2003-09-11 23:42:01 +0000201 if (ncname == NULL) return(NULL);
202 if (prefix == NULL) return((xmlChar *) ncname);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000203
204 lenn = strlen((char *) ncname);
205 lenp = strlen((char *) prefix);
206
207 if ((memory == NULL) || (len < lenn + lenp + 2)) {
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000208 ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000209 if (ret == NULL) {
210 xmlTreeErrMemory("building QName");
211 return(NULL);
212 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000213 } else {
214 ret = memory;
215 }
216 memcpy(&ret[0], prefix, lenp);
217 ret[lenp] = ':';
218 memcpy(&ret[lenp + 1], ncname, lenn);
219 ret[lenn + lenp + 1] = 0;
220 return(ret);
221}
222
223/**
224 * xmlSplitQName2:
225 * @name: the full QName
226 * @prefix: a xmlChar **
227 *
228 * parse an XML qualified name string
229 *
230 * [NS 5] QName ::= (Prefix ':')? LocalPart
231 *
232 * [NS 6] Prefix ::= NCName
233 *
234 * [NS 7] LocalPart ::= NCName
235 *
236 * Returns NULL if not a QName, otherwise the local part, and prefix
237 * is updated to get the Prefix if any.
238 */
239
240xmlChar *
241xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
242 int len = 0;
243 xmlChar *ret = NULL;
244
245 *prefix = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000246 if (name == NULL) return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000247
248#ifndef XML_XML_NAMESPACE
249 /* xml: prefix is not really a namespace */
250 if ((name[0] == 'x') && (name[1] == 'm') &&
251 (name[2] == 'l') && (name[3] == ':'))
252 return(NULL);
253#endif
254
255 /* nasty but valid */
256 if (name[0] == ':')
257 return(NULL);
258
259 /*
260 * we are not trying to validate but just to cut, and yes it will
261 * work even if this is as set of UTF-8 encoded chars
262 */
263 while ((name[len] != 0) && (name[len] != ':'))
264 len++;
265
266 if (name[len] == 0)
267 return(NULL);
268
269 *prefix = xmlStrndup(name, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000270 if (*prefix == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000271 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000272 return(NULL);
273 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000274 ret = xmlStrdup(&name[len + 1]);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000275 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000276 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000277 if (*prefix != NULL) {
278 xmlFree(*prefix);
279 *prefix = NULL;
280 }
281 return(NULL);
282 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000283
284 return(ret);
285}
286
Daniel Veillard8d73bcb2003-08-04 01:06:15 +0000287/**
288 * xmlSplitQName3:
289 * @name: the full QName
290 * @len: an int *
291 *
292 * parse an XML qualified name string,i
293 *
294 * returns NULL if it is not a Qualified Name, otherwise, update len
295 * with the lenght in byte of the prefix and return a pointer
296 */
297
298const xmlChar *
299xmlSplitQName3(const xmlChar *name, int *len) {
300 int l = 0;
301
302 if (name == NULL) return(NULL);
303 if (len == NULL) return(NULL);
304
305 /* nasty but valid */
306 if (name[0] == ':')
307 return(NULL);
308
309 /*
310 * we are not trying to validate but just to cut, and yes it will
311 * work even if this is as set of UTF-8 encoded chars
312 */
313 while ((name[l] != 0) && (name[l] != ':'))
314 l++;
315
316 if (name[l] == 0)
317 return(NULL);
318
319 *len = l;
320
321 return(&name[l+1]);
322}
323
Daniel Veillard652327a2003-09-29 18:02:38 +0000324#ifdef LIBXML_TREE_ENABLED
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
333/**
334 * xmlValidateNCName:
335 * @value: the value to check
336 * @space: allow spaces in front and end of the string
337 *
338 * Check that a value conforms to the lexical space of NCName
339 *
340 * Returns 0 if this validates, a positive error code number otherwise
341 * and -1 in case of internal or API error.
342 */
343int
344xmlValidateNCName(const xmlChar *value, int space) {
345 const xmlChar *cur = value;
346 int c,l;
347
348 /*
349 * First quick algorithm for ASCII range
350 */
351 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000352 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000353 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
354 (*cur == '_'))
355 cur++;
356 else
357 goto try_complex;
358 while (((*cur >= 'a') && (*cur <= 'z')) ||
359 ((*cur >= 'A') && (*cur <= 'Z')) ||
360 ((*cur >= '0') && (*cur <= '9')) ||
361 (*cur == '_') || (*cur == '-') || (*cur == '.'))
362 cur++;
363 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000364 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000365 if (*cur == 0)
366 return(0);
367
368try_complex:
369 /*
370 * Second check for chars outside the ASCII range
371 */
372 cur = value;
373 c = CUR_SCHAR(cur, l);
374 if (space) {
375 while (IS_BLANK(c)) {
376 cur += l;
377 c = CUR_SCHAR(cur, l);
378 }
379 }
William M. Brack871611b2003-10-18 04:53:14 +0000380 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000381 return(1);
382 cur += l;
383 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000384 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
385 (c == '-') || (c == '_') || IS_COMBINING(c) ||
386 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000387 cur += l;
388 c = CUR_SCHAR(cur, l);
389 }
390 if (space) {
391 while (IS_BLANK(c)) {
392 cur += l;
393 c = CUR_SCHAR(cur, l);
394 }
395 }
396 if (c != 0)
397 return(1);
398
399 return(0);
400}
401
402/**
403 * xmlValidateQName:
404 * @value: the value to check
405 * @space: allow spaces in front and end of the string
406 *
407 * Check that a value conforms to the lexical space of QName
408 *
409 * Returns 0 if this validates, a positive error code number otherwise
410 * and -1 in case of internal or API error.
411 */
412int
413xmlValidateQName(const xmlChar *value, int space) {
414 const xmlChar *cur = value;
415 int c,l;
416
417 /*
418 * First quick algorithm for ASCII range
419 */
420 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000421 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000422 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
423 (*cur == '_'))
424 cur++;
425 else
426 goto try_complex;
427 while (((*cur >= 'a') && (*cur <= 'z')) ||
428 ((*cur >= 'A') && (*cur <= 'Z')) ||
429 ((*cur >= '0') && (*cur <= '9')) ||
430 (*cur == '_') || (*cur == '-') || (*cur == '.'))
431 cur++;
432 if (*cur == ':') {
433 cur++;
434 if (((*cur >= 'a') && (*cur <= 'z')) ||
435 ((*cur >= 'A') && (*cur <= 'Z')) ||
436 (*cur == '_'))
437 cur++;
438 else
439 goto try_complex;
440 while (((*cur >= 'a') && (*cur <= 'z')) ||
441 ((*cur >= 'A') && (*cur <= 'Z')) ||
442 ((*cur >= '0') && (*cur <= '9')) ||
443 (*cur == '_') || (*cur == '-') || (*cur == '.'))
444 cur++;
445 }
446 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000447 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000448 if (*cur == 0)
449 return(0);
450
451try_complex:
452 /*
453 * Second check for chars outside the ASCII range
454 */
455 cur = value;
456 c = CUR_SCHAR(cur, l);
457 if (space) {
458 while (IS_BLANK(c)) {
459 cur += l;
460 c = CUR_SCHAR(cur, l);
461 }
462 }
William M. Brack871611b2003-10-18 04:53:14 +0000463 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000464 return(1);
465 cur += l;
466 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000467 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
468 (c == '-') || (c == '_') || IS_COMBINING(c) ||
469 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000470 cur += l;
471 c = CUR_SCHAR(cur, l);
472 }
473 if (c == ':') {
474 cur += l;
475 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000476 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000477 return(1);
478 cur += l;
479 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000480 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
481 (c == '-') || (c == '_') || IS_COMBINING(c) ||
482 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000483 cur += l;
484 c = CUR_SCHAR(cur, l);
485 }
486 }
487 if (space) {
488 while (IS_BLANK(c)) {
489 cur += l;
490 c = CUR_SCHAR(cur, l);
491 }
492 }
493 if (c != 0)
494 return(1);
495 return(0);
496}
497
498/**
499 * xmlValidateName:
500 * @value: the value to check
501 * @space: allow spaces in front and end of the string
502 *
503 * Check that a value conforms to the lexical space of Name
504 *
505 * Returns 0 if this validates, a positive error code number otherwise
506 * and -1 in case of internal or API error.
507 */
508int
509xmlValidateName(const xmlChar *value, int space) {
510 const xmlChar *cur = value;
511 int c,l;
512
513 /*
514 * First quick algorithm for ASCII range
515 */
516 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000517 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000518 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
519 (*cur == '_') || (*cur == ':'))
520 cur++;
521 else
522 goto try_complex;
523 while (((*cur >= 'a') && (*cur <= 'z')) ||
524 ((*cur >= 'A') && (*cur <= 'Z')) ||
525 ((*cur >= '0') && (*cur <= '9')) ||
526 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
527 cur++;
528 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000529 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000530 if (*cur == 0)
531 return(0);
532
533try_complex:
534 /*
535 * Second check for chars outside the ASCII range
536 */
537 cur = value;
538 c = CUR_SCHAR(cur, l);
539 if (space) {
540 while (IS_BLANK(c)) {
541 cur += l;
542 c = CUR_SCHAR(cur, l);
543 }
544 }
William M. Brack871611b2003-10-18 04:53:14 +0000545 if ((!IS_LETTER(c)) && (c != '_') && (c != ':'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000546 return(1);
547 cur += l;
548 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000549 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
550 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000551 cur += l;
552 c = CUR_SCHAR(cur, l);
553 }
554 if (space) {
555 while (IS_BLANK(c)) {
556 cur += l;
557 c = CUR_SCHAR(cur, l);
558 }
559 }
560 if (c != 0)
561 return(1);
562 return(0);
563}
564
Daniel Veillardd4310742003-02-18 21:12:46 +0000565/**
566 * xmlValidateNMToken:
567 * @value: the value to check
568 * @space: allow spaces in front and end of the string
569 *
570 * Check that a value conforms to the lexical space of NMToken
571 *
572 * Returns 0 if this validates, a positive error code number otherwise
573 * and -1 in case of internal or API error.
574 */
575int
576xmlValidateNMToken(const xmlChar *value, int space) {
577 const xmlChar *cur = value;
578 int c,l;
579
580 /*
581 * First quick algorithm for ASCII range
582 */
583 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000584 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000585 if (((*cur >= 'a') && (*cur <= 'z')) ||
586 ((*cur >= 'A') && (*cur <= 'Z')) ||
587 ((*cur >= '0') && (*cur <= '9')) ||
588 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
589 cur++;
590 else
591 goto try_complex;
592 while (((*cur >= 'a') && (*cur <= 'z')) ||
593 ((*cur >= 'A') && (*cur <= 'Z')) ||
594 ((*cur >= '0') && (*cur <= '9')) ||
595 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
596 cur++;
597 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000598 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000599 if (*cur == 0)
600 return(0);
601
602try_complex:
603 /*
604 * Second check for chars outside the ASCII range
605 */
606 cur = value;
607 c = CUR_SCHAR(cur, l);
608 if (space) {
609 while (IS_BLANK(c)) {
610 cur += l;
611 c = CUR_SCHAR(cur, l);
612 }
613 }
William M. Brack871611b2003-10-18 04:53:14 +0000614 if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
615 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)))
Daniel Veillardd4310742003-02-18 21:12:46 +0000616 return(1);
617 cur += l;
618 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000619 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
620 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd4310742003-02-18 21:12:46 +0000621 cur += l;
622 c = CUR_SCHAR(cur, l);
623 }
624 if (space) {
625 while (IS_BLANK(c)) {
626 cur += l;
627 c = CUR_SCHAR(cur, l);
628 }
629 }
630 if (c != 0)
631 return(1);
632 return(0);
633}
Daniel Veillard652327a2003-09-29 18:02:38 +0000634#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardd4310742003-02-18 21:12:46 +0000635
Daniel Veillardd2298792003-02-14 16:54:11 +0000636/************************************************************************
637 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000638 * Allocation and deallocation of basic structures *
639 * *
640 ************************************************************************/
641
642/**
643 * xmlSetBufferAllocationScheme:
644 * @scheme: allocation method to use
645 *
646 * Set the buffer allocation method. Types are
647 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
648 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
649 * improves performance
650 */
651void
652xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
653 xmlBufferAllocScheme = scheme;
654}
655
656/**
657 * xmlGetBufferAllocationScheme:
658 *
659 * Types are
660 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
661 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
662 * improves performance
663 *
664 * Returns the current allocation scheme
665 */
666xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000667xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000668 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000669}
670
671/**
672 * xmlNewNs:
673 * @node: the element carrying the namespace
674 * @href: the URI associated
675 * @prefix: the prefix for the namespace
676 *
677 * Creation of a new Namespace. This function will refuse to create
678 * a namespace with a similar prefix than an existing one present on this
679 * node.
680 * We use href==NULL in the case of an element creation where the namespace
681 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000682 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000683 */
684xmlNsPtr
685xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
686 xmlNsPtr cur;
687
688 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
689 return(NULL);
690
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000691 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
692 return(NULL);
693
Owen Taylor3473f882001-02-23 17:55:21 +0000694 /*
695 * Allocate a new Namespace and fill the fields.
696 */
697 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
698 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000699 xmlTreeErrMemory("building namespace");
Owen Taylor3473f882001-02-23 17:55:21 +0000700 return(NULL);
701 }
702 memset(cur, 0, sizeof(xmlNs));
703 cur->type = XML_LOCAL_NAMESPACE;
704
705 if (href != NULL)
706 cur->href = xmlStrdup(href);
707 if (prefix != NULL)
708 cur->prefix = xmlStrdup(prefix);
709
710 /*
711 * Add it at the end to preserve parsing order ...
712 * and checks for existing use of the prefix
713 */
714 if (node != NULL) {
715 if (node->nsDef == NULL) {
716 node->nsDef = cur;
717 } else {
718 xmlNsPtr prev = node->nsDef;
719
720 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
721 (xmlStrEqual(prev->prefix, cur->prefix))) {
722 xmlFreeNs(cur);
723 return(NULL);
724 }
725 while (prev->next != NULL) {
726 prev = prev->next;
727 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
728 (xmlStrEqual(prev->prefix, cur->prefix))) {
729 xmlFreeNs(cur);
730 return(NULL);
731 }
732 }
733 prev->next = cur;
734 }
735 }
736 return(cur);
737}
738
739/**
740 * xmlSetNs:
741 * @node: a node in the document
742 * @ns: a namespace pointer
743 *
744 * Associate a namespace to a node, a posteriori.
745 */
746void
747xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
748 if (node == NULL) {
749#ifdef DEBUG_TREE
750 xmlGenericError(xmlGenericErrorContext,
751 "xmlSetNs: node == NULL\n");
752#endif
753 return;
754 }
755 node->ns = ns;
756}
757
758/**
759 * xmlFreeNs:
760 * @cur: the namespace pointer
761 *
762 * Free up the structures associated to a namespace
763 */
764void
765xmlFreeNs(xmlNsPtr cur) {
766 if (cur == NULL) {
767#ifdef DEBUG_TREE
768 xmlGenericError(xmlGenericErrorContext,
769 "xmlFreeNs : ns == NULL\n");
770#endif
771 return;
772 }
773 if (cur->href != NULL) xmlFree((char *) cur->href);
774 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000775 xmlFree(cur);
776}
777
778/**
779 * xmlFreeNsList:
780 * @cur: the first namespace pointer
781 *
782 * Free up all the structures associated to the chained namespaces.
783 */
784void
785xmlFreeNsList(xmlNsPtr cur) {
786 xmlNsPtr next;
787 if (cur == NULL) {
788#ifdef DEBUG_TREE
789 xmlGenericError(xmlGenericErrorContext,
790 "xmlFreeNsList : ns == NULL\n");
791#endif
792 return;
793 }
794 while (cur != NULL) {
795 next = cur->next;
796 xmlFreeNs(cur);
797 cur = next;
798 }
799}
800
801/**
802 * xmlNewDtd:
803 * @doc: the document pointer
804 * @name: the DTD name
805 * @ExternalID: the external ID
806 * @SystemID: the system ID
807 *
808 * Creation of a new DTD for the external subset. To create an
809 * internal subset, use xmlCreateIntSubset().
810 *
811 * Returns a pointer to the new DTD structure
812 */
813xmlDtdPtr
814xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
815 const xmlChar *ExternalID, const xmlChar *SystemID) {
816 xmlDtdPtr cur;
817
818 if ((doc != NULL) && (doc->extSubset != NULL)) {
819#ifdef DEBUG_TREE
820 xmlGenericError(xmlGenericErrorContext,
821 "xmlNewDtd(%s): document %s already have a DTD %s\n",
822 /* !!! */ (char *) name, doc->name,
823 /* !!! */ (char *)doc->extSubset->name);
824#endif
825 return(NULL);
826 }
827
828 /*
829 * Allocate a new DTD and fill the fields.
830 */
831 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
832 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000833 xmlTreeErrMemory("building DTD");
Owen Taylor3473f882001-02-23 17:55:21 +0000834 return(NULL);
835 }
836 memset(cur, 0 , sizeof(xmlDtd));
837 cur->type = XML_DTD_NODE;
838
839 if (name != NULL)
840 cur->name = xmlStrdup(name);
841 if (ExternalID != NULL)
842 cur->ExternalID = xmlStrdup(ExternalID);
843 if (SystemID != NULL)
844 cur->SystemID = xmlStrdup(SystemID);
845 if (doc != NULL)
846 doc->extSubset = cur;
847 cur->doc = doc;
848
Daniel Veillarda880b122003-04-21 21:36:41 +0000849 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000850 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000851 return(cur);
852}
853
854/**
855 * xmlGetIntSubset:
856 * @doc: the document pointer
857 *
858 * Get the internal subset of a document
859 * Returns a pointer to the DTD structure or NULL if not found
860 */
861
862xmlDtdPtr
863xmlGetIntSubset(xmlDocPtr doc) {
864 xmlNodePtr cur;
865
866 if (doc == NULL)
867 return(NULL);
868 cur = doc->children;
869 while (cur != NULL) {
870 if (cur->type == XML_DTD_NODE)
871 return((xmlDtdPtr) cur);
872 cur = cur->next;
873 }
874 return((xmlDtdPtr) doc->intSubset);
875}
876
877/**
878 * xmlCreateIntSubset:
879 * @doc: the document pointer
880 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000881 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000882 * @SystemID: the system ID
883 *
884 * Create the internal subset of a document
885 * Returns a pointer to the new DTD structure
886 */
887xmlDtdPtr
888xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
889 const xmlChar *ExternalID, const xmlChar *SystemID) {
890 xmlDtdPtr cur;
891
892 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
893#ifdef DEBUG_TREE
894 xmlGenericError(xmlGenericErrorContext,
895
896 "xmlCreateIntSubset(): document %s already have an internal subset\n",
897 doc->name);
898#endif
899 return(NULL);
900 }
901
902 /*
903 * Allocate a new DTD and fill the fields.
904 */
905 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
906 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000907 xmlTreeErrMemory("building internal subset");
Owen Taylor3473f882001-02-23 17:55:21 +0000908 return(NULL);
909 }
910 memset(cur, 0, sizeof(xmlDtd));
911 cur->type = XML_DTD_NODE;
912
913 if (name != NULL)
914 cur->name = xmlStrdup(name);
915 if (ExternalID != NULL)
916 cur->ExternalID = xmlStrdup(ExternalID);
917 if (SystemID != NULL)
918 cur->SystemID = xmlStrdup(SystemID);
919 if (doc != NULL) {
920 doc->intSubset = cur;
921 cur->parent = doc;
922 cur->doc = doc;
923 if (doc->children == NULL) {
924 doc->children = (xmlNodePtr) cur;
925 doc->last = (xmlNodePtr) cur;
926 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000927 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000928 xmlNodePtr prev;
929
Owen Taylor3473f882001-02-23 17:55:21 +0000930 prev = doc->children;
931 prev->prev = (xmlNodePtr) cur;
932 cur->next = prev;
933 doc->children = (xmlNodePtr) cur;
934 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000935 xmlNodePtr next;
936
937 next = doc->children;
938 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
939 next = next->next;
940 if (next == NULL) {
941 cur->prev = doc->last;
942 cur->prev->next = (xmlNodePtr) cur;
943 cur->next = NULL;
944 doc->last = (xmlNodePtr) cur;
945 } else {
946 cur->next = next;
947 cur->prev = next->prev;
948 if (cur->prev == NULL)
949 doc->children = (xmlNodePtr) cur;
950 else
951 cur->prev->next = (xmlNodePtr) cur;
952 next->prev = (xmlNodePtr) cur;
953 }
Owen Taylor3473f882001-02-23 17:55:21 +0000954 }
955 }
956 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000957
Daniel Veillarda880b122003-04-21 21:36:41 +0000958 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000959 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000960 return(cur);
961}
962
963/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000964 * DICT_FREE:
965 * @str: a string
966 *
967 * Free a string if it is not owned by the "dict" dictionnary in the
968 * current scope
969 */
970#define DICT_FREE(str) \
971 if ((str) && ((!dict) || \
972 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
973 xmlFree((char *)(str));
974
975/**
Owen Taylor3473f882001-02-23 17:55:21 +0000976 * xmlFreeDtd:
977 * @cur: the DTD structure to free up
978 *
979 * Free a DTD structure.
980 */
981void
982xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000983 xmlDictPtr dict = NULL;
984
Owen Taylor3473f882001-02-23 17:55:21 +0000985 if (cur == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000986 return;
987 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000988 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +0000989
Daniel Veillarda880b122003-04-21 21:36:41 +0000990 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000991 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
992
Owen Taylor3473f882001-02-23 17:55:21 +0000993 if (cur->children != NULL) {
994 xmlNodePtr next, c = cur->children;
995
996 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000997 * Cleanup all the DTD comments they are not in the DTD
Owen Taylor3473f882001-02-23 17:55:21 +0000998 * indexes.
999 */
1000 while (c != NULL) {
1001 next = c->next;
Daniel Veillardd72c7e32003-05-12 21:55:03 +00001002 if ((c->type == XML_COMMENT_NODE) || (c->type == XML_PI_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001003 xmlUnlinkNode(c);
1004 xmlFreeNode(c);
1005 }
1006 c = next;
1007 }
1008 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001009 DICT_FREE(cur->name)
1010 DICT_FREE(cur->SystemID)
1011 DICT_FREE(cur->ExternalID)
Owen Taylor3473f882001-02-23 17:55:21 +00001012 /* TODO !!! */
1013 if (cur->notations != NULL)
1014 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
1015
1016 if (cur->elements != NULL)
1017 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
1018 if (cur->attributes != NULL)
1019 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
1020 if (cur->entities != NULL)
1021 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
1022 if (cur->pentities != NULL)
1023 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
1024
Owen Taylor3473f882001-02-23 17:55:21 +00001025 xmlFree(cur);
1026}
1027
1028/**
1029 * xmlNewDoc:
1030 * @version: xmlChar string giving the version of XML "1.0"
1031 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001032 * Creates a new XML document
1033 *
Owen Taylor3473f882001-02-23 17:55:21 +00001034 * Returns a new document
1035 */
1036xmlDocPtr
1037xmlNewDoc(const xmlChar *version) {
1038 xmlDocPtr cur;
1039
1040 if (version == NULL)
1041 version = (const xmlChar *) "1.0";
1042
1043 /*
1044 * Allocate a new document and fill the fields.
1045 */
1046 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
1047 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001048 xmlTreeErrMemory("building doc");
Owen Taylor3473f882001-02-23 17:55:21 +00001049 return(NULL);
1050 }
1051 memset(cur, 0, sizeof(xmlDoc));
1052 cur->type = XML_DOCUMENT_NODE;
1053
1054 cur->version = xmlStrdup(version);
1055 cur->standalone = -1;
1056 cur->compression = -1; /* not initialized */
1057 cur->doc = cur;
Daniel Veillarda6874ca2003-07-29 16:47:24 +00001058 /*
1059 * The in memory encoding is always UTF8
1060 * This field will never change and would
1061 * be obsolete if not for binary compatibility.
1062 */
Daniel Veillardd2f3ec72001-04-11 07:50:02 +00001063 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001064
Daniel Veillarda880b122003-04-21 21:36:41 +00001065 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001066 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001067 return(cur);
1068}
1069
1070/**
1071 * xmlFreeDoc:
1072 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +00001073 *
1074 * Free up all the structures used by a document, tree included.
1075 */
1076void
1077xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +00001078 xmlDtdPtr extSubset, intSubset;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001079 xmlDictPtr dict = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001080
Owen Taylor3473f882001-02-23 17:55:21 +00001081 if (cur == NULL) {
1082#ifdef DEBUG_TREE
1083 xmlGenericError(xmlGenericErrorContext,
1084 "xmlFreeDoc : document == NULL\n");
1085#endif
1086 return;
1087 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001088 if (cur != NULL) dict = cur->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001089
Daniel Veillarda880b122003-04-21 21:36:41 +00001090 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001091 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1092
Daniel Veillard76d66f42001-05-16 21:05:17 +00001093 /*
1094 * Do this before freeing the children list to avoid ID lookups
1095 */
1096 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1097 cur->ids = NULL;
1098 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1099 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001100 extSubset = cur->extSubset;
1101 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +00001102 if (intSubset == extSubset)
1103 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001104 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001105 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001106 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001107 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001108 }
Daniel Veillarda9142e72001-06-19 11:07:54 +00001109 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001110 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001111 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001112 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001113 }
1114
1115 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001116 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001117
1118 DICT_FREE(cur->version)
1119 DICT_FREE(cur->name)
1120 DICT_FREE(cur->encoding)
1121 DICT_FREE(cur->URL)
Owen Taylor3473f882001-02-23 17:55:21 +00001122 xmlFree(cur);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001123 if (dict) xmlDictFree(dict);
Owen Taylor3473f882001-02-23 17:55:21 +00001124}
1125
1126/**
1127 * xmlStringLenGetNodeList:
1128 * @doc: the document
1129 * @value: the value of the text
1130 * @len: the length of the string value
1131 *
1132 * Parse the value string and build the node list associated. Should
1133 * produce a flat tree with only TEXTs and ENTITY_REFs.
1134 * Returns a pointer to the first child
1135 */
1136xmlNodePtr
1137xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1138 xmlNodePtr ret = NULL, last = NULL;
1139 xmlNodePtr node;
1140 xmlChar *val;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001141 const xmlChar *cur = value, *end = cur + len;
Owen Taylor3473f882001-02-23 17:55:21 +00001142 const xmlChar *q;
1143 xmlEntityPtr ent;
1144
1145 if (value == NULL) return(NULL);
1146
1147 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001148 while ((cur < end) && (*cur != 0)) {
1149 if (cur[0] == '&') {
1150 int charval = 0;
1151 xmlChar tmp;
1152
Owen Taylor3473f882001-02-23 17:55:21 +00001153 /*
1154 * Save the current text.
1155 */
1156 if (cur != q) {
1157 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1158 xmlNodeAddContentLen(last, q, cur - q);
1159 } else {
1160 node = xmlNewDocTextLen(doc, q, cur - q);
1161 if (node == NULL) return(ret);
1162 if (last == NULL)
1163 last = ret = node;
1164 else {
1165 last->next = node;
1166 node->prev = last;
1167 last = node;
1168 }
1169 }
1170 }
Owen Taylor3473f882001-02-23 17:55:21 +00001171 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001172 if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
1173 cur += 3;
1174 if (cur < end)
1175 tmp = *cur;
1176 else
1177 tmp = 0;
1178 while (tmp != ';') { /* Non input consuming loop */
1179 if ((tmp >= '0') && (tmp <= '9'))
1180 charval = charval * 16 + (tmp - '0');
1181 else if ((tmp >= 'a') && (tmp <= 'f'))
1182 charval = charval * 16 + (tmp - 'a') + 10;
1183 else if ((tmp >= 'A') && (tmp <= 'F'))
1184 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001185 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001186 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1187 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001188 charval = 0;
1189 break;
1190 }
1191 cur++;
1192 if (cur < end)
1193 tmp = *cur;
1194 else
1195 tmp = 0;
1196 }
1197 if (tmp == ';')
1198 cur++;
1199 q = cur;
1200 } else if ((cur + 1 < end) && (cur[1] == '#')) {
1201 cur += 2;
1202 if (cur < end)
1203 tmp = *cur;
1204 else
1205 tmp = 0;
1206 while (tmp != ';') { /* Non input consuming loops */
1207 if ((tmp >= '0') && (tmp <= '9'))
1208 charval = charval * 10 + (tmp - '0');
1209 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001210 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1211 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001212 charval = 0;
1213 break;
1214 }
1215 cur++;
1216 if (cur < end)
1217 tmp = *cur;
1218 else
1219 tmp = 0;
1220 }
1221 if (tmp == ';')
1222 cur++;
1223 q = cur;
1224 } else {
1225 /*
1226 * Read the entity string
1227 */
1228 cur++;
1229 q = cur;
1230 while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1231 if ((cur >= end) || (*cur == 0)) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001232 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc,
1233 (const char *) q);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001234 return(ret);
1235 }
1236 if (cur != q) {
1237 /*
1238 * Predefined entities don't generate nodes
1239 */
1240 val = xmlStrndup(q, cur - q);
1241 ent = xmlGetDocEntity(doc, val);
1242 if ((ent != NULL) &&
1243 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1244 if (last == NULL) {
1245 node = xmlNewDocText(doc, ent->content);
1246 last = ret = node;
1247 } else if (last->type != XML_TEXT_NODE) {
1248 node = xmlNewDocText(doc, ent->content);
1249 last = xmlAddNextSibling(last, node);
1250 } else
1251 xmlNodeAddContent(last, ent->content);
1252
1253 } else {
1254 /*
1255 * Create a new REFERENCE_REF node
1256 */
1257 node = xmlNewReference(doc, val);
1258 if (node == NULL) {
1259 if (val != NULL) xmlFree(val);
1260 return(ret);
1261 }
1262 else if ((ent != NULL) && (ent->children == NULL)) {
1263 xmlNodePtr temp;
1264
1265 ent->children = xmlStringGetNodeList(doc,
1266 (const xmlChar*)node->content);
1267 ent->owner = 1;
1268 temp = ent->children;
1269 while (temp) {
1270 temp->parent = (xmlNodePtr)ent;
1271 temp = temp->next;
1272 }
1273 }
1274 if (last == NULL) {
1275 last = ret = node;
1276 } else {
1277 last = xmlAddNextSibling(last, node);
1278 }
1279 }
1280 xmlFree(val);
1281 }
1282 cur++;
1283 q = cur;
1284 }
1285 if (charval != 0) {
1286 xmlChar buf[10];
1287 int l;
1288
1289 l = xmlCopyCharMultiByte(buf, charval);
1290 buf[l] = 0;
1291 node = xmlNewDocText(doc, buf);
1292 if (node != NULL) {
1293 if (last == NULL) {
1294 last = ret = node;
1295 } else {
1296 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001297 }
1298 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001299 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001300 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001301 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001302 cur++;
1303 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001304 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001305 /*
1306 * Handle the last piece of text.
1307 */
1308 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1309 xmlNodeAddContentLen(last, q, cur - q);
1310 } else {
1311 node = xmlNewDocTextLen(doc, q, cur - q);
1312 if (node == NULL) return(ret);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001313 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001314 last = ret = node;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001315 } else {
1316 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001317 }
1318 }
1319 }
1320 return(ret);
1321}
1322
1323/**
1324 * xmlStringGetNodeList:
1325 * @doc: the document
1326 * @value: the value of the attribute
1327 *
1328 * Parse the value string and build the node list associated. Should
1329 * produce a flat tree with only TEXTs and ENTITY_REFs.
1330 * Returns a pointer to the first child
1331 */
1332xmlNodePtr
1333xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1334 xmlNodePtr ret = NULL, last = NULL;
1335 xmlNodePtr node;
1336 xmlChar *val;
1337 const xmlChar *cur = value;
1338 const xmlChar *q;
1339 xmlEntityPtr ent;
1340
1341 if (value == NULL) return(NULL);
1342
1343 q = cur;
1344 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001345 if (cur[0] == '&') {
1346 int charval = 0;
1347 xmlChar tmp;
1348
Owen Taylor3473f882001-02-23 17:55:21 +00001349 /*
1350 * Save the current text.
1351 */
1352 if (cur != q) {
1353 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1354 xmlNodeAddContentLen(last, q, cur - q);
1355 } else {
1356 node = xmlNewDocTextLen(doc, q, cur - q);
1357 if (node == NULL) return(ret);
1358 if (last == NULL)
1359 last = ret = node;
1360 else {
1361 last->next = node;
1362 node->prev = last;
1363 last = node;
1364 }
1365 }
1366 }
Owen Taylor3473f882001-02-23 17:55:21 +00001367 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001368 if ((cur[1] == '#') && (cur[2] == 'x')) {
1369 cur += 3;
1370 tmp = *cur;
1371 while (tmp != ';') { /* Non input consuming loop */
1372 if ((tmp >= '0') && (tmp <= '9'))
1373 charval = charval * 16 + (tmp - '0');
1374 else if ((tmp >= 'a') && (tmp <= 'f'))
1375 charval = charval * 16 + (tmp - 'a') + 10;
1376 else if ((tmp >= 'A') && (tmp <= 'F'))
1377 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001378 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001379 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1380 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001381 charval = 0;
1382 break;
1383 }
1384 cur++;
1385 tmp = *cur;
1386 }
1387 if (tmp == ';')
1388 cur++;
1389 q = cur;
1390 } else if (cur[1] == '#') {
1391 cur += 2;
1392 tmp = *cur;
1393 while (tmp != ';') { /* Non input consuming loops */
1394 if ((tmp >= '0') && (tmp <= '9'))
1395 charval = charval * 10 + (tmp - '0');
1396 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001397 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1398 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001399 charval = 0;
1400 break;
1401 }
1402 cur++;
1403 tmp = *cur;
1404 }
1405 if (tmp == ';')
1406 cur++;
1407 q = cur;
1408 } else {
1409 /*
1410 * Read the entity string
1411 */
1412 cur++;
1413 q = cur;
1414 while ((*cur != 0) && (*cur != ';')) cur++;
1415 if (*cur == 0) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001416 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY,
1417 (xmlNodePtr) doc, (const char *) q);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001418 return(ret);
1419 }
1420 if (cur != q) {
1421 /*
1422 * Predefined entities don't generate nodes
1423 */
1424 val = xmlStrndup(q, cur - q);
1425 ent = xmlGetDocEntity(doc, val);
1426 if ((ent != NULL) &&
1427 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1428 if (last == NULL) {
1429 node = xmlNewDocText(doc, ent->content);
1430 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001431 } else if (last->type != XML_TEXT_NODE) {
1432 node = xmlNewDocText(doc, ent->content);
1433 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001434 } else
1435 xmlNodeAddContent(last, ent->content);
1436
1437 } else {
1438 /*
1439 * Create a new REFERENCE_REF node
1440 */
1441 node = xmlNewReference(doc, val);
1442 if (node == NULL) {
1443 if (val != NULL) xmlFree(val);
1444 return(ret);
1445 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001446 else if ((ent != NULL) && (ent->children == NULL)) {
1447 xmlNodePtr temp;
1448
1449 ent->children = xmlStringGetNodeList(doc,
1450 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001451 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001452 temp = ent->children;
1453 while (temp) {
1454 temp->parent = (xmlNodePtr)ent;
1455 temp = temp->next;
1456 }
1457 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001458 if (last == NULL) {
1459 last = ret = node;
1460 } else {
1461 last = xmlAddNextSibling(last, node);
1462 }
1463 }
1464 xmlFree(val);
1465 }
1466 cur++;
1467 q = cur;
1468 }
1469 if (charval != 0) {
1470 xmlChar buf[10];
1471 int len;
1472
1473 len = xmlCopyCharMultiByte(buf, charval);
1474 buf[len] = 0;
1475 node = xmlNewDocText(doc, buf);
1476 if (node != NULL) {
1477 if (last == NULL) {
1478 last = ret = node;
1479 } else {
1480 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001481 }
1482 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001483
1484 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001485 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001486 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001487 cur++;
1488 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001489 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001490 /*
1491 * Handle the last piece of text.
1492 */
1493 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1494 xmlNodeAddContentLen(last, q, cur - q);
1495 } else {
1496 node = xmlNewDocTextLen(doc, q, cur - q);
1497 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001498 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001499 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001500 } else {
1501 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001502 }
1503 }
1504 }
1505 return(ret);
1506}
1507
1508/**
1509 * xmlNodeListGetString:
1510 * @doc: the document
1511 * @list: a Node list
1512 * @inLine: should we replace entity contents or show their external form
1513 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001514 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001515 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001516 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001517 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001518 */
1519xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001520xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1521{
Owen Taylor3473f882001-02-23 17:55:21 +00001522 xmlNodePtr node = list;
1523 xmlChar *ret = NULL;
1524 xmlEntityPtr ent;
1525
Daniel Veillard7646b182002-04-20 06:41:40 +00001526 if (list == NULL)
1527 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001528
1529 while (node != NULL) {
1530 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001531 (node->type == XML_CDATA_SECTION_NODE)) {
1532 if (inLine) {
1533 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001534 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001535 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001536
Daniel Veillard7646b182002-04-20 06:41:40 +00001537 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1538 if (buffer != NULL) {
1539 ret = xmlStrcat(ret, buffer);
1540 xmlFree(buffer);
1541 }
1542 }
1543 } else if (node->type == XML_ENTITY_REF_NODE) {
1544 if (inLine) {
1545 ent = xmlGetDocEntity(doc, node->name);
1546 if (ent != NULL) {
1547 xmlChar *buffer;
1548
1549 /* an entity content can be any "well balanced chunk",
1550 * i.e. the result of the content [43] production:
1551 * http://www.w3.org/TR/REC-xml#NT-content.
1552 * So it can contain text, CDATA section or nested
1553 * entity reference nodes (among others).
1554 * -> we recursive call xmlNodeListGetString()
1555 * which handles these types */
1556 buffer = xmlNodeListGetString(doc, ent->children, 1);
1557 if (buffer != NULL) {
1558 ret = xmlStrcat(ret, buffer);
1559 xmlFree(buffer);
1560 }
1561 } else {
1562 ret = xmlStrcat(ret, node->content);
1563 }
1564 } else {
1565 xmlChar buf[2];
1566
1567 buf[0] = '&';
1568 buf[1] = 0;
1569 ret = xmlStrncat(ret, buf, 1);
1570 ret = xmlStrcat(ret, node->name);
1571 buf[0] = ';';
1572 buf[1] = 0;
1573 ret = xmlStrncat(ret, buf, 1);
1574 }
1575 }
1576#if 0
1577 else {
1578 xmlGenericError(xmlGenericErrorContext,
1579 "xmlGetNodeListString : invalid node type %d\n",
1580 node->type);
1581 }
1582#endif
1583 node = node->next;
1584 }
1585 return (ret);
1586}
Daniel Veillard652327a2003-09-29 18:02:38 +00001587
1588#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001589/**
1590 * xmlNodeListGetRawString:
1591 * @doc: the document
1592 * @list: a Node list
1593 * @inLine: should we replace entity contents or show their external form
1594 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001595 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001596 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1597 * this function doesn't do any character encoding handling.
1598 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001599 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001600 */
1601xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001602xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1603{
Owen Taylor3473f882001-02-23 17:55:21 +00001604 xmlNodePtr node = list;
1605 xmlChar *ret = NULL;
1606 xmlEntityPtr ent;
1607
Daniel Veillard7646b182002-04-20 06:41:40 +00001608 if (list == NULL)
1609 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001610
1611 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001612 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001613 (node->type == XML_CDATA_SECTION_NODE)) {
1614 if (inLine) {
1615 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001616 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001617 xmlChar *buffer;
1618
1619 buffer = xmlEncodeSpecialChars(doc, node->content);
1620 if (buffer != NULL) {
1621 ret = xmlStrcat(ret, buffer);
1622 xmlFree(buffer);
1623 }
1624 }
1625 } else if (node->type == XML_ENTITY_REF_NODE) {
1626 if (inLine) {
1627 ent = xmlGetDocEntity(doc, node->name);
1628 if (ent != NULL) {
1629 xmlChar *buffer;
1630
1631 /* an entity content can be any "well balanced chunk",
1632 * i.e. the result of the content [43] production:
1633 * http://www.w3.org/TR/REC-xml#NT-content.
1634 * So it can contain text, CDATA section or nested
1635 * entity reference nodes (among others).
1636 * -> we recursive call xmlNodeListGetRawString()
1637 * which handles these types */
1638 buffer =
1639 xmlNodeListGetRawString(doc, ent->children, 1);
1640 if (buffer != NULL) {
1641 ret = xmlStrcat(ret, buffer);
1642 xmlFree(buffer);
1643 }
1644 } else {
1645 ret = xmlStrcat(ret, node->content);
1646 }
1647 } else {
1648 xmlChar buf[2];
1649
1650 buf[0] = '&';
1651 buf[1] = 0;
1652 ret = xmlStrncat(ret, buf, 1);
1653 ret = xmlStrcat(ret, node->name);
1654 buf[0] = ';';
1655 buf[1] = 0;
1656 ret = xmlStrncat(ret, buf, 1);
1657 }
1658 }
Owen Taylor3473f882001-02-23 17:55:21 +00001659#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001660 else {
1661 xmlGenericError(xmlGenericErrorContext,
1662 "xmlGetNodeListString : invalid node type %d\n",
1663 node->type);
1664 }
Owen Taylor3473f882001-02-23 17:55:21 +00001665#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001666 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001667 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001668 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001669}
Daniel Veillard652327a2003-09-29 18:02:38 +00001670#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001671
Daniel Veillard652327a2003-09-29 18:02:38 +00001672#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001673/**
1674 * xmlNewProp:
1675 * @node: the holding node
1676 * @name: the name of the attribute
1677 * @value: the value of the attribute
1678 *
1679 * Create a new property carried by a node.
1680 * Returns a pointer to the attribute
1681 */
1682xmlAttrPtr
1683xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1684 xmlAttrPtr cur;
1685 xmlDocPtr doc = NULL;
1686
1687 if (name == NULL) {
1688#ifdef DEBUG_TREE
1689 xmlGenericError(xmlGenericErrorContext,
1690 "xmlNewProp : name == NULL\n");
1691#endif
1692 return(NULL);
1693 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00001694 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
1695 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001696
1697 /*
1698 * Allocate a new property and fill the fields.
1699 */
1700 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1701 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001702 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001703 return(NULL);
1704 }
1705 memset(cur, 0, sizeof(xmlAttr));
1706 cur->type = XML_ATTRIBUTE_NODE;
1707
1708 cur->parent = node;
1709 if (node != NULL) {
1710 doc = node->doc;
1711 cur->doc = doc;
1712 }
1713 cur->name = xmlStrdup(name);
1714 if (value != NULL) {
1715 xmlChar *buffer;
1716 xmlNodePtr tmp;
1717
1718 buffer = xmlEncodeEntitiesReentrant(doc, value);
1719 cur->children = xmlStringGetNodeList(doc, buffer);
1720 cur->last = NULL;
1721 tmp = cur->children;
1722 while (tmp != NULL) {
1723 tmp->parent = (xmlNodePtr) cur;
1724 tmp->doc = doc;
1725 if (tmp->next == NULL)
1726 cur->last = tmp;
1727 tmp = tmp->next;
1728 }
1729 xmlFree(buffer);
1730 }
1731
1732 /*
1733 * Add it at the end to preserve parsing order ...
1734 */
1735 if (node != NULL) {
1736 if (node->properties == NULL) {
1737 node->properties = cur;
1738 } else {
1739 xmlAttrPtr prev = node->properties;
1740
1741 while (prev->next != NULL) prev = prev->next;
1742 prev->next = cur;
1743 cur->prev = prev;
1744 }
1745 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001746
Daniel Veillarda880b122003-04-21 21:36:41 +00001747 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001748 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001749 return(cur);
1750}
Daniel Veillard652327a2003-09-29 18:02:38 +00001751#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001752
1753/**
1754 * xmlNewNsProp:
1755 * @node: the holding node
1756 * @ns: the namespace
1757 * @name: the name of the attribute
1758 * @value: the value of the attribute
1759 *
1760 * Create a new property tagged with a namespace and carried by a node.
1761 * Returns a pointer to the attribute
1762 */
1763xmlAttrPtr
1764xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1765 const xmlChar *value) {
1766 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001767 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001768
1769 if (name == NULL) {
1770#ifdef DEBUG_TREE
1771 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001772 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001773#endif
1774 return(NULL);
1775 }
1776
1777 /*
1778 * Allocate a new property and fill the fields.
1779 */
1780 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1781 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001782 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001783 return(NULL);
1784 }
1785 memset(cur, 0, sizeof(xmlAttr));
1786 cur->type = XML_ATTRIBUTE_NODE;
1787
1788 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001789 if (node != NULL) {
1790 doc = node->doc;
1791 cur->doc = doc;
1792 }
Owen Taylor3473f882001-02-23 17:55:21 +00001793 cur->ns = ns;
1794 cur->name = xmlStrdup(name);
1795 if (value != NULL) {
1796 xmlChar *buffer;
1797 xmlNodePtr tmp;
1798
Daniel Veillarda682b212001-06-07 19:59:42 +00001799 buffer = xmlEncodeEntitiesReentrant(doc, value);
1800 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001801 cur->last = NULL;
1802 tmp = cur->children;
1803 while (tmp != NULL) {
1804 tmp->parent = (xmlNodePtr) cur;
1805 if (tmp->next == NULL)
1806 cur->last = tmp;
1807 tmp = tmp->next;
1808 }
1809 xmlFree(buffer);
1810 }
1811
1812 /*
1813 * Add it at the end to preserve parsing order ...
1814 */
1815 if (node != NULL) {
1816 if (node->properties == NULL) {
1817 node->properties = cur;
1818 } else {
1819 xmlAttrPtr prev = node->properties;
1820
1821 while (prev->next != NULL) prev = prev->next;
1822 prev->next = cur;
1823 cur->prev = prev;
1824 }
1825 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001826
Daniel Veillarda880b122003-04-21 21:36:41 +00001827 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001828 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001829 return(cur);
1830}
1831
1832/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001833 * xmlNewNsPropEatName:
1834 * @node: the holding node
1835 * @ns: the namespace
1836 * @name: the name of the attribute
1837 * @value: the value of the attribute
1838 *
1839 * Create a new property tagged with a namespace and carried by a node.
1840 * Returns a pointer to the attribute
1841 */
1842xmlAttrPtr
1843xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1844 const xmlChar *value) {
1845 xmlAttrPtr cur;
1846 xmlDocPtr doc = NULL;
1847
1848 if (name == NULL) {
1849#ifdef DEBUG_TREE
1850 xmlGenericError(xmlGenericErrorContext,
1851 "xmlNewNsPropEatName : name == NULL\n");
1852#endif
1853 return(NULL);
1854 }
1855
1856 /*
1857 * Allocate a new property and fill the fields.
1858 */
1859 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1860 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001861 xmlTreeErrMemory("building attribute");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001862 xmlFree(name);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001863 return(NULL);
1864 }
1865 memset(cur, 0, sizeof(xmlAttr));
1866 cur->type = XML_ATTRIBUTE_NODE;
1867
1868 cur->parent = node;
1869 if (node != NULL) {
1870 doc = node->doc;
1871 cur->doc = doc;
1872 }
1873 cur->ns = ns;
1874 cur->name = name;
1875 if (value != NULL) {
1876 xmlChar *buffer;
1877 xmlNodePtr tmp;
1878
1879 buffer = xmlEncodeEntitiesReentrant(doc, value);
1880 cur->children = xmlStringGetNodeList(doc, buffer);
1881 cur->last = NULL;
1882 tmp = cur->children;
1883 while (tmp != NULL) {
1884 tmp->parent = (xmlNodePtr) cur;
1885 if (tmp->next == NULL)
1886 cur->last = tmp;
1887 tmp = tmp->next;
1888 }
1889 xmlFree(buffer);
1890 }
1891
1892 /*
1893 * Add it at the end to preserve parsing order ...
1894 */
1895 if (node != NULL) {
1896 if (node->properties == NULL) {
1897 node->properties = cur;
1898 } else {
1899 xmlAttrPtr prev = node->properties;
1900
1901 while (prev->next != NULL) prev = prev->next;
1902 prev->next = cur;
1903 cur->prev = prev;
1904 }
1905 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001906
Daniel Veillarda880b122003-04-21 21:36:41 +00001907 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001908 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001909 return(cur);
1910}
1911
1912/**
Owen Taylor3473f882001-02-23 17:55:21 +00001913 * xmlNewDocProp:
1914 * @doc: the document
1915 * @name: the name of the attribute
1916 * @value: the value of the attribute
1917 *
1918 * Create a new property carried by a document.
1919 * Returns a pointer to the attribute
1920 */
1921xmlAttrPtr
1922xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1923 xmlAttrPtr cur;
1924
1925 if (name == NULL) {
1926#ifdef DEBUG_TREE
1927 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001928 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001929#endif
1930 return(NULL);
1931 }
1932
1933 /*
1934 * Allocate a new property and fill the fields.
1935 */
1936 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1937 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001938 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001939 return(NULL);
1940 }
1941 memset(cur, 0, sizeof(xmlAttr));
1942 cur->type = XML_ATTRIBUTE_NODE;
1943
1944 cur->name = xmlStrdup(name);
1945 cur->doc = doc;
1946 if (value != NULL) {
1947 xmlNodePtr tmp;
1948
1949 cur->children = xmlStringGetNodeList(doc, value);
1950 cur->last = NULL;
1951
1952 tmp = cur->children;
1953 while (tmp != NULL) {
1954 tmp->parent = (xmlNodePtr) cur;
1955 if (tmp->next == NULL)
1956 cur->last = tmp;
1957 tmp = tmp->next;
1958 }
1959 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001960
Daniel Veillarda880b122003-04-21 21:36:41 +00001961 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001962 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001963 return(cur);
1964}
1965
1966/**
1967 * xmlFreePropList:
1968 * @cur: the first property in the list
1969 *
1970 * Free a property and all its siblings, all the children are freed too.
1971 */
1972void
1973xmlFreePropList(xmlAttrPtr cur) {
1974 xmlAttrPtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001975 if (cur == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001976 while (cur != NULL) {
1977 next = cur->next;
1978 xmlFreeProp(cur);
1979 cur = next;
1980 }
1981}
1982
1983/**
1984 * xmlFreeProp:
1985 * @cur: an attribute
1986 *
1987 * Free one attribute, all the content is freed too
1988 */
1989void
1990xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001991 xmlDictPtr dict = NULL;
1992 if (cur == NULL) return;
1993
1994 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001995
Daniel Veillarda880b122003-04-21 21:36:41 +00001996 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001997 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1998
Owen Taylor3473f882001-02-23 17:55:21 +00001999 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00002000 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
2001 ((cur->parent->doc->intSubset != NULL) ||
2002 (cur->parent->doc->extSubset != NULL))) {
2003 if (xmlIsID(cur->parent->doc, cur->parent, cur))
2004 xmlRemoveID(cur->parent->doc, cur);
2005 }
Owen Taylor3473f882001-02-23 17:55:21 +00002006 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002007 DICT_FREE(cur->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002008 xmlFree(cur);
2009}
2010
Daniel Veillard652327a2003-09-29 18:02:38 +00002011#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002012/**
2013 * xmlRemoveProp:
2014 * @cur: an attribute
2015 *
2016 * Unlink and free one attribute, all the content is freed too
2017 * Note this doesn't work for namespace definition attributes
2018 *
2019 * Returns 0 if success and -1 in case of error.
2020 */
2021int
2022xmlRemoveProp(xmlAttrPtr cur) {
2023 xmlAttrPtr tmp;
2024 if (cur == NULL) {
2025#ifdef DEBUG_TREE
2026 xmlGenericError(xmlGenericErrorContext,
2027 "xmlRemoveProp : cur == NULL\n");
2028#endif
2029 return(-1);
2030 }
2031 if (cur->parent == NULL) {
2032#ifdef DEBUG_TREE
2033 xmlGenericError(xmlGenericErrorContext,
2034 "xmlRemoveProp : cur->parent == NULL\n");
2035#endif
2036 return(-1);
2037 }
2038 tmp = cur->parent->properties;
2039 if (tmp == cur) {
2040 cur->parent->properties = cur->next;
2041 xmlFreeProp(cur);
2042 return(0);
2043 }
2044 while (tmp != NULL) {
2045 if (tmp->next == cur) {
2046 tmp->next = cur->next;
2047 if (tmp->next != NULL)
2048 tmp->next->prev = tmp;
2049 xmlFreeProp(cur);
2050 return(0);
2051 }
2052 tmp = tmp->next;
2053 }
2054#ifdef DEBUG_TREE
2055 xmlGenericError(xmlGenericErrorContext,
2056 "xmlRemoveProp : attribute not owned by its node\n");
2057#endif
2058 return(-1);
2059}
Daniel Veillard652327a2003-09-29 18:02:38 +00002060#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002061
2062/**
2063 * xmlNewPI:
2064 * @name: the processing instruction name
2065 * @content: the PI content
2066 *
2067 * Creation of a processing instruction element.
2068 * Returns a pointer to the new node object.
2069 */
2070xmlNodePtr
2071xmlNewPI(const xmlChar *name, const xmlChar *content) {
2072 xmlNodePtr cur;
2073
2074 if (name == NULL) {
2075#ifdef DEBUG_TREE
2076 xmlGenericError(xmlGenericErrorContext,
2077 "xmlNewPI : name == NULL\n");
2078#endif
2079 return(NULL);
2080 }
2081
2082 /*
2083 * Allocate a new node and fill the fields.
2084 */
2085 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2086 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002087 xmlTreeErrMemory("building PI");
Owen Taylor3473f882001-02-23 17:55:21 +00002088 return(NULL);
2089 }
2090 memset(cur, 0, sizeof(xmlNode));
2091 cur->type = XML_PI_NODE;
2092
2093 cur->name = xmlStrdup(name);
2094 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002095 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002096 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002097
Daniel Veillarda880b122003-04-21 21:36:41 +00002098 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002099 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002100 return(cur);
2101}
2102
2103/**
2104 * xmlNewNode:
2105 * @ns: namespace if any
2106 * @name: the node name
2107 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002108 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002109 *
2110 * Returns a pointer to the new node object.
2111 */
2112xmlNodePtr
2113xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2114 xmlNodePtr cur;
2115
2116 if (name == NULL) {
2117#ifdef DEBUG_TREE
2118 xmlGenericError(xmlGenericErrorContext,
2119 "xmlNewNode : name == NULL\n");
2120#endif
2121 return(NULL);
2122 }
2123
2124 /*
2125 * Allocate a new node and fill the fields.
2126 */
2127 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2128 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002129 xmlTreeErrMemory("building node");
Owen Taylor3473f882001-02-23 17:55:21 +00002130 return(NULL);
2131 }
2132 memset(cur, 0, sizeof(xmlNode));
2133 cur->type = XML_ELEMENT_NODE;
2134
2135 cur->name = xmlStrdup(name);
2136 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002137
Daniel Veillarda880b122003-04-21 21:36:41 +00002138 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002139 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002140 return(cur);
2141}
2142
2143/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00002144 * xmlNewNodeEatName:
2145 * @ns: namespace if any
2146 * @name: the node name
2147 *
2148 * Creation of a new node element. @ns is optional (NULL).
2149 *
2150 * Returns a pointer to the new node object.
2151 */
2152xmlNodePtr
2153xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2154 xmlNodePtr cur;
2155
2156 if (name == NULL) {
2157#ifdef DEBUG_TREE
2158 xmlGenericError(xmlGenericErrorContext,
2159 "xmlNewNode : name == NULL\n");
2160#endif
2161 return(NULL);
2162 }
2163
2164 /*
2165 * Allocate a new node and fill the fields.
2166 */
2167 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2168 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002169 xmlTreeErrMemory("building node");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00002170 xmlFree(name);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002171 return(NULL);
2172 }
2173 memset(cur, 0, sizeof(xmlNode));
2174 cur->type = XML_ELEMENT_NODE;
2175
2176 cur->name = name;
2177 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002178
Daniel Veillarda880b122003-04-21 21:36:41 +00002179 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002180 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002181 return(cur);
2182}
2183
2184/**
Owen Taylor3473f882001-02-23 17:55:21 +00002185 * xmlNewDocNode:
2186 * @doc: the document
2187 * @ns: namespace if any
2188 * @name: the node name
2189 * @content: the XML text content if any
2190 *
2191 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002192 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002193 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2194 * references, but XML special chars need to be escaped first by using
2195 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2196 * need entities support.
2197 *
2198 * Returns a pointer to the new node object.
2199 */
2200xmlNodePtr
2201xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2202 const xmlChar *name, const xmlChar *content) {
2203 xmlNodePtr cur;
2204
2205 cur = xmlNewNode(ns, name);
2206 if (cur != NULL) {
2207 cur->doc = doc;
2208 if (content != NULL) {
2209 cur->children = xmlStringGetNodeList(doc, content);
2210 UPDATE_LAST_CHILD_AND_PARENT(cur)
2211 }
2212 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002213
Owen Taylor3473f882001-02-23 17:55:21 +00002214 return(cur);
2215}
2216
Daniel Veillard46de64e2002-05-29 08:21:33 +00002217/**
2218 * xmlNewDocNodeEatName:
2219 * @doc: the document
2220 * @ns: namespace if any
2221 * @name: the node name
2222 * @content: the XML text content if any
2223 *
2224 * Creation of a new node element within a document. @ns and @content
2225 * are optional (NULL).
2226 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2227 * references, but XML special chars need to be escaped first by using
2228 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2229 * need entities support.
2230 *
2231 * Returns a pointer to the new node object.
2232 */
2233xmlNodePtr
2234xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2235 xmlChar *name, const xmlChar *content) {
2236 xmlNodePtr cur;
2237
2238 cur = xmlNewNodeEatName(ns, name);
2239 if (cur != NULL) {
2240 cur->doc = doc;
2241 if (content != NULL) {
2242 cur->children = xmlStringGetNodeList(doc, content);
2243 UPDATE_LAST_CHILD_AND_PARENT(cur)
2244 }
2245 }
2246 return(cur);
2247}
2248
Daniel Veillard652327a2003-09-29 18:02:38 +00002249#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002250/**
2251 * xmlNewDocRawNode:
2252 * @doc: the document
2253 * @ns: namespace if any
2254 * @name: the node name
2255 * @content: the text content if any
2256 *
2257 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002258 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002259 *
2260 * Returns a pointer to the new node object.
2261 */
2262xmlNodePtr
2263xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2264 const xmlChar *name, const xmlChar *content) {
2265 xmlNodePtr cur;
2266
2267 cur = xmlNewNode(ns, name);
2268 if (cur != NULL) {
2269 cur->doc = doc;
2270 if (content != NULL) {
2271 cur->children = xmlNewDocText(doc, content);
2272 UPDATE_LAST_CHILD_AND_PARENT(cur)
2273 }
2274 }
2275 return(cur);
2276}
2277
2278/**
2279 * xmlNewDocFragment:
2280 * @doc: the document owning the fragment
2281 *
2282 * Creation of a new Fragment node.
2283 * Returns a pointer to the new node object.
2284 */
2285xmlNodePtr
2286xmlNewDocFragment(xmlDocPtr doc) {
2287 xmlNodePtr cur;
2288
2289 /*
2290 * Allocate a new DocumentFragment node and fill the fields.
2291 */
2292 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2293 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002294 xmlTreeErrMemory("building fragment");
Owen Taylor3473f882001-02-23 17:55:21 +00002295 return(NULL);
2296 }
2297 memset(cur, 0, sizeof(xmlNode));
2298 cur->type = XML_DOCUMENT_FRAG_NODE;
2299
2300 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002301
Daniel Veillarda880b122003-04-21 21:36:41 +00002302 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002303 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002304 return(cur);
2305}
Daniel Veillard652327a2003-09-29 18:02:38 +00002306#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002307
2308/**
2309 * xmlNewText:
2310 * @content: the text content
2311 *
2312 * Creation of a new text node.
2313 * Returns a pointer to the new node object.
2314 */
2315xmlNodePtr
2316xmlNewText(const xmlChar *content) {
2317 xmlNodePtr cur;
2318
2319 /*
2320 * Allocate a new node and fill the fields.
2321 */
2322 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2323 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002324 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002325 return(NULL);
2326 }
2327 memset(cur, 0, sizeof(xmlNode));
2328 cur->type = XML_TEXT_NODE;
2329
2330 cur->name = xmlStringText;
2331 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002332 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002333 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002334
Daniel Veillarda880b122003-04-21 21:36:41 +00002335 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002336 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002337 return(cur);
2338}
2339
Daniel Veillard652327a2003-09-29 18:02:38 +00002340#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002341/**
2342 * xmlNewTextChild:
2343 * @parent: the parent node
2344 * @ns: a namespace if any
2345 * @name: the name of the child
2346 * @content: the text content of the child if any.
2347 *
2348 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002349 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002350 * a child TEXT node will be created containing the string content.
2351 *
2352 * Returns a pointer to the new node object.
2353 */
2354xmlNodePtr
2355xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2356 const xmlChar *name, const xmlChar *content) {
2357 xmlNodePtr cur, prev;
2358
2359 if (parent == NULL) {
2360#ifdef DEBUG_TREE
2361 xmlGenericError(xmlGenericErrorContext,
2362 "xmlNewTextChild : parent == NULL\n");
2363#endif
2364 return(NULL);
2365 }
2366
2367 if (name == NULL) {
2368#ifdef DEBUG_TREE
2369 xmlGenericError(xmlGenericErrorContext,
2370 "xmlNewTextChild : name == NULL\n");
2371#endif
2372 return(NULL);
2373 }
2374
2375 /*
2376 * Allocate a new node
2377 */
2378 if (ns == NULL)
2379 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2380 else
2381 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2382 if (cur == NULL) return(NULL);
2383
2384 /*
2385 * add the new element at the end of the children list.
2386 */
2387 cur->type = XML_ELEMENT_NODE;
2388 cur->parent = parent;
2389 cur->doc = parent->doc;
2390 if (parent->children == NULL) {
2391 parent->children = cur;
2392 parent->last = cur;
2393 } else {
2394 prev = parent->last;
2395 prev->next = cur;
2396 cur->prev = prev;
2397 parent->last = cur;
2398 }
2399
2400 return(cur);
2401}
Daniel Veillard652327a2003-09-29 18:02:38 +00002402#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002403
2404/**
2405 * xmlNewCharRef:
2406 * @doc: the document
2407 * @name: the char ref string, starting with # or "&# ... ;"
2408 *
2409 * Creation of a new character reference node.
2410 * Returns a pointer to the new node object.
2411 */
2412xmlNodePtr
2413xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2414 xmlNodePtr cur;
2415
2416 /*
2417 * Allocate a new node and fill the fields.
2418 */
2419 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2420 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002421 xmlTreeErrMemory("building character reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002422 return(NULL);
2423 }
2424 memset(cur, 0, sizeof(xmlNode));
2425 cur->type = XML_ENTITY_REF_NODE;
2426
2427 cur->doc = doc;
2428 if (name[0] == '&') {
2429 int len;
2430 name++;
2431 len = xmlStrlen(name);
2432 if (name[len - 1] == ';')
2433 cur->name = xmlStrndup(name, len - 1);
2434 else
2435 cur->name = xmlStrndup(name, len);
2436 } else
2437 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002438
Daniel Veillarda880b122003-04-21 21:36:41 +00002439 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002440 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002441 return(cur);
2442}
2443
2444/**
2445 * xmlNewReference:
2446 * @doc: the document
2447 * @name: the reference name, or the reference string with & and ;
2448 *
2449 * Creation of a new reference node.
2450 * Returns a pointer to the new node object.
2451 */
2452xmlNodePtr
2453xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2454 xmlNodePtr cur;
2455 xmlEntityPtr ent;
2456
2457 /*
2458 * Allocate a new node and fill the fields.
2459 */
2460 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2461 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002462 xmlTreeErrMemory("building reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002463 return(NULL);
2464 }
2465 memset(cur, 0, sizeof(xmlNode));
2466 cur->type = XML_ENTITY_REF_NODE;
2467
2468 cur->doc = doc;
2469 if (name[0] == '&') {
2470 int len;
2471 name++;
2472 len = xmlStrlen(name);
2473 if (name[len - 1] == ';')
2474 cur->name = xmlStrndup(name, len - 1);
2475 else
2476 cur->name = xmlStrndup(name, len);
2477 } else
2478 cur->name = xmlStrdup(name);
2479
2480 ent = xmlGetDocEntity(doc, cur->name);
2481 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002482 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002483 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002484 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002485 * updated. Not sure if this is 100% correct.
2486 * -George
2487 */
2488 cur->children = (xmlNodePtr) ent;
2489 cur->last = (xmlNodePtr) ent;
2490 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002491
Daniel Veillarda880b122003-04-21 21:36:41 +00002492 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002493 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002494 return(cur);
2495}
2496
2497/**
2498 * xmlNewDocText:
2499 * @doc: the document
2500 * @content: the text content
2501 *
2502 * Creation of a new text node within a document.
2503 * Returns a pointer to the new node object.
2504 */
2505xmlNodePtr
2506xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2507 xmlNodePtr cur;
2508
2509 cur = xmlNewText(content);
2510 if (cur != NULL) cur->doc = doc;
2511 return(cur);
2512}
2513
2514/**
2515 * xmlNewTextLen:
2516 * @content: the text content
2517 * @len: the text len.
2518 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002519 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002520 * Returns a pointer to the new node object.
2521 */
2522xmlNodePtr
2523xmlNewTextLen(const xmlChar *content, int len) {
2524 xmlNodePtr cur;
2525
2526 /*
2527 * Allocate a new node and fill the fields.
2528 */
2529 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2530 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002531 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002532 return(NULL);
2533 }
2534 memset(cur, 0, sizeof(xmlNode));
2535 cur->type = XML_TEXT_NODE;
2536
2537 cur->name = xmlStringText;
2538 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002539 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002540 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002541
Daniel Veillarda880b122003-04-21 21:36:41 +00002542 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002543 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002544 return(cur);
2545}
2546
2547/**
2548 * xmlNewDocTextLen:
2549 * @doc: the document
2550 * @content: the text content
2551 * @len: the text len.
2552 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002553 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002554 * text node pertain to a given document.
2555 * Returns a pointer to the new node object.
2556 */
2557xmlNodePtr
2558xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2559 xmlNodePtr cur;
2560
2561 cur = xmlNewTextLen(content, len);
2562 if (cur != NULL) cur->doc = doc;
2563 return(cur);
2564}
2565
2566/**
2567 * xmlNewComment:
2568 * @content: the comment content
2569 *
2570 * Creation of a new node containing a comment.
2571 * Returns a pointer to the new node object.
2572 */
2573xmlNodePtr
2574xmlNewComment(const xmlChar *content) {
2575 xmlNodePtr cur;
2576
2577 /*
2578 * Allocate a new node and fill the fields.
2579 */
2580 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2581 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002582 xmlTreeErrMemory("building comment");
Owen Taylor3473f882001-02-23 17:55:21 +00002583 return(NULL);
2584 }
2585 memset(cur, 0, sizeof(xmlNode));
2586 cur->type = XML_COMMENT_NODE;
2587
2588 cur->name = xmlStringComment;
2589 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002590 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002591 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002592
Daniel Veillarda880b122003-04-21 21:36:41 +00002593 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002594 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002595 return(cur);
2596}
2597
2598/**
2599 * xmlNewCDataBlock:
2600 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002601 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002602 * @len: the length of the block
2603 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002604 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002605 * Returns a pointer to the new node object.
2606 */
2607xmlNodePtr
2608xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2609 xmlNodePtr cur;
2610
2611 /*
2612 * Allocate a new node and fill the fields.
2613 */
2614 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2615 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002616 xmlTreeErrMemory("building CDATA");
Owen Taylor3473f882001-02-23 17:55:21 +00002617 return(NULL);
2618 }
2619 memset(cur, 0, sizeof(xmlNode));
2620 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002621 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002622
2623 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002624 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002625 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002626
Daniel Veillarda880b122003-04-21 21:36:41 +00002627 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002628 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002629 return(cur);
2630}
2631
2632/**
2633 * xmlNewDocComment:
2634 * @doc: the document
2635 * @content: the comment content
2636 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002637 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002638 * Returns a pointer to the new node object.
2639 */
2640xmlNodePtr
2641xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2642 xmlNodePtr cur;
2643
2644 cur = xmlNewComment(content);
2645 if (cur != NULL) cur->doc = doc;
2646 return(cur);
2647}
2648
2649/**
2650 * xmlSetTreeDoc:
2651 * @tree: the top element
2652 * @doc: the document
2653 *
2654 * update all nodes under the tree to point to the right document
2655 */
2656void
2657xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002658 xmlAttrPtr prop;
2659
Owen Taylor3473f882001-02-23 17:55:21 +00002660 if (tree == NULL)
2661 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002662 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002663 if(tree->type == XML_ELEMENT_NODE) {
2664 prop = tree->properties;
2665 while (prop != NULL) {
2666 prop->doc = doc;
2667 xmlSetListDoc(prop->children, doc);
2668 prop = prop->next;
2669 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002670 }
Owen Taylor3473f882001-02-23 17:55:21 +00002671 if (tree->children != NULL)
2672 xmlSetListDoc(tree->children, doc);
2673 tree->doc = doc;
2674 }
2675}
2676
2677/**
2678 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002679 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002680 * @doc: the document
2681 *
2682 * update all nodes in the list to point to the right document
2683 */
2684void
2685xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2686 xmlNodePtr cur;
2687
2688 if (list == NULL)
2689 return;
2690 cur = list;
2691 while (cur != NULL) {
2692 if (cur->doc != doc)
2693 xmlSetTreeDoc(cur, doc);
2694 cur = cur->next;
2695 }
2696}
2697
Daniel Veillard652327a2003-09-29 18:02:38 +00002698#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002699/**
2700 * xmlNewChild:
2701 * @parent: the parent node
2702 * @ns: a namespace if any
2703 * @name: the name of the child
2704 * @content: the XML content of the child if any.
2705 *
2706 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002707 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002708 * a child list containing the TEXTs and ENTITY_REFs node will be created.
2709 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2710 * references, but XML special chars need to be escaped first by using
2711 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
2712 * support is not needed.
2713 *
2714 * Returns a pointer to the new node object.
2715 */
2716xmlNodePtr
2717xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2718 const xmlChar *name, const xmlChar *content) {
2719 xmlNodePtr cur, prev;
2720
2721 if (parent == NULL) {
2722#ifdef DEBUG_TREE
2723 xmlGenericError(xmlGenericErrorContext,
2724 "xmlNewChild : parent == NULL\n");
2725#endif
2726 return(NULL);
2727 }
2728
2729 if (name == NULL) {
2730#ifdef DEBUG_TREE
2731 xmlGenericError(xmlGenericErrorContext,
2732 "xmlNewChild : name == NULL\n");
2733#endif
2734 return(NULL);
2735 }
2736
2737 /*
2738 * Allocate a new node
2739 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002740 if (parent->type == XML_ELEMENT_NODE) {
2741 if (ns == NULL)
2742 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2743 else
2744 cur = xmlNewDocNode(parent->doc, ns, name, content);
2745 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2746 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2747 if (ns == NULL)
2748 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2749 else
2750 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002751 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2752 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002753 } else {
2754 return(NULL);
2755 }
Owen Taylor3473f882001-02-23 17:55:21 +00002756 if (cur == NULL) return(NULL);
2757
2758 /*
2759 * add the new element at the end of the children list.
2760 */
2761 cur->type = XML_ELEMENT_NODE;
2762 cur->parent = parent;
2763 cur->doc = parent->doc;
2764 if (parent->children == NULL) {
2765 parent->children = cur;
2766 parent->last = cur;
2767 } else {
2768 prev = parent->last;
2769 prev->next = cur;
2770 cur->prev = prev;
2771 parent->last = cur;
2772 }
2773
2774 return(cur);
2775}
Daniel Veillard652327a2003-09-29 18:02:38 +00002776#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002777
2778/**
2779 * xmlAddNextSibling:
2780 * @cur: the child node
2781 * @elem: the new node
2782 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002783 * Add a new node @elem as the next sibling of @cur
2784 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002785 * first unlinked from its existing context.
2786 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002787 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2788 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002789 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002790 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002791 */
2792xmlNodePtr
2793xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2794 if (cur == NULL) {
2795#ifdef DEBUG_TREE
2796 xmlGenericError(xmlGenericErrorContext,
2797 "xmlAddNextSibling : cur == NULL\n");
2798#endif
2799 return(NULL);
2800 }
2801 if (elem == NULL) {
2802#ifdef DEBUG_TREE
2803 xmlGenericError(xmlGenericErrorContext,
2804 "xmlAddNextSibling : elem == NULL\n");
2805#endif
2806 return(NULL);
2807 }
2808
2809 xmlUnlinkNode(elem);
2810
2811 if (elem->type == XML_TEXT_NODE) {
2812 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002813 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002814 xmlFreeNode(elem);
2815 return(cur);
2816 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002817 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2818 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002819 xmlChar *tmp;
2820
2821 tmp = xmlStrdup(elem->content);
2822 tmp = xmlStrcat(tmp, cur->next->content);
2823 xmlNodeSetContent(cur->next, tmp);
2824 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002825 xmlFreeNode(elem);
2826 return(cur->next);
2827 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002828 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2829 /* check if an attribute with the same name exists */
2830 xmlAttrPtr attr;
2831
2832 if (elem->ns == NULL)
2833 attr = xmlHasProp(cur->parent, elem->name);
2834 else
2835 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2836 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2837 /* different instance, destroy it (attributes must be unique) */
2838 xmlFreeProp(attr);
2839 }
Owen Taylor3473f882001-02-23 17:55:21 +00002840 }
2841
2842 if (elem->doc != cur->doc) {
2843 xmlSetTreeDoc(elem, cur->doc);
2844 }
2845 elem->parent = cur->parent;
2846 elem->prev = cur;
2847 elem->next = cur->next;
2848 cur->next = elem;
2849 if (elem->next != NULL)
2850 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002851 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002852 elem->parent->last = elem;
2853 return(elem);
2854}
2855
Daniel Veillard652327a2003-09-29 18:02:38 +00002856#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002857/**
2858 * xmlAddPrevSibling:
2859 * @cur: the child node
2860 * @elem: the new node
2861 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002862 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002863 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002864 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002865 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002866 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2867 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002868 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002869 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002870 */
2871xmlNodePtr
2872xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2873 if (cur == NULL) {
2874#ifdef DEBUG_TREE
2875 xmlGenericError(xmlGenericErrorContext,
2876 "xmlAddPrevSibling : cur == NULL\n");
2877#endif
2878 return(NULL);
2879 }
2880 if (elem == NULL) {
2881#ifdef DEBUG_TREE
2882 xmlGenericError(xmlGenericErrorContext,
2883 "xmlAddPrevSibling : elem == NULL\n");
2884#endif
2885 return(NULL);
2886 }
2887
2888 xmlUnlinkNode(elem);
2889
2890 if (elem->type == XML_TEXT_NODE) {
2891 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002892 xmlChar *tmp;
2893
2894 tmp = xmlStrdup(elem->content);
2895 tmp = xmlStrcat(tmp, cur->content);
2896 xmlNodeSetContent(cur, tmp);
2897 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002898 xmlFreeNode(elem);
2899 return(cur);
2900 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002901 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2902 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002903 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002904 xmlFreeNode(elem);
2905 return(cur->prev);
2906 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002907 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2908 /* check if an attribute with the same name exists */
2909 xmlAttrPtr attr;
2910
2911 if (elem->ns == NULL)
2912 attr = xmlHasProp(cur->parent, elem->name);
2913 else
2914 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2915 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2916 /* different instance, destroy it (attributes must be unique) */
2917 xmlFreeProp(attr);
2918 }
Owen Taylor3473f882001-02-23 17:55:21 +00002919 }
2920
2921 if (elem->doc != cur->doc) {
2922 xmlSetTreeDoc(elem, cur->doc);
2923 }
2924 elem->parent = cur->parent;
2925 elem->next = cur;
2926 elem->prev = cur->prev;
2927 cur->prev = elem;
2928 if (elem->prev != NULL)
2929 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002930 if (elem->parent != NULL) {
2931 if (elem->type == XML_ATTRIBUTE_NODE) {
2932 if (elem->parent->properties == (xmlAttrPtr) cur) {
2933 elem->parent->properties = (xmlAttrPtr) elem;
2934 }
2935 } else {
2936 if (elem->parent->children == cur) {
2937 elem->parent->children = elem;
2938 }
2939 }
2940 }
Owen Taylor3473f882001-02-23 17:55:21 +00002941 return(elem);
2942}
Daniel Veillard652327a2003-09-29 18:02:38 +00002943#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002944
2945/**
2946 * xmlAddSibling:
2947 * @cur: the child node
2948 * @elem: the new node
2949 *
2950 * Add a new element @elem to the list of siblings of @cur
2951 * merging adjacent TEXT nodes (@elem may be freed)
2952 * If the new element was already inserted in a document it is
2953 * first unlinked from its existing context.
2954 *
2955 * Returns the new element or NULL in case of error.
2956 */
2957xmlNodePtr
2958xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2959 xmlNodePtr parent;
2960
2961 if (cur == NULL) {
2962#ifdef DEBUG_TREE
2963 xmlGenericError(xmlGenericErrorContext,
2964 "xmlAddSibling : cur == NULL\n");
2965#endif
2966 return(NULL);
2967 }
2968
2969 if (elem == NULL) {
2970#ifdef DEBUG_TREE
2971 xmlGenericError(xmlGenericErrorContext,
2972 "xmlAddSibling : elem == NULL\n");
2973#endif
2974 return(NULL);
2975 }
2976
2977 /*
2978 * Constant time is we can rely on the ->parent->last to find
2979 * the last sibling.
2980 */
2981 if ((cur->parent != NULL) &&
2982 (cur->parent->children != NULL) &&
2983 (cur->parent->last != NULL) &&
2984 (cur->parent->last->next == NULL)) {
2985 cur = cur->parent->last;
2986 } else {
2987 while (cur->next != NULL) cur = cur->next;
2988 }
2989
2990 xmlUnlinkNode(elem);
2991
2992 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002993 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002994 xmlFreeNode(elem);
2995 return(cur);
2996 }
2997
2998 if (elem->doc != cur->doc) {
2999 xmlSetTreeDoc(elem, cur->doc);
3000 }
3001 parent = cur->parent;
3002 elem->prev = cur;
3003 elem->next = NULL;
3004 elem->parent = parent;
3005 cur->next = elem;
3006 if (parent != NULL)
3007 parent->last = elem;
3008
3009 return(elem);
3010}
3011
3012/**
3013 * xmlAddChildList:
3014 * @parent: the parent node
3015 * @cur: the first node in the list
3016 *
3017 * Add a list of node at the end of the child list of the parent
3018 * merging adjacent TEXT nodes (@cur may be freed)
3019 *
3020 * Returns the last child or NULL in case of error.
3021 */
3022xmlNodePtr
3023xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3024 xmlNodePtr prev;
3025
3026 if (parent == NULL) {
3027#ifdef DEBUG_TREE
3028 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003029 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003030#endif
3031 return(NULL);
3032 }
3033
3034 if (cur == NULL) {
3035#ifdef DEBUG_TREE
3036 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003037 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003038#endif
3039 return(NULL);
3040 }
3041
3042 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3043 (cur->doc != parent->doc)) {
3044#ifdef DEBUG_TREE
3045 xmlGenericError(xmlGenericErrorContext,
3046 "Elements moved to a different document\n");
3047#endif
3048 }
3049
3050 /*
3051 * add the first element at the end of the children list.
3052 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003053
Owen Taylor3473f882001-02-23 17:55:21 +00003054 if (parent->children == NULL) {
3055 parent->children = cur;
3056 } else {
3057 /*
3058 * If cur and parent->last both are TEXT nodes, then merge them.
3059 */
3060 if ((cur->type == XML_TEXT_NODE) &&
3061 (parent->last->type == XML_TEXT_NODE) &&
3062 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003063 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003064 /*
3065 * if it's the only child, nothing more to be done.
3066 */
3067 if (cur->next == NULL) {
3068 xmlFreeNode(cur);
3069 return(parent->last);
3070 }
3071 prev = cur;
3072 cur = cur->next;
3073 xmlFreeNode(prev);
3074 }
3075 prev = parent->last;
3076 prev->next = cur;
3077 cur->prev = prev;
3078 }
3079 while (cur->next != NULL) {
3080 cur->parent = parent;
3081 if (cur->doc != parent->doc) {
3082 xmlSetTreeDoc(cur, parent->doc);
3083 }
3084 cur = cur->next;
3085 }
3086 cur->parent = parent;
3087 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
3088 parent->last = cur;
3089
3090 return(cur);
3091}
3092
3093/**
3094 * xmlAddChild:
3095 * @parent: the parent node
3096 * @cur: the child node
3097 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003098 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003099 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003100 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3101 * If there is an attribute with equal name, it is first destroyed.
3102 *
Owen Taylor3473f882001-02-23 17:55:21 +00003103 * Returns the child or NULL in case of error.
3104 */
3105xmlNodePtr
3106xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3107 xmlNodePtr prev;
3108
3109 if (parent == NULL) {
3110#ifdef DEBUG_TREE
3111 xmlGenericError(xmlGenericErrorContext,
3112 "xmlAddChild : parent == NULL\n");
3113#endif
3114 return(NULL);
3115 }
3116
3117 if (cur == NULL) {
3118#ifdef DEBUG_TREE
3119 xmlGenericError(xmlGenericErrorContext,
3120 "xmlAddChild : child == NULL\n");
3121#endif
3122 return(NULL);
3123 }
3124
Owen Taylor3473f882001-02-23 17:55:21 +00003125 /*
3126 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003127 * cur is then freed.
3128 */
3129 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003130 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003131 (parent->content != NULL) &&
3132 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003133 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003134 xmlFreeNode(cur);
3135 return(parent);
3136 }
3137 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003138 (parent->last->name == cur->name) &&
3139 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003140 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003141 xmlFreeNode(cur);
3142 return(parent->last);
3143 }
3144 }
3145
3146 /*
3147 * add the new element at the end of the children list.
3148 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003149 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003150 cur->parent = parent;
3151 if (cur->doc != parent->doc) {
3152 xmlSetTreeDoc(cur, parent->doc);
3153 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003154 /* this check prevents a loop on tree-traversions if a developer
3155 * tries to add a node to its parent multiple times
3156 */
3157 if (prev == parent)
3158 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003159
3160 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003161 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003162 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003163 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003164 (parent->content != NULL) &&
3165 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003166 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003167 xmlFreeNode(cur);
3168 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003169 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003170 if (cur->type == XML_ATTRIBUTE_NODE) {
3171 if (parent->properties == NULL) {
3172 parent->properties = (xmlAttrPtr) cur;
3173 } else {
3174 /* check if an attribute with the same name exists */
3175 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003176
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003177 if (cur->ns == NULL)
3178 lastattr = xmlHasProp(parent, cur->name);
3179 else
3180 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3181 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
3182 /* different instance, destroy it (attributes must be unique) */
3183 xmlFreeProp(lastattr);
3184 }
3185 /* find the end */
3186 lastattr = parent->properties;
3187 while (lastattr->next != NULL) {
3188 lastattr = lastattr->next;
3189 }
3190 lastattr->next = (xmlAttrPtr) cur;
3191 ((xmlAttrPtr) cur)->prev = lastattr;
3192 }
3193 } else {
3194 if (parent->children == NULL) {
3195 parent->children = cur;
3196 parent->last = cur;
3197 } else {
3198 prev = parent->last;
3199 prev->next = cur;
3200 cur->prev = prev;
3201 parent->last = cur;
3202 }
3203 }
Owen Taylor3473f882001-02-23 17:55:21 +00003204 return(cur);
3205}
3206
3207/**
3208 * xmlGetLastChild:
3209 * @parent: the parent node
3210 *
3211 * Search the last child of a node.
3212 * Returns the last child or NULL if none.
3213 */
3214xmlNodePtr
3215xmlGetLastChild(xmlNodePtr parent) {
3216 if (parent == NULL) {
3217#ifdef DEBUG_TREE
3218 xmlGenericError(xmlGenericErrorContext,
3219 "xmlGetLastChild : parent == NULL\n");
3220#endif
3221 return(NULL);
3222 }
3223 return(parent->last);
3224}
3225
3226/**
3227 * xmlFreeNodeList:
3228 * @cur: the first node in the list
3229 *
3230 * Free a node and all its siblings, this is a recursive behaviour, all
3231 * the children are freed too.
3232 */
3233void
3234xmlFreeNodeList(xmlNodePtr cur) {
3235 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003236 xmlDictPtr dict = NULL;
3237
3238 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003239 if (cur->type == XML_NAMESPACE_DECL) {
3240 xmlFreeNsList((xmlNsPtr) cur);
3241 return;
3242 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003243 if ((cur->type == XML_DOCUMENT_NODE) ||
3244#ifdef LIBXML_DOCB_ENABLED
3245 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003246#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003247 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003248 xmlFreeDoc((xmlDocPtr) cur);
3249 return;
3250 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003251 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003252 while (cur != NULL) {
3253 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003254 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003255
Daniel Veillarda880b122003-04-21 21:36:41 +00003256 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003257 xmlDeregisterNodeDefaultValue(cur);
3258
Daniel Veillard02141ea2001-04-30 11:46:40 +00003259 if ((cur->children != NULL) &&
3260 (cur->type != XML_ENTITY_REF_NODE))
3261 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003262 if (((cur->type == XML_ELEMENT_NODE) ||
3263 (cur->type == XML_XINCLUDE_START) ||
3264 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003265 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003266 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003267 if ((cur->type != XML_ELEMENT_NODE) &&
3268 (cur->type != XML_XINCLUDE_START) &&
3269 (cur->type != XML_XINCLUDE_END) &&
3270 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003271 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003272 }
3273 if (((cur->type == XML_ELEMENT_NODE) ||
3274 (cur->type == XML_XINCLUDE_START) ||
3275 (cur->type == XML_XINCLUDE_END)) &&
3276 (cur->nsDef != NULL))
3277 xmlFreeNsList(cur->nsDef);
3278
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003279 /*
3280 * When a node is a text node or a comment, it uses a global static
3281 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003282 * Otherwise the node name might come from the document's
3283 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003284 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003285 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003286 (cur->type != XML_TEXT_NODE) &&
3287 (cur->type != XML_COMMENT_NODE))
3288 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003289 xmlFree(cur);
3290 }
Owen Taylor3473f882001-02-23 17:55:21 +00003291 cur = next;
3292 }
3293}
3294
3295/**
3296 * xmlFreeNode:
3297 * @cur: the node
3298 *
3299 * Free a node, this is a recursive behaviour, all the children are freed too.
3300 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3301 */
3302void
3303xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003304 xmlDictPtr dict = NULL;
3305
3306 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003307
Daniel Veillard02141ea2001-04-30 11:46:40 +00003308 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003309 if (cur->type == XML_DTD_NODE) {
3310 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003311 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003312 }
3313 if (cur->type == XML_NAMESPACE_DECL) {
3314 xmlFreeNs((xmlNsPtr) cur);
3315 return;
3316 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003317 if (cur->type == XML_ATTRIBUTE_NODE) {
3318 xmlFreeProp((xmlAttrPtr) cur);
3319 return;
3320 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003321
Daniel Veillarda880b122003-04-21 21:36:41 +00003322 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003323 xmlDeregisterNodeDefaultValue(cur);
3324
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003325 if (cur->doc != NULL) dict = cur->doc->dict;
3326
Owen Taylor3473f882001-02-23 17:55:21 +00003327 if ((cur->children != NULL) &&
3328 (cur->type != XML_ENTITY_REF_NODE))
3329 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003330 if (((cur->type == XML_ELEMENT_NODE) ||
3331 (cur->type == XML_XINCLUDE_START) ||
3332 (cur->type == XML_XINCLUDE_END)) &&
3333 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003334 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003335 if ((cur->type != XML_ELEMENT_NODE) &&
3336 (cur->content != NULL) &&
3337 (cur->type != XML_ENTITY_REF_NODE) &&
3338 (cur->type != XML_XINCLUDE_END) &&
3339 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003340 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003341 }
3342
Daniel Veillardacd370f2001-06-09 17:17:51 +00003343 /*
3344 * When a node is a text node or a comment, it uses a global static
3345 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003346 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003347 */
Owen Taylor3473f882001-02-23 17:55:21 +00003348 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003349 (cur->type != XML_TEXT_NODE) &&
3350 (cur->type != XML_COMMENT_NODE))
3351 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003352
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003353 if (((cur->type == XML_ELEMENT_NODE) ||
3354 (cur->type == XML_XINCLUDE_START) ||
3355 (cur->type == XML_XINCLUDE_END)) &&
3356 (cur->nsDef != NULL))
3357 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003358 xmlFree(cur);
3359}
3360
3361/**
3362 * xmlUnlinkNode:
3363 * @cur: the node
3364 *
3365 * Unlink a node from it's current context, the node is not freed
3366 */
3367void
3368xmlUnlinkNode(xmlNodePtr cur) {
3369 if (cur == NULL) {
3370#ifdef DEBUG_TREE
3371 xmlGenericError(xmlGenericErrorContext,
3372 "xmlUnlinkNode : node == NULL\n");
3373#endif
3374 return;
3375 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003376 if (cur->type == XML_DTD_NODE) {
3377 xmlDocPtr doc;
3378 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003379 if (doc != NULL) {
3380 if (doc->intSubset == (xmlDtdPtr) cur)
3381 doc->intSubset = NULL;
3382 if (doc->extSubset == (xmlDtdPtr) cur)
3383 doc->extSubset = NULL;
3384 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003385 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003386 if (cur->parent != NULL) {
3387 xmlNodePtr parent;
3388 parent = cur->parent;
3389 if (cur->type == XML_ATTRIBUTE_NODE) {
3390 if (parent->properties == (xmlAttrPtr) cur)
3391 parent->properties = ((xmlAttrPtr) cur)->next;
3392 } else {
3393 if (parent->children == cur)
3394 parent->children = cur->next;
3395 if (parent->last == cur)
3396 parent->last = cur->prev;
3397 }
3398 cur->parent = NULL;
3399 }
Owen Taylor3473f882001-02-23 17:55:21 +00003400 if (cur->next != NULL)
3401 cur->next->prev = cur->prev;
3402 if (cur->prev != NULL)
3403 cur->prev->next = cur->next;
3404 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003405}
3406
Daniel Veillard652327a2003-09-29 18:02:38 +00003407#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003408/**
3409 * xmlReplaceNode:
3410 * @old: the old node
3411 * @cur: the node
3412 *
3413 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003414 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003415 * first unlinked from its existing context.
3416 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003417 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003418 */
3419xmlNodePtr
3420xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3421 if (old == NULL) {
3422#ifdef DEBUG_TREE
3423 xmlGenericError(xmlGenericErrorContext,
3424 "xmlReplaceNode : old == NULL\n");
3425#endif
3426 return(NULL);
3427 }
3428 if (cur == NULL) {
3429 xmlUnlinkNode(old);
3430 return(old);
3431 }
3432 if (cur == old) {
3433 return(old);
3434 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003435 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3436#ifdef DEBUG_TREE
3437 xmlGenericError(xmlGenericErrorContext,
3438 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3439#endif
3440 return(old);
3441 }
3442 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3443#ifdef DEBUG_TREE
3444 xmlGenericError(xmlGenericErrorContext,
3445 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3446#endif
3447 return(old);
3448 }
Owen Taylor3473f882001-02-23 17:55:21 +00003449 xmlUnlinkNode(cur);
3450 cur->doc = old->doc;
3451 cur->parent = old->parent;
3452 cur->next = old->next;
3453 if (cur->next != NULL)
3454 cur->next->prev = cur;
3455 cur->prev = old->prev;
3456 if (cur->prev != NULL)
3457 cur->prev->next = cur;
3458 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003459 if (cur->type == XML_ATTRIBUTE_NODE) {
3460 if (cur->parent->properties == (xmlAttrPtr)old)
3461 cur->parent->properties = ((xmlAttrPtr) cur);
3462 } else {
3463 if (cur->parent->children == old)
3464 cur->parent->children = cur;
3465 if (cur->parent->last == old)
3466 cur->parent->last = cur;
3467 }
Owen Taylor3473f882001-02-23 17:55:21 +00003468 }
3469 old->next = old->prev = NULL;
3470 old->parent = NULL;
3471 return(old);
3472}
Daniel Veillard652327a2003-09-29 18:02:38 +00003473#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003474
3475/************************************************************************
3476 * *
3477 * Copy operations *
3478 * *
3479 ************************************************************************/
3480
3481/**
3482 * xmlCopyNamespace:
3483 * @cur: the namespace
3484 *
3485 * Do a copy of the namespace.
3486 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003487 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003488 */
3489xmlNsPtr
3490xmlCopyNamespace(xmlNsPtr cur) {
3491 xmlNsPtr ret;
3492
3493 if (cur == NULL) return(NULL);
3494 switch (cur->type) {
3495 case XML_LOCAL_NAMESPACE:
3496 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3497 break;
3498 default:
3499#ifdef DEBUG_TREE
3500 xmlGenericError(xmlGenericErrorContext,
3501 "xmlCopyNamespace: invalid type %d\n", cur->type);
3502#endif
3503 return(NULL);
3504 }
3505 return(ret);
3506}
3507
3508/**
3509 * xmlCopyNamespaceList:
3510 * @cur: the first namespace
3511 *
3512 * Do a copy of an namespace list.
3513 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003514 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003515 */
3516xmlNsPtr
3517xmlCopyNamespaceList(xmlNsPtr cur) {
3518 xmlNsPtr ret = NULL;
3519 xmlNsPtr p = NULL,q;
3520
3521 while (cur != NULL) {
3522 q = xmlCopyNamespace(cur);
3523 if (p == NULL) {
3524 ret = p = q;
3525 } else {
3526 p->next = q;
3527 p = q;
3528 }
3529 cur = cur->next;
3530 }
3531 return(ret);
3532}
3533
3534static xmlNodePtr
3535xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3536/**
3537 * xmlCopyProp:
3538 * @target: the element where the attribute will be grafted
3539 * @cur: the attribute
3540 *
3541 * Do a copy of the attribute.
3542 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003543 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003544 */
3545xmlAttrPtr
3546xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3547 xmlAttrPtr ret;
3548
3549 if (cur == NULL) return(NULL);
3550 if (target != NULL)
3551 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3552 else if (cur->parent != NULL)
3553 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3554 else if (cur->children != NULL)
3555 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3556 else
3557 ret = xmlNewDocProp(NULL, cur->name, NULL);
3558 if (ret == NULL) return(NULL);
3559 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003560
Owen Taylor3473f882001-02-23 17:55:21 +00003561 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003562 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003563
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003564 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3565 if (ns == NULL) {
3566 /*
3567 * Humm, we are copying an element whose namespace is defined
3568 * out of the new tree scope. Search it in the original tree
3569 * and add it at the top of the new tree
3570 */
3571 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3572 if (ns != NULL) {
3573 xmlNodePtr root = target;
3574 xmlNodePtr pred = NULL;
3575
3576 while (root->parent != NULL) {
3577 pred = root;
3578 root = root->parent;
3579 }
3580 if (root == (xmlNodePtr) target->doc) {
3581 /* correct possibly cycling above the document elt */
3582 root = pred;
3583 }
3584 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3585 }
3586 } else {
3587 /*
3588 * we have to find something appropriate here since
3589 * we cant be sure, that the namespce we found is identified
3590 * by the prefix
3591 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003592 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003593 /* this is the nice case */
3594 ret->ns = ns;
3595 } else {
3596 /*
3597 * we are in trouble: we need a new reconcilied namespace.
3598 * This is expensive
3599 */
3600 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3601 }
3602 }
3603
Owen Taylor3473f882001-02-23 17:55:21 +00003604 } else
3605 ret->ns = NULL;
3606
3607 if (cur->children != NULL) {
3608 xmlNodePtr tmp;
3609
3610 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3611 ret->last = NULL;
3612 tmp = ret->children;
3613 while (tmp != NULL) {
3614 /* tmp->parent = (xmlNodePtr)ret; */
3615 if (tmp->next == NULL)
3616 ret->last = tmp;
3617 tmp = tmp->next;
3618 }
3619 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003620 /*
3621 * Try to handle IDs
3622 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003623 if ((target!= NULL) && (cur!= NULL) &&
3624 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003625 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3626 if (xmlIsID(cur->doc, cur->parent, cur)) {
3627 xmlChar *id;
3628
3629 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3630 if (id != NULL) {
3631 xmlAddID(NULL, target->doc, id, ret);
3632 xmlFree(id);
3633 }
3634 }
3635 }
Owen Taylor3473f882001-02-23 17:55:21 +00003636 return(ret);
3637}
3638
3639/**
3640 * xmlCopyPropList:
3641 * @target: the element where the attributes will be grafted
3642 * @cur: the first attribute
3643 *
3644 * Do a copy of an attribute list.
3645 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003646 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003647 */
3648xmlAttrPtr
3649xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3650 xmlAttrPtr ret = NULL;
3651 xmlAttrPtr p = NULL,q;
3652
3653 while (cur != NULL) {
3654 q = xmlCopyProp(target, cur);
3655 if (p == NULL) {
3656 ret = p = q;
3657 } else {
3658 p->next = q;
3659 q->prev = p;
3660 p = q;
3661 }
3662 cur = cur->next;
3663 }
3664 return(ret);
3665}
3666
3667/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003668 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003669 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003670 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003671 * tricky reason: namespaces. Doing a direct copy of a node
3672 * say RPM:Copyright without changing the namespace pointer to
3673 * something else can produce stale links. One way to do it is
3674 * to keep a reference counter but this doesn't work as soon
3675 * as one move the element or the subtree out of the scope of
3676 * the existing namespace. The actual solution seems to add
3677 * a copy of the namespace at the top of the copied tree if
3678 * not available in the subtree.
3679 * Hence two functions, the public front-end call the inner ones
3680 */
3681
3682static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003683xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003684 int recursive) {
3685 xmlNodePtr ret;
3686
3687 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003688 switch (node->type) {
3689 case XML_TEXT_NODE:
3690 case XML_CDATA_SECTION_NODE:
3691 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003692 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003693 case XML_ENTITY_REF_NODE:
3694 case XML_ENTITY_NODE:
3695 case XML_PI_NODE:
3696 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003697 case XML_XINCLUDE_START:
3698 case XML_XINCLUDE_END:
3699 break;
3700 case XML_ATTRIBUTE_NODE:
3701 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3702 case XML_NAMESPACE_DECL:
3703 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3704
Daniel Veillard39196eb2001-06-19 18:09:42 +00003705 case XML_DOCUMENT_NODE:
3706 case XML_HTML_DOCUMENT_NODE:
3707#ifdef LIBXML_DOCB_ENABLED
3708 case XML_DOCB_DOCUMENT_NODE:
3709#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00003710#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003711 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard652327a2003-09-29 18:02:38 +00003712#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00003713 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003714 case XML_NOTATION_NODE:
3715 case XML_DTD_NODE:
3716 case XML_ELEMENT_DECL:
3717 case XML_ATTRIBUTE_DECL:
3718 case XML_ENTITY_DECL:
3719 return(NULL);
3720 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003721
Owen Taylor3473f882001-02-23 17:55:21 +00003722 /*
3723 * Allocate a new node and fill the fields.
3724 */
3725 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3726 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00003727 xmlTreeErrMemory("copying node");
Owen Taylor3473f882001-02-23 17:55:21 +00003728 return(NULL);
3729 }
3730 memset(ret, 0, sizeof(xmlNode));
3731 ret->type = node->type;
3732
3733 ret->doc = doc;
3734 ret->parent = parent;
3735 if (node->name == xmlStringText)
3736 ret->name = xmlStringText;
3737 else if (node->name == xmlStringTextNoenc)
3738 ret->name = xmlStringTextNoenc;
3739 else if (node->name == xmlStringComment)
3740 ret->name = xmlStringComment;
3741 else if (node->name != NULL)
3742 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003743 if ((node->type != XML_ELEMENT_NODE) &&
3744 (node->content != NULL) &&
3745 (node->type != XML_ENTITY_REF_NODE) &&
3746 (node->type != XML_XINCLUDE_END) &&
3747 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003748 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003749 }else{
3750 if (node->type == XML_ELEMENT_NODE)
3751 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00003752 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003753 if (parent != NULL) {
3754 xmlNodePtr tmp;
3755
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003756 /*
3757 * this is a tricky part for the node register thing:
3758 * in case ret does get coalesced in xmlAddChild
3759 * the deregister-node callback is called; so we register ret now already
3760 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003761 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003762 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3763
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003764 tmp = xmlAddChild(parent, ret);
3765 /* node could have coalesced */
3766 if (tmp != ret)
3767 return(tmp);
3768 }
Owen Taylor3473f882001-02-23 17:55:21 +00003769
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003770 if (!recursive)
3771 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003772 if (node->nsDef != NULL)
3773 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3774
3775 if (node->ns != NULL) {
3776 xmlNsPtr ns;
3777
3778 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3779 if (ns == NULL) {
3780 /*
3781 * Humm, we are copying an element whose namespace is defined
3782 * out of the new tree scope. Search it in the original tree
3783 * and add it at the top of the new tree
3784 */
3785 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3786 if (ns != NULL) {
3787 xmlNodePtr root = ret;
3788
3789 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003790 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003791 }
3792 } else {
3793 /*
3794 * reference the existing namespace definition in our own tree.
3795 */
3796 ret->ns = ns;
3797 }
3798 }
3799 if (node->properties != NULL)
3800 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003801 if (node->type == XML_ENTITY_REF_NODE) {
3802 if ((doc == NULL) || (node->doc != doc)) {
3803 /*
3804 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003805 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003806 * we cannot keep the reference. Try to find it in the
3807 * target document.
3808 */
3809 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3810 } else {
3811 ret->children = node->children;
3812 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003813 ret->last = ret->children;
3814 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003815 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003816 UPDATE_LAST_CHILD_AND_PARENT(ret)
3817 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003818
3819out:
3820 /* if parent != NULL we already registered the node above */
3821 if (parent == NULL && xmlRegisterNodeDefaultValue)
3822 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003823 return(ret);
3824}
3825
3826static xmlNodePtr
3827xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3828 xmlNodePtr ret = NULL;
3829 xmlNodePtr p = NULL,q;
3830
3831 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00003832#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003833 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003834 if (doc == NULL) {
3835 node = node->next;
3836 continue;
3837 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003838 if (doc->intSubset == NULL) {
3839 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3840 q->doc = doc;
3841 q->parent = parent;
3842 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003843 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003844 } else {
3845 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003846 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003847 }
3848 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00003849#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00003850 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003851 if (ret == NULL) {
3852 q->prev = NULL;
3853 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003854 } else if (p != q) {
3855 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003856 p->next = q;
3857 q->prev = p;
3858 p = q;
3859 }
3860 node = node->next;
3861 }
3862 return(ret);
3863}
3864
3865/**
3866 * xmlCopyNode:
3867 * @node: the node
3868 * @recursive: if 1 do a recursive copy.
3869 *
3870 * Do a copy of the node.
3871 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003872 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003873 */
3874xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003875xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003876 xmlNodePtr ret;
3877
3878 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3879 return(ret);
3880}
3881
3882/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003883 * xmlDocCopyNode:
3884 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003885 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003886 * @recursive: if 1 do a recursive copy.
3887 *
3888 * Do a copy of the node to a given document.
3889 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003890 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003891 */
3892xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003893xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003894 xmlNodePtr ret;
3895
3896 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3897 return(ret);
3898}
3899
3900/**
Owen Taylor3473f882001-02-23 17:55:21 +00003901 * xmlCopyNodeList:
3902 * @node: the first node in the list.
3903 *
3904 * Do a recursive copy of the node list.
3905 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003906 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003907 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003908xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003909 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3910 return(ret);
3911}
3912
Daniel Veillard652327a2003-09-29 18:02:38 +00003913#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003914/**
Owen Taylor3473f882001-02-23 17:55:21 +00003915 * xmlCopyDtd:
3916 * @dtd: the dtd
3917 *
3918 * Do a copy of the dtd.
3919 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003920 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003921 */
3922xmlDtdPtr
3923xmlCopyDtd(xmlDtdPtr dtd) {
3924 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003925 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003926
3927 if (dtd == NULL) return(NULL);
3928 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3929 if (ret == NULL) return(NULL);
3930 if (dtd->entities != NULL)
3931 ret->entities = (void *) xmlCopyEntitiesTable(
3932 (xmlEntitiesTablePtr) dtd->entities);
3933 if (dtd->notations != NULL)
3934 ret->notations = (void *) xmlCopyNotationTable(
3935 (xmlNotationTablePtr) dtd->notations);
3936 if (dtd->elements != NULL)
3937 ret->elements = (void *) xmlCopyElementTable(
3938 (xmlElementTablePtr) dtd->elements);
3939 if (dtd->attributes != NULL)
3940 ret->attributes = (void *) xmlCopyAttributeTable(
3941 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003942 if (dtd->pentities != NULL)
3943 ret->pentities = (void *) xmlCopyEntitiesTable(
3944 (xmlEntitiesTablePtr) dtd->pentities);
3945
3946 cur = dtd->children;
3947 while (cur != NULL) {
3948 q = NULL;
3949
3950 if (cur->type == XML_ENTITY_DECL) {
3951 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3952 switch (tmp->etype) {
3953 case XML_INTERNAL_GENERAL_ENTITY:
3954 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3955 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3956 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3957 break;
3958 case XML_INTERNAL_PARAMETER_ENTITY:
3959 case XML_EXTERNAL_PARAMETER_ENTITY:
3960 q = (xmlNodePtr)
3961 xmlGetParameterEntityFromDtd(ret, tmp->name);
3962 break;
3963 case XML_INTERNAL_PREDEFINED_ENTITY:
3964 break;
3965 }
3966 } else if (cur->type == XML_ELEMENT_DECL) {
3967 xmlElementPtr tmp = (xmlElementPtr) cur;
3968 q = (xmlNodePtr)
3969 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3970 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3971 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3972 q = (xmlNodePtr)
3973 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3974 } else if (cur->type == XML_COMMENT_NODE) {
3975 q = xmlCopyNode(cur, 0);
3976 }
3977
3978 if (q == NULL) {
3979 cur = cur->next;
3980 continue;
3981 }
3982
3983 if (p == NULL)
3984 ret->children = q;
3985 else
3986 p->next = q;
3987
3988 q->prev = p;
3989 q->parent = (xmlNodePtr) ret;
3990 q->next = NULL;
3991 ret->last = q;
3992 p = q;
3993 cur = cur->next;
3994 }
3995
Owen Taylor3473f882001-02-23 17:55:21 +00003996 return(ret);
3997}
3998
3999/**
4000 * xmlCopyDoc:
4001 * @doc: the document
4002 * @recursive: if 1 do a recursive copy.
4003 *
4004 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004005 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004006 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004007 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004008 */
4009xmlDocPtr
4010xmlCopyDoc(xmlDocPtr doc, int recursive) {
4011 xmlDocPtr ret;
4012
4013 if (doc == NULL) return(NULL);
4014 ret = xmlNewDoc(doc->version);
4015 if (ret == NULL) return(NULL);
4016 if (doc->name != NULL)
4017 ret->name = xmlMemStrdup(doc->name);
4018 if (doc->encoding != NULL)
4019 ret->encoding = xmlStrdup(doc->encoding);
4020 ret->charset = doc->charset;
4021 ret->compression = doc->compression;
4022 ret->standalone = doc->standalone;
4023 if (!recursive) return(ret);
4024
Daniel Veillardb33c2012001-04-25 12:59:04 +00004025 ret->last = NULL;
4026 ret->children = NULL;
4027 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004028 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004029 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004030 ret->intSubset->parent = ret;
4031 }
Owen Taylor3473f882001-02-23 17:55:21 +00004032 if (doc->oldNs != NULL)
4033 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4034 if (doc->children != NULL) {
4035 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00004036
4037 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4038 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004039 ret->last = NULL;
4040 tmp = ret->children;
4041 while (tmp != NULL) {
4042 if (tmp->next == NULL)
4043 ret->last = tmp;
4044 tmp = tmp->next;
4045 }
4046 }
4047 return(ret);
4048}
Daniel Veillard652327a2003-09-29 18:02:38 +00004049#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004050
4051/************************************************************************
4052 * *
4053 * Content access functions *
4054 * *
4055 ************************************************************************/
4056
4057/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004058 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004059 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004060 *
4061 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004062 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004063 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004064 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004065 */
4066long
4067xmlGetLineNo(xmlNodePtr node)
4068{
4069 long result = -1;
4070
4071 if (!node)
4072 return result;
4073 if (node->type == XML_ELEMENT_NODE)
4074 result = (long) node->content;
4075 else if ((node->prev != NULL) &&
4076 ((node->prev->type == XML_ELEMENT_NODE) ||
4077 (node->prev->type == XML_TEXT_NODE)))
4078 result = xmlGetLineNo(node->prev);
4079 else if ((node->parent != NULL) &&
4080 ((node->parent->type == XML_ELEMENT_NODE) ||
4081 (node->parent->type == XML_TEXT_NODE)))
4082 result = xmlGetLineNo(node->parent);
4083
4084 return result;
4085}
4086
Daniel Veillard652327a2003-09-29 18:02:38 +00004087#ifdef LIBXML_TREE_ENABLED
Daniel Veillard8faa7832001-11-26 15:58:08 +00004088/**
4089 * xmlGetNodePath:
4090 * @node: a node
4091 *
4092 * Build a structure based Path for the given node
4093 *
4094 * Returns the new path or NULL in case of error. The caller must free
4095 * the returned string
4096 */
4097xmlChar *
4098xmlGetNodePath(xmlNodePtr node)
4099{
4100 xmlNodePtr cur, tmp, next;
4101 xmlChar *buffer = NULL, *temp;
4102 size_t buf_len;
4103 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004104 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004105 const char *name;
4106 char nametemp[100];
4107 int occur = 0;
4108
4109 if (node == NULL)
4110 return (NULL);
4111
4112 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004113 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004114 if (buffer == NULL) {
4115 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004116 return (NULL);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004117 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004118 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004119 if (buf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004120 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004121 xmlFree(buffer);
4122 return (NULL);
4123 }
4124
4125 buffer[0] = 0;
4126 cur = node;
4127 do {
4128 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004129 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004130 occur = 0;
4131 if ((cur->type == XML_DOCUMENT_NODE) ||
4132 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4133 if (buffer[0] == '/')
4134 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004135 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004136 next = NULL;
4137 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004138 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004139 name = (const char *) cur->name;
4140 if (cur->ns) {
4141 snprintf(nametemp, sizeof(nametemp) - 1,
4142 "%s:%s", cur->ns->prefix, cur->name);
4143 nametemp[sizeof(nametemp) - 1] = 0;
4144 name = nametemp;
4145 }
4146 next = cur->parent;
4147
4148 /*
4149 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004150 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004151 */
4152 tmp = cur->prev;
4153 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004154 if ((tmp->type == XML_ELEMENT_NODE) &&
4155 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004156 occur++;
4157 tmp = tmp->prev;
4158 }
4159 if (occur == 0) {
4160 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004161 while (tmp != NULL && occur == 0) {
4162 if ((tmp->type == XML_ELEMENT_NODE) &&
4163 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004164 occur++;
4165 tmp = tmp->next;
4166 }
4167 if (occur != 0)
4168 occur = 1;
4169 } else
4170 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004171 } else if (cur->type == XML_COMMENT_NODE) {
4172 sep = "/";
4173 name = "comment()";
4174 next = cur->parent;
4175
4176 /*
4177 * Thumbler index computation
4178 */
4179 tmp = cur->prev;
4180 while (tmp != NULL) {
4181 if (tmp->type == XML_COMMENT_NODE)
4182 occur++;
4183 tmp = tmp->prev;
4184 }
4185 if (occur == 0) {
4186 tmp = cur->next;
4187 while (tmp != NULL && occur == 0) {
4188 if (tmp->type == XML_COMMENT_NODE)
4189 occur++;
4190 tmp = tmp->next;
4191 }
4192 if (occur != 0)
4193 occur = 1;
4194 } else
4195 occur++;
4196 } else if ((cur->type == XML_TEXT_NODE) ||
4197 (cur->type == XML_CDATA_SECTION_NODE)) {
4198 sep = "/";
4199 name = "text()";
4200 next = cur->parent;
4201
4202 /*
4203 * Thumbler index computation
4204 */
4205 tmp = cur->prev;
4206 while (tmp != NULL) {
4207 if ((cur->type == XML_TEXT_NODE) ||
4208 (cur->type == XML_CDATA_SECTION_NODE))
4209 occur++;
4210 tmp = tmp->prev;
4211 }
4212 if (occur == 0) {
4213 tmp = cur->next;
4214 while (tmp != NULL && occur == 0) {
4215 if ((cur->type == XML_TEXT_NODE) ||
4216 (cur->type == XML_CDATA_SECTION_NODE))
4217 occur++;
4218 tmp = tmp->next;
4219 }
4220 if (occur != 0)
4221 occur = 1;
4222 } else
4223 occur++;
4224 } else if (cur->type == XML_PI_NODE) {
4225 sep = "/";
4226 snprintf(nametemp, sizeof(nametemp) - 1,
4227 "processing-instruction('%s')", cur->name);
4228 nametemp[sizeof(nametemp) - 1] = 0;
4229 name = nametemp;
4230
4231 next = cur->parent;
4232
4233 /*
4234 * Thumbler index computation
4235 */
4236 tmp = cur->prev;
4237 while (tmp != NULL) {
4238 if ((tmp->type == XML_PI_NODE) &&
4239 (xmlStrEqual(cur->name, tmp->name)))
4240 occur++;
4241 tmp = tmp->prev;
4242 }
4243 if (occur == 0) {
4244 tmp = cur->next;
4245 while (tmp != NULL && occur == 0) {
4246 if ((tmp->type == XML_PI_NODE) &&
4247 (xmlStrEqual(cur->name, tmp->name)))
4248 occur++;
4249 tmp = tmp->next;
4250 }
4251 if (occur != 0)
4252 occur = 1;
4253 } else
4254 occur++;
4255
Daniel Veillard8faa7832001-11-26 15:58:08 +00004256 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004257 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004258 name = (const char *) (((xmlAttrPtr) cur)->name);
4259 next = ((xmlAttrPtr) cur)->parent;
4260 } else {
4261 next = cur->parent;
4262 }
4263
4264 /*
4265 * Make sure there is enough room
4266 */
4267 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4268 buf_len =
4269 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4270 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4271 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004272 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004273 xmlFree(buf);
4274 xmlFree(buffer);
4275 return (NULL);
4276 }
4277 buffer = temp;
4278 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4279 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004280 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004281 xmlFree(buf);
4282 xmlFree(buffer);
4283 return (NULL);
4284 }
4285 buf = temp;
4286 }
4287 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004288 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004289 sep, name, (char *) buffer);
4290 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004291 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004292 sep, name, occur, (char *) buffer);
4293 snprintf((char *) buffer, buf_len, "%s", buf);
4294 cur = next;
4295 } while (cur != NULL);
4296 xmlFree(buf);
4297 return (buffer);
4298}
Daniel Veillard652327a2003-09-29 18:02:38 +00004299#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004300
4301/**
Owen Taylor3473f882001-02-23 17:55:21 +00004302 * xmlDocGetRootElement:
4303 * @doc: the document
4304 *
4305 * Get the root element of the document (doc->children is a list
4306 * containing possibly comments, PIs, etc ...).
4307 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004308 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004309 */
4310xmlNodePtr
4311xmlDocGetRootElement(xmlDocPtr doc) {
4312 xmlNodePtr ret;
4313
4314 if (doc == NULL) return(NULL);
4315 ret = doc->children;
4316 while (ret != NULL) {
4317 if (ret->type == XML_ELEMENT_NODE)
4318 return(ret);
4319 ret = ret->next;
4320 }
4321 return(ret);
4322}
4323
Daniel Veillard652327a2003-09-29 18:02:38 +00004324#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004325/**
4326 * xmlDocSetRootElement:
4327 * @doc: the document
4328 * @root: the new document root element
4329 *
4330 * Set the root element of the document (doc->children is a list
4331 * containing possibly comments, PIs, etc ...).
4332 *
4333 * Returns the old root element if any was found
4334 */
4335xmlNodePtr
4336xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4337 xmlNodePtr old = NULL;
4338
4339 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004340 if (root == NULL)
4341 return(NULL);
4342 xmlUnlinkNode(root);
4343 root->doc = doc;
4344 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004345 old = doc->children;
4346 while (old != NULL) {
4347 if (old->type == XML_ELEMENT_NODE)
4348 break;
4349 old = old->next;
4350 }
4351 if (old == NULL) {
4352 if (doc->children == NULL) {
4353 doc->children = root;
4354 doc->last = root;
4355 } else {
4356 xmlAddSibling(doc->children, root);
4357 }
4358 } else {
4359 xmlReplaceNode(old, root);
4360 }
4361 return(old);
4362}
4363
4364/**
4365 * xmlNodeSetLang:
4366 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004367 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004368 *
4369 * Set the language of a node, i.e. the values of the xml:lang
4370 * attribute.
4371 */
4372void
4373xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004374 xmlNsPtr ns;
4375
Owen Taylor3473f882001-02-23 17:55:21 +00004376 if (cur == NULL) return;
4377 switch(cur->type) {
4378 case XML_TEXT_NODE:
4379 case XML_CDATA_SECTION_NODE:
4380 case XML_COMMENT_NODE:
4381 case XML_DOCUMENT_NODE:
4382 case XML_DOCUMENT_TYPE_NODE:
4383 case XML_DOCUMENT_FRAG_NODE:
4384 case XML_NOTATION_NODE:
4385 case XML_HTML_DOCUMENT_NODE:
4386 case XML_DTD_NODE:
4387 case XML_ELEMENT_DECL:
4388 case XML_ATTRIBUTE_DECL:
4389 case XML_ENTITY_DECL:
4390 case XML_PI_NODE:
4391 case XML_ENTITY_REF_NODE:
4392 case XML_ENTITY_NODE:
4393 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004394#ifdef LIBXML_DOCB_ENABLED
4395 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004396#endif
4397 case XML_XINCLUDE_START:
4398 case XML_XINCLUDE_END:
4399 return;
4400 case XML_ELEMENT_NODE:
4401 case XML_ATTRIBUTE_NODE:
4402 break;
4403 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004404 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4405 if (ns == NULL)
4406 return;
4407 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004408}
Daniel Veillard652327a2003-09-29 18:02:38 +00004409#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004410
4411/**
4412 * xmlNodeGetLang:
4413 * @cur: the node being checked
4414 *
4415 * Searches the language of a node, i.e. the values of the xml:lang
4416 * attribute or the one carried by the nearest ancestor.
4417 *
4418 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004419 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004420 */
4421xmlChar *
4422xmlNodeGetLang(xmlNodePtr cur) {
4423 xmlChar *lang;
4424
4425 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004426 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004427 if (lang != NULL)
4428 return(lang);
4429 cur = cur->parent;
4430 }
4431 return(NULL);
4432}
4433
4434
Daniel Veillard652327a2003-09-29 18:02:38 +00004435#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004436/**
4437 * xmlNodeSetSpacePreserve:
4438 * @cur: the node being changed
4439 * @val: the xml:space value ("0": default, 1: "preserve")
4440 *
4441 * Set (or reset) the space preserving behaviour of a node, i.e. the
4442 * value of the xml:space attribute.
4443 */
4444void
4445xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004446 xmlNsPtr ns;
4447
Owen Taylor3473f882001-02-23 17:55:21 +00004448 if (cur == NULL) return;
4449 switch(cur->type) {
4450 case XML_TEXT_NODE:
4451 case XML_CDATA_SECTION_NODE:
4452 case XML_COMMENT_NODE:
4453 case XML_DOCUMENT_NODE:
4454 case XML_DOCUMENT_TYPE_NODE:
4455 case XML_DOCUMENT_FRAG_NODE:
4456 case XML_NOTATION_NODE:
4457 case XML_HTML_DOCUMENT_NODE:
4458 case XML_DTD_NODE:
4459 case XML_ELEMENT_DECL:
4460 case XML_ATTRIBUTE_DECL:
4461 case XML_ENTITY_DECL:
4462 case XML_PI_NODE:
4463 case XML_ENTITY_REF_NODE:
4464 case XML_ENTITY_NODE:
4465 case XML_NAMESPACE_DECL:
4466 case XML_XINCLUDE_START:
4467 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004468#ifdef LIBXML_DOCB_ENABLED
4469 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004470#endif
4471 return;
4472 case XML_ELEMENT_NODE:
4473 case XML_ATTRIBUTE_NODE:
4474 break;
4475 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004476 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4477 if (ns == NULL)
4478 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004479 switch (val) {
4480 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004481 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004482 break;
4483 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004484 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004485 break;
4486 }
4487}
Daniel Veillard652327a2003-09-29 18:02:38 +00004488#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004489
4490/**
4491 * xmlNodeGetSpacePreserve:
4492 * @cur: the node being checked
4493 *
4494 * Searches the space preserving behaviour of a node, i.e. the values
4495 * of the xml:space attribute or the one carried by the nearest
4496 * ancestor.
4497 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004498 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004499 */
4500int
4501xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4502 xmlChar *space;
4503
4504 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004505 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004506 if (space != NULL) {
4507 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4508 xmlFree(space);
4509 return(1);
4510 }
4511 if (xmlStrEqual(space, BAD_CAST "default")) {
4512 xmlFree(space);
4513 return(0);
4514 }
4515 xmlFree(space);
4516 }
4517 cur = cur->parent;
4518 }
4519 return(-1);
4520}
4521
Daniel Veillard652327a2003-09-29 18:02:38 +00004522#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004523/**
4524 * xmlNodeSetName:
4525 * @cur: the node being changed
4526 * @name: the new tag name
4527 *
4528 * Set (or reset) the name of a node.
4529 */
4530void
4531xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
4532 if (cur == NULL) return;
4533 if (name == NULL) return;
4534 switch(cur->type) {
4535 case XML_TEXT_NODE:
4536 case XML_CDATA_SECTION_NODE:
4537 case XML_COMMENT_NODE:
4538 case XML_DOCUMENT_TYPE_NODE:
4539 case XML_DOCUMENT_FRAG_NODE:
4540 case XML_NOTATION_NODE:
4541 case XML_HTML_DOCUMENT_NODE:
4542 case XML_NAMESPACE_DECL:
4543 case XML_XINCLUDE_START:
4544 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004545#ifdef LIBXML_DOCB_ENABLED
4546 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004547#endif
4548 return;
4549 case XML_ELEMENT_NODE:
4550 case XML_ATTRIBUTE_NODE:
4551 case XML_PI_NODE:
4552 case XML_ENTITY_REF_NODE:
4553 case XML_ENTITY_NODE:
4554 case XML_DTD_NODE:
4555 case XML_DOCUMENT_NODE:
4556 case XML_ELEMENT_DECL:
4557 case XML_ATTRIBUTE_DECL:
4558 case XML_ENTITY_DECL:
4559 break;
4560 }
4561 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4562 cur->name = xmlStrdup(name);
4563}
4564
4565/**
4566 * xmlNodeSetBase:
4567 * @cur: the node being changed
4568 * @uri: the new base URI
4569 *
4570 * Set (or reset) the base URI of a node, i.e. the value of the
4571 * xml:base attribute.
4572 */
4573void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00004574xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004575 xmlNsPtr ns;
4576
Owen Taylor3473f882001-02-23 17:55:21 +00004577 if (cur == NULL) return;
4578 switch(cur->type) {
4579 case XML_TEXT_NODE:
4580 case XML_CDATA_SECTION_NODE:
4581 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004582 case XML_DOCUMENT_TYPE_NODE:
4583 case XML_DOCUMENT_FRAG_NODE:
4584 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004585 case XML_DTD_NODE:
4586 case XML_ELEMENT_DECL:
4587 case XML_ATTRIBUTE_DECL:
4588 case XML_ENTITY_DECL:
4589 case XML_PI_NODE:
4590 case XML_ENTITY_REF_NODE:
4591 case XML_ENTITY_NODE:
4592 case XML_NAMESPACE_DECL:
4593 case XML_XINCLUDE_START:
4594 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004595 return;
4596 case XML_ELEMENT_NODE:
4597 case XML_ATTRIBUTE_NODE:
4598 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004599 case XML_DOCUMENT_NODE:
4600#ifdef LIBXML_DOCB_ENABLED
4601 case XML_DOCB_DOCUMENT_NODE:
4602#endif
4603 case XML_HTML_DOCUMENT_NODE: {
4604 xmlDocPtr doc = (xmlDocPtr) cur;
4605
4606 if (doc->URL != NULL)
4607 xmlFree((xmlChar *) doc->URL);
4608 if (uri == NULL)
4609 doc->URL = NULL;
4610 else
4611 doc->URL = xmlStrdup(uri);
4612 return;
4613 }
Owen Taylor3473f882001-02-23 17:55:21 +00004614 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004615
4616 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4617 if (ns == NULL)
4618 return;
4619 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004620}
Daniel Veillard652327a2003-09-29 18:02:38 +00004621#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004622
4623/**
Owen Taylor3473f882001-02-23 17:55:21 +00004624 * xmlNodeGetBase:
4625 * @doc: the document the node pertains to
4626 * @cur: the node being checked
4627 *
4628 * Searches for the BASE URL. The code should work on both XML
4629 * and HTML document even if base mechanisms are completely different.
4630 * It returns the base as defined in RFC 2396 sections
4631 * 5.1.1. Base URI within Document Content
4632 * and
4633 * 5.1.2. Base URI from the Encapsulating Entity
4634 * However it does not return the document base (5.1.3), use
4635 * xmlDocumentGetBase() for this
4636 *
4637 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004638 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004639 */
4640xmlChar *
4641xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004642 xmlChar *oldbase = NULL;
4643 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004644
4645 if ((cur == NULL) && (doc == NULL))
4646 return(NULL);
4647 if (doc == NULL) doc = cur->doc;
4648 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4649 cur = doc->children;
4650 while ((cur != NULL) && (cur->name != NULL)) {
4651 if (cur->type != XML_ELEMENT_NODE) {
4652 cur = cur->next;
4653 continue;
4654 }
4655 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4656 cur = cur->children;
4657 continue;
4658 }
4659 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4660 cur = cur->children;
4661 continue;
4662 }
4663 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4664 return(xmlGetProp(cur, BAD_CAST "href"));
4665 }
4666 cur = cur->next;
4667 }
4668 return(NULL);
4669 }
4670 while (cur != NULL) {
4671 if (cur->type == XML_ENTITY_DECL) {
4672 xmlEntityPtr ent = (xmlEntityPtr) cur;
4673 return(xmlStrdup(ent->URI));
4674 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004675 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004676 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004677 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004678 if (oldbase != NULL) {
4679 newbase = xmlBuildURI(oldbase, base);
4680 if (newbase != NULL) {
4681 xmlFree(oldbase);
4682 xmlFree(base);
4683 oldbase = newbase;
4684 } else {
4685 xmlFree(oldbase);
4686 xmlFree(base);
4687 return(NULL);
4688 }
4689 } else {
4690 oldbase = base;
4691 }
4692 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4693 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4694 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4695 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004696 }
4697 }
Owen Taylor3473f882001-02-23 17:55:21 +00004698 cur = cur->parent;
4699 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004700 if ((doc != NULL) && (doc->URL != NULL)) {
4701 if (oldbase == NULL)
4702 return(xmlStrdup(doc->URL));
4703 newbase = xmlBuildURI(oldbase, doc->URL);
4704 xmlFree(oldbase);
4705 return(newbase);
4706 }
4707 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004708}
4709
4710/**
Daniel Veillard78697292003-10-19 20:44:43 +00004711 * xmlNodeBufGetContent:
4712 * @buffer: a buffer
4713 * @cur: the node being read
4714 *
4715 * Read the value of a node @cur, this can be either the text carried
4716 * directly by this node if it's a TEXT node or the aggregate string
4717 * of the values carried by this node child's (TEXT and ENTITY_REF).
4718 * Entity references are substituted.
4719 * Fills up the buffer @buffer with this value
4720 *
4721 * Returns 0 in case of success and -1 in case of error.
4722 */
4723int
4724xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
4725{
4726 if ((cur == NULL) || (buffer == NULL)) return(-1);
4727 switch (cur->type) {
4728 case XML_CDATA_SECTION_NODE:
4729 case XML_TEXT_NODE:
4730 xmlBufferCat(buffer, cur->content);
4731 break;
4732 case XML_DOCUMENT_FRAG_NODE:
4733 case XML_ELEMENT_NODE:{
4734 xmlNodePtr tmp = cur;
4735
4736 while (tmp != NULL) {
4737 switch (tmp->type) {
4738 case XML_CDATA_SECTION_NODE:
4739 case XML_TEXT_NODE:
4740 if (tmp->content != NULL)
4741 xmlBufferCat(buffer, tmp->content);
4742 break;
4743 case XML_ENTITY_REF_NODE:
4744 xmlNodeBufGetContent(buffer, tmp->children);
4745 break;
4746 default:
4747 break;
4748 }
4749 /*
4750 * Skip to next node
4751 */
4752 if (tmp->children != NULL) {
4753 if (tmp->children->type != XML_ENTITY_DECL) {
4754 tmp = tmp->children;
4755 continue;
4756 }
4757 }
4758 if (tmp == cur)
4759 break;
4760
4761 if (tmp->next != NULL) {
4762 tmp = tmp->next;
4763 continue;
4764 }
4765
4766 do {
4767 tmp = tmp->parent;
4768 if (tmp == NULL)
4769 break;
4770 if (tmp == cur) {
4771 tmp = NULL;
4772 break;
4773 }
4774 if (tmp->next != NULL) {
4775 tmp = tmp->next;
4776 break;
4777 }
4778 } while (tmp != NULL);
4779 }
4780 break;
4781 }
4782 case XML_ATTRIBUTE_NODE:{
4783 xmlAttrPtr attr = (xmlAttrPtr) cur;
4784 xmlNodePtr tmp = attr->children;
4785
4786 while (tmp != NULL) {
4787 if (tmp->type == XML_TEXT_NODE)
4788 xmlBufferCat(buffer, tmp->content);
4789 else
4790 xmlNodeBufGetContent(buffer, tmp);
4791 tmp = tmp->next;
4792 }
4793 break;
4794 }
4795 case XML_COMMENT_NODE:
4796 case XML_PI_NODE:
4797 xmlBufferCat(buffer, cur->content);
4798 break;
4799 case XML_ENTITY_REF_NODE:{
4800 xmlEntityPtr ent;
4801 xmlNodePtr tmp;
4802
4803 /* lookup entity declaration */
4804 ent = xmlGetDocEntity(cur->doc, cur->name);
4805 if (ent == NULL)
4806 return(-1);
4807
4808 /* an entity content can be any "well balanced chunk",
4809 * i.e. the result of the content [43] production:
4810 * http://www.w3.org/TR/REC-xml#NT-content
4811 * -> we iterate through child nodes and recursive call
4812 * xmlNodeGetContent() which handles all possible node types */
4813 tmp = ent->children;
4814 while (tmp) {
4815 xmlNodeBufGetContent(buffer, tmp);
4816 tmp = tmp->next;
4817 }
4818 break;
4819 }
4820 case XML_ENTITY_NODE:
4821 case XML_DOCUMENT_TYPE_NODE:
4822 case XML_NOTATION_NODE:
4823 case XML_DTD_NODE:
4824 case XML_XINCLUDE_START:
4825 case XML_XINCLUDE_END:
4826 break;
4827 case XML_DOCUMENT_NODE:
4828#ifdef LIBXML_DOCB_ENABLED
4829 case XML_DOCB_DOCUMENT_NODE:
4830#endif
4831 case XML_HTML_DOCUMENT_NODE:
4832 cur = cur->children;
4833 while (cur!= NULL) {
4834 if ((cur->type == XML_ELEMENT_NODE) ||
4835 (cur->type == XML_TEXT_NODE) ||
4836 (cur->type == XML_CDATA_SECTION_NODE)) {
4837 xmlNodeBufGetContent(buffer, cur);
4838 }
4839 cur = cur->next;
4840 }
4841 break;
4842 case XML_NAMESPACE_DECL:
4843 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
4844 break;
4845 case XML_ELEMENT_DECL:
4846 case XML_ATTRIBUTE_DECL:
4847 case XML_ENTITY_DECL:
4848 break;
4849 }
4850 return(0);
4851}
4852/**
Owen Taylor3473f882001-02-23 17:55:21 +00004853 * xmlNodeGetContent:
4854 * @cur: the node being read
4855 *
4856 * Read the value of a node, this can be either the text carried
4857 * directly by this node if it's a TEXT node or the aggregate string
4858 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004859 * Entity references are substituted.
4860 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004861 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004862 */
4863xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004864xmlNodeGetContent(xmlNodePtr cur)
4865{
4866 if (cur == NULL)
4867 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004868 switch (cur->type) {
4869 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004870 case XML_ELEMENT_NODE:{
4871 xmlNodePtr tmp = cur;
4872 xmlBufferPtr buffer;
4873 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004874
Daniel Veillard814a76d2003-01-23 18:24:20 +00004875 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004876 if (buffer == NULL)
4877 return (NULL);
4878 while (tmp != NULL) {
4879 switch (tmp->type) {
4880 case XML_CDATA_SECTION_NODE:
4881 case XML_TEXT_NODE:
4882 if (tmp->content != NULL)
4883 xmlBufferCat(buffer, tmp->content);
4884 break;
4885 case XML_ENTITY_REF_NODE:{
4886 /* recursive substitution of entity references */
4887 xmlChar *cont = xmlNodeGetContent(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00004888
Daniel Veillard7646b182002-04-20 06:41:40 +00004889 if (cont) {
4890 xmlBufferCat(buffer,
4891 (const xmlChar *) cont);
4892 xmlFree(cont);
4893 }
4894 break;
4895 }
4896 default:
4897 break;
4898 }
4899 /*
4900 * Skip to next node
4901 */
4902 if (tmp->children != NULL) {
4903 if (tmp->children->type != XML_ENTITY_DECL) {
4904 tmp = tmp->children;
4905 continue;
4906 }
4907 }
4908 if (tmp == cur)
4909 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00004910
Daniel Veillard7646b182002-04-20 06:41:40 +00004911 if (tmp->next != NULL) {
4912 tmp = tmp->next;
4913 continue;
4914 }
4915
4916 do {
4917 tmp = tmp->parent;
4918 if (tmp == NULL)
4919 break;
4920 if (tmp == cur) {
4921 tmp = NULL;
4922 break;
4923 }
4924 if (tmp->next != NULL) {
4925 tmp = tmp->next;
4926 break;
4927 }
4928 } while (tmp != NULL);
4929 }
4930 ret = buffer->content;
4931 buffer->content = NULL;
4932 xmlBufferFree(buffer);
4933 return (ret);
4934 }
4935 case XML_ATTRIBUTE_NODE:{
4936 xmlAttrPtr attr = (xmlAttrPtr) cur;
4937
4938 if (attr->parent != NULL)
4939 return (xmlNodeListGetString
4940 (attr->parent->doc, attr->children, 1));
4941 else
4942 return (xmlNodeListGetString(NULL, attr->children, 1));
4943 break;
4944 }
Owen Taylor3473f882001-02-23 17:55:21 +00004945 case XML_COMMENT_NODE:
4946 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004947 if (cur->content != NULL)
4948 return (xmlStrdup(cur->content));
4949 return (NULL);
4950 case XML_ENTITY_REF_NODE:{
4951 xmlEntityPtr ent;
4952 xmlNodePtr tmp;
4953 xmlBufferPtr buffer;
4954 xmlChar *ret;
4955
4956 /* lookup entity declaration */
4957 ent = xmlGetDocEntity(cur->doc, cur->name);
4958 if (ent == NULL)
4959 return (NULL);
4960
4961 buffer = xmlBufferCreate();
4962 if (buffer == NULL)
4963 return (NULL);
4964
4965 /* an entity content can be any "well balanced chunk",
4966 * i.e. the result of the content [43] production:
4967 * http://www.w3.org/TR/REC-xml#NT-content
4968 * -> we iterate through child nodes and recursive call
4969 * xmlNodeGetContent() which handles all possible node types */
4970 tmp = ent->children;
4971 while (tmp) {
4972 xmlChar *cont = xmlNodeGetContent(tmp);
4973
4974 if (cont) {
4975 xmlBufferCat(buffer, (const xmlChar *) cont);
4976 xmlFree(cont);
4977 }
4978 tmp = tmp->next;
4979 }
4980
4981 ret = buffer->content;
4982 buffer->content = NULL;
4983 xmlBufferFree(buffer);
4984 return (ret);
4985 }
Owen Taylor3473f882001-02-23 17:55:21 +00004986 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004987 case XML_DOCUMENT_TYPE_NODE:
4988 case XML_NOTATION_NODE:
4989 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004990 case XML_XINCLUDE_START:
4991 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00004992 return (NULL);
4993 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004994#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004995 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004996#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00004997 case XML_HTML_DOCUMENT_NODE: {
4998 xmlChar *tmp;
4999 xmlChar *res = NULL;
5000
5001 cur = cur->children;
5002 while (cur!= NULL) {
5003 if ((cur->type == XML_ELEMENT_NODE) ||
5004 (cur->type == XML_TEXT_NODE) ||
5005 (cur->type == XML_CDATA_SECTION_NODE)) {
5006 tmp = xmlNodeGetContent(cur);
5007 if (tmp != NULL) {
5008 if (res == NULL)
5009 res = tmp;
5010 else {
5011 res = xmlStrcat(res, tmp);
5012 xmlFree(tmp);
5013 }
5014 }
5015 }
5016 cur = cur->next;
5017 }
5018 return(res);
5019 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00005020 case XML_NAMESPACE_DECL: {
5021 xmlChar *tmp;
5022
5023 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
5024 return (tmp);
5025 }
Owen Taylor3473f882001-02-23 17:55:21 +00005026 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005027 /* TODO !!! */
5028 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005029 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005030 /* TODO !!! */
5031 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005032 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00005033 /* TODO !!! */
5034 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005035 case XML_CDATA_SECTION_NODE:
5036 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00005037 if (cur->content != NULL)
5038 return (xmlStrdup(cur->content));
5039 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005040 }
Daniel Veillard7646b182002-04-20 06:41:40 +00005041 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005042}
Daniel Veillard652327a2003-09-29 18:02:38 +00005043
Owen Taylor3473f882001-02-23 17:55:21 +00005044/**
5045 * xmlNodeSetContent:
5046 * @cur: the node being modified
5047 * @content: the new value of the content
5048 *
5049 * Replace the content of a node.
5050 */
5051void
5052xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5053 if (cur == NULL) {
5054#ifdef DEBUG_TREE
5055 xmlGenericError(xmlGenericErrorContext,
5056 "xmlNodeSetContent : node == NULL\n");
5057#endif
5058 return;
5059 }
5060 switch (cur->type) {
5061 case XML_DOCUMENT_FRAG_NODE:
5062 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005063 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005064 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5065 cur->children = xmlStringGetNodeList(cur->doc, content);
5066 UPDATE_LAST_CHILD_AND_PARENT(cur)
5067 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005068 case XML_TEXT_NODE:
5069 case XML_CDATA_SECTION_NODE:
5070 case XML_ENTITY_REF_NODE:
5071 case XML_ENTITY_NODE:
5072 case XML_PI_NODE:
5073 case XML_COMMENT_NODE:
5074 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005075 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005076 }
5077 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5078 cur->last = cur->children = NULL;
5079 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005080 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00005081 } else
5082 cur->content = NULL;
5083 break;
5084 case XML_DOCUMENT_NODE:
5085 case XML_HTML_DOCUMENT_NODE:
5086 case XML_DOCUMENT_TYPE_NODE:
5087 case XML_XINCLUDE_START:
5088 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005089#ifdef LIBXML_DOCB_ENABLED
5090 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005091#endif
5092 break;
5093 case XML_NOTATION_NODE:
5094 break;
5095 case XML_DTD_NODE:
5096 break;
5097 case XML_NAMESPACE_DECL:
5098 break;
5099 case XML_ELEMENT_DECL:
5100 /* TODO !!! */
5101 break;
5102 case XML_ATTRIBUTE_DECL:
5103 /* TODO !!! */
5104 break;
5105 case XML_ENTITY_DECL:
5106 /* TODO !!! */
5107 break;
5108 }
5109}
5110
Daniel Veillard652327a2003-09-29 18:02:38 +00005111#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005112/**
5113 * xmlNodeSetContentLen:
5114 * @cur: the node being modified
5115 * @content: the new value of the content
5116 * @len: the size of @content
5117 *
5118 * Replace the content of a node.
5119 */
5120void
5121xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5122 if (cur == NULL) {
5123#ifdef DEBUG_TREE
5124 xmlGenericError(xmlGenericErrorContext,
5125 "xmlNodeSetContentLen : node == NULL\n");
5126#endif
5127 return;
5128 }
5129 switch (cur->type) {
5130 case XML_DOCUMENT_FRAG_NODE:
5131 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005132 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005133 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5134 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5135 UPDATE_LAST_CHILD_AND_PARENT(cur)
5136 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005137 case XML_TEXT_NODE:
5138 case XML_CDATA_SECTION_NODE:
5139 case XML_ENTITY_REF_NODE:
5140 case XML_ENTITY_NODE:
5141 case XML_PI_NODE:
5142 case XML_COMMENT_NODE:
5143 case XML_NOTATION_NODE:
5144 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005145 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005146 }
5147 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5148 cur->children = cur->last = NULL;
5149 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005150 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005151 } else
5152 cur->content = NULL;
5153 break;
5154 case XML_DOCUMENT_NODE:
5155 case XML_DTD_NODE:
5156 case XML_HTML_DOCUMENT_NODE:
5157 case XML_DOCUMENT_TYPE_NODE:
5158 case XML_NAMESPACE_DECL:
5159 case XML_XINCLUDE_START:
5160 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005161#ifdef LIBXML_DOCB_ENABLED
5162 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005163#endif
5164 break;
5165 case XML_ELEMENT_DECL:
5166 /* TODO !!! */
5167 break;
5168 case XML_ATTRIBUTE_DECL:
5169 /* TODO !!! */
5170 break;
5171 case XML_ENTITY_DECL:
5172 /* TODO !!! */
5173 break;
5174 }
5175}
Daniel Veillard652327a2003-09-29 18:02:38 +00005176#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005177
5178/**
5179 * xmlNodeAddContentLen:
5180 * @cur: the node being modified
5181 * @content: extra content
5182 * @len: the size of @content
5183 *
5184 * Append the extra substring to the node content.
5185 */
5186void
5187xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5188 if (cur == NULL) {
5189#ifdef DEBUG_TREE
5190 xmlGenericError(xmlGenericErrorContext,
5191 "xmlNodeAddContentLen : node == NULL\n");
5192#endif
5193 return;
5194 }
5195 if (len <= 0) return;
5196 switch (cur->type) {
5197 case XML_DOCUMENT_FRAG_NODE:
5198 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005199 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005200
Daniel Veillard7db37732001-07-12 01:20:08 +00005201 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005202 newNode = xmlNewTextLen(content, len);
5203 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005204 tmp = xmlAddChild(cur, newNode);
5205 if (tmp != newNode)
5206 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005207 if ((last != NULL) && (last->next == newNode)) {
5208 xmlTextMerge(last, newNode);
5209 }
5210 }
5211 break;
5212 }
5213 case XML_ATTRIBUTE_NODE:
5214 break;
5215 case XML_TEXT_NODE:
5216 case XML_CDATA_SECTION_NODE:
5217 case XML_ENTITY_REF_NODE:
5218 case XML_ENTITY_NODE:
5219 case XML_PI_NODE:
5220 case XML_COMMENT_NODE:
5221 case XML_NOTATION_NODE:
5222 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005223 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005224 }
5225 case XML_DOCUMENT_NODE:
5226 case XML_DTD_NODE:
5227 case XML_HTML_DOCUMENT_NODE:
5228 case XML_DOCUMENT_TYPE_NODE:
5229 case XML_NAMESPACE_DECL:
5230 case XML_XINCLUDE_START:
5231 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005232#ifdef LIBXML_DOCB_ENABLED
5233 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005234#endif
5235 break;
5236 case XML_ELEMENT_DECL:
5237 case XML_ATTRIBUTE_DECL:
5238 case XML_ENTITY_DECL:
5239 break;
5240 }
5241}
5242
5243/**
5244 * xmlNodeAddContent:
5245 * @cur: the node being modified
5246 * @content: extra content
5247 *
5248 * Append the extra substring to the node content.
5249 */
5250void
5251xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5252 int len;
5253
5254 if (cur == NULL) {
5255#ifdef DEBUG_TREE
5256 xmlGenericError(xmlGenericErrorContext,
5257 "xmlNodeAddContent : node == NULL\n");
5258#endif
5259 return;
5260 }
5261 if (content == NULL) return;
5262 len = xmlStrlen(content);
5263 xmlNodeAddContentLen(cur, content, len);
5264}
5265
5266/**
5267 * xmlTextMerge:
5268 * @first: the first text node
5269 * @second: the second text node being merged
5270 *
5271 * Merge two text nodes into one
5272 * Returns the first text node augmented
5273 */
5274xmlNodePtr
5275xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5276 if (first == NULL) return(second);
5277 if (second == NULL) return(first);
5278 if (first->type != XML_TEXT_NODE) return(first);
5279 if (second->type != XML_TEXT_NODE) return(first);
5280 if (second->name != first->name)
5281 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005282 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005283 xmlUnlinkNode(second);
5284 xmlFreeNode(second);
5285 return(first);
5286}
5287
Daniel Veillard652327a2003-09-29 18:02:38 +00005288#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005289/**
5290 * xmlGetNsList:
5291 * @doc: the document
5292 * @node: the current node
5293 *
5294 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005295 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005296 * that need to be freed by the caller or NULL if no
5297 * namespace if defined
5298 */
5299xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005300xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5301{
Owen Taylor3473f882001-02-23 17:55:21 +00005302 xmlNsPtr cur;
5303 xmlNsPtr *ret = NULL;
5304 int nbns = 0;
5305 int maxns = 10;
5306 int i;
5307
5308 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005309 if (node->type == XML_ELEMENT_NODE) {
5310 cur = node->nsDef;
5311 while (cur != NULL) {
5312 if (ret == NULL) {
5313 ret =
5314 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5315 sizeof(xmlNsPtr));
5316 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005317 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005318 return (NULL);
5319 }
5320 ret[nbns] = NULL;
5321 }
5322 for (i = 0; i < nbns; i++) {
5323 if ((cur->prefix == ret[i]->prefix) ||
5324 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5325 break;
5326 }
5327 if (i >= nbns) {
5328 if (nbns >= maxns) {
5329 maxns *= 2;
5330 ret = (xmlNsPtr *) xmlRealloc(ret,
5331 (maxns +
5332 1) *
5333 sizeof(xmlNsPtr));
5334 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005335 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005336 return (NULL);
5337 }
5338 }
5339 ret[nbns++] = cur;
5340 ret[nbns] = NULL;
5341 }
Owen Taylor3473f882001-02-23 17:55:21 +00005342
Daniel Veillard77044732001-06-29 21:31:07 +00005343 cur = cur->next;
5344 }
5345 }
5346 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005347 }
Daniel Veillard77044732001-06-29 21:31:07 +00005348 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005349}
Daniel Veillard652327a2003-09-29 18:02:38 +00005350#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005351
5352/**
5353 * xmlSearchNs:
5354 * @doc: the document
5355 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005356 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005357 *
5358 * Search a Ns registered under a given name space for a document.
5359 * recurse on the parents until it finds the defined namespace
5360 * or return NULL otherwise.
5361 * @nameSpace can be NULL, this is a search for the default namespace.
5362 * We don't allow to cross entities boundaries. If you don't declare
5363 * the namespace within those you will be in troubles !!! A warning
5364 * is generated to cover this case.
5365 *
5366 * Returns the namespace pointer or NULL.
5367 */
5368xmlNsPtr
5369xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
5370 xmlNsPtr cur;
5371
5372 if (node == NULL) return(NULL);
5373 if ((nameSpace != NULL) &&
5374 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005375 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5376 /*
5377 * The XML-1.0 namespace is normally held on the root
5378 * element. In this case exceptionally create it on the
5379 * node element.
5380 */
5381 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5382 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005383 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005384 return(NULL);
5385 }
5386 memset(cur, 0, sizeof(xmlNs));
5387 cur->type = XML_LOCAL_NAMESPACE;
5388 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5389 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5390 cur->next = node->nsDef;
5391 node->nsDef = cur;
5392 return(cur);
5393 }
Owen Taylor3473f882001-02-23 17:55:21 +00005394 if (doc->oldNs == NULL) {
5395 /*
5396 * Allocate a new Namespace and fill the fields.
5397 */
5398 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5399 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005400 xmlTreeErrMemory("searching namespace");
Owen Taylor3473f882001-02-23 17:55:21 +00005401 return(NULL);
5402 }
5403 memset(doc->oldNs, 0, sizeof(xmlNs));
5404 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5405
5406 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5407 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5408 }
5409 return(doc->oldNs);
5410 }
5411 while (node != NULL) {
5412 if ((node->type == XML_ENTITY_REF_NODE) ||
5413 (node->type == XML_ENTITY_NODE) ||
5414 (node->type == XML_ENTITY_DECL))
5415 return(NULL);
5416 if (node->type == XML_ELEMENT_NODE) {
5417 cur = node->nsDef;
5418 while (cur != NULL) {
5419 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5420 (cur->href != NULL))
5421 return(cur);
5422 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5423 (cur->href != NULL) &&
5424 (xmlStrEqual(cur->prefix, nameSpace)))
5425 return(cur);
5426 cur = cur->next;
5427 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005428 cur = node->ns;
5429 if (cur != NULL) {
5430 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5431 (cur->href != NULL))
5432 return(cur);
5433 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5434 (cur->href != NULL) &&
5435 (xmlStrEqual(cur->prefix, nameSpace)))
5436 return(cur);
5437 }
Owen Taylor3473f882001-02-23 17:55:21 +00005438 }
5439 node = node->parent;
5440 }
5441 return(NULL);
5442}
5443
5444/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005445 * xmlNsInScope:
5446 * @doc: the document
5447 * @node: the current node
5448 * @ancestor: the ancestor carrying the namespace
5449 * @prefix: the namespace prefix
5450 *
5451 * Verify that the given namespace held on @ancestor is still in scope
5452 * on node.
5453 *
5454 * Returns 1 if true, 0 if false and -1 in case of error.
5455 */
5456static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005457xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5458 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005459{
5460 xmlNsPtr tst;
5461
5462 while ((node != NULL) && (node != ancestor)) {
5463 if ((node->type == XML_ENTITY_REF_NODE) ||
5464 (node->type == XML_ENTITY_NODE) ||
5465 (node->type == XML_ENTITY_DECL))
5466 return (-1);
5467 if (node->type == XML_ELEMENT_NODE) {
5468 tst = node->nsDef;
5469 while (tst != NULL) {
5470 if ((tst->prefix == NULL)
5471 && (prefix == NULL))
5472 return (0);
5473 if ((tst->prefix != NULL)
5474 && (prefix != NULL)
5475 && (xmlStrEqual(tst->prefix, prefix)))
5476 return (0);
5477 tst = tst->next;
5478 }
5479 }
5480 node = node->parent;
5481 }
5482 if (node != ancestor)
5483 return (-1);
5484 return (1);
5485}
5486
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005487/**
Owen Taylor3473f882001-02-23 17:55:21 +00005488 * xmlSearchNsByHref:
5489 * @doc: the document
5490 * @node: the current node
5491 * @href: the namespace value
5492 *
5493 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5494 * the defined namespace or return NULL otherwise.
5495 * Returns the namespace pointer or NULL.
5496 */
5497xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005498xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5499{
Owen Taylor3473f882001-02-23 17:55:21 +00005500 xmlNsPtr cur;
5501 xmlNodePtr orig = node;
5502
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005503 if ((node == NULL) || (href == NULL))
5504 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005505 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005506 /*
5507 * Only the document can hold the XML spec namespace.
5508 */
5509 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5510 /*
5511 * The XML-1.0 namespace is normally held on the root
5512 * element. In this case exceptionally create it on the
5513 * node element.
5514 */
5515 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5516 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005517 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005518 return (NULL);
5519 }
5520 memset(cur, 0, sizeof(xmlNs));
5521 cur->type = XML_LOCAL_NAMESPACE;
5522 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5523 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5524 cur->next = node->nsDef;
5525 node->nsDef = cur;
5526 return (cur);
5527 }
5528 if (doc->oldNs == NULL) {
5529 /*
5530 * Allocate a new Namespace and fill the fields.
5531 */
5532 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5533 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005534 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005535 return (NULL);
5536 }
5537 memset(doc->oldNs, 0, sizeof(xmlNs));
5538 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005539
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005540 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5541 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5542 }
5543 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005544 }
5545 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005546 if ((node->type == XML_ENTITY_REF_NODE) ||
5547 (node->type == XML_ENTITY_NODE) ||
5548 (node->type == XML_ENTITY_DECL))
5549 return (NULL);
5550 if (node->type == XML_ELEMENT_NODE) {
5551 cur = node->nsDef;
5552 while (cur != NULL) {
5553 if ((cur->href != NULL) && (href != NULL) &&
5554 (xmlStrEqual(cur->href, href))) {
5555 if (xmlNsInScope(doc, orig, node, cur->href) == 1)
5556 return (cur);
5557 }
5558 cur = cur->next;
5559 }
5560 cur = node->ns;
5561 if (cur != NULL) {
5562 if ((cur->href != NULL) && (href != NULL) &&
5563 (xmlStrEqual(cur->href, href))) {
5564 if (xmlNsInScope(doc, orig, node, cur->href) == 1)
5565 return (cur);
5566 }
5567 }
5568 }
5569 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005570 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005571 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005572}
5573
5574/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005575 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005576 * @doc: the document
5577 * @tree: a node expected to hold the new namespace
5578 * @ns: the original namespace
5579 *
5580 * This function tries to locate a namespace definition in a tree
5581 * ancestors, or create a new namespace definition node similar to
5582 * @ns trying to reuse the same prefix. However if the given prefix is
5583 * null (default namespace) or reused within the subtree defined by
5584 * @tree or on one of its ancestors then a new prefix is generated.
5585 * Returns the (new) namespace definition or NULL in case of error
5586 */
5587xmlNsPtr
5588xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5589 xmlNsPtr def;
5590 xmlChar prefix[50];
5591 int counter = 1;
5592
5593 if (tree == NULL) {
5594#ifdef DEBUG_TREE
5595 xmlGenericError(xmlGenericErrorContext,
5596 "xmlNewReconciliedNs : tree == NULL\n");
5597#endif
5598 return(NULL);
5599 }
5600 if (ns == NULL) {
5601#ifdef DEBUG_TREE
5602 xmlGenericError(xmlGenericErrorContext,
5603 "xmlNewReconciliedNs : ns == NULL\n");
5604#endif
5605 return(NULL);
5606 }
5607 /*
5608 * Search an existing namespace definition inherited.
5609 */
5610 def = xmlSearchNsByHref(doc, tree, ns->href);
5611 if (def != NULL)
5612 return(def);
5613
5614 /*
5615 * Find a close prefix which is not already in use.
5616 * Let's strip namespace prefixes longer than 20 chars !
5617 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005618 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005619 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005620 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005621 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005622
Owen Taylor3473f882001-02-23 17:55:21 +00005623 def = xmlSearchNs(doc, tree, prefix);
5624 while (def != NULL) {
5625 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005626 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005627 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005628 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005629 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005630 def = xmlSearchNs(doc, tree, prefix);
5631 }
5632
5633 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005634 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005635 */
5636 def = xmlNewNs(tree, ns->href, prefix);
5637 return(def);
5638}
5639
Daniel Veillard652327a2003-09-29 18:02:38 +00005640#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005641/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005642 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005643 * @doc: the document
5644 * @tree: a node defining the subtree to reconciliate
5645 *
5646 * This function checks that all the namespaces declared within the given
5647 * tree are properly declared. This is needed for example after Copy or Cut
5648 * and then paste operations. The subtree may still hold pointers to
5649 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005650 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005651 * the new environment. If not possible the new namespaces are redeclared
5652 * on @tree at the top of the given subtree.
5653 * Returns the number of namespace declarations created or -1 in case of error.
5654 */
5655int
5656xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5657 xmlNsPtr *oldNs = NULL;
5658 xmlNsPtr *newNs = NULL;
5659 int sizeCache = 0;
5660 int nbCache = 0;
5661
5662 xmlNsPtr n;
5663 xmlNodePtr node = tree;
5664 xmlAttrPtr attr;
5665 int ret = 0, i;
5666
5667 while (node != NULL) {
5668 /*
5669 * Reconciliate the node namespace
5670 */
5671 if (node->ns != NULL) {
5672 /*
5673 * initialize the cache if needed
5674 */
5675 if (sizeCache == 0) {
5676 sizeCache = 10;
5677 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5678 sizeof(xmlNsPtr));
5679 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005680 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005681 return(-1);
5682 }
5683 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5684 sizeof(xmlNsPtr));
5685 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005686 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005687 xmlFree(oldNs);
5688 return(-1);
5689 }
5690 }
5691 for (i = 0;i < nbCache;i++) {
5692 if (oldNs[i] == node->ns) {
5693 node->ns = newNs[i];
5694 break;
5695 }
5696 }
5697 if (i == nbCache) {
5698 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005699 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005700 */
5701 n = xmlNewReconciliedNs(doc, tree, node->ns);
5702 if (n != NULL) { /* :-( what if else ??? */
5703 /*
5704 * check if we need to grow the cache buffers.
5705 */
5706 if (sizeCache <= nbCache) {
5707 sizeCache *= 2;
5708 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5709 sizeof(xmlNsPtr));
5710 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005711 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005712 xmlFree(newNs);
5713 return(-1);
5714 }
5715 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5716 sizeof(xmlNsPtr));
5717 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005718 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005719 xmlFree(oldNs);
5720 return(-1);
5721 }
5722 }
5723 newNs[nbCache] = n;
5724 oldNs[nbCache++] = node->ns;
5725 node->ns = n;
5726 }
5727 }
5728 }
5729 /*
5730 * now check for namespace hold by attributes on the node.
5731 */
5732 attr = node->properties;
5733 while (attr != NULL) {
5734 if (attr->ns != NULL) {
5735 /*
5736 * initialize the cache if needed
5737 */
5738 if (sizeCache == 0) {
5739 sizeCache = 10;
5740 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5741 sizeof(xmlNsPtr));
5742 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005743 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005744 return(-1);
5745 }
5746 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5747 sizeof(xmlNsPtr));
5748 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005749 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005750 xmlFree(oldNs);
5751 return(-1);
5752 }
5753 }
5754 for (i = 0;i < nbCache;i++) {
5755 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005756 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005757 break;
5758 }
5759 }
5760 if (i == nbCache) {
5761 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005762 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005763 */
5764 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5765 if (n != NULL) { /* :-( what if else ??? */
5766 /*
5767 * check if we need to grow the cache buffers.
5768 */
5769 if (sizeCache <= nbCache) {
5770 sizeCache *= 2;
5771 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5772 sizeof(xmlNsPtr));
5773 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005774 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005775 xmlFree(newNs);
5776 return(-1);
5777 }
5778 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5779 sizeof(xmlNsPtr));
5780 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005781 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005782 xmlFree(oldNs);
5783 return(-1);
5784 }
5785 }
5786 newNs[nbCache] = n;
5787 oldNs[nbCache++] = attr->ns;
5788 attr->ns = n;
5789 }
5790 }
5791 }
5792 attr = attr->next;
5793 }
5794
5795 /*
5796 * Browse the full subtree, deep first
5797 */
5798 if (node->children != NULL) {
5799 /* deep first */
5800 node = node->children;
5801 } else if ((node != tree) && (node->next != NULL)) {
5802 /* then siblings */
5803 node = node->next;
5804 } else if (node != tree) {
5805 /* go up to parents->next if needed */
5806 while (node != tree) {
5807 if (node->parent != NULL)
5808 node = node->parent;
5809 if ((node != tree) && (node->next != NULL)) {
5810 node = node->next;
5811 break;
5812 }
5813 if (node->parent == NULL) {
5814 node = NULL;
5815 break;
5816 }
5817 }
5818 /* exit condition */
5819 if (node == tree)
5820 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005821 } else
5822 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005823 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005824 if (oldNs != NULL)
5825 xmlFree(oldNs);
5826 if (newNs != NULL)
5827 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005828 return(ret);
5829}
Daniel Veillard652327a2003-09-29 18:02:38 +00005830#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005831
5832/**
5833 * xmlHasProp:
5834 * @node: the node
5835 * @name: the attribute name
5836 *
5837 * Search an attribute associated to a node
5838 * This function also looks in DTD attribute declaration for #FIXED or
5839 * default declaration values unless DTD use has been turned off.
5840 *
5841 * Returns the attribute or the attribute declaration or NULL if
5842 * neither was found.
5843 */
5844xmlAttrPtr
5845xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5846 xmlAttrPtr prop;
5847 xmlDocPtr doc;
5848
5849 if ((node == NULL) || (name == NULL)) return(NULL);
5850 /*
5851 * Check on the properties attached to the node
5852 */
5853 prop = node->properties;
5854 while (prop != NULL) {
5855 if (xmlStrEqual(prop->name, name)) {
5856 return(prop);
5857 }
5858 prop = prop->next;
5859 }
5860 if (!xmlCheckDTD) return(NULL);
5861
5862 /*
5863 * Check if there is a default declaration in the internal
5864 * or external subsets
5865 */
5866 doc = node->doc;
5867 if (doc != NULL) {
5868 xmlAttributePtr attrDecl;
5869 if (doc->intSubset != NULL) {
5870 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5871 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5872 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005873 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5874 /* return attribute declaration only if a default value is given
5875 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005876 return((xmlAttrPtr) attrDecl);
5877 }
5878 }
5879 return(NULL);
5880}
5881
5882/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005883 * xmlHasNsProp:
5884 * @node: the node
5885 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005886 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005887 *
5888 * Search for an attribute associated to a node
5889 * This attribute has to be anchored in the namespace specified.
5890 * This does the entity substitution.
5891 * This function looks in DTD attribute declaration for #FIXED or
5892 * default declaration values unless DTD use has been turned off.
5893 *
5894 * Returns the attribute or the attribute declaration or NULL
5895 * if neither was found.
5896 */
5897xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005898xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005899 xmlAttrPtr prop;
Daniel Veillard652327a2003-09-29 18:02:38 +00005900#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005901 xmlDocPtr doc;
Daniel Veillard652327a2003-09-29 18:02:38 +00005902#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005903
5904 if (node == NULL)
5905 return(NULL);
5906
5907 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005908 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005909 return(xmlHasProp(node, name));
5910 while (prop != NULL) {
5911 /*
5912 * One need to have
5913 * - same attribute names
5914 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005915 */
5916 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005917 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5918 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005919 }
5920 prop = prop->next;
5921 }
5922 if (!xmlCheckDTD) return(NULL);
5923
Daniel Veillard652327a2003-09-29 18:02:38 +00005924#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005925 /*
5926 * Check if there is a default declaration in the internal
5927 * or external subsets
5928 */
5929 doc = node->doc;
5930 if (doc != NULL) {
5931 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005932 xmlAttributePtr attrDecl = NULL;
5933 xmlNsPtr *nsList, *cur;
5934 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005935
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005936 nsList = xmlGetNsList(node->doc, node);
5937 if (nsList == NULL)
5938 return(NULL);
5939 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5940 ename = xmlStrdup(node->ns->prefix);
5941 ename = xmlStrcat(ename, BAD_CAST ":");
5942 ename = xmlStrcat(ename, node->name);
5943 } else {
5944 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005945 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005946 if (ename == NULL) {
5947 xmlFree(nsList);
5948 return(NULL);
5949 }
5950
5951 cur = nsList;
5952 while (*cur != NULL) {
5953 if (xmlStrEqual((*cur)->href, nameSpace)) {
5954 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5955 name, (*cur)->prefix);
5956 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5957 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5958 name, (*cur)->prefix);
5959 }
5960 cur++;
5961 }
5962 xmlFree(nsList);
5963 xmlFree(ename);
5964 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005965 }
5966 }
Daniel Veillard652327a2003-09-29 18:02:38 +00005967#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005968 return(NULL);
5969}
5970
5971/**
Owen Taylor3473f882001-02-23 17:55:21 +00005972 * xmlGetProp:
5973 * @node: the node
5974 * @name: the attribute name
5975 *
5976 * Search and get the value of an attribute associated to a node
5977 * This does the entity substitution.
5978 * This function looks in DTD attribute declaration for #FIXED or
5979 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00005980 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00005981 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
5982 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00005983 *
5984 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005985 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005986 */
5987xmlChar *
5988xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5989 xmlAttrPtr prop;
5990 xmlDocPtr doc;
5991
5992 if ((node == NULL) || (name == NULL)) return(NULL);
5993 /*
5994 * Check on the properties attached to the node
5995 */
5996 prop = node->properties;
5997 while (prop != NULL) {
5998 if (xmlStrEqual(prop->name, name)) {
5999 xmlChar *ret;
6000
6001 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6002 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6003 return(ret);
6004 }
6005 prop = prop->next;
6006 }
6007 if (!xmlCheckDTD) return(NULL);
6008
6009 /*
6010 * Check if there is a default declaration in the internal
6011 * or external subsets
6012 */
6013 doc = node->doc;
6014 if (doc != NULL) {
6015 xmlAttributePtr attrDecl;
6016 if (doc->intSubset != NULL) {
6017 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6018 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6019 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006020 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6021 /* return attribute declaration only if a default value is given
6022 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00006023 return(xmlStrdup(attrDecl->defaultValue));
6024 }
6025 }
6026 return(NULL);
6027}
6028
6029/**
Daniel Veillard71531f32003-02-05 13:19:53 +00006030 * xmlGetNoNsProp:
6031 * @node: the node
6032 * @name: the attribute name
6033 *
6034 * Search and get the value of an attribute associated to a node
6035 * This does the entity substitution.
6036 * This function looks in DTD attribute declaration for #FIXED or
6037 * default declaration values unless DTD use has been turned off.
6038 * This function is similar to xmlGetProp except it will accept only
6039 * an attribute in no namespace.
6040 *
6041 * Returns the attribute value or NULL if not found.
6042 * It's up to the caller to free the memory with xmlFree().
6043 */
6044xmlChar *
6045xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
6046 xmlAttrPtr prop;
6047 xmlDocPtr doc;
6048
6049 if ((node == NULL) || (name == NULL)) return(NULL);
6050 /*
6051 * Check on the properties attached to the node
6052 */
6053 prop = node->properties;
6054 while (prop != NULL) {
6055 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
6056 xmlChar *ret;
6057
6058 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6059 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6060 return(ret);
6061 }
6062 prop = prop->next;
6063 }
6064 if (!xmlCheckDTD) return(NULL);
6065
6066 /*
6067 * Check if there is a default declaration in the internal
6068 * or external subsets
6069 */
6070 doc = node->doc;
6071 if (doc != NULL) {
6072 xmlAttributePtr attrDecl;
6073 if (doc->intSubset != NULL) {
6074 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6075 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6076 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006077 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6078 /* return attribute declaration only if a default value is given
6079 (that includes #FIXED declarations) */
Daniel Veillard71531f32003-02-05 13:19:53 +00006080 return(xmlStrdup(attrDecl->defaultValue));
6081 }
6082 }
6083 return(NULL);
6084}
6085
6086/**
Owen Taylor3473f882001-02-23 17:55:21 +00006087 * xmlGetNsProp:
6088 * @node: the node
6089 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006090 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006091 *
6092 * Search and get the value of an attribute associated to a node
6093 * This attribute has to be anchored in the namespace specified.
6094 * This does the entity substitution.
6095 * This function looks in DTD attribute declaration for #FIXED or
6096 * default declaration values unless DTD use has been turned off.
6097 *
6098 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006099 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006100 */
6101xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006102xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006103 xmlAttrPtr prop;
6104 xmlDocPtr doc;
6105 xmlNsPtr ns;
6106
6107 if (node == NULL)
6108 return(NULL);
6109
6110 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00006111 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00006112 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00006113 while (prop != NULL) {
6114 /*
6115 * One need to have
6116 * - same attribute names
6117 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006118 */
6119 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00006120 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00006121 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006122 xmlChar *ret;
6123
6124 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6125 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6126 return(ret);
6127 }
6128 prop = prop->next;
6129 }
6130 if (!xmlCheckDTD) return(NULL);
6131
6132 /*
6133 * Check if there is a default declaration in the internal
6134 * or external subsets
6135 */
6136 doc = node->doc;
6137 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006138 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00006139 xmlAttributePtr attrDecl;
6140
Owen Taylor3473f882001-02-23 17:55:21 +00006141 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6142 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6143 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
6144
6145 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
6146 /*
6147 * The DTD declaration only allows a prefix search
6148 */
6149 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00006150 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00006151 return(xmlStrdup(attrDecl->defaultValue));
6152 }
6153 }
6154 }
6155 return(NULL);
6156}
6157
Daniel Veillard652327a2003-09-29 18:02:38 +00006158#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00006159/**
6160 * xmlSetProp:
6161 * @node: the node
6162 * @name: the attribute name
6163 * @value: the attribute value
6164 *
6165 * Set (or reset) an attribute carried by a node.
6166 * Returns the attribute pointer.
6167 */
6168xmlAttrPtr
6169xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006170 xmlAttrPtr prop;
6171 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00006172
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006173 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006174 return(NULL);
6175 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006176 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00006177 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006178 if ((xmlStrEqual(prop->name, name)) &&
6179 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006180 xmlNodePtr oldprop = prop->children;
6181
Owen Taylor3473f882001-02-23 17:55:21 +00006182 prop->children = NULL;
6183 prop->last = NULL;
6184 if (value != NULL) {
6185 xmlChar *buffer;
6186 xmlNodePtr tmp;
6187
6188 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6189 prop->children = xmlStringGetNodeList(node->doc, buffer);
6190 prop->last = NULL;
6191 prop->doc = doc;
6192 tmp = prop->children;
6193 while (tmp != NULL) {
6194 tmp->parent = (xmlNodePtr) prop;
6195 tmp->doc = doc;
6196 if (tmp->next == NULL)
6197 prop->last = tmp;
6198 tmp = tmp->next;
6199 }
6200 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00006201 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006202 if (oldprop != NULL)
6203 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00006204 return(prop);
6205 }
6206 prop = prop->next;
6207 }
6208 prop = xmlNewProp(node, name, value);
6209 return(prop);
6210}
6211
6212/**
Daniel Veillard75bea542001-05-11 17:41:21 +00006213 * xmlUnsetProp:
6214 * @node: the node
6215 * @name: the attribute name
6216 *
6217 * Remove an attribute carried by a node.
6218 * Returns 0 if successful, -1 if not found
6219 */
6220int
6221xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Daniel Veillard814a76d2003-01-23 18:24:20 +00006222 xmlAttrPtr prop, prev = NULL;;
Daniel Veillard75bea542001-05-11 17:41:21 +00006223
6224 if ((node == NULL) || (name == NULL))
6225 return(-1);
Daniel Veillard814a76d2003-01-23 18:24:20 +00006226 prop = node->properties;
Daniel Veillard75bea542001-05-11 17:41:21 +00006227 while (prop != NULL) {
6228 if ((xmlStrEqual(prop->name, name)) &&
6229 (prop->ns == NULL)) {
6230 if (prev == NULL)
6231 node->properties = prop->next;
6232 else
6233 prev->next = prop->next;
6234 xmlFreeProp(prop);
6235 return(0);
6236 }
6237 prev = prop;
6238 prop = prop->next;
6239 }
6240 return(-1);
6241}
6242
6243/**
Owen Taylor3473f882001-02-23 17:55:21 +00006244 * xmlSetNsProp:
6245 * @node: the node
6246 * @ns: the namespace definition
6247 * @name: the attribute name
6248 * @value: the attribute value
6249 *
6250 * Set (or reset) an attribute carried by a node.
6251 * The ns structure must be in scope, this is not checked.
6252 *
6253 * Returns the attribute pointer.
6254 */
6255xmlAttrPtr
6256xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
6257 const xmlChar *value) {
6258 xmlAttrPtr prop;
6259
6260 if ((node == NULL) || (name == NULL))
6261 return(NULL);
6262
6263 if (ns == NULL)
6264 return(xmlSetProp(node, name, value));
6265 if (ns->href == NULL)
6266 return(NULL);
6267 prop = node->properties;
6268
6269 while (prop != NULL) {
6270 /*
6271 * One need to have
6272 * - same attribute names
6273 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006274 */
6275 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00006276 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006277 if (prop->children != NULL)
6278 xmlFreeNodeList(prop->children);
6279 prop->children = NULL;
6280 prop->last = NULL;
6281 prop->ns = ns;
6282 if (value != NULL) {
6283 xmlChar *buffer;
6284 xmlNodePtr tmp;
6285
6286 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6287 prop->children = xmlStringGetNodeList(node->doc, buffer);
6288 prop->last = NULL;
6289 tmp = prop->children;
6290 while (tmp != NULL) {
6291 tmp->parent = (xmlNodePtr) prop;
6292 if (tmp->next == NULL)
6293 prop->last = tmp;
6294 tmp = tmp->next;
6295 }
6296 xmlFree(buffer);
6297 }
6298 return(prop);
6299 }
6300 prop = prop->next;
6301 }
6302 prop = xmlNewNsProp(node, ns, name, value);
6303 return(prop);
6304}
6305
6306/**
Daniel Veillard75bea542001-05-11 17:41:21 +00006307 * xmlUnsetNsProp:
6308 * @node: the node
6309 * @ns: the namespace definition
6310 * @name: the attribute name
6311 *
6312 * Remove an attribute carried by a node.
6313 * Returns 0 if successful, -1 if not found
6314 */
6315int
6316xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
6317 xmlAttrPtr prop = node->properties, prev = NULL;;
6318
6319 if ((node == NULL) || (name == NULL))
6320 return(-1);
6321 if (ns == NULL)
6322 return(xmlUnsetProp(node, name));
6323 if (ns->href == NULL)
6324 return(-1);
6325 while (prop != NULL) {
6326 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00006327 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006328 if (prev == NULL)
6329 node->properties = prop->next;
6330 else
6331 prev->next = prop->next;
6332 xmlFreeProp(prop);
6333 return(0);
6334 }
6335 prev = prop;
6336 prop = prop->next;
6337 }
6338 return(-1);
6339}
Daniel Veillard652327a2003-09-29 18:02:38 +00006340#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006341
6342/**
Owen Taylor3473f882001-02-23 17:55:21 +00006343 * xmlNodeIsText:
6344 * @node: the node
6345 *
6346 * Is this node a Text node ?
6347 * Returns 1 yes, 0 no
6348 */
6349int
6350xmlNodeIsText(xmlNodePtr node) {
6351 if (node == NULL) return(0);
6352
6353 if (node->type == XML_TEXT_NODE) return(1);
6354 return(0);
6355}
6356
6357/**
6358 * xmlIsBlankNode:
6359 * @node: the node
6360 *
6361 * Checks whether this node is an empty or whitespace only
6362 * (and possibly ignorable) text-node.
6363 *
6364 * Returns 1 yes, 0 no
6365 */
6366int
6367xmlIsBlankNode(xmlNodePtr node) {
6368 const xmlChar *cur;
6369 if (node == NULL) return(0);
6370
Daniel Veillard7db37732001-07-12 01:20:08 +00006371 if ((node->type != XML_TEXT_NODE) &&
6372 (node->type != XML_CDATA_SECTION_NODE))
6373 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006374 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006375 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006376 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006377 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006378 cur++;
6379 }
6380
6381 return(1);
6382}
6383
6384/**
6385 * xmlTextConcat:
6386 * @node: the node
6387 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006388 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006389 *
6390 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006391 *
6392 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006393 */
6394
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006395int
Owen Taylor3473f882001-02-23 17:55:21 +00006396xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006397 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006398
6399 if ((node->type != XML_TEXT_NODE) &&
6400 (node->type != XML_CDATA_SECTION_NODE)) {
6401#ifdef DEBUG_TREE
6402 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006403 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006404#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006405 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006406 }
Owen Taylor3473f882001-02-23 17:55:21 +00006407 node->content = xmlStrncat(node->content, content, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006408 if (node->content == NULL)
6409 return(-1);
6410 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006411}
6412
6413/************************************************************************
6414 * *
6415 * Output : to a FILE or in memory *
6416 * *
6417 ************************************************************************/
6418
Owen Taylor3473f882001-02-23 17:55:21 +00006419/**
6420 * xmlBufferCreate:
6421 *
6422 * routine to create an XML buffer.
6423 * returns the new structure.
6424 */
6425xmlBufferPtr
6426xmlBufferCreate(void) {
6427 xmlBufferPtr ret;
6428
6429 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6430 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006431 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006432 return(NULL);
6433 }
6434 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006435 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006436 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006437 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006438 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006439 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006440 xmlFree(ret);
6441 return(NULL);
6442 }
6443 ret->content[0] = 0;
6444 return(ret);
6445}
6446
6447/**
6448 * xmlBufferCreateSize:
6449 * @size: initial size of buffer
6450 *
6451 * routine to create an XML buffer.
6452 * returns the new structure.
6453 */
6454xmlBufferPtr
6455xmlBufferCreateSize(size_t size) {
6456 xmlBufferPtr ret;
6457
6458 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6459 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006460 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006461 return(NULL);
6462 }
6463 ret->use = 0;
6464 ret->alloc = xmlBufferAllocScheme;
6465 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6466 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006467 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006468 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006469 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006470 xmlFree(ret);
6471 return(NULL);
6472 }
6473 ret->content[0] = 0;
6474 } else
6475 ret->content = NULL;
6476 return(ret);
6477}
6478
6479/**
Daniel Veillard53350552003-09-18 13:35:51 +00006480 * xmlBufferCreateStatic:
6481 * @mem: the memory area
6482 * @size: the size in byte
6483 *
6484 * routine to create an XML buffer from an immutable memory area,
6485 * The are won't be modified nor copied, and is expected to be
6486 * present until the end of the buffer lifetime.
6487 *
6488 * returns the new structure.
6489 */
6490xmlBufferPtr
6491xmlBufferCreateStatic(void *mem, size_t size) {
6492 xmlBufferPtr ret;
6493
6494 if ((mem == NULL) || (size == 0))
6495 return(NULL);
6496
6497 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6498 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006499 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00006500 return(NULL);
6501 }
6502 ret->use = size;
6503 ret->size = size;
6504 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6505 ret->content = (xmlChar *) mem;
6506 return(ret);
6507}
6508
6509/**
Owen Taylor3473f882001-02-23 17:55:21 +00006510 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006511 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006512 * @scheme: allocation scheme to use
6513 *
6514 * Sets the allocation scheme for this buffer
6515 */
6516void
6517xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6518 xmlBufferAllocationScheme scheme) {
6519 if (buf == NULL) {
6520#ifdef DEBUG_BUFFER
6521 xmlGenericError(xmlGenericErrorContext,
6522 "xmlBufferSetAllocationScheme: buf == NULL\n");
6523#endif
6524 return;
6525 }
Daniel Veillard53350552003-09-18 13:35:51 +00006526 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006527
6528 buf->alloc = scheme;
6529}
6530
6531/**
6532 * xmlBufferFree:
6533 * @buf: the buffer to free
6534 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006535 * Frees an XML buffer. It frees both the content and the structure which
6536 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006537 */
6538void
6539xmlBufferFree(xmlBufferPtr buf) {
6540 if (buf == NULL) {
6541#ifdef DEBUG_BUFFER
6542 xmlGenericError(xmlGenericErrorContext,
6543 "xmlBufferFree: buf == NULL\n");
6544#endif
6545 return;
6546 }
Daniel Veillard53350552003-09-18 13:35:51 +00006547
6548 if ((buf->content != NULL) &&
6549 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006550 xmlFree(buf->content);
6551 }
Owen Taylor3473f882001-02-23 17:55:21 +00006552 xmlFree(buf);
6553}
6554
6555/**
6556 * xmlBufferEmpty:
6557 * @buf: the buffer
6558 *
6559 * empty a buffer.
6560 */
6561void
6562xmlBufferEmpty(xmlBufferPtr buf) {
6563 if (buf->content == NULL) return;
6564 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006565 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00006566 buf->content = BAD_CAST "";
Daniel Veillard53350552003-09-18 13:35:51 +00006567 } else {
6568 memset(buf->content, 0, buf->size);
6569 }
Owen Taylor3473f882001-02-23 17:55:21 +00006570}
6571
6572/**
6573 * xmlBufferShrink:
6574 * @buf: the buffer to dump
6575 * @len: the number of xmlChar to remove
6576 *
6577 * Remove the beginning of an XML buffer.
6578 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006579 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006580 */
6581int
6582xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
6583 if (len == 0) return(0);
6584 if (len > buf->use) return(-1);
6585
6586 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006587 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6588 buf->content += len;
6589 } else {
6590 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6591 buf->content[buf->use] = 0;
6592 }
Owen Taylor3473f882001-02-23 17:55:21 +00006593 return(len);
6594}
6595
6596/**
6597 * xmlBufferGrow:
6598 * @buf: the buffer
6599 * @len: the minimum free size to allocate
6600 *
6601 * Grow the available space of an XML buffer.
6602 *
6603 * Returns the new available space or -1 in case of error
6604 */
6605int
6606xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6607 int size;
6608 xmlChar *newbuf;
6609
Daniel Veillard53350552003-09-18 13:35:51 +00006610 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006611 if (len + buf->use < buf->size) return(0);
6612
6613 size = buf->use + len + 100;
6614
6615 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006616 if (newbuf == NULL) {
6617 xmlTreeErrMemory("growing buffer");
6618 return(-1);
6619 }
Owen Taylor3473f882001-02-23 17:55:21 +00006620 buf->content = newbuf;
6621 buf->size = size;
6622 return(buf->size - buf->use);
6623}
6624
6625/**
6626 * xmlBufferDump:
6627 * @file: the file output
6628 * @buf: the buffer to dump
6629 *
6630 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006631 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006632 */
6633int
6634xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6635 int ret;
6636
6637 if (buf == NULL) {
6638#ifdef DEBUG_BUFFER
6639 xmlGenericError(xmlGenericErrorContext,
6640 "xmlBufferDump: buf == NULL\n");
6641#endif
6642 return(0);
6643 }
6644 if (buf->content == NULL) {
6645#ifdef DEBUG_BUFFER
6646 xmlGenericError(xmlGenericErrorContext,
6647 "xmlBufferDump: buf->content == NULL\n");
6648#endif
6649 return(0);
6650 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006651 if (file == NULL)
6652 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006653 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6654 return(ret);
6655}
6656
6657/**
6658 * xmlBufferContent:
6659 * @buf: the buffer
6660 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006661 * Function to extract the content of a buffer
6662 *
Owen Taylor3473f882001-02-23 17:55:21 +00006663 * Returns the internal content
6664 */
6665
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006666const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006667xmlBufferContent(const xmlBufferPtr buf)
6668{
6669 if(!buf)
6670 return NULL;
6671
6672 return buf->content;
6673}
6674
6675/**
6676 * xmlBufferLength:
6677 * @buf: the buffer
6678 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006679 * Function to get the length of a buffer
6680 *
Owen Taylor3473f882001-02-23 17:55:21 +00006681 * Returns the length of data in the internal content
6682 */
6683
6684int
6685xmlBufferLength(const xmlBufferPtr buf)
6686{
6687 if(!buf)
6688 return 0;
6689
6690 return buf->use;
6691}
6692
6693/**
6694 * xmlBufferResize:
6695 * @buf: the buffer to resize
6696 * @size: the desired size
6697 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006698 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006699 *
6700 * Returns 0 in case of problems, 1 otherwise
6701 */
6702int
6703xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6704{
6705 unsigned int newSize;
6706 xmlChar* rebuf = NULL;
6707
Daniel Veillard53350552003-09-18 13:35:51 +00006708 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6709
Owen Taylor3473f882001-02-23 17:55:21 +00006710 /*take care of empty case*/
6711 newSize = (buf->size ? buf->size*2 : size);
6712
6713 /* Don't resize if we don't have to */
6714 if (size < buf->size)
6715 return 1;
6716
6717 /* figure out new size */
6718 switch (buf->alloc){
6719 case XML_BUFFER_ALLOC_DOUBLEIT:
6720 while (size > newSize) newSize *= 2;
6721 break;
6722 case XML_BUFFER_ALLOC_EXACT:
6723 newSize = size+10;
6724 break;
6725 default:
6726 newSize = size+10;
6727 break;
6728 }
6729
6730 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006731 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006732 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006733 rebuf = (xmlChar *) xmlRealloc(buf->content,
6734 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006735 } else {
6736 /*
6737 * if we are reallocating a buffer far from being full, it's
6738 * better to make a new allocation and copy only the used range
6739 * and free the old one.
6740 */
6741 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6742 if (rebuf != NULL) {
6743 memcpy(rebuf, buf->content, buf->use);
6744 xmlFree(buf->content);
6745 }
Daniel Veillarde5984082003-08-19 22:21:13 +00006746 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006747 }
Owen Taylor3473f882001-02-23 17:55:21 +00006748 if (rebuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006749 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006750 return 0;
6751 }
6752 buf->content = rebuf;
6753 buf->size = newSize;
6754
6755 return 1;
6756}
6757
6758/**
6759 * xmlBufferAdd:
6760 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006761 * @str: the #xmlChar string
6762 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006763 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006764 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006765 * str is recomputed.
6766 */
6767void
6768xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6769 unsigned int needSize;
6770
6771 if (str == NULL) {
6772#ifdef DEBUG_BUFFER
6773 xmlGenericError(xmlGenericErrorContext,
6774 "xmlBufferAdd: str == NULL\n");
6775#endif
6776 return;
6777 }
Daniel Veillard53350552003-09-18 13:35:51 +00006778 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006779 if (len < -1) {
6780#ifdef DEBUG_BUFFER
6781 xmlGenericError(xmlGenericErrorContext,
6782 "xmlBufferAdd: len < 0\n");
6783#endif
6784 return;
6785 }
6786 if (len == 0) return;
6787
6788 if (len < 0)
6789 len = xmlStrlen(str);
6790
6791 if (len <= 0) return;
6792
6793 needSize = buf->use + len + 2;
6794 if (needSize > buf->size){
6795 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006796 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006797 return;
6798 }
6799 }
6800
6801 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6802 buf->use += len;
6803 buf->content[buf->use] = 0;
6804}
6805
6806/**
6807 * xmlBufferAddHead:
6808 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006809 * @str: the #xmlChar string
6810 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006811 *
6812 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006813 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00006814 */
6815void
6816xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6817 unsigned int needSize;
6818
Daniel Veillard53350552003-09-18 13:35:51 +00006819 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006820 if (str == NULL) {
6821#ifdef DEBUG_BUFFER
6822 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006823 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006824#endif
6825 return;
6826 }
6827 if (len < -1) {
6828#ifdef DEBUG_BUFFER
6829 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006830 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006831#endif
6832 return;
6833 }
6834 if (len == 0) return;
6835
6836 if (len < 0)
6837 len = xmlStrlen(str);
6838
6839 if (len <= 0) return;
6840
6841 needSize = buf->use + len + 2;
6842 if (needSize > buf->size){
6843 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006844 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006845 return;
6846 }
6847 }
6848
6849 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6850 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6851 buf->use += len;
6852 buf->content[buf->use] = 0;
6853}
6854
6855/**
6856 * xmlBufferCat:
6857 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006858 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006859 *
6860 * Append a zero terminated string to an XML buffer.
6861 */
6862void
6863xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillard53350552003-09-18 13:35:51 +00006864 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006865 if (str != NULL)
6866 xmlBufferAdd(buf, str, -1);
6867}
6868
6869/**
6870 * xmlBufferCCat:
6871 * @buf: the buffer to dump
6872 * @str: the C char string
6873 *
6874 * Append a zero terminated C string to an XML buffer.
6875 */
6876void
6877xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6878 const char *cur;
6879
Daniel Veillard53350552003-09-18 13:35:51 +00006880 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006881 if (str == NULL) {
6882#ifdef DEBUG_BUFFER
6883 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006884 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006885#endif
6886 return;
6887 }
6888 for (cur = str;*cur != 0;cur++) {
6889 if (buf->use + 10 >= buf->size) {
6890 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006891 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006892 return;
6893 }
6894 }
6895 buf->content[buf->use++] = *cur;
6896 }
6897 buf->content[buf->use] = 0;
6898}
6899
6900/**
6901 * xmlBufferWriteCHAR:
6902 * @buf: the XML buffer
6903 * @string: the string to add
6904 *
6905 * routine which manages and grows an output buffer. This one adds
6906 * xmlChars at the end of the buffer.
6907 */
6908void
Daniel Veillard53350552003-09-18 13:35:51 +00006909xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
6910 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006911 xmlBufferCat(buf, string);
6912}
6913
6914/**
6915 * xmlBufferWriteChar:
6916 * @buf: the XML buffer output
6917 * @string: the string to add
6918 *
6919 * routine which manage and grows an output buffer. This one add
6920 * C chars at the end of the array.
6921 */
6922void
6923xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillard53350552003-09-18 13:35:51 +00006924 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006925 xmlBufferCCat(buf, string);
6926}
6927
6928
6929/**
6930 * xmlBufferWriteQuotedString:
6931 * @buf: the XML buffer output
6932 * @string: the string to add
6933 *
6934 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00006935 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00006936 * quote or double-quotes internally
6937 */
6938void
6939xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00006940 const xmlChar *cur, *base;
Daniel Veillard53350552003-09-18 13:35:51 +00006941 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00006942 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00006943 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00006944#ifdef DEBUG_BUFFER
6945 xmlGenericError(xmlGenericErrorContext,
6946 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
6947#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00006948 xmlBufferCCat(buf, "\"");
6949 base = cur = string;
6950 while(*cur != 0){
6951 if(*cur == '"'){
6952 if (base != cur)
6953 xmlBufferAdd(buf, base, cur - base);
6954 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6955 cur++;
6956 base = cur;
6957 }
6958 else {
6959 cur++;
6960 }
6961 }
6962 if (base != cur)
6963 xmlBufferAdd(buf, base, cur - base);
6964 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006965 }
Daniel Veillard39057f42003-08-04 01:33:43 +00006966 else{
6967 xmlBufferCCat(buf, "\'");
6968 xmlBufferCat(buf, string);
6969 xmlBufferCCat(buf, "\'");
6970 }
Owen Taylor3473f882001-02-23 17:55:21 +00006971 } else {
6972 xmlBufferCCat(buf, "\"");
6973 xmlBufferCat(buf, string);
6974 xmlBufferCCat(buf, "\"");
6975 }
6976}
6977
6978
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00006979#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00006980/************************************************************************
6981 * *
Daniel Veillarde2238d52003-10-09 13:14:55 +00006982 * Output error handlers *
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006983 * *
6984 ************************************************************************/
6985/**
6986 * xmlSaveErrMemory:
6987 * @extra: extra informations
6988 *
6989 * Handle an out of memory condition
6990 */
6991static void
6992xmlSaveErrMemory(const char *extra)
6993{
6994 __xmlSimpleError(XML_FROM_OUTPUT, XML_ERR_NO_MEMORY, NULL, NULL, extra);
6995}
6996
6997/**
6998 * xmlSaveErr:
6999 * @code: the error number
7000 * @node: the location of the error.
7001 * @extra: extra informations
7002 *
7003 * Handle an out of memory condition
7004 */
7005static void
7006xmlSaveErr(int code, xmlNodePtr node, const char *extra)
7007{
7008 const char *msg = NULL;
7009
7010 switch(code) {
7011 case XML_SAVE_NOT_UTF8:
7012 msg = "string is not in UTF-8";
7013 break;
7014 case XML_SAVE_CHAR_INVALID:
7015 msg = "invalid character value";
7016 break;
7017 case XML_SAVE_UNKNOWN_ENCODING:
7018 msg = "unknown encoding %s";
7019 break;
Daniel Veillarde2238d52003-10-09 13:14:55 +00007020 case XML_SAVE_NO_DOCTYPE:
7021 msg = "document has no DOCTYPE";
7022 break;
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007023 default:
7024 msg = "unexpected error number";
7025 }
Daniel Veillarde2238d52003-10-09 13:14:55 +00007026 __xmlSimpleError(XML_FROM_OUTPUT, code, node, msg, extra);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007027}
7028/************************************************************************
7029 * *
Owen Taylor3473f882001-02-23 17:55:21 +00007030 * Dumping XML tree content to a simple buffer *
7031 * *
7032 ************************************************************************/
7033
Owen Taylor3473f882001-02-23 17:55:21 +00007034/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00007035 * xmlAttrSerializeContent:
7036 * @buf: the XML buffer output
7037 * @doc: the document
7038 * @attr: the attribute pointer
7039 *
7040 * Serialize the attribute in the buffer
7041 */
7042static void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007043xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr)
7044{
Daniel Veillarda6d05382002-02-13 13:07:41 +00007045 const xmlChar *cur, *base;
7046 xmlNodePtr children;
7047
7048 children = attr->children;
7049 while (children != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007050 switch (children->type) {
7051 case XML_TEXT_NODE:
7052 base = cur = children->content;
7053 while (*cur != 0) {
7054 if (*cur == '\n') {
7055 if (base != cur)
7056 xmlBufferAdd(buf, base, cur - base);
7057 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
7058 cur++;
7059 base = cur;
Daniel Veillard0046c0f2003-02-23 13:52:30 +00007060 } else if (*cur == '\r') {
7061 if (base != cur)
7062 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00007063 xmlBufferAdd(buf, BAD_CAST "&#13;", 5);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00007064 cur++;
7065 base = cur;
7066 } else if (*cur == '\t') {
7067 if (base != cur)
7068 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00007069 xmlBufferAdd(buf, BAD_CAST "&#9;", 4);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00007070 cur++;
7071 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00007072#if 0
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007073 } else if (*cur == '\'') {
7074 if (base != cur)
7075 xmlBufferAdd(buf, base, cur - base);
7076 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
7077 cur++;
7078 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00007079#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007080 } else if (*cur == '"') {
7081 if (base != cur)
7082 xmlBufferAdd(buf, base, cur - base);
7083 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7084 cur++;
7085 base = cur;
7086 } else if (*cur == '<') {
7087 if (base != cur)
7088 xmlBufferAdd(buf, base, cur - base);
7089 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
7090 cur++;
7091 base = cur;
7092 } else if (*cur == '>') {
7093 if (base != cur)
7094 xmlBufferAdd(buf, base, cur - base);
7095 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
7096 cur++;
7097 base = cur;
7098 } else if (*cur == '&') {
7099 if (base != cur)
7100 xmlBufferAdd(buf, base, cur - base);
7101 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
7102 cur++;
7103 base = cur;
7104 } else if ((*cur >= 0x80) && ((doc == NULL) ||
7105 (doc->encoding ==
7106 NULL))) {
7107 /*
7108 * We assume we have UTF-8 content.
7109 */
7110 char tmp[10];
7111 int val = 0, l = 1;
Daniel Veillarda6d05382002-02-13 13:07:41 +00007112
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007113 if (base != cur)
7114 xmlBufferAdd(buf, base, cur - base);
7115 if (*cur < 0xC0) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007116 xmlSaveErr(XML_SAVE_NOT_UTF8, (xmlNodePtr) attr,
7117 NULL);
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007118 if (doc != NULL)
7119 doc->encoding =
7120 xmlStrdup(BAD_CAST "ISO-8859-1");
7121 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
7122 tmp[sizeof(tmp) - 1] = 0;
7123 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
7124 cur++;
7125 base = cur;
7126 continue;
7127 } else if (*cur < 0xE0) {
7128 val = (cur[0]) & 0x1F;
7129 val <<= 6;
7130 val |= (cur[1]) & 0x3F;
7131 l = 2;
7132 } else if (*cur < 0xF0) {
7133 val = (cur[0]) & 0x0F;
7134 val <<= 6;
7135 val |= (cur[1]) & 0x3F;
7136 val <<= 6;
7137 val |= (cur[2]) & 0x3F;
7138 l = 3;
7139 } else if (*cur < 0xF8) {
7140 val = (cur[0]) & 0x07;
7141 val <<= 6;
7142 val |= (cur[1]) & 0x3F;
7143 val <<= 6;
7144 val |= (cur[2]) & 0x3F;
7145 val <<= 6;
7146 val |= (cur[3]) & 0x3F;
7147 l = 4;
7148 }
7149 if ((l == 1) || (!IS_CHAR(val))) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007150 xmlSaveErr(XML_SAVE_CHAR_INVALID, (xmlNodePtr) attr,
7151 NULL);
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007152 if (doc != NULL)
7153 doc->encoding =
7154 xmlStrdup(BAD_CAST "ISO-8859-1");
7155 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
7156 tmp[sizeof(tmp) - 1] = 0;
7157 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
7158 cur++;
7159 base = cur;
7160 continue;
7161 }
7162 /*
7163 * We could do multiple things here. Just save
7164 * as a char ref
7165 */
7166 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
7167 tmp[sizeof(tmp) - 1] = 0;
7168 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
7169 cur += l;
7170 base = cur;
7171 } else {
7172 cur++;
7173 }
7174 }
7175 if (base != cur)
7176 xmlBufferAdd(buf, base, cur - base);
7177 break;
7178 case XML_ENTITY_REF_NODE:
7179 xmlBufferAdd(buf, BAD_CAST "&", 1);
7180 xmlBufferAdd(buf, children->name,
7181 xmlStrlen(children->name));
7182 xmlBufferAdd(buf, BAD_CAST ";", 1);
7183 break;
7184 default:
7185 /* should not happen unless we have a badly built tree */
7186 break;
7187 }
7188 children = children->next;
Owen Taylor3473f882001-02-23 17:55:21 +00007189 }
7190}
7191
7192/**
7193 * xmlNodeDump:
7194 * @buf: the XML buffer output
7195 * @doc: the document
7196 * @cur: the current node
7197 * @level: the imbrication level for indenting
7198 * @format: is formatting allowed
7199 *
7200 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007201 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007202 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007203 *
7204 * Returns the number of bytes written to the buffer or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00007205 */
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007206int
Owen Taylor3473f882001-02-23 17:55:21 +00007207xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007208 int format)
7209{
7210 unsigned int use;
7211 int ret;
7212 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00007213
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007214 xmlInitParser();
7215
Owen Taylor3473f882001-02-23 17:55:21 +00007216 if (cur == NULL) {
7217#ifdef DEBUG_TREE
7218 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007219 "xmlNodeDump : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007220#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007221 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007222 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007223 if (buf == NULL) {
7224#ifdef DEBUG_TREE
7225 xmlGenericError(xmlGenericErrorContext,
7226 "xmlNodeDump : buf == NULL\n");
7227#endif
7228 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007229 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007230 outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
7231 if (outbuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007232 xmlSaveErrMemory("creating buffer");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007233 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007234 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007235 memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
7236 outbuf->buffer = buf;
7237 outbuf->encoder = NULL;
7238 outbuf->writecallback = NULL;
7239 outbuf->closecallback = NULL;
7240 outbuf->context = NULL;
7241 outbuf->written = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007242
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007243 use = buf->use;
7244 xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
7245 xmlFree(outbuf);
7246 ret = buf->use - use;
7247 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00007248}
7249
7250/**
7251 * xmlElemDump:
7252 * @f: the FILE * for the output
7253 * @doc: the document
7254 * @cur: the current node
7255 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007256 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00007257 */
7258void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007259xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur)
7260{
7261 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00007262
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007263 xmlInitParser();
7264
Owen Taylor3473f882001-02-23 17:55:21 +00007265 if (cur == NULL) {
7266#ifdef DEBUG_TREE
7267 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007268 "xmlElemDump : cur == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007269#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007270 return;
Owen Taylor3473f882001-02-23 17:55:21 +00007271 }
Owen Taylor3473f882001-02-23 17:55:21 +00007272#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007273 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00007274 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007275 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007276 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007277#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007278
7279 outbuf = xmlOutputBufferCreateFile(f, NULL);
7280 if (outbuf == NULL)
7281 return;
7282 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007283#ifdef LIBXML_HTML_ENABLED
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007284 htmlNodeDumpOutput(outbuf, doc, cur, NULL);
7285#else
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007286 xmlSaveErr(XML_ERR_INTERNAL_ERROR, "HTML support not compiled in\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007287#endif /* LIBXML_HTML_ENABLED */
7288 } else
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007289 xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL);
7290 xmlOutputBufferClose(outbuf);
Owen Taylor3473f882001-02-23 17:55:21 +00007291}
7292
7293/************************************************************************
7294 * *
7295 * Dumping XML tree content to an I/O output buffer *
7296 * *
7297 ************************************************************************/
7298
Daniel Veillard4432df22003-09-28 18:58:27 +00007299#ifdef LIBXML_HTML_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00007300static void
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007301xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7302 int level, int format, const char *encoding);
Daniel Veillard4432df22003-09-28 18:58:27 +00007303#endif
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007304static void
Owen Taylor3473f882001-02-23 17:55:21 +00007305xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7306 int level, int format, const char *encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007307static void
7308xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
7309 xmlNodePtr cur, int level, int format, const char *encoding);
7310
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00007311void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
7312
Owen Taylor3473f882001-02-23 17:55:21 +00007313/**
7314 * xmlNsDumpOutput:
7315 * @buf: the XML buffer output
7316 * @cur: a namespace
7317 *
7318 * Dump a local Namespace definition.
7319 * Should be called in the context of attributes dumps.
7320 */
7321static void
7322xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
7323 if (cur == NULL) {
7324#ifdef DEBUG_TREE
7325 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007326 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007327#endif
7328 return;
7329 }
7330 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00007331 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
7332 return;
7333
Owen Taylor3473f882001-02-23 17:55:21 +00007334 /* Within the context of an element attributes */
7335 if (cur->prefix != NULL) {
7336 xmlOutputBufferWriteString(buf, " xmlns:");
7337 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
7338 } else
7339 xmlOutputBufferWriteString(buf, " xmlns");
7340 xmlOutputBufferWriteString(buf, "=");
7341 xmlBufferWriteQuotedString(buf->buffer, cur->href);
7342 }
7343}
7344
7345/**
7346 * xmlNsListDumpOutput:
7347 * @buf: the XML buffer output
7348 * @cur: the first namespace
7349 *
7350 * Dump a list of local Namespace definitions.
7351 * Should be called in the context of attributes dumps.
7352 */
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00007353void
Owen Taylor3473f882001-02-23 17:55:21 +00007354xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
7355 while (cur != NULL) {
7356 xmlNsDumpOutput(buf, cur);
7357 cur = cur->next;
7358 }
7359}
7360
7361/**
7362 * xmlDtdDumpOutput:
7363 * @buf: the XML buffer output
7364 * @doc: the document
7365 * @encoding: an optional encoding string
7366 *
7367 * Dump the XML document DTD, if any.
7368 */
7369static void
7370xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
7371 if (dtd == NULL) {
7372#ifdef DEBUG_TREE
7373 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007374 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007375#endif
7376 return;
7377 }
7378 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
7379 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
7380 if (dtd->ExternalID != NULL) {
7381 xmlOutputBufferWriteString(buf, " PUBLIC ");
7382 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
7383 xmlOutputBufferWriteString(buf, " ");
7384 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
7385 } else if (dtd->SystemID != NULL) {
7386 xmlOutputBufferWriteString(buf, " SYSTEM ");
7387 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
7388 }
7389 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
7390 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
7391 xmlOutputBufferWriteString(buf, ">");
7392 return;
7393 }
7394 xmlOutputBufferWriteString(buf, " [\n");
7395 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
7396 xmlOutputBufferWriteString(buf, "]>");
7397}
7398
7399/**
7400 * xmlAttrDumpOutput:
7401 * @buf: the XML buffer output
7402 * @doc: the document
7403 * @cur: the attribute pointer
7404 * @encoding: an optional encoding string
7405 *
7406 * Dump an XML attribute
7407 */
7408static void
7409xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00007410 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00007411 if (cur == NULL) {
7412#ifdef DEBUG_TREE
7413 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007414 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007415#endif
7416 return;
7417 }
7418 xmlOutputBufferWriteString(buf, " ");
7419 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7420 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7421 xmlOutputBufferWriteString(buf, ":");
7422 }
7423 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00007424 xmlOutputBufferWriteString(buf, "=\"");
7425 xmlAttrSerializeContent(buf->buffer, doc, cur);
7426 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007427}
7428
7429/**
7430 * xmlAttrListDumpOutput:
7431 * @buf: the XML buffer output
7432 * @doc: the document
7433 * @cur: the first attribute pointer
7434 * @encoding: an optional encoding string
7435 *
7436 * Dump a list of XML attributes
7437 */
7438static void
7439xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7440 xmlAttrPtr cur, const char *encoding) {
7441 if (cur == NULL) {
7442#ifdef DEBUG_TREE
7443 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007444 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007445#endif
7446 return;
7447 }
7448 while (cur != NULL) {
7449 xmlAttrDumpOutput(buf, doc, cur, encoding);
7450 cur = cur->next;
7451 }
7452}
7453
7454
7455
7456/**
7457 * xmlNodeListDumpOutput:
7458 * @buf: the XML buffer output
7459 * @doc: the document
7460 * @cur: the first node
7461 * @level: the imbrication level for indenting
7462 * @format: is formatting allowed
7463 * @encoding: an optional encoding string
7464 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007465 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007466 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007467 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007468 */
7469static void
7470xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7471 xmlNodePtr cur, int level, int format, const char *encoding) {
7472 int i;
7473
7474 if (cur == NULL) {
7475#ifdef DEBUG_TREE
7476 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007477 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007478#endif
7479 return;
7480 }
7481 while (cur != NULL) {
7482 if ((format) && (xmlIndentTreeOutput) &&
7483 (cur->type == XML_ELEMENT_NODE))
7484 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007485 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007486 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007487 if (format) {
7488 xmlOutputBufferWriteString(buf, "\n");
7489 }
7490 cur = cur->next;
7491 }
7492}
7493
7494/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007495 * xmlNodeDumpOutputInternal:
Owen Taylor3473f882001-02-23 17:55:21 +00007496 * @buf: the XML buffer output
7497 * @doc: the document
7498 * @cur: the current node
7499 * @level: the imbrication level for indenting
7500 * @format: is formatting allowed
7501 * @encoding: an optional encoding string
7502 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007503 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007504 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007505 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007506 */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007507static void
7508xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
7509 xmlNodePtr cur, int level, int format, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007510 int i;
7511 xmlNodePtr tmp;
Daniel Veillard9475a352003-09-26 12:47:50 +00007512 xmlChar *start, *end;
Owen Taylor3473f882001-02-23 17:55:21 +00007513
7514 if (cur == NULL) {
7515#ifdef DEBUG_TREE
7516 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007517 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007518#endif
7519 return;
7520 }
7521 if (cur->type == XML_XINCLUDE_START)
7522 return;
7523 if (cur->type == XML_XINCLUDE_END)
7524 return;
7525 if (cur->type == XML_DTD_NODE) {
7526 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7527 return;
7528 }
7529 if (cur->type == XML_ELEMENT_DECL) {
7530 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7531 return;
7532 }
7533 if (cur->type == XML_ATTRIBUTE_DECL) {
7534 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7535 return;
7536 }
7537 if (cur->type == XML_ENTITY_DECL) {
7538 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7539 return;
7540 }
7541 if (cur->type == XML_TEXT_NODE) {
7542 if (cur->content != NULL) {
7543 if ((cur->name == xmlStringText) ||
7544 (cur->name != xmlStringTextNoenc)) {
7545 xmlChar *buffer;
7546
Owen Taylor3473f882001-02-23 17:55:21 +00007547 if (encoding == NULL)
7548 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7549 else
7550 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007551 if (buffer != NULL) {
7552 xmlOutputBufferWriteString(buf, (const char *)buffer);
7553 xmlFree(buffer);
7554 }
7555 } else {
7556 /*
7557 * Disable escaping, needed for XSLT
7558 */
Owen Taylor3473f882001-02-23 17:55:21 +00007559 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007560 }
7561 }
7562
7563 return;
7564 }
7565 if (cur->type == XML_PI_NODE) {
7566 if (cur->content != NULL) {
7567 xmlOutputBufferWriteString(buf, "<?");
7568 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7569 if (cur->content != NULL) {
7570 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00007571 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007572 }
7573 xmlOutputBufferWriteString(buf, "?>");
7574 } else {
7575 xmlOutputBufferWriteString(buf, "<?");
7576 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7577 xmlOutputBufferWriteString(buf, "?>");
7578 }
7579 return;
7580 }
7581 if (cur->type == XML_COMMENT_NODE) {
7582 if (cur->content != NULL) {
7583 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00007584 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007585 xmlOutputBufferWriteString(buf, "-->");
7586 }
7587 return;
7588 }
7589 if (cur->type == XML_ENTITY_REF_NODE) {
7590 xmlOutputBufferWriteString(buf, "&");
7591 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7592 xmlOutputBufferWriteString(buf, ";");
7593 return;
7594 }
7595 if (cur->type == XML_CDATA_SECTION_NODE) {
Daniel Veillard9475a352003-09-26 12:47:50 +00007596 start = end = cur->content;
7597 while (*end != '\0') {
7598 if ((*end == ']') && (*(end + 1) == ']') && (*(end + 2) == '>')) {
7599 end = end + 2;
7600 xmlOutputBufferWriteString(buf, "<![CDATA[");
7601 xmlOutputBufferWrite(buf, end - start, (const char *)start);
7602 xmlOutputBufferWriteString(buf, "]]>");
7603 start = end;
7604 }
7605 end++;
7606 }
7607 if (start != end) {
7608 xmlOutputBufferWriteString(buf, "<![CDATA[");
7609 xmlOutputBufferWriteString(buf, (const char *)start);
7610 xmlOutputBufferWriteString(buf, "]]>");
7611 }
Owen Taylor3473f882001-02-23 17:55:21 +00007612 return;
7613 }
Daniel Veillard7b72ee52003-02-27 23:24:53 +00007614 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillarda1a9d042003-03-18 16:53:17 +00007615 xmlAttrDumpOutput(buf,doc, (xmlAttrPtr) cur,encoding);
Daniel Veillard7b72ee52003-02-27 23:24:53 +00007616 return;
7617 }
Daniel Veillard6aa2f602003-02-10 00:01:56 +00007618 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007619 xmlNsDumpOutput(buf, (xmlNsPtr) cur);
Daniel Veillard6aa2f602003-02-10 00:01:56 +00007620 return;
7621 }
Owen Taylor3473f882001-02-23 17:55:21 +00007622
7623 if (format == 1) {
7624 tmp = cur->children;
7625 while (tmp != NULL) {
William M. Brack9ca682f2003-10-19 10:01:59 +00007626 if ((tmp->type == XML_TEXT_NODE) ||
7627 (tmp->type == XML_CDATA_SECTION_NODE) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007628 (tmp->type == XML_ENTITY_REF_NODE)) {
7629 format = 0;
7630 break;
7631 }
7632 tmp = tmp->next;
7633 }
7634 }
7635 xmlOutputBufferWriteString(buf, "<");
7636 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7637 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7638 xmlOutputBufferWriteString(buf, ":");
7639 }
7640
7641 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7642 if (cur->nsDef)
7643 xmlNsListDumpOutput(buf, cur->nsDef);
7644 if (cur->properties != NULL)
7645 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7646
Daniel Veillard7db37732001-07-12 01:20:08 +00007647 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
7648 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007649 xmlOutputBufferWriteString(buf, "/>");
7650 return;
7651 }
7652 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00007653 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007654 xmlChar *buffer;
7655
Owen Taylor3473f882001-02-23 17:55:21 +00007656 if (encoding == NULL)
7657 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7658 else
7659 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007660 if (buffer != NULL) {
7661 xmlOutputBufferWriteString(buf, (const char *)buffer);
7662 xmlFree(buffer);
7663 }
7664 }
7665 if (cur->children != NULL) {
7666 if (format) xmlOutputBufferWriteString(buf, "\n");
7667 xmlNodeListDumpOutput(buf, doc, cur->children,
7668 (level >= 0?level+1:-1), format, encoding);
7669 if ((xmlIndentTreeOutput) && (format))
7670 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007671 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00007672 }
7673 xmlOutputBufferWriteString(buf, "</");
7674 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7675 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7676 xmlOutputBufferWriteString(buf, ":");
7677 }
7678
7679 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7680 xmlOutputBufferWriteString(buf, ">");
7681}
7682
7683/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007684 * xmlNodeDumpOutput:
7685 * @buf: the XML buffer output
7686 * @doc: the document
7687 * @cur: the current node
7688 * @level: the imbrication level for indenting
7689 * @format: is formatting allowed
7690 * @encoding: an optional encoding string
7691 *
7692 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007693 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007694 * or xmlKeepBlanksDefault(0) was called
7695 */
7696void
7697xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007698 int level, int format, const char *encoding)
7699{
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007700#ifdef LIBXML_HTML_ENABLED
7701 xmlDtdPtr dtd;
7702 int is_xhtml = 0;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007703#endif
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007704
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007705 xmlInitParser();
7706
7707#ifdef LIBXML_HTML_ENABLED
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007708 dtd = xmlGetIntSubset(doc);
7709 if (dtd != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007710 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7711 if (is_xhtml < 0)
7712 is_xhtml = 0;
7713 if ((is_xhtml) && (cur->parent == (xmlNodePtr) doc) &&
7714 (cur->type == XML_ELEMENT_NODE) &&
7715 (xmlStrEqual(cur->name, BAD_CAST "html"))) {
7716 if (encoding != NULL)
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007717 htmlSetMetaEncoding((htmlDocPtr) doc,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007718 (const xmlChar *) encoding);
7719 else
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007720 htmlSetMetaEncoding((htmlDocPtr) doc, BAD_CAST "UTF-8");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007721 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007722 }
7723
7724 if (is_xhtml)
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007725 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007726 else
7727#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007728 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007729}
7730
7731/**
Owen Taylor3473f882001-02-23 17:55:21 +00007732 * xmlDocContentDumpOutput:
7733 * @buf: the XML buffer output
7734 * @cur: the document
7735 * @encoding: an optional encoding string
7736 * @format: should formatting spaces been added
7737 *
7738 * Dump an XML document.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007739 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007740 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007741 */
7742static void
7743xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
7744 const char *encoding, int format) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007745#ifdef LIBXML_HTML_ENABLED
7746 xmlDtdPtr dtd;
7747 int is_xhtml = 0;
7748#endif
7749
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007750 xmlInitParser();
7751
Owen Taylor3473f882001-02-23 17:55:21 +00007752 xmlOutputBufferWriteString(buf, "<?xml version=");
7753 if (cur->version != NULL)
7754 xmlBufferWriteQuotedString(buf->buffer, cur->version);
7755 else
7756 xmlOutputBufferWriteString(buf, "\"1.0\"");
7757 if (encoding == NULL) {
7758 if (cur->encoding != NULL)
7759 encoding = (const char *) cur->encoding;
7760 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
7761 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
7762 }
7763 if (encoding != NULL) {
7764 xmlOutputBufferWriteString(buf, " encoding=");
7765 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
7766 }
7767 switch (cur->standalone) {
7768 case 0:
7769 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
7770 break;
7771 case 1:
7772 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
7773 break;
7774 }
7775 xmlOutputBufferWriteString(buf, "?>\n");
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007776
7777#ifdef LIBXML_HTML_ENABLED
7778 dtd = xmlGetIntSubset(cur);
7779 if (dtd != NULL) {
7780 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7781 if (is_xhtml < 0) is_xhtml = 0;
7782 }
7783 if (is_xhtml) {
7784 if (encoding != NULL)
7785 htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
7786 else
7787 htmlSetMetaEncoding(cur, BAD_CAST "UTF-8");
7788 }
7789#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007790 if (cur->children != NULL) {
7791 xmlNodePtr child = cur->children;
7792
7793 while (child != NULL) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007794#ifdef LIBXML_HTML_ENABLED
7795 if (is_xhtml)
7796 xhtmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
7797 else
7798#endif
7799 xmlNodeDumpOutputInternal(buf, cur, child, 0, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007800 xmlOutputBufferWriteString(buf, "\n");
7801 child = child->next;
7802 }
7803 }
7804}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007805#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00007806
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007807#ifdef LIBXML_HTML_ENABLED
7808/************************************************************************
7809 * *
7810 * Functions specific to XHTML serialization *
7811 * *
7812 ************************************************************************/
7813
7814#define XHTML_STRICT_PUBLIC_ID BAD_CAST \
7815 "-//W3C//DTD XHTML 1.0 Strict//EN"
7816#define XHTML_STRICT_SYSTEM_ID BAD_CAST \
7817 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
7818#define XHTML_FRAME_PUBLIC_ID BAD_CAST \
7819 "-//W3C//DTD XHTML 1.0 Frameset//EN"
7820#define XHTML_FRAME_SYSTEM_ID BAD_CAST \
7821 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
7822#define XHTML_TRANS_PUBLIC_ID BAD_CAST \
7823 "-//W3C//DTD XHTML 1.0 Transitional//EN"
7824#define XHTML_TRANS_SYSTEM_ID BAD_CAST \
7825 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
7826
7827#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
7828/**
7829 * xmlIsXHTML:
7830 * @systemID: the system identifier
7831 * @publicID: the public identifier
7832 *
7833 * Try to find if the document correspond to an XHTML DTD
7834 *
7835 * Returns 1 if true, 0 if not and -1 in case of error
7836 */
7837int
7838xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) {
7839 if ((systemID == NULL) && (publicID == NULL))
7840 return(-1);
7841 if (publicID != NULL) {
7842 if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1);
7843 if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1);
7844 if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1);
7845 }
7846 if (systemID != NULL) {
7847 if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1);
7848 if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1);
7849 if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1);
7850 }
7851 return(0);
7852}
7853
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007854#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007855/**
7856 * xhtmlIsEmpty:
7857 * @node: the node
7858 *
7859 * Check if a node is an empty xhtml node
7860 *
7861 * Returns 1 if the node is an empty node, 0 if not and -1 in case of error
7862 */
7863static int
7864xhtmlIsEmpty(xmlNodePtr node) {
7865 if (node == NULL)
7866 return(-1);
7867 if (node->type != XML_ELEMENT_NODE)
7868 return(0);
7869 if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME)))
7870 return(0);
7871 if (node->children != NULL)
7872 return(0);
7873 switch (node->name[0]) {
7874 case 'a':
7875 if (xmlStrEqual(node->name, BAD_CAST "area"))
7876 return(1);
7877 return(0);
7878 case 'b':
7879 if (xmlStrEqual(node->name, BAD_CAST "br"))
7880 return(1);
7881 if (xmlStrEqual(node->name, BAD_CAST "base"))
7882 return(1);
7883 if (xmlStrEqual(node->name, BAD_CAST "basefont"))
7884 return(1);
7885 return(0);
7886 case 'c':
7887 if (xmlStrEqual(node->name, BAD_CAST "col"))
7888 return(1);
7889 return(0);
7890 case 'f':
7891 if (xmlStrEqual(node->name, BAD_CAST "frame"))
7892 return(1);
7893 return(0);
7894 case 'h':
7895 if (xmlStrEqual(node->name, BAD_CAST "hr"))
7896 return(1);
7897 return(0);
7898 case 'i':
7899 if (xmlStrEqual(node->name, BAD_CAST "img"))
7900 return(1);
7901 if (xmlStrEqual(node->name, BAD_CAST "input"))
7902 return(1);
7903 if (xmlStrEqual(node->name, BAD_CAST "isindex"))
7904 return(1);
7905 return(0);
7906 case 'l':
7907 if (xmlStrEqual(node->name, BAD_CAST "link"))
7908 return(1);
7909 return(0);
7910 case 'm':
7911 if (xmlStrEqual(node->name, BAD_CAST "meta"))
7912 return(1);
7913 return(0);
7914 case 'p':
7915 if (xmlStrEqual(node->name, BAD_CAST "param"))
7916 return(1);
7917 return(0);
7918 }
7919 return(0);
7920}
7921
7922/**
7923 * xhtmlAttrListDumpOutput:
7924 * @buf: the XML buffer output
7925 * @doc: the document
7926 * @cur: the first attribute pointer
7927 * @encoding: an optional encoding string
7928 *
7929 * Dump a list of XML attributes
7930 */
7931static void
7932xhtmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7933 xmlAttrPtr cur, const char *encoding) {
7934 xmlAttrPtr xml_lang = NULL;
7935 xmlAttrPtr lang = NULL;
7936 xmlAttrPtr name = NULL;
7937 xmlAttrPtr id = NULL;
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007938 xmlNodePtr parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007939
7940 if (cur == NULL) {
7941#ifdef DEBUG_TREE
7942 xmlGenericError(xmlGenericErrorContext,
7943 "xmlAttrListDumpOutput : property == NULL\n");
7944#endif
7945 return;
7946 }
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007947 parent = cur->parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007948 while (cur != NULL) {
7949 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id")))
7950 id = cur;
7951 else
7952 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name")))
7953 name = cur;
7954 else
7955 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")))
7956 lang = cur;
7957 else
7958 if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) &&
7959 (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml")))
7960 xml_lang = cur;
7961 else if ((cur->ns == NULL) &&
7962 ((cur->children == NULL) ||
7963 (cur->children->content == NULL) ||
7964 (cur->children->content[0] == 0)) &&
7965 (htmlIsBooleanAttr(cur->name))) {
7966 if (cur->children != NULL)
7967 xmlFreeNode(cur->children);
7968 cur->children = xmlNewText(cur->name);
7969 if (cur->children != NULL)
7970 cur->children->parent = (xmlNodePtr) cur;
7971 }
7972 xmlAttrDumpOutput(buf, doc, cur, encoding);
7973 cur = cur->next;
7974 }
7975 /*
7976 * C.8
7977 */
7978 if ((name != NULL) && (id == NULL)) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007979 if ((parent != NULL) && (parent->name != NULL) &&
7980 ((xmlStrEqual(parent->name, BAD_CAST "a")) ||
7981 (xmlStrEqual(parent->name, BAD_CAST "p")) ||
7982 (xmlStrEqual(parent->name, BAD_CAST "div")) ||
7983 (xmlStrEqual(parent->name, BAD_CAST "img")) ||
7984 (xmlStrEqual(parent->name, BAD_CAST "map")) ||
7985 (xmlStrEqual(parent->name, BAD_CAST "applet")) ||
7986 (xmlStrEqual(parent->name, BAD_CAST "form")) ||
7987 (xmlStrEqual(parent->name, BAD_CAST "frame")) ||
7988 (xmlStrEqual(parent->name, BAD_CAST "iframe")))) {
7989 xmlOutputBufferWriteString(buf, " id=\"");
7990 xmlAttrSerializeContent(buf->buffer, doc, name);
7991 xmlOutputBufferWriteString(buf, "\"");
7992 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007993 }
7994 /*
7995 * C.7.
7996 */
7997 if ((lang != NULL) && (xml_lang == NULL)) {
7998 xmlOutputBufferWriteString(buf, " xml:lang=\"");
7999 xmlAttrSerializeContent(buf->buffer, doc, lang);
8000 xmlOutputBufferWriteString(buf, "\"");
8001 } else
8002 if ((xml_lang != NULL) && (lang == NULL)) {
8003 xmlOutputBufferWriteString(buf, " lang=\"");
8004 xmlAttrSerializeContent(buf->buffer, doc, xml_lang);
8005 xmlOutputBufferWriteString(buf, "\"");
8006 }
8007}
8008
8009/**
8010 * xhtmlNodeListDumpOutput:
8011 * @buf: the XML buffer output
8012 * @doc: the XHTML document
8013 * @cur: the first node
8014 * @level: the imbrication level for indenting
8015 * @format: is formatting allowed
8016 * @encoding: an optional encoding string
8017 *
8018 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008019 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00008020 * or xmlKeepBlanksDefault(0) was called
8021 */
8022static void
8023xhtmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
8024 xmlNodePtr cur, int level, int format, const char *encoding) {
8025 int i;
8026
8027 if (cur == NULL) {
8028#ifdef DEBUG_TREE
8029 xmlGenericError(xmlGenericErrorContext,
8030 "xhtmlNodeListDumpOutput : node == NULL\n");
8031#endif
8032 return;
8033 }
8034 while (cur != NULL) {
8035 if ((format) && (xmlIndentTreeOutput) &&
8036 (cur->type == XML_ELEMENT_NODE))
8037 for (i = 0;i < level;i++)
8038 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
8039 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
8040 if (format) {
8041 xmlOutputBufferWriteString(buf, "\n");
8042 }
8043 cur = cur->next;
8044 }
8045}
8046
8047/**
8048 * xhtmlNodeDumpOutput:
8049 * @buf: the XML buffer output
8050 * @doc: the XHTML document
8051 * @cur: the current node
8052 * @level: the imbrication level for indenting
8053 * @format: is formatting allowed
8054 * @encoding: an optional encoding string
8055 *
8056 * Dump an XHTML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008057 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00008058 * or xmlKeepBlanksDefault(0) was called
8059 */
8060static void
8061xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
8062 int level, int format, const char *encoding) {
8063 int i;
8064 xmlNodePtr tmp;
Daniel Veillard9475a352003-09-26 12:47:50 +00008065 xmlChar *start, *end;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00008066
8067 if (cur == NULL) {
8068#ifdef DEBUG_TREE
8069 xmlGenericError(xmlGenericErrorContext,
8070 "xmlNodeDumpOutput : node == NULL\n");
8071#endif
8072 return;
8073 }
8074 if (cur->type == XML_XINCLUDE_START)
8075 return;
8076 if (cur->type == XML_XINCLUDE_END)
8077 return;
8078 if (cur->type == XML_DTD_NODE) {
8079 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
8080 return;
8081 }
8082 if (cur->type == XML_ELEMENT_DECL) {
8083 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
8084 return;
8085 }
8086 if (cur->type == XML_ATTRIBUTE_DECL) {
8087 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
8088 return;
8089 }
8090 if (cur->type == XML_ENTITY_DECL) {
8091 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
8092 return;
8093 }
8094 if (cur->type == XML_TEXT_NODE) {
8095 if (cur->content != NULL) {
8096 if ((cur->name == xmlStringText) ||
8097 (cur->name != xmlStringTextNoenc)) {
8098 xmlChar *buffer;
8099
8100 if (encoding == NULL)
8101 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
8102 else
8103 buffer = xmlEncodeSpecialChars(doc, cur->content);
8104 if (buffer != NULL) {
8105 xmlOutputBufferWriteString(buf, (const char *)buffer);
8106 xmlFree(buffer);
8107 }
8108 } else {
8109 /*
8110 * Disable escaping, needed for XSLT
8111 */
8112 xmlOutputBufferWriteString(buf, (const char *) cur->content);
8113 }
8114 }
8115
8116 return;
8117 }
8118 if (cur->type == XML_PI_NODE) {
8119 if (cur->content != NULL) {
8120 xmlOutputBufferWriteString(buf, "<?");
8121 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8122 if (cur->content != NULL) {
8123 xmlOutputBufferWriteString(buf, " ");
8124 xmlOutputBufferWriteString(buf, (const char *)cur->content);
8125 }
8126 xmlOutputBufferWriteString(buf, "?>");
8127 } else {
8128 xmlOutputBufferWriteString(buf, "<?");
8129 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8130 xmlOutputBufferWriteString(buf, "?>");
8131 }
8132 return;
8133 }
8134 if (cur->type == XML_COMMENT_NODE) {
8135 if (cur->content != NULL) {
8136 xmlOutputBufferWriteString(buf, "<!--");
8137 xmlOutputBufferWriteString(buf, (const char *)cur->content);
8138 xmlOutputBufferWriteString(buf, "-->");
8139 }
8140 return;
8141 }
8142 if (cur->type == XML_ENTITY_REF_NODE) {
8143 xmlOutputBufferWriteString(buf, "&");
8144 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8145 xmlOutputBufferWriteString(buf, ";");
8146 return;
8147 }
8148 if (cur->type == XML_CDATA_SECTION_NODE) {
Daniel Veillard9475a352003-09-26 12:47:50 +00008149 start = end = cur->content;
8150 while (*end != '\0') {
8151 if (*end == ']' && *(end + 1) == ']' && *(end + 2) == '>') {
8152 end = end + 2;
8153 xmlOutputBufferWriteString(buf, "<![CDATA[");
8154 xmlOutputBufferWrite(buf, end - start, (const char *)start);
8155 xmlOutputBufferWriteString(buf, "]]>");
8156 start = end;
8157 }
8158 end++;
8159 }
8160 if (start != end) {
8161 xmlOutputBufferWriteString(buf, "<![CDATA[");
8162 xmlOutputBufferWriteString(buf, (const char *)start);
8163 xmlOutputBufferWriteString(buf, "]]>");
8164 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00008165 return;
8166 }
8167
8168 if (format == 1) {
8169 tmp = cur->children;
8170 while (tmp != NULL) {
8171 if ((tmp->type == XML_TEXT_NODE) ||
8172 (tmp->type == XML_ENTITY_REF_NODE)) {
8173 format = 0;
8174 break;
8175 }
8176 tmp = tmp->next;
8177 }
8178 }
8179 xmlOutputBufferWriteString(buf, "<");
8180 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
8181 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
8182 xmlOutputBufferWriteString(buf, ":");
8183 }
8184
8185 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8186 if (cur->nsDef)
8187 xmlNsListDumpOutput(buf, cur->nsDef);
8188 if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
8189 (cur->ns == NULL) && (cur->nsDef == NULL))) {
8190 /*
8191 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
8192 */
8193 xmlOutputBufferWriteString(buf,
8194 " xmlns=\"http://www.w3.org/1999/xhtml\"");
8195 }
8196 if (cur->properties != NULL)
8197 xhtmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
8198
8199 if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) {
8200 if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
8201 (xhtmlIsEmpty(cur) == 1)) {
8202 /*
8203 * C.2. Empty Elements
8204 */
8205 xmlOutputBufferWriteString(buf, " />");
8206 } else {
8207 /*
8208 * C.3. Element Minimization and Empty Element Content
8209 */
8210 xmlOutputBufferWriteString(buf, "></");
8211 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
8212 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
8213 xmlOutputBufferWriteString(buf, ":");
8214 }
8215 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8216 xmlOutputBufferWriteString(buf, ">");
8217 }
8218 return;
8219 }
8220 xmlOutputBufferWriteString(buf, ">");
8221 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
8222 xmlChar *buffer;
8223
8224 if (encoding == NULL)
8225 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
8226 else
8227 buffer = xmlEncodeSpecialChars(doc, cur->content);
8228 if (buffer != NULL) {
8229 xmlOutputBufferWriteString(buf, (const char *)buffer);
8230 xmlFree(buffer);
8231 }
8232 }
8233
8234 /*
8235 * 4.8. Script and Style elements
8236 */
8237 if ((cur->type == XML_ELEMENT_NODE) &&
8238 ((xmlStrEqual(cur->name, BAD_CAST "script")) ||
8239 (xmlStrEqual(cur->name, BAD_CAST "style"))) &&
8240 ((cur->ns == NULL) ||
8241 (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) {
8242 xmlNodePtr child = cur->children;
8243
8244 while (child != NULL) {
8245 if ((child->type == XML_TEXT_NODE) ||
8246 (child->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard64b35282002-12-04 15:10:40 +00008247 /*
8248 * Apparently CDATA escaping for style just break on IE,
8249 * mozilla and galeon, so ...
8250 */
8251 if (xmlStrEqual(cur->name, BAD_CAST "style") &&
8252 (xmlStrchr(child->content, '<') == NULL) &&
8253 (xmlStrchr(child->content, '>') == NULL) &&
8254 (xmlStrchr(child->content, '&') == NULL)) {
8255 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
8256 } else {
Daniel Veillard9475a352003-09-26 12:47:50 +00008257 start = end = child->content;
8258 while (*end != '\0') {
8259 if (*end == ']' &&
8260 *(end + 1) == ']' &&
8261 *(end + 2) == '>') {
8262 end = end + 2;
8263 xmlOutputBufferWriteString(buf, "<![CDATA[");
8264 xmlOutputBufferWrite(buf, end - start,
8265 (const char *)start);
8266 xmlOutputBufferWriteString(buf, "]]>");
8267 start = end;
8268 }
8269 end++;
8270 }
8271 if (start != end) {
8272 xmlOutputBufferWriteString(buf, "<![CDATA[");
8273 xmlOutputBufferWriteString(buf, (const char *)start);
8274 xmlOutputBufferWriteString(buf, "]]>");
8275 }
Daniel Veillard64b35282002-12-04 15:10:40 +00008276 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00008277 } else {
8278 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
8279 }
8280 child = child->next;
8281 }
8282 } else if (cur->children != NULL) {
8283 if (format) xmlOutputBufferWriteString(buf, "\n");
8284 xhtmlNodeListDumpOutput(buf, doc, cur->children,
8285 (level >= 0?level+1:-1), format, encoding);
8286 if ((xmlIndentTreeOutput) && (format))
8287 for (i = 0;i < level;i++)
8288 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
8289 }
8290 xmlOutputBufferWriteString(buf, "</");
8291 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
8292 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
8293 xmlOutputBufferWriteString(buf, ":");
8294 }
8295
8296 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8297 xmlOutputBufferWriteString(buf, ">");
8298}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00008299#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00008300#endif
8301
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00008302#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00008303/************************************************************************
8304 * *
8305 * Saving functions front-ends *
8306 * *
8307 ************************************************************************/
8308
8309/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00008310 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00008311 * @out_doc: Document to generate XML text from
8312 * @doc_txt_ptr: Memory pointer for allocated XML text
8313 * @doc_txt_len: Length of the generated XML text
8314 * @txt_encoding: Character encoding to use when generating XML text
8315 * @format: should formatting spaces been added
8316 *
8317 * Dump the current DOM tree into memory using the character encoding specified
8318 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008319 * allocated memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00008320 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00008321 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008322 */
8323
8324void
8325xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008326 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008327 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00008328 int dummy = 0;
8329
Owen Taylor3473f882001-02-23 17:55:21 +00008330 xmlOutputBufferPtr out_buff = NULL;
8331 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
8332
8333 if (doc_txt_len == NULL) {
8334 doc_txt_len = &dummy; /* Continue, caller just won't get length */
8335 }
8336
8337 if (doc_txt_ptr == NULL) {
8338 *doc_txt_len = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008339 return;
8340 }
8341
8342 *doc_txt_ptr = NULL;
8343 *doc_txt_len = 0;
8344
8345 if (out_doc == NULL) {
8346 /* No document, no output */
Owen Taylor3473f882001-02-23 17:55:21 +00008347 return;
8348 }
8349
8350 /*
8351 * Validate the encoding value, if provided.
8352 * This logic is copied from xmlSaveFileEnc.
8353 */
8354
8355 if (txt_encoding == NULL)
8356 txt_encoding = (const char *) out_doc->encoding;
8357 if (txt_encoding != NULL) {
Daniel Veillarde1326112003-06-05 09:32:20 +00008358 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00008359 if ( conv_hdlr == NULL ) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00008360 xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, (xmlNodePtr) out_doc,
8361 txt_encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00008362 return;
8363 }
8364 }
Owen Taylor3473f882001-02-23 17:55:21 +00008365
8366 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00008367 xmlSaveErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00008368 return;
8369 }
8370
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008371 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008372 xmlOutputBufferFlush(out_buff);
8373 if (out_buff->conv != NULL) {
8374 *doc_txt_len = out_buff->conv->use;
8375 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
8376 } else {
8377 *doc_txt_len = out_buff->buffer->use;
8378 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
8379 }
8380 (void)xmlOutputBufferClose(out_buff);
8381
8382 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
8383 *doc_txt_len = 0;
Daniel Veillard18ec16e2003-10-07 23:16:40 +00008384 xmlSaveErrMemory("creating output");
Owen Taylor3473f882001-02-23 17:55:21 +00008385 }
8386
8387 return;
8388}
8389
8390/**
8391 * xmlDocDumpMemory:
8392 * @cur: the document
8393 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00008394 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00008395 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008396 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008397 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00008398 */
8399void
8400xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
8401 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
8402}
8403
8404/**
8405 * xmlDocDumpFormatMemory:
8406 * @cur: the document
8407 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00008408 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00008409 * @format: should formatting spaces been added
8410 *
8411 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008412 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008413 * It's up to the caller to free the memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00008414 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00008415 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008416 */
8417void
8418xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
8419 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
8420}
8421
8422/**
8423 * xmlDocDumpMemoryEnc:
8424 * @out_doc: Document to generate XML text from
8425 * @doc_txt_ptr: Memory pointer for allocated XML text
8426 * @doc_txt_len: Length of the generated XML text
8427 * @txt_encoding: Character encoding to use when generating XML text
8428 *
8429 * Dump the current DOM tree into memory using the character encoding specified
8430 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008431 * allocated memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00008432 */
8433
8434void
8435xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
8436 int * doc_txt_len, const char * txt_encoding) {
8437 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008438 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008439}
8440
8441/**
Daniel Veillard9e412302002-06-10 15:59:44 +00008442 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00008443 * @f: the FILE*
8444 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00008445 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00008446 *
8447 * Dump an XML document to an open FILE.
8448 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008449 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008450 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8451 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008452 */
8453int
Daniel Veillard9e412302002-06-10 15:59:44 +00008454xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00008455 xmlOutputBufferPtr buf;
8456 const char * encoding;
8457 xmlCharEncodingHandlerPtr handler = NULL;
8458 int ret;
8459
8460 if (cur == NULL) {
8461#ifdef DEBUG_TREE
8462 xmlGenericError(xmlGenericErrorContext,
8463 "xmlDocDump : document == NULL\n");
8464#endif
8465 return(-1);
8466 }
8467 encoding = (const char *) cur->encoding;
8468
8469 if (encoding != NULL) {
Daniel Veillarde1326112003-06-05 09:32:20 +00008470 handler = xmlFindCharEncodingHandler(encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00008471 if (handler == NULL) {
8472 xmlFree((char *) cur->encoding);
8473 cur->encoding = NULL;
8474 }
8475 }
Owen Taylor3473f882001-02-23 17:55:21 +00008476 buf = xmlOutputBufferCreateFile(f, handler);
8477 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00008478 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008479
8480 ret = xmlOutputBufferClose(buf);
8481 return(ret);
8482}
8483
8484/**
Daniel Veillard9e412302002-06-10 15:59:44 +00008485 * xmlDocDump:
8486 * @f: the FILE*
8487 * @cur: the document
8488 *
8489 * Dump an XML document to an open FILE.
8490 *
8491 * returns: the number of bytes written or -1 in case of failure.
8492 */
8493int
8494xmlDocDump(FILE *f, xmlDocPtr cur) {
Daniel Veillard828ce832003-10-08 19:19:10 +00008495 return(xmlDocFormatDump (f, cur, 0));
Daniel Veillard9e412302002-06-10 15:59:44 +00008496}
8497
8498/**
Owen Taylor3473f882001-02-23 17:55:21 +00008499 * xmlSaveFileTo:
8500 * @buf: an output I/O buffer
8501 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00008502 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00008503 *
8504 * Dump an XML document to an I/O buffer.
8505 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008506 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008507 */
8508int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00008509xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00008510 int ret;
8511
8512 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008513 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008514 ret = xmlOutputBufferClose(buf);
8515 return(ret);
8516}
8517
8518/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00008519 * xmlSaveFormatFileTo:
8520 * @buf: an output I/O buffer
8521 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00008522 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00008523 * @format: should formatting spaces been added
8524 *
8525 * Dump an XML document to an I/O buffer.
8526 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008527 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008528 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8529 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardeefd4492001-04-28 16:55:50 +00008530 */
8531int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00008532xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00008533 int ret;
8534
8535 if (buf == NULL) return(0);
8536 xmlDocContentDumpOutput(buf, cur, encoding, format);
8537 ret = xmlOutputBufferClose(buf);
8538 return(ret);
8539}
8540
8541/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00008542 * xmlSaveFormatFileEnc:
Daniel Veillardf012a642001-07-23 19:10:52 +00008543 * @filename: the filename or URL to output
8544 * @cur: the document being saved
8545 * @encoding: the name of the encoding to use or NULL.
8546 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00008547 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00008548 * Dump an XML document to a file or an URL.
8549 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008550 * Returns the number of bytes written or -1 in case of error.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008551 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8552 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008553 */
8554int
Daniel Veillardf012a642001-07-23 19:10:52 +00008555xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
8556 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00008557 xmlOutputBufferPtr buf;
8558 xmlCharEncodingHandlerPtr handler = NULL;
8559 int ret;
8560
Daniel Veillard4dbe77a2003-01-14 00:17:42 +00008561 if (cur == NULL)
8562 return(-1);
8563
Daniel Veillardfb25a512002-01-13 20:32:08 +00008564 if (encoding == NULL)
8565 encoding = (const char *) cur->encoding;
8566
Owen Taylor3473f882001-02-23 17:55:21 +00008567 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00008568
Owen Taylor3473f882001-02-23 17:55:21 +00008569 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00008570 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00008571 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00008572 }
8573
Daniel Veillardf012a642001-07-23 19:10:52 +00008574#ifdef HAVE_ZLIB_H
8575 if (cur->compression < 0) cur->compression = xmlCompressMode;
8576#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008577 /*
8578 * save the content to a temp buffer.
8579 */
Daniel Veillardf012a642001-07-23 19:10:52 +00008580 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00008581 if (buf == NULL) return(-1);
8582
Daniel Veillardf012a642001-07-23 19:10:52 +00008583 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008584
8585 ret = xmlOutputBufferClose(buf);
8586 return(ret);
8587}
8588
Daniel Veillardf012a642001-07-23 19:10:52 +00008589
8590/**
8591 * xmlSaveFileEnc:
8592 * @filename: the filename (or URL)
8593 * @cur: the document
8594 * @encoding: the name of an encoding (or NULL)
8595 *
8596 * Dump an XML document, converting it to the given encoding
8597 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008598 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00008599 */
8600int
8601xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
8602 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
8603}
8604
Owen Taylor3473f882001-02-23 17:55:21 +00008605/**
Daniel Veillard67fee942001-04-26 18:59:03 +00008606 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00008607 * @filename: the filename (or URL)
8608 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00008609 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00008610 *
8611 * Dump an XML document to a file. Will use compression if
8612 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00008613 * used. If @format is set then the document will be indented on output.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008614 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8615 * or xmlKeepBlanksDefault(0) was called
Daniel Veillard67fee942001-04-26 18:59:03 +00008616 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008617 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008618 */
8619int
Daniel Veillard67fee942001-04-26 18:59:03 +00008620xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008621 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00008622}
8623
Daniel Veillard67fee942001-04-26 18:59:03 +00008624/**
8625 * xmlSaveFile:
8626 * @filename: the filename (or URL)
8627 * @cur: the document
8628 *
8629 * Dump an XML document to a file. Will use compression if
8630 * compiled in and enabled. If @filename is "-" the stdout file is
8631 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00008632 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00008633 */
8634int
8635xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008636 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00008637}
8638
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00008639#endif /* LIBXML_OUTPUT_ENABLED */
8640
8641/**
8642 * xmlGetDocCompressMode:
8643 * @doc: the document
8644 *
8645 * get the compression ratio for a document, ZLIB based
8646 * Returns 0 (uncompressed) to 9 (max compression)
8647 */
8648int
8649xmlGetDocCompressMode (xmlDocPtr doc) {
8650 if (doc == NULL) return(-1);
8651 return(doc->compression);
8652}
8653
8654/**
8655 * xmlSetDocCompressMode:
8656 * @doc: the document
8657 * @mode: the compression ratio
8658 *
8659 * set the compression ratio for a document, ZLIB based
8660 * Correct values: 0 (uncompressed) to 9 (max compression)
8661 */
8662void
8663xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
8664 if (doc == NULL) return;
8665 if (mode < 0) doc->compression = 0;
8666 else if (mode > 9) doc->compression = 9;
8667 else doc->compression = mode;
8668}
8669
8670/**
8671 * xmlGetCompressMode:
8672 *
8673 * get the default compression mode used, ZLIB based.
8674 * Returns 0 (uncompressed) to 9 (max compression)
8675 */
8676int
8677xmlGetCompressMode(void)
8678{
8679 return (xmlCompressMode);
8680}
8681
8682/**
8683 * xmlSetCompressMode:
8684 * @mode: the compression ratio
8685 *
8686 * set the default compression mode used, ZLIB based
8687 * Correct values: 0 (uncompressed) to 9 (max compression)
8688 */
8689void
8690xmlSetCompressMode(int mode) {
8691 if (mode < 0) xmlCompressMode = 0;
8692 else if (mode > 9) xmlCompressMode = 9;
8693 else xmlCompressMode = mode;
8694}
8695