blob: c232960b29332c74c29fec23cafafb7a1187b8c8 [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 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002110 * Returns a pointer to the new node object. Uses xmlStrdup() to make
2111 * copy of @name.
Owen Taylor3473f882001-02-23 17:55:21 +00002112 */
2113xmlNodePtr
2114xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2115 xmlNodePtr cur;
2116
2117 if (name == NULL) {
2118#ifdef DEBUG_TREE
2119 xmlGenericError(xmlGenericErrorContext,
2120 "xmlNewNode : name == NULL\n");
2121#endif
2122 return(NULL);
2123 }
2124
2125 /*
2126 * Allocate a new node and fill the fields.
2127 */
2128 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2129 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002130 xmlTreeErrMemory("building node");
Owen Taylor3473f882001-02-23 17:55:21 +00002131 return(NULL);
2132 }
2133 memset(cur, 0, sizeof(xmlNode));
2134 cur->type = XML_ELEMENT_NODE;
2135
2136 cur->name = xmlStrdup(name);
2137 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002138
Daniel Veillarda880b122003-04-21 21:36:41 +00002139 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002140 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002141 return(cur);
2142}
2143
2144/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00002145 * xmlNewNodeEatName:
2146 * @ns: namespace if any
2147 * @name: the node name
2148 *
2149 * Creation of a new node element. @ns is optional (NULL).
2150 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002151 * Returns a pointer to the new node object, with pointer @name as
2152 * new node's name. Use xmlNewNode() if a copy of @name string is
2153 * is needed as new node's name.
Daniel Veillard46de64e2002-05-29 08:21:33 +00002154 */
2155xmlNodePtr
2156xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2157 xmlNodePtr cur;
2158
2159 if (name == NULL) {
2160#ifdef DEBUG_TREE
2161 xmlGenericError(xmlGenericErrorContext,
2162 "xmlNewNode : name == NULL\n");
2163#endif
2164 return(NULL);
2165 }
2166
2167 /*
2168 * Allocate a new node and fill the fields.
2169 */
2170 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2171 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002172 xmlTreeErrMemory("building node");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00002173 xmlFree(name);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002174 return(NULL);
2175 }
2176 memset(cur, 0, sizeof(xmlNode));
2177 cur->type = XML_ELEMENT_NODE;
2178
2179 cur->name = name;
2180 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002181
Daniel Veillarda880b122003-04-21 21:36:41 +00002182 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002183 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002184 return(cur);
2185}
2186
2187/**
Owen Taylor3473f882001-02-23 17:55:21 +00002188 * xmlNewDocNode:
2189 * @doc: the document
2190 * @ns: namespace if any
2191 * @name: the node name
2192 * @content: the XML text content if any
2193 *
2194 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002195 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002196 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2197 * references, but XML special chars need to be escaped first by using
2198 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2199 * need entities support.
2200 *
2201 * Returns a pointer to the new node object.
2202 */
2203xmlNodePtr
2204xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2205 const xmlChar *name, const xmlChar *content) {
2206 xmlNodePtr cur;
2207
2208 cur = xmlNewNode(ns, name);
2209 if (cur != NULL) {
2210 cur->doc = doc;
2211 if (content != NULL) {
2212 cur->children = xmlStringGetNodeList(doc, content);
2213 UPDATE_LAST_CHILD_AND_PARENT(cur)
2214 }
2215 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002216
Owen Taylor3473f882001-02-23 17:55:21 +00002217 return(cur);
2218}
2219
Daniel Veillard46de64e2002-05-29 08:21:33 +00002220/**
2221 * xmlNewDocNodeEatName:
2222 * @doc: the document
2223 * @ns: namespace if any
2224 * @name: the node name
2225 * @content: the XML text content if any
2226 *
2227 * Creation of a new node element within a document. @ns and @content
2228 * are optional (NULL).
2229 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2230 * references, but XML special chars need to be escaped first by using
2231 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2232 * need entities support.
2233 *
2234 * Returns a pointer to the new node object.
2235 */
2236xmlNodePtr
2237xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2238 xmlChar *name, const xmlChar *content) {
2239 xmlNodePtr cur;
2240
2241 cur = xmlNewNodeEatName(ns, name);
2242 if (cur != NULL) {
2243 cur->doc = doc;
2244 if (content != NULL) {
2245 cur->children = xmlStringGetNodeList(doc, content);
2246 UPDATE_LAST_CHILD_AND_PARENT(cur)
2247 }
2248 }
2249 return(cur);
2250}
2251
Daniel Veillard652327a2003-09-29 18:02:38 +00002252#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002253/**
2254 * xmlNewDocRawNode:
2255 * @doc: the document
2256 * @ns: namespace if any
2257 * @name: the node name
2258 * @content: the text content if any
2259 *
2260 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002261 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002262 *
2263 * Returns a pointer to the new node object.
2264 */
2265xmlNodePtr
2266xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2267 const xmlChar *name, const xmlChar *content) {
2268 xmlNodePtr cur;
2269
2270 cur = xmlNewNode(ns, name);
2271 if (cur != NULL) {
2272 cur->doc = doc;
2273 if (content != NULL) {
2274 cur->children = xmlNewDocText(doc, content);
2275 UPDATE_LAST_CHILD_AND_PARENT(cur)
2276 }
2277 }
2278 return(cur);
2279}
2280
2281/**
2282 * xmlNewDocFragment:
2283 * @doc: the document owning the fragment
2284 *
2285 * Creation of a new Fragment node.
2286 * Returns a pointer to the new node object.
2287 */
2288xmlNodePtr
2289xmlNewDocFragment(xmlDocPtr doc) {
2290 xmlNodePtr cur;
2291
2292 /*
2293 * Allocate a new DocumentFragment node and fill the fields.
2294 */
2295 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2296 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002297 xmlTreeErrMemory("building fragment");
Owen Taylor3473f882001-02-23 17:55:21 +00002298 return(NULL);
2299 }
2300 memset(cur, 0, sizeof(xmlNode));
2301 cur->type = XML_DOCUMENT_FRAG_NODE;
2302
2303 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002304
Daniel Veillarda880b122003-04-21 21:36:41 +00002305 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002306 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002307 return(cur);
2308}
Daniel Veillard652327a2003-09-29 18:02:38 +00002309#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002310
2311/**
2312 * xmlNewText:
2313 * @content: the text content
2314 *
2315 * Creation of a new text node.
2316 * Returns a pointer to the new node object.
2317 */
2318xmlNodePtr
2319xmlNewText(const xmlChar *content) {
2320 xmlNodePtr cur;
2321
2322 /*
2323 * Allocate a new node and fill the fields.
2324 */
2325 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2326 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002327 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002328 return(NULL);
2329 }
2330 memset(cur, 0, sizeof(xmlNode));
2331 cur->type = XML_TEXT_NODE;
2332
2333 cur->name = xmlStringText;
2334 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002335 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002336 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002337
Daniel Veillarda880b122003-04-21 21:36:41 +00002338 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002339 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002340 return(cur);
2341}
2342
Daniel Veillard652327a2003-09-29 18:02:38 +00002343#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002344/**
2345 * xmlNewTextChild:
2346 * @parent: the parent node
2347 * @ns: a namespace if any
2348 * @name: the name of the child
2349 * @content: the text content of the child if any.
2350 *
2351 * Creation of a new child element, added at the end of @parent children list.
William M. Brackd7cf7f82003-11-14 07:13:16 +00002352 * @ns and @content parameters are optional (NULL). If @content is non NULL,
2353 * a child TEXT node will be created containing the string @content.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002354 * NOTE: Use xmlNewChild() if @content will contain entities that need to be
2355 * preserved. Use this function, xmlNewTextChild(), if you need to ensure that
2356 * reserved XML chars that might appear in @content, such as the ampersand,
2357 * greater-than or less-than signs, are automatically replaced by their XML
2358 * escaped entity representations.
Owen Taylor3473f882001-02-23 17:55:21 +00002359 *
2360 * Returns a pointer to the new node object.
2361 */
2362xmlNodePtr
2363xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2364 const xmlChar *name, const xmlChar *content) {
2365 xmlNodePtr cur, prev;
2366
2367 if (parent == NULL) {
2368#ifdef DEBUG_TREE
2369 xmlGenericError(xmlGenericErrorContext,
2370 "xmlNewTextChild : parent == NULL\n");
2371#endif
2372 return(NULL);
2373 }
2374
2375 if (name == NULL) {
2376#ifdef DEBUG_TREE
2377 xmlGenericError(xmlGenericErrorContext,
2378 "xmlNewTextChild : name == NULL\n");
2379#endif
2380 return(NULL);
2381 }
2382
2383 /*
2384 * Allocate a new node
2385 */
Daniel Veillard254b1262003-11-01 17:04:58 +00002386 if (parent->type == XML_ELEMENT_NODE) {
2387 if (ns == NULL)
2388 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2389 else
2390 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2391 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2392 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2393 if (ns == NULL)
2394 cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2395 else
2396 cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2397 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2398 cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2399 } else {
2400 return(NULL);
2401 }
Owen Taylor3473f882001-02-23 17:55:21 +00002402 if (cur == NULL) return(NULL);
2403
2404 /*
2405 * add the new element at the end of the children list.
2406 */
2407 cur->type = XML_ELEMENT_NODE;
2408 cur->parent = parent;
2409 cur->doc = parent->doc;
2410 if (parent->children == NULL) {
2411 parent->children = cur;
2412 parent->last = cur;
2413 } else {
2414 prev = parent->last;
2415 prev->next = cur;
2416 cur->prev = prev;
2417 parent->last = cur;
2418 }
2419
2420 return(cur);
2421}
Daniel Veillard652327a2003-09-29 18:02:38 +00002422#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002423
2424/**
2425 * xmlNewCharRef:
2426 * @doc: the document
2427 * @name: the char ref string, starting with # or "&# ... ;"
2428 *
2429 * Creation of a new character reference node.
2430 * Returns a pointer to the new node object.
2431 */
2432xmlNodePtr
2433xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2434 xmlNodePtr cur;
2435
2436 /*
2437 * Allocate a new node and fill the fields.
2438 */
2439 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2440 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002441 xmlTreeErrMemory("building character reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002442 return(NULL);
2443 }
2444 memset(cur, 0, sizeof(xmlNode));
2445 cur->type = XML_ENTITY_REF_NODE;
2446
2447 cur->doc = doc;
2448 if (name[0] == '&') {
2449 int len;
2450 name++;
2451 len = xmlStrlen(name);
2452 if (name[len - 1] == ';')
2453 cur->name = xmlStrndup(name, len - 1);
2454 else
2455 cur->name = xmlStrndup(name, len);
2456 } else
2457 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002458
Daniel Veillarda880b122003-04-21 21:36:41 +00002459 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002460 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002461 return(cur);
2462}
2463
2464/**
2465 * xmlNewReference:
2466 * @doc: the document
2467 * @name: the reference name, or the reference string with & and ;
2468 *
2469 * Creation of a new reference node.
2470 * Returns a pointer to the new node object.
2471 */
2472xmlNodePtr
2473xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2474 xmlNodePtr cur;
2475 xmlEntityPtr ent;
2476
2477 /*
2478 * Allocate a new node and fill the fields.
2479 */
2480 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2481 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002482 xmlTreeErrMemory("building reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002483 return(NULL);
2484 }
2485 memset(cur, 0, sizeof(xmlNode));
2486 cur->type = XML_ENTITY_REF_NODE;
2487
2488 cur->doc = doc;
2489 if (name[0] == '&') {
2490 int len;
2491 name++;
2492 len = xmlStrlen(name);
2493 if (name[len - 1] == ';')
2494 cur->name = xmlStrndup(name, len - 1);
2495 else
2496 cur->name = xmlStrndup(name, len);
2497 } else
2498 cur->name = xmlStrdup(name);
2499
2500 ent = xmlGetDocEntity(doc, cur->name);
2501 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002502 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002503 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002504 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002505 * updated. Not sure if this is 100% correct.
2506 * -George
2507 */
2508 cur->children = (xmlNodePtr) ent;
2509 cur->last = (xmlNodePtr) ent;
2510 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002511
Daniel Veillarda880b122003-04-21 21:36:41 +00002512 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002513 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002514 return(cur);
2515}
2516
2517/**
2518 * xmlNewDocText:
2519 * @doc: the document
2520 * @content: the text content
2521 *
2522 * Creation of a new text node within a document.
2523 * Returns a pointer to the new node object.
2524 */
2525xmlNodePtr
2526xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2527 xmlNodePtr cur;
2528
2529 cur = xmlNewText(content);
2530 if (cur != NULL) cur->doc = doc;
2531 return(cur);
2532}
2533
2534/**
2535 * xmlNewTextLen:
2536 * @content: the text content
2537 * @len: the text len.
2538 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002539 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002540 * Returns a pointer to the new node object.
2541 */
2542xmlNodePtr
2543xmlNewTextLen(const xmlChar *content, int len) {
2544 xmlNodePtr cur;
2545
2546 /*
2547 * Allocate a new node and fill the fields.
2548 */
2549 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2550 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002551 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002552 return(NULL);
2553 }
2554 memset(cur, 0, sizeof(xmlNode));
2555 cur->type = XML_TEXT_NODE;
2556
2557 cur->name = xmlStringText;
2558 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002559 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002560 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002561
Daniel Veillarda880b122003-04-21 21:36:41 +00002562 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002563 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002564 return(cur);
2565}
2566
2567/**
2568 * xmlNewDocTextLen:
2569 * @doc: the document
2570 * @content: the text content
2571 * @len: the text len.
2572 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002573 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002574 * text node pertain to a given document.
2575 * Returns a pointer to the new node object.
2576 */
2577xmlNodePtr
2578xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2579 xmlNodePtr cur;
2580
2581 cur = xmlNewTextLen(content, len);
2582 if (cur != NULL) cur->doc = doc;
2583 return(cur);
2584}
2585
2586/**
2587 * xmlNewComment:
2588 * @content: the comment content
2589 *
2590 * Creation of a new node containing a comment.
2591 * Returns a pointer to the new node object.
2592 */
2593xmlNodePtr
2594xmlNewComment(const xmlChar *content) {
2595 xmlNodePtr cur;
2596
2597 /*
2598 * Allocate a new node and fill the fields.
2599 */
2600 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2601 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002602 xmlTreeErrMemory("building comment");
Owen Taylor3473f882001-02-23 17:55:21 +00002603 return(NULL);
2604 }
2605 memset(cur, 0, sizeof(xmlNode));
2606 cur->type = XML_COMMENT_NODE;
2607
2608 cur->name = xmlStringComment;
2609 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002610 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002611 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002612
Daniel Veillarda880b122003-04-21 21:36:41 +00002613 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002614 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002615 return(cur);
2616}
2617
2618/**
2619 * xmlNewCDataBlock:
2620 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002621 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002622 * @len: the length of the block
2623 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002624 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002625 * Returns a pointer to the new node object.
2626 */
2627xmlNodePtr
2628xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2629 xmlNodePtr cur;
2630
2631 /*
2632 * Allocate a new node and fill the fields.
2633 */
2634 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2635 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002636 xmlTreeErrMemory("building CDATA");
Owen Taylor3473f882001-02-23 17:55:21 +00002637 return(NULL);
2638 }
2639 memset(cur, 0, sizeof(xmlNode));
2640 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002641 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002642
2643 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002644 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002645 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002646
Daniel Veillarda880b122003-04-21 21:36:41 +00002647 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002648 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002649 return(cur);
2650}
2651
2652/**
2653 * xmlNewDocComment:
2654 * @doc: the document
2655 * @content: the comment content
2656 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002657 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002658 * Returns a pointer to the new node object.
2659 */
2660xmlNodePtr
2661xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2662 xmlNodePtr cur;
2663
2664 cur = xmlNewComment(content);
2665 if (cur != NULL) cur->doc = doc;
2666 return(cur);
2667}
2668
2669/**
2670 * xmlSetTreeDoc:
2671 * @tree: the top element
2672 * @doc: the document
2673 *
2674 * update all nodes under the tree to point to the right document
2675 */
2676void
2677xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002678 xmlAttrPtr prop;
2679
Owen Taylor3473f882001-02-23 17:55:21 +00002680 if (tree == NULL)
2681 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002682 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002683 if(tree->type == XML_ELEMENT_NODE) {
2684 prop = tree->properties;
2685 while (prop != NULL) {
2686 prop->doc = doc;
2687 xmlSetListDoc(prop->children, doc);
2688 prop = prop->next;
2689 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002690 }
Owen Taylor3473f882001-02-23 17:55:21 +00002691 if (tree->children != NULL)
2692 xmlSetListDoc(tree->children, doc);
2693 tree->doc = doc;
2694 }
2695}
2696
2697/**
2698 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002699 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002700 * @doc: the document
2701 *
2702 * update all nodes in the list to point to the right document
2703 */
2704void
2705xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2706 xmlNodePtr cur;
2707
2708 if (list == NULL)
2709 return;
2710 cur = list;
2711 while (cur != NULL) {
2712 if (cur->doc != doc)
2713 xmlSetTreeDoc(cur, doc);
2714 cur = cur->next;
2715 }
2716}
2717
Daniel Veillard652327a2003-09-29 18:02:38 +00002718#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002719/**
2720 * xmlNewChild:
2721 * @parent: the parent node
2722 * @ns: a namespace if any
2723 * @name: the name of the child
2724 * @content: the XML content of the child if any.
2725 *
2726 * Creation of a new child element, added at the end of @parent children list.
William M. Brackd7cf7f82003-11-14 07:13:16 +00002727 * @ns and @content parameters are optional (NULL). If @content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002728 * a child list containing the TEXTs and ENTITY_REFs node will be created.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002729 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
2730 * references. XML special chars must be escaped first by using
2731 * xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used.
Owen Taylor3473f882001-02-23 17:55:21 +00002732 *
2733 * Returns a pointer to the new node object.
2734 */
2735xmlNodePtr
2736xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2737 const xmlChar *name, const xmlChar *content) {
2738 xmlNodePtr cur, prev;
2739
2740 if (parent == NULL) {
2741#ifdef DEBUG_TREE
2742 xmlGenericError(xmlGenericErrorContext,
2743 "xmlNewChild : parent == NULL\n");
2744#endif
2745 return(NULL);
2746 }
2747
2748 if (name == NULL) {
2749#ifdef DEBUG_TREE
2750 xmlGenericError(xmlGenericErrorContext,
2751 "xmlNewChild : name == NULL\n");
2752#endif
2753 return(NULL);
2754 }
2755
2756 /*
2757 * Allocate a new node
2758 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002759 if (parent->type == XML_ELEMENT_NODE) {
2760 if (ns == NULL)
2761 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2762 else
2763 cur = xmlNewDocNode(parent->doc, ns, name, content);
2764 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2765 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2766 if (ns == NULL)
2767 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2768 else
2769 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002770 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2771 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002772 } else {
2773 return(NULL);
2774 }
Owen Taylor3473f882001-02-23 17:55:21 +00002775 if (cur == NULL) return(NULL);
2776
2777 /*
2778 * add the new element at the end of the children list.
2779 */
2780 cur->type = XML_ELEMENT_NODE;
2781 cur->parent = parent;
2782 cur->doc = parent->doc;
2783 if (parent->children == NULL) {
2784 parent->children = cur;
2785 parent->last = cur;
2786 } else {
2787 prev = parent->last;
2788 prev->next = cur;
2789 cur->prev = prev;
2790 parent->last = cur;
2791 }
2792
2793 return(cur);
2794}
Daniel Veillard652327a2003-09-29 18:02:38 +00002795#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002796
2797/**
2798 * xmlAddNextSibling:
2799 * @cur: the child node
2800 * @elem: the new node
2801 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002802 * Add a new node @elem as the next sibling of @cur
2803 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002804 * first unlinked from its existing context.
2805 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002806 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2807 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002808 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002809 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002810 */
2811xmlNodePtr
2812xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2813 if (cur == NULL) {
2814#ifdef DEBUG_TREE
2815 xmlGenericError(xmlGenericErrorContext,
2816 "xmlAddNextSibling : cur == NULL\n");
2817#endif
2818 return(NULL);
2819 }
2820 if (elem == NULL) {
2821#ifdef DEBUG_TREE
2822 xmlGenericError(xmlGenericErrorContext,
2823 "xmlAddNextSibling : elem == NULL\n");
2824#endif
2825 return(NULL);
2826 }
2827
2828 xmlUnlinkNode(elem);
2829
2830 if (elem->type == XML_TEXT_NODE) {
2831 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002832 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002833 xmlFreeNode(elem);
2834 return(cur);
2835 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002836 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2837 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002838 xmlChar *tmp;
2839
2840 tmp = xmlStrdup(elem->content);
2841 tmp = xmlStrcat(tmp, cur->next->content);
2842 xmlNodeSetContent(cur->next, tmp);
2843 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002844 xmlFreeNode(elem);
2845 return(cur->next);
2846 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002847 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2848 /* check if an attribute with the same name exists */
2849 xmlAttrPtr attr;
2850
2851 if (elem->ns == NULL)
2852 attr = xmlHasProp(cur->parent, elem->name);
2853 else
2854 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2855 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2856 /* different instance, destroy it (attributes must be unique) */
2857 xmlFreeProp(attr);
2858 }
Owen Taylor3473f882001-02-23 17:55:21 +00002859 }
2860
2861 if (elem->doc != cur->doc) {
2862 xmlSetTreeDoc(elem, cur->doc);
2863 }
2864 elem->parent = cur->parent;
2865 elem->prev = cur;
2866 elem->next = cur->next;
2867 cur->next = elem;
2868 if (elem->next != NULL)
2869 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002870 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002871 elem->parent->last = elem;
2872 return(elem);
2873}
2874
Daniel Veillard652327a2003-09-29 18:02:38 +00002875#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002876/**
2877 * xmlAddPrevSibling:
2878 * @cur: the child node
2879 * @elem: the new node
2880 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002881 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002882 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002883 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002884 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002885 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2886 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002887 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002888 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002889 */
2890xmlNodePtr
2891xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2892 if (cur == NULL) {
2893#ifdef DEBUG_TREE
2894 xmlGenericError(xmlGenericErrorContext,
2895 "xmlAddPrevSibling : cur == NULL\n");
2896#endif
2897 return(NULL);
2898 }
2899 if (elem == NULL) {
2900#ifdef DEBUG_TREE
2901 xmlGenericError(xmlGenericErrorContext,
2902 "xmlAddPrevSibling : elem == NULL\n");
2903#endif
2904 return(NULL);
2905 }
2906
2907 xmlUnlinkNode(elem);
2908
2909 if (elem->type == XML_TEXT_NODE) {
2910 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002911 xmlChar *tmp;
2912
2913 tmp = xmlStrdup(elem->content);
2914 tmp = xmlStrcat(tmp, cur->content);
2915 xmlNodeSetContent(cur, tmp);
2916 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002917 xmlFreeNode(elem);
2918 return(cur);
2919 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002920 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2921 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002922 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002923 xmlFreeNode(elem);
2924 return(cur->prev);
2925 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002926 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2927 /* check if an attribute with the same name exists */
2928 xmlAttrPtr attr;
2929
2930 if (elem->ns == NULL)
2931 attr = xmlHasProp(cur->parent, elem->name);
2932 else
2933 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2934 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2935 /* different instance, destroy it (attributes must be unique) */
2936 xmlFreeProp(attr);
2937 }
Owen Taylor3473f882001-02-23 17:55:21 +00002938 }
2939
2940 if (elem->doc != cur->doc) {
2941 xmlSetTreeDoc(elem, cur->doc);
2942 }
2943 elem->parent = cur->parent;
2944 elem->next = cur;
2945 elem->prev = cur->prev;
2946 cur->prev = elem;
2947 if (elem->prev != NULL)
2948 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002949 if (elem->parent != NULL) {
2950 if (elem->type == XML_ATTRIBUTE_NODE) {
2951 if (elem->parent->properties == (xmlAttrPtr) cur) {
2952 elem->parent->properties = (xmlAttrPtr) elem;
2953 }
2954 } else {
2955 if (elem->parent->children == cur) {
2956 elem->parent->children = elem;
2957 }
2958 }
2959 }
Owen Taylor3473f882001-02-23 17:55:21 +00002960 return(elem);
2961}
Daniel Veillard652327a2003-09-29 18:02:38 +00002962#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002963
2964/**
2965 * xmlAddSibling:
2966 * @cur: the child node
2967 * @elem: the new node
2968 *
2969 * Add a new element @elem to the list of siblings of @cur
2970 * merging adjacent TEXT nodes (@elem may be freed)
2971 * If the new element was already inserted in a document it is
2972 * first unlinked from its existing context.
2973 *
2974 * Returns the new element or NULL in case of error.
2975 */
2976xmlNodePtr
2977xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2978 xmlNodePtr parent;
2979
2980 if (cur == NULL) {
2981#ifdef DEBUG_TREE
2982 xmlGenericError(xmlGenericErrorContext,
2983 "xmlAddSibling : cur == NULL\n");
2984#endif
2985 return(NULL);
2986 }
2987
2988 if (elem == NULL) {
2989#ifdef DEBUG_TREE
2990 xmlGenericError(xmlGenericErrorContext,
2991 "xmlAddSibling : elem == NULL\n");
2992#endif
2993 return(NULL);
2994 }
2995
2996 /*
2997 * Constant time is we can rely on the ->parent->last to find
2998 * the last sibling.
2999 */
3000 if ((cur->parent != NULL) &&
3001 (cur->parent->children != NULL) &&
3002 (cur->parent->last != NULL) &&
3003 (cur->parent->last->next == NULL)) {
3004 cur = cur->parent->last;
3005 } else {
3006 while (cur->next != NULL) cur = cur->next;
3007 }
3008
3009 xmlUnlinkNode(elem);
3010
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003011 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3012 (cur->name == elem->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003013 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003014 xmlFreeNode(elem);
3015 return(cur);
3016 }
3017
3018 if (elem->doc != cur->doc) {
3019 xmlSetTreeDoc(elem, cur->doc);
3020 }
3021 parent = cur->parent;
3022 elem->prev = cur;
3023 elem->next = NULL;
3024 elem->parent = parent;
3025 cur->next = elem;
3026 if (parent != NULL)
3027 parent->last = elem;
3028
3029 return(elem);
3030}
3031
3032/**
3033 * xmlAddChildList:
3034 * @parent: the parent node
3035 * @cur: the first node in the list
3036 *
3037 * Add a list of node at the end of the child list of the parent
3038 * merging adjacent TEXT nodes (@cur may be freed)
3039 *
3040 * Returns the last child or NULL in case of error.
3041 */
3042xmlNodePtr
3043xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3044 xmlNodePtr prev;
3045
3046 if (parent == NULL) {
3047#ifdef DEBUG_TREE
3048 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003049 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003050#endif
3051 return(NULL);
3052 }
3053
3054 if (cur == NULL) {
3055#ifdef DEBUG_TREE
3056 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003057 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003058#endif
3059 return(NULL);
3060 }
3061
3062 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3063 (cur->doc != parent->doc)) {
3064#ifdef DEBUG_TREE
3065 xmlGenericError(xmlGenericErrorContext,
3066 "Elements moved to a different document\n");
3067#endif
3068 }
3069
3070 /*
3071 * add the first element at the end of the children list.
3072 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003073
Owen Taylor3473f882001-02-23 17:55:21 +00003074 if (parent->children == NULL) {
3075 parent->children = cur;
3076 } else {
3077 /*
3078 * If cur and parent->last both are TEXT nodes, then merge them.
3079 */
3080 if ((cur->type == XML_TEXT_NODE) &&
3081 (parent->last->type == XML_TEXT_NODE) &&
3082 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003083 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003084 /*
3085 * if it's the only child, nothing more to be done.
3086 */
3087 if (cur->next == NULL) {
3088 xmlFreeNode(cur);
3089 return(parent->last);
3090 }
3091 prev = cur;
3092 cur = cur->next;
3093 xmlFreeNode(prev);
3094 }
3095 prev = parent->last;
3096 prev->next = cur;
3097 cur->prev = prev;
3098 }
3099 while (cur->next != NULL) {
3100 cur->parent = parent;
3101 if (cur->doc != parent->doc) {
3102 xmlSetTreeDoc(cur, parent->doc);
3103 }
3104 cur = cur->next;
3105 }
3106 cur->parent = parent;
3107 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
3108 parent->last = cur;
3109
3110 return(cur);
3111}
3112
3113/**
3114 * xmlAddChild:
3115 * @parent: the parent node
3116 * @cur: the child node
3117 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003118 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003119 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003120 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3121 * If there is an attribute with equal name, it is first destroyed.
3122 *
Owen Taylor3473f882001-02-23 17:55:21 +00003123 * Returns the child or NULL in case of error.
3124 */
3125xmlNodePtr
3126xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3127 xmlNodePtr prev;
3128
3129 if (parent == NULL) {
3130#ifdef DEBUG_TREE
3131 xmlGenericError(xmlGenericErrorContext,
3132 "xmlAddChild : parent == NULL\n");
3133#endif
3134 return(NULL);
3135 }
3136
3137 if (cur == NULL) {
3138#ifdef DEBUG_TREE
3139 xmlGenericError(xmlGenericErrorContext,
3140 "xmlAddChild : child == NULL\n");
3141#endif
3142 return(NULL);
3143 }
3144
Owen Taylor3473f882001-02-23 17:55:21 +00003145 /*
3146 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003147 * cur is then freed.
3148 */
3149 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003150 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003151 (parent->content != NULL) &&
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003152 (parent->name == cur->name) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003153 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003154 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003155 xmlFreeNode(cur);
3156 return(parent);
3157 }
3158 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003159 (parent->last->name == cur->name) &&
3160 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003161 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003162 xmlFreeNode(cur);
3163 return(parent->last);
3164 }
3165 }
3166
3167 /*
3168 * add the new element at the end of the children list.
3169 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003170 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003171 cur->parent = parent;
3172 if (cur->doc != parent->doc) {
3173 xmlSetTreeDoc(cur, parent->doc);
3174 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003175 /* this check prevents a loop on tree-traversions if a developer
3176 * tries to add a node to its parent multiple times
3177 */
3178 if (prev == parent)
3179 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003180
3181 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003182 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003183 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003184 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003185 (parent->content != NULL) &&
3186 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003187 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003188 xmlFreeNode(cur);
3189 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003190 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003191 if (cur->type == XML_ATTRIBUTE_NODE) {
3192 if (parent->properties == NULL) {
3193 parent->properties = (xmlAttrPtr) cur;
3194 } else {
3195 /* check if an attribute with the same name exists */
3196 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003197
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003198 if (cur->ns == NULL)
3199 lastattr = xmlHasProp(parent, cur->name);
3200 else
3201 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3202 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
3203 /* different instance, destroy it (attributes must be unique) */
3204 xmlFreeProp(lastattr);
3205 }
3206 /* find the end */
3207 lastattr = parent->properties;
3208 while (lastattr->next != NULL) {
3209 lastattr = lastattr->next;
3210 }
3211 lastattr->next = (xmlAttrPtr) cur;
3212 ((xmlAttrPtr) cur)->prev = lastattr;
3213 }
3214 } else {
3215 if (parent->children == NULL) {
3216 parent->children = cur;
3217 parent->last = cur;
3218 } else {
3219 prev = parent->last;
3220 prev->next = cur;
3221 cur->prev = prev;
3222 parent->last = cur;
3223 }
3224 }
Owen Taylor3473f882001-02-23 17:55:21 +00003225 return(cur);
3226}
3227
3228/**
3229 * xmlGetLastChild:
3230 * @parent: the parent node
3231 *
3232 * Search the last child of a node.
3233 * Returns the last child or NULL if none.
3234 */
3235xmlNodePtr
3236xmlGetLastChild(xmlNodePtr parent) {
3237 if (parent == NULL) {
3238#ifdef DEBUG_TREE
3239 xmlGenericError(xmlGenericErrorContext,
3240 "xmlGetLastChild : parent == NULL\n");
3241#endif
3242 return(NULL);
3243 }
3244 return(parent->last);
3245}
3246
3247/**
3248 * xmlFreeNodeList:
3249 * @cur: the first node in the list
3250 *
3251 * Free a node and all its siblings, this is a recursive behaviour, all
3252 * the children are freed too.
3253 */
3254void
3255xmlFreeNodeList(xmlNodePtr cur) {
3256 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003257 xmlDictPtr dict = NULL;
3258
3259 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003260 if (cur->type == XML_NAMESPACE_DECL) {
3261 xmlFreeNsList((xmlNsPtr) cur);
3262 return;
3263 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003264 if ((cur->type == XML_DOCUMENT_NODE) ||
3265#ifdef LIBXML_DOCB_ENABLED
3266 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003267#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003268 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003269 xmlFreeDoc((xmlDocPtr) cur);
3270 return;
3271 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003272 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003273 while (cur != NULL) {
3274 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003275 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003276
Daniel Veillarda880b122003-04-21 21:36:41 +00003277 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003278 xmlDeregisterNodeDefaultValue(cur);
3279
Daniel Veillard02141ea2001-04-30 11:46:40 +00003280 if ((cur->children != NULL) &&
3281 (cur->type != XML_ENTITY_REF_NODE))
3282 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003283 if (((cur->type == XML_ELEMENT_NODE) ||
3284 (cur->type == XML_XINCLUDE_START) ||
3285 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003286 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003287 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003288 if ((cur->type != XML_ELEMENT_NODE) &&
3289 (cur->type != XML_XINCLUDE_START) &&
3290 (cur->type != XML_XINCLUDE_END) &&
3291 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003292 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003293 }
3294 if (((cur->type == XML_ELEMENT_NODE) ||
3295 (cur->type == XML_XINCLUDE_START) ||
3296 (cur->type == XML_XINCLUDE_END)) &&
3297 (cur->nsDef != NULL))
3298 xmlFreeNsList(cur->nsDef);
3299
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003300 /*
3301 * When a node is a text node or a comment, it uses a global static
3302 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003303 * Otherwise the node name might come from the document's
3304 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003305 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003306 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003307 (cur->type != XML_TEXT_NODE) &&
3308 (cur->type != XML_COMMENT_NODE))
3309 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003310 xmlFree(cur);
3311 }
Owen Taylor3473f882001-02-23 17:55:21 +00003312 cur = next;
3313 }
3314}
3315
3316/**
3317 * xmlFreeNode:
3318 * @cur: the node
3319 *
3320 * Free a node, this is a recursive behaviour, all the children are freed too.
3321 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3322 */
3323void
3324xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003325 xmlDictPtr dict = NULL;
3326
3327 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003328
Daniel Veillard02141ea2001-04-30 11:46:40 +00003329 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003330 if (cur->type == XML_DTD_NODE) {
3331 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003332 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003333 }
3334 if (cur->type == XML_NAMESPACE_DECL) {
3335 xmlFreeNs((xmlNsPtr) cur);
3336 return;
3337 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003338 if (cur->type == XML_ATTRIBUTE_NODE) {
3339 xmlFreeProp((xmlAttrPtr) cur);
3340 return;
3341 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003342
Daniel Veillarda880b122003-04-21 21:36:41 +00003343 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003344 xmlDeregisterNodeDefaultValue(cur);
3345
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003346 if (cur->doc != NULL) dict = cur->doc->dict;
3347
Owen Taylor3473f882001-02-23 17:55:21 +00003348 if ((cur->children != NULL) &&
3349 (cur->type != XML_ENTITY_REF_NODE))
3350 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003351 if (((cur->type == XML_ELEMENT_NODE) ||
3352 (cur->type == XML_XINCLUDE_START) ||
3353 (cur->type == XML_XINCLUDE_END)) &&
3354 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003355 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003356 if ((cur->type != XML_ELEMENT_NODE) &&
3357 (cur->content != NULL) &&
3358 (cur->type != XML_ENTITY_REF_NODE) &&
3359 (cur->type != XML_XINCLUDE_END) &&
3360 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003361 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003362 }
3363
Daniel Veillardacd370f2001-06-09 17:17:51 +00003364 /*
3365 * When a node is a text node or a comment, it uses a global static
3366 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003367 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003368 */
Owen Taylor3473f882001-02-23 17:55:21 +00003369 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003370 (cur->type != XML_TEXT_NODE) &&
3371 (cur->type != XML_COMMENT_NODE))
3372 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003373
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003374 if (((cur->type == XML_ELEMENT_NODE) ||
3375 (cur->type == XML_XINCLUDE_START) ||
3376 (cur->type == XML_XINCLUDE_END)) &&
3377 (cur->nsDef != NULL))
3378 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003379 xmlFree(cur);
3380}
3381
3382/**
3383 * xmlUnlinkNode:
3384 * @cur: the node
3385 *
3386 * Unlink a node from it's current context, the node is not freed
3387 */
3388void
3389xmlUnlinkNode(xmlNodePtr cur) {
3390 if (cur == NULL) {
3391#ifdef DEBUG_TREE
3392 xmlGenericError(xmlGenericErrorContext,
3393 "xmlUnlinkNode : node == NULL\n");
3394#endif
3395 return;
3396 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003397 if (cur->type == XML_DTD_NODE) {
3398 xmlDocPtr doc;
3399 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003400 if (doc != NULL) {
3401 if (doc->intSubset == (xmlDtdPtr) cur)
3402 doc->intSubset = NULL;
3403 if (doc->extSubset == (xmlDtdPtr) cur)
3404 doc->extSubset = NULL;
3405 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003406 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003407 if (cur->parent != NULL) {
3408 xmlNodePtr parent;
3409 parent = cur->parent;
3410 if (cur->type == XML_ATTRIBUTE_NODE) {
3411 if (parent->properties == (xmlAttrPtr) cur)
3412 parent->properties = ((xmlAttrPtr) cur)->next;
3413 } else {
3414 if (parent->children == cur)
3415 parent->children = cur->next;
3416 if (parent->last == cur)
3417 parent->last = cur->prev;
3418 }
3419 cur->parent = NULL;
3420 }
Owen Taylor3473f882001-02-23 17:55:21 +00003421 if (cur->next != NULL)
3422 cur->next->prev = cur->prev;
3423 if (cur->prev != NULL)
3424 cur->prev->next = cur->next;
3425 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003426}
3427
Daniel Veillard652327a2003-09-29 18:02:38 +00003428#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003429/**
3430 * xmlReplaceNode:
3431 * @old: the old node
3432 * @cur: the node
3433 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00003434 * Unlink the old node from its current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003435 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003436 * first unlinked from its existing context.
3437 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003438 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003439 */
3440xmlNodePtr
3441xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3442 if (old == NULL) {
3443#ifdef DEBUG_TREE
3444 xmlGenericError(xmlGenericErrorContext,
3445 "xmlReplaceNode : old == NULL\n");
3446#endif
3447 return(NULL);
3448 }
3449 if (cur == NULL) {
3450 xmlUnlinkNode(old);
3451 return(old);
3452 }
3453 if (cur == old) {
3454 return(old);
3455 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003456 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3457#ifdef DEBUG_TREE
3458 xmlGenericError(xmlGenericErrorContext,
3459 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3460#endif
3461 return(old);
3462 }
3463 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3464#ifdef DEBUG_TREE
3465 xmlGenericError(xmlGenericErrorContext,
3466 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3467#endif
3468 return(old);
3469 }
Owen Taylor3473f882001-02-23 17:55:21 +00003470 xmlUnlinkNode(cur);
3471 cur->doc = old->doc;
3472 cur->parent = old->parent;
3473 cur->next = old->next;
3474 if (cur->next != NULL)
3475 cur->next->prev = cur;
3476 cur->prev = old->prev;
3477 if (cur->prev != NULL)
3478 cur->prev->next = cur;
3479 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003480 if (cur->type == XML_ATTRIBUTE_NODE) {
3481 if (cur->parent->properties == (xmlAttrPtr)old)
3482 cur->parent->properties = ((xmlAttrPtr) cur);
3483 } else {
3484 if (cur->parent->children == old)
3485 cur->parent->children = cur;
3486 if (cur->parent->last == old)
3487 cur->parent->last = cur;
3488 }
Owen Taylor3473f882001-02-23 17:55:21 +00003489 }
3490 old->next = old->prev = NULL;
3491 old->parent = NULL;
3492 return(old);
3493}
Daniel Veillard652327a2003-09-29 18:02:38 +00003494#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003495
3496/************************************************************************
3497 * *
3498 * Copy operations *
3499 * *
3500 ************************************************************************/
3501
3502/**
3503 * xmlCopyNamespace:
3504 * @cur: the namespace
3505 *
3506 * Do a copy of the namespace.
3507 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003508 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003509 */
3510xmlNsPtr
3511xmlCopyNamespace(xmlNsPtr cur) {
3512 xmlNsPtr ret;
3513
3514 if (cur == NULL) return(NULL);
3515 switch (cur->type) {
3516 case XML_LOCAL_NAMESPACE:
3517 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3518 break;
3519 default:
3520#ifdef DEBUG_TREE
3521 xmlGenericError(xmlGenericErrorContext,
3522 "xmlCopyNamespace: invalid type %d\n", cur->type);
3523#endif
3524 return(NULL);
3525 }
3526 return(ret);
3527}
3528
3529/**
3530 * xmlCopyNamespaceList:
3531 * @cur: the first namespace
3532 *
3533 * Do a copy of an namespace list.
3534 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003535 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003536 */
3537xmlNsPtr
3538xmlCopyNamespaceList(xmlNsPtr cur) {
3539 xmlNsPtr ret = NULL;
3540 xmlNsPtr p = NULL,q;
3541
3542 while (cur != NULL) {
3543 q = xmlCopyNamespace(cur);
3544 if (p == NULL) {
3545 ret = p = q;
3546 } else {
3547 p->next = q;
3548 p = q;
3549 }
3550 cur = cur->next;
3551 }
3552 return(ret);
3553}
3554
3555static xmlNodePtr
3556xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3557/**
3558 * xmlCopyProp:
3559 * @target: the element where the attribute will be grafted
3560 * @cur: the attribute
3561 *
3562 * Do a copy of the attribute.
3563 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003564 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003565 */
3566xmlAttrPtr
3567xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3568 xmlAttrPtr ret;
3569
3570 if (cur == NULL) return(NULL);
3571 if (target != NULL)
3572 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3573 else if (cur->parent != NULL)
3574 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3575 else if (cur->children != NULL)
3576 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3577 else
3578 ret = xmlNewDocProp(NULL, cur->name, NULL);
3579 if (ret == NULL) return(NULL);
3580 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003581
Owen Taylor3473f882001-02-23 17:55:21 +00003582 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003583 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003584
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003585 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3586 if (ns == NULL) {
3587 /*
3588 * Humm, we are copying an element whose namespace is defined
3589 * out of the new tree scope. Search it in the original tree
3590 * and add it at the top of the new tree
3591 */
3592 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3593 if (ns != NULL) {
3594 xmlNodePtr root = target;
3595 xmlNodePtr pred = NULL;
3596
3597 while (root->parent != NULL) {
3598 pred = root;
3599 root = root->parent;
3600 }
3601 if (root == (xmlNodePtr) target->doc) {
3602 /* correct possibly cycling above the document elt */
3603 root = pred;
3604 }
3605 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3606 }
3607 } else {
3608 /*
3609 * we have to find something appropriate here since
3610 * we cant be sure, that the namespce we found is identified
3611 * by the prefix
3612 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003613 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003614 /* this is the nice case */
3615 ret->ns = ns;
3616 } else {
3617 /*
3618 * we are in trouble: we need a new reconcilied namespace.
3619 * This is expensive
3620 */
3621 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3622 }
3623 }
3624
Owen Taylor3473f882001-02-23 17:55:21 +00003625 } else
3626 ret->ns = NULL;
3627
3628 if (cur->children != NULL) {
3629 xmlNodePtr tmp;
3630
3631 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3632 ret->last = NULL;
3633 tmp = ret->children;
3634 while (tmp != NULL) {
3635 /* tmp->parent = (xmlNodePtr)ret; */
3636 if (tmp->next == NULL)
3637 ret->last = tmp;
3638 tmp = tmp->next;
3639 }
3640 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003641 /*
3642 * Try to handle IDs
3643 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003644 if ((target!= NULL) && (cur!= NULL) &&
3645 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003646 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3647 if (xmlIsID(cur->doc, cur->parent, cur)) {
3648 xmlChar *id;
3649
3650 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3651 if (id != NULL) {
3652 xmlAddID(NULL, target->doc, id, ret);
3653 xmlFree(id);
3654 }
3655 }
3656 }
Owen Taylor3473f882001-02-23 17:55:21 +00003657 return(ret);
3658}
3659
3660/**
3661 * xmlCopyPropList:
3662 * @target: the element where the attributes will be grafted
3663 * @cur: the first attribute
3664 *
3665 * Do a copy of an attribute list.
3666 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003667 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003668 */
3669xmlAttrPtr
3670xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3671 xmlAttrPtr ret = NULL;
3672 xmlAttrPtr p = NULL,q;
3673
3674 while (cur != NULL) {
3675 q = xmlCopyProp(target, cur);
3676 if (p == NULL) {
3677 ret = p = q;
3678 } else {
3679 p->next = q;
3680 q->prev = p;
3681 p = q;
3682 }
3683 cur = cur->next;
3684 }
3685 return(ret);
3686}
3687
3688/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003689 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003690 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003691 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003692 * tricky reason: namespaces. Doing a direct copy of a node
3693 * say RPM:Copyright without changing the namespace pointer to
3694 * something else can produce stale links. One way to do it is
3695 * to keep a reference counter but this doesn't work as soon
3696 * as one move the element or the subtree out of the scope of
3697 * the existing namespace. The actual solution seems to add
3698 * a copy of the namespace at the top of the copied tree if
3699 * not available in the subtree.
3700 * Hence two functions, the public front-end call the inner ones
3701 */
3702
3703static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003704xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003705 int recursive) {
3706 xmlNodePtr ret;
3707
3708 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003709 switch (node->type) {
3710 case XML_TEXT_NODE:
3711 case XML_CDATA_SECTION_NODE:
3712 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003713 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003714 case XML_ENTITY_REF_NODE:
3715 case XML_ENTITY_NODE:
3716 case XML_PI_NODE:
3717 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003718 case XML_XINCLUDE_START:
3719 case XML_XINCLUDE_END:
3720 break;
3721 case XML_ATTRIBUTE_NODE:
3722 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3723 case XML_NAMESPACE_DECL:
3724 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3725
Daniel Veillard39196eb2001-06-19 18:09:42 +00003726 case XML_DOCUMENT_NODE:
3727 case XML_HTML_DOCUMENT_NODE:
3728#ifdef LIBXML_DOCB_ENABLED
3729 case XML_DOCB_DOCUMENT_NODE:
3730#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00003731#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003732 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard652327a2003-09-29 18:02:38 +00003733#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00003734 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003735 case XML_NOTATION_NODE:
3736 case XML_DTD_NODE:
3737 case XML_ELEMENT_DECL:
3738 case XML_ATTRIBUTE_DECL:
3739 case XML_ENTITY_DECL:
3740 return(NULL);
3741 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003742
Owen Taylor3473f882001-02-23 17:55:21 +00003743 /*
3744 * Allocate a new node and fill the fields.
3745 */
3746 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3747 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00003748 xmlTreeErrMemory("copying node");
Owen Taylor3473f882001-02-23 17:55:21 +00003749 return(NULL);
3750 }
3751 memset(ret, 0, sizeof(xmlNode));
3752 ret->type = node->type;
3753
3754 ret->doc = doc;
3755 ret->parent = parent;
3756 if (node->name == xmlStringText)
3757 ret->name = xmlStringText;
3758 else if (node->name == xmlStringTextNoenc)
3759 ret->name = xmlStringTextNoenc;
3760 else if (node->name == xmlStringComment)
3761 ret->name = xmlStringComment;
3762 else if (node->name != NULL)
3763 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003764 if ((node->type != XML_ELEMENT_NODE) &&
3765 (node->content != NULL) &&
3766 (node->type != XML_ENTITY_REF_NODE) &&
3767 (node->type != XML_XINCLUDE_END) &&
3768 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003769 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003770 }else{
3771 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00003772 ret->line = node->line;
Owen Taylor3473f882001-02-23 17:55:21 +00003773 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003774 if (parent != NULL) {
3775 xmlNodePtr tmp;
3776
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003777 /*
3778 * this is a tricky part for the node register thing:
3779 * in case ret does get coalesced in xmlAddChild
3780 * the deregister-node callback is called; so we register ret now already
3781 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003782 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003783 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3784
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003785 tmp = xmlAddChild(parent, ret);
3786 /* node could have coalesced */
3787 if (tmp != ret)
3788 return(tmp);
3789 }
Owen Taylor3473f882001-02-23 17:55:21 +00003790
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003791 if (!recursive)
3792 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003793 if (node->nsDef != NULL)
3794 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3795
3796 if (node->ns != NULL) {
3797 xmlNsPtr ns;
3798
3799 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3800 if (ns == NULL) {
3801 /*
3802 * Humm, we are copying an element whose namespace is defined
3803 * out of the new tree scope. Search it in the original tree
3804 * and add it at the top of the new tree
3805 */
3806 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3807 if (ns != NULL) {
3808 xmlNodePtr root = ret;
3809
3810 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003811 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003812 }
3813 } else {
3814 /*
3815 * reference the existing namespace definition in our own tree.
3816 */
3817 ret->ns = ns;
3818 }
3819 }
3820 if (node->properties != NULL)
3821 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003822 if (node->type == XML_ENTITY_REF_NODE) {
3823 if ((doc == NULL) || (node->doc != doc)) {
3824 /*
3825 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003826 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003827 * we cannot keep the reference. Try to find it in the
3828 * target document.
3829 */
3830 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3831 } else {
3832 ret->children = node->children;
3833 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003834 ret->last = ret->children;
3835 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003836 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003837 UPDATE_LAST_CHILD_AND_PARENT(ret)
3838 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003839
3840out:
3841 /* if parent != NULL we already registered the node above */
3842 if (parent == NULL && xmlRegisterNodeDefaultValue)
3843 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003844 return(ret);
3845}
3846
3847static xmlNodePtr
3848xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3849 xmlNodePtr ret = NULL;
3850 xmlNodePtr p = NULL,q;
3851
3852 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00003853#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003854 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003855 if (doc == NULL) {
3856 node = node->next;
3857 continue;
3858 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003859 if (doc->intSubset == NULL) {
3860 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3861 q->doc = doc;
3862 q->parent = parent;
3863 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003864 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003865 } else {
3866 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003867 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003868 }
3869 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00003870#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00003871 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003872 if (ret == NULL) {
3873 q->prev = NULL;
3874 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003875 } else if (p != q) {
3876 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003877 p->next = q;
3878 q->prev = p;
3879 p = q;
3880 }
3881 node = node->next;
3882 }
3883 return(ret);
3884}
3885
3886/**
3887 * xmlCopyNode:
3888 * @node: the node
3889 * @recursive: if 1 do a recursive copy.
3890 *
3891 * Do a copy of the node.
3892 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003893 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003894 */
3895xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003896xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003897 xmlNodePtr ret;
3898
3899 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3900 return(ret);
3901}
3902
3903/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003904 * xmlDocCopyNode:
3905 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003906 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003907 * @recursive: if 1 do a recursive copy.
3908 *
3909 * Do a copy of the node to a given document.
3910 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003911 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003912 */
3913xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003914xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003915 xmlNodePtr ret;
3916
3917 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3918 return(ret);
3919}
3920
3921/**
Owen Taylor3473f882001-02-23 17:55:21 +00003922 * xmlCopyNodeList:
3923 * @node: the first node in the list.
3924 *
3925 * Do a recursive copy of the node list.
3926 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003927 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003928 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003929xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003930 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3931 return(ret);
3932}
3933
Daniel Veillard652327a2003-09-29 18:02:38 +00003934#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003935/**
Owen Taylor3473f882001-02-23 17:55:21 +00003936 * xmlCopyDtd:
3937 * @dtd: the dtd
3938 *
3939 * Do a copy of the dtd.
3940 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003941 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003942 */
3943xmlDtdPtr
3944xmlCopyDtd(xmlDtdPtr dtd) {
3945 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003946 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003947
3948 if (dtd == NULL) return(NULL);
3949 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3950 if (ret == NULL) return(NULL);
3951 if (dtd->entities != NULL)
3952 ret->entities = (void *) xmlCopyEntitiesTable(
3953 (xmlEntitiesTablePtr) dtd->entities);
3954 if (dtd->notations != NULL)
3955 ret->notations = (void *) xmlCopyNotationTable(
3956 (xmlNotationTablePtr) dtd->notations);
3957 if (dtd->elements != NULL)
3958 ret->elements = (void *) xmlCopyElementTable(
3959 (xmlElementTablePtr) dtd->elements);
3960 if (dtd->attributes != NULL)
3961 ret->attributes = (void *) xmlCopyAttributeTable(
3962 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003963 if (dtd->pentities != NULL)
3964 ret->pentities = (void *) xmlCopyEntitiesTable(
3965 (xmlEntitiesTablePtr) dtd->pentities);
3966
3967 cur = dtd->children;
3968 while (cur != NULL) {
3969 q = NULL;
3970
3971 if (cur->type == XML_ENTITY_DECL) {
3972 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3973 switch (tmp->etype) {
3974 case XML_INTERNAL_GENERAL_ENTITY:
3975 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3976 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3977 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3978 break;
3979 case XML_INTERNAL_PARAMETER_ENTITY:
3980 case XML_EXTERNAL_PARAMETER_ENTITY:
3981 q = (xmlNodePtr)
3982 xmlGetParameterEntityFromDtd(ret, tmp->name);
3983 break;
3984 case XML_INTERNAL_PREDEFINED_ENTITY:
3985 break;
3986 }
3987 } else if (cur->type == XML_ELEMENT_DECL) {
3988 xmlElementPtr tmp = (xmlElementPtr) cur;
3989 q = (xmlNodePtr)
3990 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3991 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3992 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3993 q = (xmlNodePtr)
3994 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3995 } else if (cur->type == XML_COMMENT_NODE) {
3996 q = xmlCopyNode(cur, 0);
3997 }
3998
3999 if (q == NULL) {
4000 cur = cur->next;
4001 continue;
4002 }
4003
4004 if (p == NULL)
4005 ret->children = q;
4006 else
4007 p->next = q;
4008
4009 q->prev = p;
4010 q->parent = (xmlNodePtr) ret;
4011 q->next = NULL;
4012 ret->last = q;
4013 p = q;
4014 cur = cur->next;
4015 }
4016
Owen Taylor3473f882001-02-23 17:55:21 +00004017 return(ret);
4018}
4019
4020/**
4021 * xmlCopyDoc:
4022 * @doc: the document
4023 * @recursive: if 1 do a recursive copy.
4024 *
4025 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004026 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004027 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004028 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004029 */
4030xmlDocPtr
4031xmlCopyDoc(xmlDocPtr doc, int recursive) {
4032 xmlDocPtr ret;
4033
4034 if (doc == NULL) return(NULL);
4035 ret = xmlNewDoc(doc->version);
4036 if (ret == NULL) return(NULL);
4037 if (doc->name != NULL)
4038 ret->name = xmlMemStrdup(doc->name);
4039 if (doc->encoding != NULL)
4040 ret->encoding = xmlStrdup(doc->encoding);
4041 ret->charset = doc->charset;
4042 ret->compression = doc->compression;
4043 ret->standalone = doc->standalone;
4044 if (!recursive) return(ret);
4045
Daniel Veillardb33c2012001-04-25 12:59:04 +00004046 ret->last = NULL;
4047 ret->children = NULL;
4048 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004049 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004050 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004051 ret->intSubset->parent = ret;
4052 }
Owen Taylor3473f882001-02-23 17:55:21 +00004053 if (doc->oldNs != NULL)
4054 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4055 if (doc->children != NULL) {
4056 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00004057
4058 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4059 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004060 ret->last = NULL;
4061 tmp = ret->children;
4062 while (tmp != NULL) {
4063 if (tmp->next == NULL)
4064 ret->last = tmp;
4065 tmp = tmp->next;
4066 }
4067 }
4068 return(ret);
4069}
Daniel Veillard652327a2003-09-29 18:02:38 +00004070#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004071
4072/************************************************************************
4073 * *
4074 * Content access functions *
4075 * *
4076 ************************************************************************/
4077
4078/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004079 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004080 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004081 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00004082 * Get line number of @node. This requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004083 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004084 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004085 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004086 */
4087long
4088xmlGetLineNo(xmlNodePtr node)
4089{
4090 long result = -1;
4091
4092 if (!node)
4093 return result;
4094 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004095 result = (long) node->line;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004096 else if ((node->prev != NULL) &&
4097 ((node->prev->type == XML_ELEMENT_NODE) ||
4098 (node->prev->type == XML_TEXT_NODE)))
4099 result = xmlGetLineNo(node->prev);
4100 else if ((node->parent != NULL) &&
4101 ((node->parent->type == XML_ELEMENT_NODE) ||
4102 (node->parent->type == XML_TEXT_NODE)))
4103 result = xmlGetLineNo(node->parent);
4104
4105 return result;
4106}
4107
Daniel Veillard652327a2003-09-29 18:02:38 +00004108#ifdef LIBXML_TREE_ENABLED
Daniel Veillard8faa7832001-11-26 15:58:08 +00004109/**
4110 * xmlGetNodePath:
4111 * @node: a node
4112 *
4113 * Build a structure based Path for the given node
4114 *
4115 * Returns the new path or NULL in case of error. The caller must free
4116 * the returned string
4117 */
4118xmlChar *
4119xmlGetNodePath(xmlNodePtr node)
4120{
4121 xmlNodePtr cur, tmp, next;
4122 xmlChar *buffer = NULL, *temp;
4123 size_t buf_len;
4124 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004125 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004126 const char *name;
4127 char nametemp[100];
4128 int occur = 0;
4129
4130 if (node == NULL)
4131 return (NULL);
4132
4133 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004134 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004135 if (buffer == NULL) {
4136 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004137 return (NULL);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004138 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004139 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004140 if (buf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004141 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004142 xmlFree(buffer);
4143 return (NULL);
4144 }
4145
4146 buffer[0] = 0;
4147 cur = node;
4148 do {
4149 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004150 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004151 occur = 0;
4152 if ((cur->type == XML_DOCUMENT_NODE) ||
4153 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4154 if (buffer[0] == '/')
4155 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004156 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004157 next = NULL;
4158 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004159 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004160 name = (const char *) cur->name;
4161 if (cur->ns) {
4162 snprintf(nametemp, sizeof(nametemp) - 1,
4163 "%s:%s", cur->ns->prefix, cur->name);
4164 nametemp[sizeof(nametemp) - 1] = 0;
4165 name = nametemp;
4166 }
4167 next = cur->parent;
4168
4169 /*
4170 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004171 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004172 */
4173 tmp = cur->prev;
4174 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004175 if ((tmp->type == XML_ELEMENT_NODE) &&
4176 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004177 occur++;
4178 tmp = tmp->prev;
4179 }
4180 if (occur == 0) {
4181 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004182 while (tmp != NULL && occur == 0) {
4183 if ((tmp->type == XML_ELEMENT_NODE) &&
4184 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004185 occur++;
4186 tmp = tmp->next;
4187 }
4188 if (occur != 0)
4189 occur = 1;
4190 } else
4191 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004192 } else if (cur->type == XML_COMMENT_NODE) {
4193 sep = "/";
4194 name = "comment()";
4195 next = cur->parent;
4196
4197 /*
4198 * Thumbler index computation
4199 */
4200 tmp = cur->prev;
4201 while (tmp != NULL) {
4202 if (tmp->type == XML_COMMENT_NODE)
4203 occur++;
4204 tmp = tmp->prev;
4205 }
4206 if (occur == 0) {
4207 tmp = cur->next;
4208 while (tmp != NULL && occur == 0) {
4209 if (tmp->type == XML_COMMENT_NODE)
4210 occur++;
4211 tmp = tmp->next;
4212 }
4213 if (occur != 0)
4214 occur = 1;
4215 } else
4216 occur++;
4217 } else if ((cur->type == XML_TEXT_NODE) ||
4218 (cur->type == XML_CDATA_SECTION_NODE)) {
4219 sep = "/";
4220 name = "text()";
4221 next = cur->parent;
4222
4223 /*
4224 * Thumbler index computation
4225 */
4226 tmp = cur->prev;
4227 while (tmp != NULL) {
4228 if ((cur->type == XML_TEXT_NODE) ||
4229 (cur->type == XML_CDATA_SECTION_NODE))
4230 occur++;
4231 tmp = tmp->prev;
4232 }
4233 if (occur == 0) {
4234 tmp = cur->next;
4235 while (tmp != NULL && occur == 0) {
4236 if ((cur->type == XML_TEXT_NODE) ||
4237 (cur->type == XML_CDATA_SECTION_NODE))
4238 occur++;
4239 tmp = tmp->next;
4240 }
4241 if (occur != 0)
4242 occur = 1;
4243 } else
4244 occur++;
4245 } else if (cur->type == XML_PI_NODE) {
4246 sep = "/";
4247 snprintf(nametemp, sizeof(nametemp) - 1,
4248 "processing-instruction('%s')", cur->name);
4249 nametemp[sizeof(nametemp) - 1] = 0;
4250 name = nametemp;
4251
4252 next = cur->parent;
4253
4254 /*
4255 * Thumbler index computation
4256 */
4257 tmp = cur->prev;
4258 while (tmp != NULL) {
4259 if ((tmp->type == XML_PI_NODE) &&
4260 (xmlStrEqual(cur->name, tmp->name)))
4261 occur++;
4262 tmp = tmp->prev;
4263 }
4264 if (occur == 0) {
4265 tmp = cur->next;
4266 while (tmp != NULL && occur == 0) {
4267 if ((tmp->type == XML_PI_NODE) &&
4268 (xmlStrEqual(cur->name, tmp->name)))
4269 occur++;
4270 tmp = tmp->next;
4271 }
4272 if (occur != 0)
4273 occur = 1;
4274 } else
4275 occur++;
4276
Daniel Veillard8faa7832001-11-26 15:58:08 +00004277 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004278 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004279 name = (const char *) (((xmlAttrPtr) cur)->name);
4280 next = ((xmlAttrPtr) cur)->parent;
4281 } else {
4282 next = cur->parent;
4283 }
4284
4285 /*
4286 * Make sure there is enough room
4287 */
4288 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4289 buf_len =
4290 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4291 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4292 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004293 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004294 xmlFree(buf);
4295 xmlFree(buffer);
4296 return (NULL);
4297 }
4298 buffer = temp;
4299 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4300 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004301 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004302 xmlFree(buf);
4303 xmlFree(buffer);
4304 return (NULL);
4305 }
4306 buf = temp;
4307 }
4308 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004309 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004310 sep, name, (char *) buffer);
4311 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004312 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004313 sep, name, occur, (char *) buffer);
4314 snprintf((char *) buffer, buf_len, "%s", buf);
4315 cur = next;
4316 } while (cur != NULL);
4317 xmlFree(buf);
4318 return (buffer);
4319}
Daniel Veillard652327a2003-09-29 18:02:38 +00004320#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004321
4322/**
Owen Taylor3473f882001-02-23 17:55:21 +00004323 * xmlDocGetRootElement:
4324 * @doc: the document
4325 *
4326 * Get the root element of the document (doc->children is a list
4327 * containing possibly comments, PIs, etc ...).
4328 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004329 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004330 */
4331xmlNodePtr
4332xmlDocGetRootElement(xmlDocPtr doc) {
4333 xmlNodePtr ret;
4334
4335 if (doc == NULL) return(NULL);
4336 ret = doc->children;
4337 while (ret != NULL) {
4338 if (ret->type == XML_ELEMENT_NODE)
4339 return(ret);
4340 ret = ret->next;
4341 }
4342 return(ret);
4343}
4344
Daniel Veillard652327a2003-09-29 18:02:38 +00004345#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004346/**
4347 * xmlDocSetRootElement:
4348 * @doc: the document
4349 * @root: the new document root element
4350 *
4351 * Set the root element of the document (doc->children is a list
4352 * containing possibly comments, PIs, etc ...).
4353 *
4354 * Returns the old root element if any was found
4355 */
4356xmlNodePtr
4357xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4358 xmlNodePtr old = NULL;
4359
4360 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004361 if (root == NULL)
4362 return(NULL);
4363 xmlUnlinkNode(root);
4364 root->doc = doc;
4365 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004366 old = doc->children;
4367 while (old != NULL) {
4368 if (old->type == XML_ELEMENT_NODE)
4369 break;
4370 old = old->next;
4371 }
4372 if (old == NULL) {
4373 if (doc->children == NULL) {
4374 doc->children = root;
4375 doc->last = root;
4376 } else {
4377 xmlAddSibling(doc->children, root);
4378 }
4379 } else {
4380 xmlReplaceNode(old, root);
4381 }
4382 return(old);
4383}
4384
4385/**
4386 * xmlNodeSetLang:
4387 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004388 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004389 *
4390 * Set the language of a node, i.e. the values of the xml:lang
4391 * attribute.
4392 */
4393void
4394xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004395 xmlNsPtr ns;
4396
Owen Taylor3473f882001-02-23 17:55:21 +00004397 if (cur == NULL) return;
4398 switch(cur->type) {
4399 case XML_TEXT_NODE:
4400 case XML_CDATA_SECTION_NODE:
4401 case XML_COMMENT_NODE:
4402 case XML_DOCUMENT_NODE:
4403 case XML_DOCUMENT_TYPE_NODE:
4404 case XML_DOCUMENT_FRAG_NODE:
4405 case XML_NOTATION_NODE:
4406 case XML_HTML_DOCUMENT_NODE:
4407 case XML_DTD_NODE:
4408 case XML_ELEMENT_DECL:
4409 case XML_ATTRIBUTE_DECL:
4410 case XML_ENTITY_DECL:
4411 case XML_PI_NODE:
4412 case XML_ENTITY_REF_NODE:
4413 case XML_ENTITY_NODE:
4414 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004415#ifdef LIBXML_DOCB_ENABLED
4416 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004417#endif
4418 case XML_XINCLUDE_START:
4419 case XML_XINCLUDE_END:
4420 return;
4421 case XML_ELEMENT_NODE:
4422 case XML_ATTRIBUTE_NODE:
4423 break;
4424 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004425 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4426 if (ns == NULL)
4427 return;
4428 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004429}
Daniel Veillard652327a2003-09-29 18:02:38 +00004430#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004431
4432/**
4433 * xmlNodeGetLang:
4434 * @cur: the node being checked
4435 *
4436 * Searches the language of a node, i.e. the values of the xml:lang
4437 * attribute or the one carried by the nearest ancestor.
4438 *
4439 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004440 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004441 */
4442xmlChar *
4443xmlNodeGetLang(xmlNodePtr cur) {
4444 xmlChar *lang;
4445
4446 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004447 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004448 if (lang != NULL)
4449 return(lang);
4450 cur = cur->parent;
4451 }
4452 return(NULL);
4453}
4454
4455
Daniel Veillard652327a2003-09-29 18:02:38 +00004456#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004457/**
4458 * xmlNodeSetSpacePreserve:
4459 * @cur: the node being changed
4460 * @val: the xml:space value ("0": default, 1: "preserve")
4461 *
4462 * Set (or reset) the space preserving behaviour of a node, i.e. the
4463 * value of the xml:space attribute.
4464 */
4465void
4466xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004467 xmlNsPtr ns;
4468
Owen Taylor3473f882001-02-23 17:55:21 +00004469 if (cur == NULL) return;
4470 switch(cur->type) {
4471 case XML_TEXT_NODE:
4472 case XML_CDATA_SECTION_NODE:
4473 case XML_COMMENT_NODE:
4474 case XML_DOCUMENT_NODE:
4475 case XML_DOCUMENT_TYPE_NODE:
4476 case XML_DOCUMENT_FRAG_NODE:
4477 case XML_NOTATION_NODE:
4478 case XML_HTML_DOCUMENT_NODE:
4479 case XML_DTD_NODE:
4480 case XML_ELEMENT_DECL:
4481 case XML_ATTRIBUTE_DECL:
4482 case XML_ENTITY_DECL:
4483 case XML_PI_NODE:
4484 case XML_ENTITY_REF_NODE:
4485 case XML_ENTITY_NODE:
4486 case XML_NAMESPACE_DECL:
4487 case XML_XINCLUDE_START:
4488 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004489#ifdef LIBXML_DOCB_ENABLED
4490 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004491#endif
4492 return;
4493 case XML_ELEMENT_NODE:
4494 case XML_ATTRIBUTE_NODE:
4495 break;
4496 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004497 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4498 if (ns == NULL)
4499 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004500 switch (val) {
4501 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004502 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004503 break;
4504 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004505 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004506 break;
4507 }
4508}
Daniel Veillard652327a2003-09-29 18:02:38 +00004509#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004510
4511/**
4512 * xmlNodeGetSpacePreserve:
4513 * @cur: the node being checked
4514 *
4515 * Searches the space preserving behaviour of a node, i.e. the values
4516 * of the xml:space attribute or the one carried by the nearest
4517 * ancestor.
4518 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004519 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004520 */
4521int
4522xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4523 xmlChar *space;
4524
4525 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004526 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004527 if (space != NULL) {
4528 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4529 xmlFree(space);
4530 return(1);
4531 }
4532 if (xmlStrEqual(space, BAD_CAST "default")) {
4533 xmlFree(space);
4534 return(0);
4535 }
4536 xmlFree(space);
4537 }
4538 cur = cur->parent;
4539 }
4540 return(-1);
4541}
4542
Daniel Veillard652327a2003-09-29 18:02:38 +00004543#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004544/**
4545 * xmlNodeSetName:
4546 * @cur: the node being changed
4547 * @name: the new tag name
4548 *
4549 * Set (or reset) the name of a node.
4550 */
4551void
4552xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
4553 if (cur == NULL) return;
4554 if (name == NULL) return;
4555 switch(cur->type) {
4556 case XML_TEXT_NODE:
4557 case XML_CDATA_SECTION_NODE:
4558 case XML_COMMENT_NODE:
4559 case XML_DOCUMENT_TYPE_NODE:
4560 case XML_DOCUMENT_FRAG_NODE:
4561 case XML_NOTATION_NODE:
4562 case XML_HTML_DOCUMENT_NODE:
4563 case XML_NAMESPACE_DECL:
4564 case XML_XINCLUDE_START:
4565 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004566#ifdef LIBXML_DOCB_ENABLED
4567 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004568#endif
4569 return;
4570 case XML_ELEMENT_NODE:
4571 case XML_ATTRIBUTE_NODE:
4572 case XML_PI_NODE:
4573 case XML_ENTITY_REF_NODE:
4574 case XML_ENTITY_NODE:
4575 case XML_DTD_NODE:
4576 case XML_DOCUMENT_NODE:
4577 case XML_ELEMENT_DECL:
4578 case XML_ATTRIBUTE_DECL:
4579 case XML_ENTITY_DECL:
4580 break;
4581 }
4582 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4583 cur->name = xmlStrdup(name);
4584}
4585
4586/**
4587 * xmlNodeSetBase:
4588 * @cur: the node being changed
4589 * @uri: the new base URI
4590 *
4591 * Set (or reset) the base URI of a node, i.e. the value of the
4592 * xml:base attribute.
4593 */
4594void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00004595xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004596 xmlNsPtr ns;
4597
Owen Taylor3473f882001-02-23 17:55:21 +00004598 if (cur == NULL) return;
4599 switch(cur->type) {
4600 case XML_TEXT_NODE:
4601 case XML_CDATA_SECTION_NODE:
4602 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004603 case XML_DOCUMENT_TYPE_NODE:
4604 case XML_DOCUMENT_FRAG_NODE:
4605 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004606 case XML_DTD_NODE:
4607 case XML_ELEMENT_DECL:
4608 case XML_ATTRIBUTE_DECL:
4609 case XML_ENTITY_DECL:
4610 case XML_PI_NODE:
4611 case XML_ENTITY_REF_NODE:
4612 case XML_ENTITY_NODE:
4613 case XML_NAMESPACE_DECL:
4614 case XML_XINCLUDE_START:
4615 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004616 return;
4617 case XML_ELEMENT_NODE:
4618 case XML_ATTRIBUTE_NODE:
4619 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004620 case XML_DOCUMENT_NODE:
4621#ifdef LIBXML_DOCB_ENABLED
4622 case XML_DOCB_DOCUMENT_NODE:
4623#endif
4624 case XML_HTML_DOCUMENT_NODE: {
4625 xmlDocPtr doc = (xmlDocPtr) cur;
4626
4627 if (doc->URL != NULL)
4628 xmlFree((xmlChar *) doc->URL);
4629 if (uri == NULL)
4630 doc->URL = NULL;
4631 else
4632 doc->URL = xmlStrdup(uri);
4633 return;
4634 }
Owen Taylor3473f882001-02-23 17:55:21 +00004635 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004636
4637 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4638 if (ns == NULL)
4639 return;
4640 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004641}
Daniel Veillard652327a2003-09-29 18:02:38 +00004642#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004643
4644/**
Owen Taylor3473f882001-02-23 17:55:21 +00004645 * xmlNodeGetBase:
4646 * @doc: the document the node pertains to
4647 * @cur: the node being checked
4648 *
4649 * Searches for the BASE URL. The code should work on both XML
4650 * and HTML document even if base mechanisms are completely different.
4651 * It returns the base as defined in RFC 2396 sections
4652 * 5.1.1. Base URI within Document Content
4653 * and
4654 * 5.1.2. Base URI from the Encapsulating Entity
4655 * However it does not return the document base (5.1.3), use
4656 * xmlDocumentGetBase() for this
4657 *
4658 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004659 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004660 */
4661xmlChar *
4662xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004663 xmlChar *oldbase = NULL;
4664 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004665
4666 if ((cur == NULL) && (doc == NULL))
4667 return(NULL);
4668 if (doc == NULL) doc = cur->doc;
4669 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4670 cur = doc->children;
4671 while ((cur != NULL) && (cur->name != NULL)) {
4672 if (cur->type != XML_ELEMENT_NODE) {
4673 cur = cur->next;
4674 continue;
4675 }
4676 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4677 cur = cur->children;
4678 continue;
4679 }
4680 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4681 cur = cur->children;
4682 continue;
4683 }
4684 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4685 return(xmlGetProp(cur, BAD_CAST "href"));
4686 }
4687 cur = cur->next;
4688 }
4689 return(NULL);
4690 }
4691 while (cur != NULL) {
4692 if (cur->type == XML_ENTITY_DECL) {
4693 xmlEntityPtr ent = (xmlEntityPtr) cur;
4694 return(xmlStrdup(ent->URI));
4695 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004696 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004697 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004698 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004699 if (oldbase != NULL) {
4700 newbase = xmlBuildURI(oldbase, base);
4701 if (newbase != NULL) {
4702 xmlFree(oldbase);
4703 xmlFree(base);
4704 oldbase = newbase;
4705 } else {
4706 xmlFree(oldbase);
4707 xmlFree(base);
4708 return(NULL);
4709 }
4710 } else {
4711 oldbase = base;
4712 }
4713 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4714 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4715 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4716 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004717 }
4718 }
Owen Taylor3473f882001-02-23 17:55:21 +00004719 cur = cur->parent;
4720 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004721 if ((doc != NULL) && (doc->URL != NULL)) {
4722 if (oldbase == NULL)
4723 return(xmlStrdup(doc->URL));
4724 newbase = xmlBuildURI(oldbase, doc->URL);
4725 xmlFree(oldbase);
4726 return(newbase);
4727 }
4728 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004729}
4730
4731/**
Daniel Veillard78697292003-10-19 20:44:43 +00004732 * xmlNodeBufGetContent:
4733 * @buffer: a buffer
4734 * @cur: the node being read
4735 *
4736 * Read the value of a node @cur, this can be either the text carried
4737 * directly by this node if it's a TEXT node or the aggregate string
4738 * of the values carried by this node child's (TEXT and ENTITY_REF).
4739 * Entity references are substituted.
4740 * Fills up the buffer @buffer with this value
4741 *
4742 * Returns 0 in case of success and -1 in case of error.
4743 */
4744int
4745xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
4746{
4747 if ((cur == NULL) || (buffer == NULL)) return(-1);
4748 switch (cur->type) {
4749 case XML_CDATA_SECTION_NODE:
4750 case XML_TEXT_NODE:
4751 xmlBufferCat(buffer, cur->content);
4752 break;
4753 case XML_DOCUMENT_FRAG_NODE:
4754 case XML_ELEMENT_NODE:{
4755 xmlNodePtr tmp = cur;
4756
4757 while (tmp != NULL) {
4758 switch (tmp->type) {
4759 case XML_CDATA_SECTION_NODE:
4760 case XML_TEXT_NODE:
4761 if (tmp->content != NULL)
4762 xmlBufferCat(buffer, tmp->content);
4763 break;
4764 case XML_ENTITY_REF_NODE:
4765 xmlNodeBufGetContent(buffer, tmp->children);
4766 break;
4767 default:
4768 break;
4769 }
4770 /*
4771 * Skip to next node
4772 */
4773 if (tmp->children != NULL) {
4774 if (tmp->children->type != XML_ENTITY_DECL) {
4775 tmp = tmp->children;
4776 continue;
4777 }
4778 }
4779 if (tmp == cur)
4780 break;
4781
4782 if (tmp->next != NULL) {
4783 tmp = tmp->next;
4784 continue;
4785 }
4786
4787 do {
4788 tmp = tmp->parent;
4789 if (tmp == NULL)
4790 break;
4791 if (tmp == cur) {
4792 tmp = NULL;
4793 break;
4794 }
4795 if (tmp->next != NULL) {
4796 tmp = tmp->next;
4797 break;
4798 }
4799 } while (tmp != NULL);
4800 }
4801 break;
4802 }
4803 case XML_ATTRIBUTE_NODE:{
4804 xmlAttrPtr attr = (xmlAttrPtr) cur;
4805 xmlNodePtr tmp = attr->children;
4806
4807 while (tmp != NULL) {
4808 if (tmp->type == XML_TEXT_NODE)
4809 xmlBufferCat(buffer, tmp->content);
4810 else
4811 xmlNodeBufGetContent(buffer, tmp);
4812 tmp = tmp->next;
4813 }
4814 break;
4815 }
4816 case XML_COMMENT_NODE:
4817 case XML_PI_NODE:
4818 xmlBufferCat(buffer, cur->content);
4819 break;
4820 case XML_ENTITY_REF_NODE:{
4821 xmlEntityPtr ent;
4822 xmlNodePtr tmp;
4823
4824 /* lookup entity declaration */
4825 ent = xmlGetDocEntity(cur->doc, cur->name);
4826 if (ent == NULL)
4827 return(-1);
4828
4829 /* an entity content can be any "well balanced chunk",
4830 * i.e. the result of the content [43] production:
4831 * http://www.w3.org/TR/REC-xml#NT-content
4832 * -> we iterate through child nodes and recursive call
4833 * xmlNodeGetContent() which handles all possible node types */
4834 tmp = ent->children;
4835 while (tmp) {
4836 xmlNodeBufGetContent(buffer, tmp);
4837 tmp = tmp->next;
4838 }
4839 break;
4840 }
4841 case XML_ENTITY_NODE:
4842 case XML_DOCUMENT_TYPE_NODE:
4843 case XML_NOTATION_NODE:
4844 case XML_DTD_NODE:
4845 case XML_XINCLUDE_START:
4846 case XML_XINCLUDE_END:
4847 break;
4848 case XML_DOCUMENT_NODE:
4849#ifdef LIBXML_DOCB_ENABLED
4850 case XML_DOCB_DOCUMENT_NODE:
4851#endif
4852 case XML_HTML_DOCUMENT_NODE:
4853 cur = cur->children;
4854 while (cur!= NULL) {
4855 if ((cur->type == XML_ELEMENT_NODE) ||
4856 (cur->type == XML_TEXT_NODE) ||
4857 (cur->type == XML_CDATA_SECTION_NODE)) {
4858 xmlNodeBufGetContent(buffer, cur);
4859 }
4860 cur = cur->next;
4861 }
4862 break;
4863 case XML_NAMESPACE_DECL:
4864 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
4865 break;
4866 case XML_ELEMENT_DECL:
4867 case XML_ATTRIBUTE_DECL:
4868 case XML_ENTITY_DECL:
4869 break;
4870 }
4871 return(0);
4872}
4873/**
Owen Taylor3473f882001-02-23 17:55:21 +00004874 * xmlNodeGetContent:
4875 * @cur: the node being read
4876 *
4877 * Read the value of a node, this can be either the text carried
4878 * directly by this node if it's a TEXT node or the aggregate string
4879 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004880 * Entity references are substituted.
4881 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004882 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004883 */
4884xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004885xmlNodeGetContent(xmlNodePtr cur)
4886{
4887 if (cur == NULL)
4888 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004889 switch (cur->type) {
4890 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004891 case XML_ELEMENT_NODE:{
Daniel Veillard7646b182002-04-20 06:41:40 +00004892 xmlBufferPtr buffer;
4893 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004894
Daniel Veillard814a76d2003-01-23 18:24:20 +00004895 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004896 if (buffer == NULL)
4897 return (NULL);
Daniel Veillardc4696922003-10-19 21:47:14 +00004898 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00004899 ret = buffer->content;
4900 buffer->content = NULL;
4901 xmlBufferFree(buffer);
4902 return (ret);
4903 }
4904 case XML_ATTRIBUTE_NODE:{
4905 xmlAttrPtr attr = (xmlAttrPtr) cur;
4906
4907 if (attr->parent != NULL)
4908 return (xmlNodeListGetString
4909 (attr->parent->doc, attr->children, 1));
4910 else
4911 return (xmlNodeListGetString(NULL, attr->children, 1));
4912 break;
4913 }
Owen Taylor3473f882001-02-23 17:55:21 +00004914 case XML_COMMENT_NODE:
4915 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004916 if (cur->content != NULL)
4917 return (xmlStrdup(cur->content));
4918 return (NULL);
4919 case XML_ENTITY_REF_NODE:{
4920 xmlEntityPtr ent;
Daniel Veillard7646b182002-04-20 06:41:40 +00004921 xmlBufferPtr buffer;
4922 xmlChar *ret;
4923
4924 /* lookup entity declaration */
4925 ent = xmlGetDocEntity(cur->doc, cur->name);
4926 if (ent == NULL)
4927 return (NULL);
4928
4929 buffer = xmlBufferCreate();
4930 if (buffer == NULL)
4931 return (NULL);
4932
Daniel Veillardc4696922003-10-19 21:47:14 +00004933 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00004934
4935 ret = buffer->content;
4936 buffer->content = NULL;
4937 xmlBufferFree(buffer);
4938 return (ret);
4939 }
Owen Taylor3473f882001-02-23 17:55:21 +00004940 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004941 case XML_DOCUMENT_TYPE_NODE:
4942 case XML_NOTATION_NODE:
4943 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004944 case XML_XINCLUDE_START:
4945 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00004946 return (NULL);
4947 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004948#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004949 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004950#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00004951 case XML_HTML_DOCUMENT_NODE: {
Daniel Veillardc4696922003-10-19 21:47:14 +00004952 xmlBufferPtr buffer;
4953 xmlChar *ret;
Daniel Veillard9adc0462003-03-24 18:39:54 +00004954
Daniel Veillardc4696922003-10-19 21:47:14 +00004955 buffer = xmlBufferCreate();
4956 if (buffer == NULL)
4957 return (NULL);
4958
4959 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
4960
4961 ret = buffer->content;
4962 buffer->content = NULL;
4963 xmlBufferFree(buffer);
4964 return (ret);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004965 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004966 case XML_NAMESPACE_DECL: {
4967 xmlChar *tmp;
4968
4969 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4970 return (tmp);
4971 }
Owen Taylor3473f882001-02-23 17:55:21 +00004972 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004973 /* TODO !!! */
4974 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004975 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004976 /* TODO !!! */
4977 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004978 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004979 /* TODO !!! */
4980 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004981 case XML_CDATA_SECTION_NODE:
4982 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004983 if (cur->content != NULL)
4984 return (xmlStrdup(cur->content));
4985 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004986 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004987 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004988}
Daniel Veillard652327a2003-09-29 18:02:38 +00004989
Owen Taylor3473f882001-02-23 17:55:21 +00004990/**
4991 * xmlNodeSetContent:
4992 * @cur: the node being modified
4993 * @content: the new value of the content
4994 *
4995 * Replace the content of a node.
4996 */
4997void
4998xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4999 if (cur == NULL) {
5000#ifdef DEBUG_TREE
5001 xmlGenericError(xmlGenericErrorContext,
5002 "xmlNodeSetContent : node == NULL\n");
5003#endif
5004 return;
5005 }
5006 switch (cur->type) {
5007 case XML_DOCUMENT_FRAG_NODE:
5008 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005009 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005010 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5011 cur->children = xmlStringGetNodeList(cur->doc, content);
5012 UPDATE_LAST_CHILD_AND_PARENT(cur)
5013 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005014 case XML_TEXT_NODE:
5015 case XML_CDATA_SECTION_NODE:
5016 case XML_ENTITY_REF_NODE:
5017 case XML_ENTITY_NODE:
5018 case XML_PI_NODE:
5019 case XML_COMMENT_NODE:
5020 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005021 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005022 }
5023 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5024 cur->last = cur->children = NULL;
5025 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005026 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00005027 } else
5028 cur->content = NULL;
5029 break;
5030 case XML_DOCUMENT_NODE:
5031 case XML_HTML_DOCUMENT_NODE:
5032 case XML_DOCUMENT_TYPE_NODE:
5033 case XML_XINCLUDE_START:
5034 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005035#ifdef LIBXML_DOCB_ENABLED
5036 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005037#endif
5038 break;
5039 case XML_NOTATION_NODE:
5040 break;
5041 case XML_DTD_NODE:
5042 break;
5043 case XML_NAMESPACE_DECL:
5044 break;
5045 case XML_ELEMENT_DECL:
5046 /* TODO !!! */
5047 break;
5048 case XML_ATTRIBUTE_DECL:
5049 /* TODO !!! */
5050 break;
5051 case XML_ENTITY_DECL:
5052 /* TODO !!! */
5053 break;
5054 }
5055}
5056
Daniel Veillard652327a2003-09-29 18:02:38 +00005057#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005058/**
5059 * xmlNodeSetContentLen:
5060 * @cur: the node being modified
5061 * @content: the new value of the content
5062 * @len: the size of @content
5063 *
5064 * Replace the content of a node.
5065 */
5066void
5067xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5068 if (cur == NULL) {
5069#ifdef DEBUG_TREE
5070 xmlGenericError(xmlGenericErrorContext,
5071 "xmlNodeSetContentLen : node == NULL\n");
5072#endif
5073 return;
5074 }
5075 switch (cur->type) {
5076 case XML_DOCUMENT_FRAG_NODE:
5077 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005078 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005079 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5080 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5081 UPDATE_LAST_CHILD_AND_PARENT(cur)
5082 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005083 case XML_TEXT_NODE:
5084 case XML_CDATA_SECTION_NODE:
5085 case XML_ENTITY_REF_NODE:
5086 case XML_ENTITY_NODE:
5087 case XML_PI_NODE:
5088 case XML_COMMENT_NODE:
5089 case XML_NOTATION_NODE:
5090 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005091 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005092 }
5093 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5094 cur->children = cur->last = NULL;
5095 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005096 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005097 } else
5098 cur->content = NULL;
5099 break;
5100 case XML_DOCUMENT_NODE:
5101 case XML_DTD_NODE:
5102 case XML_HTML_DOCUMENT_NODE:
5103 case XML_DOCUMENT_TYPE_NODE:
5104 case XML_NAMESPACE_DECL:
5105 case XML_XINCLUDE_START:
5106 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005107#ifdef LIBXML_DOCB_ENABLED
5108 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005109#endif
5110 break;
5111 case XML_ELEMENT_DECL:
5112 /* TODO !!! */
5113 break;
5114 case XML_ATTRIBUTE_DECL:
5115 /* TODO !!! */
5116 break;
5117 case XML_ENTITY_DECL:
5118 /* TODO !!! */
5119 break;
5120 }
5121}
Daniel Veillard652327a2003-09-29 18:02:38 +00005122#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005123
5124/**
5125 * xmlNodeAddContentLen:
5126 * @cur: the node being modified
5127 * @content: extra content
5128 * @len: the size of @content
5129 *
5130 * Append the extra substring to the node content.
5131 */
5132void
5133xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5134 if (cur == NULL) {
5135#ifdef DEBUG_TREE
5136 xmlGenericError(xmlGenericErrorContext,
5137 "xmlNodeAddContentLen : node == NULL\n");
5138#endif
5139 return;
5140 }
5141 if (len <= 0) return;
5142 switch (cur->type) {
5143 case XML_DOCUMENT_FRAG_NODE:
5144 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005145 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005146
Daniel Veillard7db37732001-07-12 01:20:08 +00005147 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005148 newNode = xmlNewTextLen(content, len);
5149 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005150 tmp = xmlAddChild(cur, newNode);
5151 if (tmp != newNode)
5152 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005153 if ((last != NULL) && (last->next == newNode)) {
5154 xmlTextMerge(last, newNode);
5155 }
5156 }
5157 break;
5158 }
5159 case XML_ATTRIBUTE_NODE:
5160 break;
5161 case XML_TEXT_NODE:
5162 case XML_CDATA_SECTION_NODE:
5163 case XML_ENTITY_REF_NODE:
5164 case XML_ENTITY_NODE:
5165 case XML_PI_NODE:
5166 case XML_COMMENT_NODE:
5167 case XML_NOTATION_NODE:
5168 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005169 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005170 }
5171 case XML_DOCUMENT_NODE:
5172 case XML_DTD_NODE:
5173 case XML_HTML_DOCUMENT_NODE:
5174 case XML_DOCUMENT_TYPE_NODE:
5175 case XML_NAMESPACE_DECL:
5176 case XML_XINCLUDE_START:
5177 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005178#ifdef LIBXML_DOCB_ENABLED
5179 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005180#endif
5181 break;
5182 case XML_ELEMENT_DECL:
5183 case XML_ATTRIBUTE_DECL:
5184 case XML_ENTITY_DECL:
5185 break;
5186 }
5187}
5188
5189/**
5190 * xmlNodeAddContent:
5191 * @cur: the node being modified
5192 * @content: extra content
5193 *
5194 * Append the extra substring to the node content.
5195 */
5196void
5197xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5198 int len;
5199
5200 if (cur == NULL) {
5201#ifdef DEBUG_TREE
5202 xmlGenericError(xmlGenericErrorContext,
5203 "xmlNodeAddContent : node == NULL\n");
5204#endif
5205 return;
5206 }
5207 if (content == NULL) return;
5208 len = xmlStrlen(content);
5209 xmlNodeAddContentLen(cur, content, len);
5210}
5211
5212/**
5213 * xmlTextMerge:
5214 * @first: the first text node
5215 * @second: the second text node being merged
5216 *
5217 * Merge two text nodes into one
5218 * Returns the first text node augmented
5219 */
5220xmlNodePtr
5221xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5222 if (first == NULL) return(second);
5223 if (second == NULL) return(first);
5224 if (first->type != XML_TEXT_NODE) return(first);
5225 if (second->type != XML_TEXT_NODE) return(first);
5226 if (second->name != first->name)
5227 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005228 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005229 xmlUnlinkNode(second);
5230 xmlFreeNode(second);
5231 return(first);
5232}
5233
Daniel Veillard652327a2003-09-29 18:02:38 +00005234#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005235/**
5236 * xmlGetNsList:
5237 * @doc: the document
5238 * @node: the current node
5239 *
5240 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005241 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005242 * that need to be freed by the caller or NULL if no
5243 * namespace if defined
5244 */
5245xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005246xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5247{
Owen Taylor3473f882001-02-23 17:55:21 +00005248 xmlNsPtr cur;
5249 xmlNsPtr *ret = NULL;
5250 int nbns = 0;
5251 int maxns = 10;
5252 int i;
5253
5254 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005255 if (node->type == XML_ELEMENT_NODE) {
5256 cur = node->nsDef;
5257 while (cur != NULL) {
5258 if (ret == NULL) {
5259 ret =
5260 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5261 sizeof(xmlNsPtr));
5262 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005263 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005264 return (NULL);
5265 }
5266 ret[nbns] = NULL;
5267 }
5268 for (i = 0; i < nbns; i++) {
5269 if ((cur->prefix == ret[i]->prefix) ||
5270 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5271 break;
5272 }
5273 if (i >= nbns) {
5274 if (nbns >= maxns) {
5275 maxns *= 2;
5276 ret = (xmlNsPtr *) xmlRealloc(ret,
5277 (maxns +
5278 1) *
5279 sizeof(xmlNsPtr));
5280 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005281 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005282 return (NULL);
5283 }
5284 }
5285 ret[nbns++] = cur;
5286 ret[nbns] = NULL;
5287 }
Owen Taylor3473f882001-02-23 17:55:21 +00005288
Daniel Veillard77044732001-06-29 21:31:07 +00005289 cur = cur->next;
5290 }
5291 }
5292 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005293 }
Daniel Veillard77044732001-06-29 21:31:07 +00005294 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005295}
Daniel Veillard652327a2003-09-29 18:02:38 +00005296#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005297
5298/**
5299 * xmlSearchNs:
5300 * @doc: the document
5301 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005302 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005303 *
5304 * Search a Ns registered under a given name space for a document.
5305 * recurse on the parents until it finds the defined namespace
5306 * or return NULL otherwise.
5307 * @nameSpace can be NULL, this is a search for the default namespace.
5308 * We don't allow to cross entities boundaries. If you don't declare
5309 * the namespace within those you will be in troubles !!! A warning
5310 * is generated to cover this case.
5311 *
5312 * Returns the namespace pointer or NULL.
5313 */
5314xmlNsPtr
5315xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillardf4e56292003-10-28 14:27:41 +00005316
Owen Taylor3473f882001-02-23 17:55:21 +00005317 xmlNsPtr cur;
Daniel Veillardf4e56292003-10-28 14:27:41 +00005318 xmlNodePtr orig = node;
Owen Taylor3473f882001-02-23 17:55:21 +00005319
5320 if (node == NULL) return(NULL);
5321 if ((nameSpace != NULL) &&
5322 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005323 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5324 /*
5325 * The XML-1.0 namespace is normally held on the root
5326 * element. In this case exceptionally create it on the
5327 * node element.
5328 */
5329 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5330 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005331 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005332 return(NULL);
5333 }
5334 memset(cur, 0, sizeof(xmlNs));
5335 cur->type = XML_LOCAL_NAMESPACE;
5336 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5337 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5338 cur->next = node->nsDef;
5339 node->nsDef = cur;
5340 return(cur);
5341 }
Owen Taylor3473f882001-02-23 17:55:21 +00005342 if (doc->oldNs == NULL) {
5343 /*
5344 * Allocate a new Namespace and fill the fields.
5345 */
5346 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5347 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005348 xmlTreeErrMemory("searching namespace");
Owen Taylor3473f882001-02-23 17:55:21 +00005349 return(NULL);
5350 }
5351 memset(doc->oldNs, 0, sizeof(xmlNs));
5352 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5353
5354 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5355 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5356 }
5357 return(doc->oldNs);
5358 }
5359 while (node != NULL) {
5360 if ((node->type == XML_ENTITY_REF_NODE) ||
5361 (node->type == XML_ENTITY_NODE) ||
5362 (node->type == XML_ENTITY_DECL))
5363 return(NULL);
5364 if (node->type == XML_ELEMENT_NODE) {
5365 cur = node->nsDef;
5366 while (cur != NULL) {
5367 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5368 (cur->href != NULL))
5369 return(cur);
5370 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5371 (cur->href != NULL) &&
5372 (xmlStrEqual(cur->prefix, nameSpace)))
5373 return(cur);
5374 cur = cur->next;
5375 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005376 if (orig != node) {
5377 cur = node->ns;
5378 if (cur != NULL) {
5379 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5380 (cur->href != NULL))
5381 return(cur);
5382 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5383 (cur->href != NULL) &&
5384 (xmlStrEqual(cur->prefix, nameSpace)))
5385 return(cur);
5386 }
5387 }
Owen Taylor3473f882001-02-23 17:55:21 +00005388 }
5389 node = node->parent;
5390 }
5391 return(NULL);
5392}
5393
5394/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005395 * xmlNsInScope:
5396 * @doc: the document
5397 * @node: the current node
5398 * @ancestor: the ancestor carrying the namespace
5399 * @prefix: the namespace prefix
5400 *
5401 * Verify that the given namespace held on @ancestor is still in scope
5402 * on node.
5403 *
5404 * Returns 1 if true, 0 if false and -1 in case of error.
5405 */
5406static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005407xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5408 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005409{
5410 xmlNsPtr tst;
5411
5412 while ((node != NULL) && (node != ancestor)) {
5413 if ((node->type == XML_ENTITY_REF_NODE) ||
5414 (node->type == XML_ENTITY_NODE) ||
5415 (node->type == XML_ENTITY_DECL))
5416 return (-1);
5417 if (node->type == XML_ELEMENT_NODE) {
5418 tst = node->nsDef;
5419 while (tst != NULL) {
5420 if ((tst->prefix == NULL)
5421 && (prefix == NULL))
5422 return (0);
5423 if ((tst->prefix != NULL)
5424 && (prefix != NULL)
5425 && (xmlStrEqual(tst->prefix, prefix)))
5426 return (0);
5427 tst = tst->next;
5428 }
5429 }
5430 node = node->parent;
5431 }
5432 if (node != ancestor)
5433 return (-1);
5434 return (1);
5435}
5436
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005437/**
Owen Taylor3473f882001-02-23 17:55:21 +00005438 * xmlSearchNsByHref:
5439 * @doc: the document
5440 * @node: the current node
5441 * @href: the namespace value
5442 *
5443 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5444 * the defined namespace or return NULL otherwise.
5445 * Returns the namespace pointer or NULL.
5446 */
5447xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005448xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5449{
Owen Taylor3473f882001-02-23 17:55:21 +00005450 xmlNsPtr cur;
5451 xmlNodePtr orig = node;
5452
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005453 if ((node == NULL) || (href == NULL))
5454 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005455 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005456 /*
5457 * Only the document can hold the XML spec namespace.
5458 */
5459 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5460 /*
5461 * The XML-1.0 namespace is normally held on the root
5462 * element. In this case exceptionally create it on the
5463 * node element.
5464 */
5465 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5466 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005467 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005468 return (NULL);
5469 }
5470 memset(cur, 0, sizeof(xmlNs));
5471 cur->type = XML_LOCAL_NAMESPACE;
5472 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5473 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5474 cur->next = node->nsDef;
5475 node->nsDef = cur;
5476 return (cur);
5477 }
5478 if (doc->oldNs == NULL) {
5479 /*
5480 * Allocate a new Namespace and fill the fields.
5481 */
5482 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5483 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005484 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005485 return (NULL);
5486 }
5487 memset(doc->oldNs, 0, sizeof(xmlNs));
5488 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005489
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005490 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5491 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5492 }
5493 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005494 }
5495 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005496 if ((node->type == XML_ENTITY_REF_NODE) ||
5497 (node->type == XML_ENTITY_NODE) ||
5498 (node->type == XML_ENTITY_DECL))
5499 return (NULL);
5500 if (node->type == XML_ELEMENT_NODE) {
5501 cur = node->nsDef;
5502 while (cur != NULL) {
5503 if ((cur->href != NULL) && (href != NULL) &&
5504 (xmlStrEqual(cur->href, href))) {
5505 if (xmlNsInScope(doc, orig, node, cur->href) == 1)
5506 return (cur);
5507 }
5508 cur = cur->next;
5509 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005510 if (orig != node) {
5511 cur = node->ns;
5512 if (cur != NULL) {
5513 if ((cur->href != NULL) && (href != NULL) &&
5514 (xmlStrEqual(cur->href, href))) {
5515 if (xmlNsInScope(doc, orig, node, cur->href) == 1)
5516 return (cur);
5517 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005518 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005519 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005520 }
5521 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005522 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005523 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005524}
5525
5526/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005527 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005528 * @doc: the document
5529 * @tree: a node expected to hold the new namespace
5530 * @ns: the original namespace
5531 *
5532 * This function tries to locate a namespace definition in a tree
5533 * ancestors, or create a new namespace definition node similar to
5534 * @ns trying to reuse the same prefix. However if the given prefix is
5535 * null (default namespace) or reused within the subtree defined by
5536 * @tree or on one of its ancestors then a new prefix is generated.
5537 * Returns the (new) namespace definition or NULL in case of error
5538 */
5539xmlNsPtr
5540xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5541 xmlNsPtr def;
5542 xmlChar prefix[50];
5543 int counter = 1;
5544
5545 if (tree == NULL) {
5546#ifdef DEBUG_TREE
5547 xmlGenericError(xmlGenericErrorContext,
5548 "xmlNewReconciliedNs : tree == NULL\n");
5549#endif
5550 return(NULL);
5551 }
5552 if (ns == NULL) {
5553#ifdef DEBUG_TREE
5554 xmlGenericError(xmlGenericErrorContext,
5555 "xmlNewReconciliedNs : ns == NULL\n");
5556#endif
5557 return(NULL);
5558 }
5559 /*
5560 * Search an existing namespace definition inherited.
5561 */
5562 def = xmlSearchNsByHref(doc, tree, ns->href);
5563 if (def != NULL)
5564 return(def);
5565
5566 /*
5567 * Find a close prefix which is not already in use.
5568 * Let's strip namespace prefixes longer than 20 chars !
5569 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005570 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005571 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005572 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005573 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005574
Owen Taylor3473f882001-02-23 17:55:21 +00005575 def = xmlSearchNs(doc, tree, prefix);
5576 while (def != NULL) {
5577 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005578 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005579 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005580 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005581 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005582 def = xmlSearchNs(doc, tree, prefix);
5583 }
5584
5585 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005586 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005587 */
5588 def = xmlNewNs(tree, ns->href, prefix);
5589 return(def);
5590}
5591
Daniel Veillard652327a2003-09-29 18:02:38 +00005592#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005593/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005594 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005595 * @doc: the document
5596 * @tree: a node defining the subtree to reconciliate
5597 *
5598 * This function checks that all the namespaces declared within the given
5599 * tree are properly declared. This is needed for example after Copy or Cut
5600 * and then paste operations. The subtree may still hold pointers to
5601 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005602 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005603 * the new environment. If not possible the new namespaces are redeclared
5604 * on @tree at the top of the given subtree.
5605 * Returns the number of namespace declarations created or -1 in case of error.
5606 */
5607int
5608xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5609 xmlNsPtr *oldNs = NULL;
5610 xmlNsPtr *newNs = NULL;
5611 int sizeCache = 0;
5612 int nbCache = 0;
5613
5614 xmlNsPtr n;
5615 xmlNodePtr node = tree;
5616 xmlAttrPtr attr;
5617 int ret = 0, i;
5618
5619 while (node != NULL) {
5620 /*
5621 * Reconciliate the node namespace
5622 */
5623 if (node->ns != NULL) {
5624 /*
5625 * initialize the cache if needed
5626 */
5627 if (sizeCache == 0) {
5628 sizeCache = 10;
5629 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5630 sizeof(xmlNsPtr));
5631 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005632 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005633 return(-1);
5634 }
5635 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5636 sizeof(xmlNsPtr));
5637 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005638 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005639 xmlFree(oldNs);
5640 return(-1);
5641 }
5642 }
5643 for (i = 0;i < nbCache;i++) {
5644 if (oldNs[i] == node->ns) {
5645 node->ns = newNs[i];
5646 break;
5647 }
5648 }
5649 if (i == nbCache) {
5650 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005651 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005652 */
5653 n = xmlNewReconciliedNs(doc, tree, node->ns);
5654 if (n != NULL) { /* :-( what if else ??? */
5655 /*
5656 * check if we need to grow the cache buffers.
5657 */
5658 if (sizeCache <= nbCache) {
5659 sizeCache *= 2;
5660 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5661 sizeof(xmlNsPtr));
5662 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005663 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005664 xmlFree(newNs);
5665 return(-1);
5666 }
5667 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5668 sizeof(xmlNsPtr));
5669 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005670 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005671 xmlFree(oldNs);
5672 return(-1);
5673 }
5674 }
5675 newNs[nbCache] = n;
5676 oldNs[nbCache++] = node->ns;
5677 node->ns = n;
5678 }
5679 }
5680 }
5681 /*
5682 * now check for namespace hold by attributes on the node.
5683 */
5684 attr = node->properties;
5685 while (attr != NULL) {
5686 if (attr->ns != NULL) {
5687 /*
5688 * initialize the cache if needed
5689 */
5690 if (sizeCache == 0) {
5691 sizeCache = 10;
5692 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5693 sizeof(xmlNsPtr));
5694 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005695 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005696 return(-1);
5697 }
5698 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5699 sizeof(xmlNsPtr));
5700 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005701 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005702 xmlFree(oldNs);
5703 return(-1);
5704 }
5705 }
5706 for (i = 0;i < nbCache;i++) {
5707 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005708 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005709 break;
5710 }
5711 }
5712 if (i == nbCache) {
5713 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005714 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005715 */
5716 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5717 if (n != NULL) { /* :-( what if else ??? */
5718 /*
5719 * check if we need to grow the cache buffers.
5720 */
5721 if (sizeCache <= nbCache) {
5722 sizeCache *= 2;
5723 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5724 sizeof(xmlNsPtr));
5725 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005726 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005727 xmlFree(newNs);
5728 return(-1);
5729 }
5730 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5731 sizeof(xmlNsPtr));
5732 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005733 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005734 xmlFree(oldNs);
5735 return(-1);
5736 }
5737 }
5738 newNs[nbCache] = n;
5739 oldNs[nbCache++] = attr->ns;
5740 attr->ns = n;
5741 }
5742 }
5743 }
5744 attr = attr->next;
5745 }
5746
5747 /*
5748 * Browse the full subtree, deep first
5749 */
5750 if (node->children != NULL) {
5751 /* deep first */
5752 node = node->children;
5753 } else if ((node != tree) && (node->next != NULL)) {
5754 /* then siblings */
5755 node = node->next;
5756 } else if (node != tree) {
5757 /* go up to parents->next if needed */
5758 while (node != tree) {
5759 if (node->parent != NULL)
5760 node = node->parent;
5761 if ((node != tree) && (node->next != NULL)) {
5762 node = node->next;
5763 break;
5764 }
5765 if (node->parent == NULL) {
5766 node = NULL;
5767 break;
5768 }
5769 }
5770 /* exit condition */
5771 if (node == tree)
5772 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005773 } else
5774 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005775 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005776 if (oldNs != NULL)
5777 xmlFree(oldNs);
5778 if (newNs != NULL)
5779 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005780 return(ret);
5781}
Daniel Veillard652327a2003-09-29 18:02:38 +00005782#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005783
5784/**
5785 * xmlHasProp:
5786 * @node: the node
5787 * @name: the attribute name
5788 *
5789 * Search an attribute associated to a node
5790 * This function also looks in DTD attribute declaration for #FIXED or
5791 * default declaration values unless DTD use has been turned off.
5792 *
5793 * Returns the attribute or the attribute declaration or NULL if
5794 * neither was found.
5795 */
5796xmlAttrPtr
5797xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5798 xmlAttrPtr prop;
5799 xmlDocPtr doc;
5800
5801 if ((node == NULL) || (name == NULL)) return(NULL);
5802 /*
5803 * Check on the properties attached to the node
5804 */
5805 prop = node->properties;
5806 while (prop != NULL) {
5807 if (xmlStrEqual(prop->name, name)) {
5808 return(prop);
5809 }
5810 prop = prop->next;
5811 }
5812 if (!xmlCheckDTD) return(NULL);
5813
5814 /*
5815 * Check if there is a default declaration in the internal
5816 * or external subsets
5817 */
5818 doc = node->doc;
5819 if (doc != NULL) {
5820 xmlAttributePtr attrDecl;
5821 if (doc->intSubset != NULL) {
5822 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5823 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5824 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005825 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5826 /* return attribute declaration only if a default value is given
5827 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005828 return((xmlAttrPtr) attrDecl);
5829 }
5830 }
5831 return(NULL);
5832}
5833
5834/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005835 * xmlHasNsProp:
5836 * @node: the node
5837 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005838 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005839 *
5840 * Search for an attribute associated to a node
5841 * This attribute has to be anchored in the namespace specified.
5842 * This does the entity substitution.
5843 * This function looks in DTD attribute declaration for #FIXED or
5844 * default declaration values unless DTD use has been turned off.
5845 *
5846 * Returns the attribute or the attribute declaration or NULL
5847 * if neither was found.
5848 */
5849xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005850xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005851 xmlAttrPtr prop;
Daniel Veillard652327a2003-09-29 18:02:38 +00005852#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005853 xmlDocPtr doc;
Daniel Veillard652327a2003-09-29 18:02:38 +00005854#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005855
5856 if (node == NULL)
5857 return(NULL);
5858
5859 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005860 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005861 return(xmlHasProp(node, name));
5862 while (prop != NULL) {
5863 /*
5864 * One need to have
5865 * - same attribute names
5866 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005867 */
5868 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005869 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5870 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005871 }
5872 prop = prop->next;
5873 }
5874 if (!xmlCheckDTD) return(NULL);
5875
Daniel Veillard652327a2003-09-29 18:02:38 +00005876#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005877 /*
5878 * Check if there is a default declaration in the internal
5879 * or external subsets
5880 */
5881 doc = node->doc;
5882 if (doc != NULL) {
5883 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005884 xmlAttributePtr attrDecl = NULL;
5885 xmlNsPtr *nsList, *cur;
5886 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005887
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005888 nsList = xmlGetNsList(node->doc, node);
5889 if (nsList == NULL)
5890 return(NULL);
5891 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5892 ename = xmlStrdup(node->ns->prefix);
5893 ename = xmlStrcat(ename, BAD_CAST ":");
5894 ename = xmlStrcat(ename, node->name);
5895 } else {
5896 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005897 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005898 if (ename == NULL) {
5899 xmlFree(nsList);
5900 return(NULL);
5901 }
5902
5903 cur = nsList;
5904 while (*cur != NULL) {
5905 if (xmlStrEqual((*cur)->href, nameSpace)) {
5906 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5907 name, (*cur)->prefix);
5908 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5909 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5910 name, (*cur)->prefix);
5911 }
5912 cur++;
5913 }
5914 xmlFree(nsList);
5915 xmlFree(ename);
5916 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005917 }
5918 }
Daniel Veillard652327a2003-09-29 18:02:38 +00005919#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005920 return(NULL);
5921}
5922
5923/**
Owen Taylor3473f882001-02-23 17:55:21 +00005924 * xmlGetProp:
5925 * @node: the node
5926 * @name: the attribute name
5927 *
5928 * Search and get the value of an attribute associated to a node
5929 * This does the entity substitution.
5930 * This function looks in DTD attribute declaration for #FIXED or
5931 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00005932 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00005933 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
5934 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00005935 *
5936 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005937 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005938 */
5939xmlChar *
5940xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5941 xmlAttrPtr prop;
5942 xmlDocPtr doc;
5943
5944 if ((node == NULL) || (name == NULL)) return(NULL);
5945 /*
5946 * Check on the properties attached to the node
5947 */
5948 prop = node->properties;
5949 while (prop != NULL) {
5950 if (xmlStrEqual(prop->name, name)) {
5951 xmlChar *ret;
5952
5953 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5954 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5955 return(ret);
5956 }
5957 prop = prop->next;
5958 }
5959 if (!xmlCheckDTD) return(NULL);
5960
5961 /*
5962 * Check if there is a default declaration in the internal
5963 * or external subsets
5964 */
5965 doc = node->doc;
5966 if (doc != NULL) {
5967 xmlAttributePtr attrDecl;
5968 if (doc->intSubset != NULL) {
5969 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5970 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5971 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005972 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5973 /* return attribute declaration only if a default value is given
5974 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005975 return(xmlStrdup(attrDecl->defaultValue));
5976 }
5977 }
5978 return(NULL);
5979}
5980
5981/**
Daniel Veillard71531f32003-02-05 13:19:53 +00005982 * xmlGetNoNsProp:
5983 * @node: the node
5984 * @name: the attribute name
5985 *
5986 * Search and get the value of an attribute associated to a node
5987 * This does the entity substitution.
5988 * This function looks in DTD attribute declaration for #FIXED or
5989 * default declaration values unless DTD use has been turned off.
5990 * This function is similar to xmlGetProp except it will accept only
5991 * an attribute in no namespace.
5992 *
5993 * Returns the attribute value or NULL if not found.
5994 * It's up to the caller to free the memory with xmlFree().
5995 */
5996xmlChar *
5997xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
5998 xmlAttrPtr prop;
5999 xmlDocPtr doc;
6000
6001 if ((node == NULL) || (name == NULL)) return(NULL);
6002 /*
6003 * Check on the properties attached to the node
6004 */
6005 prop = node->properties;
6006 while (prop != NULL) {
6007 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
6008 xmlChar *ret;
6009
6010 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6011 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6012 return(ret);
6013 }
6014 prop = prop->next;
6015 }
6016 if (!xmlCheckDTD) return(NULL);
6017
6018 /*
6019 * Check if there is a default declaration in the internal
6020 * or external subsets
6021 */
6022 doc = node->doc;
6023 if (doc != NULL) {
6024 xmlAttributePtr attrDecl;
6025 if (doc->intSubset != NULL) {
6026 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6027 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6028 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006029 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6030 /* return attribute declaration only if a default value is given
6031 (that includes #FIXED declarations) */
Daniel Veillard71531f32003-02-05 13:19:53 +00006032 return(xmlStrdup(attrDecl->defaultValue));
6033 }
6034 }
6035 return(NULL);
6036}
6037
6038/**
Owen Taylor3473f882001-02-23 17:55:21 +00006039 * xmlGetNsProp:
6040 * @node: the node
6041 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006042 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006043 *
6044 * Search and get the value of an attribute associated to a node
6045 * This attribute has to be anchored in the namespace specified.
6046 * This does the entity substitution.
6047 * This function looks in DTD attribute declaration for #FIXED or
6048 * default declaration values unless DTD use has been turned off.
6049 *
6050 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006051 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006052 */
6053xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006054xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006055 xmlAttrPtr prop;
6056 xmlDocPtr doc;
6057 xmlNsPtr ns;
6058
6059 if (node == NULL)
6060 return(NULL);
6061
6062 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00006063 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00006064 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00006065 while (prop != NULL) {
6066 /*
6067 * One need to have
6068 * - same attribute names
6069 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006070 */
6071 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00006072 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00006073 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006074 xmlChar *ret;
6075
6076 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6077 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6078 return(ret);
6079 }
6080 prop = prop->next;
6081 }
6082 if (!xmlCheckDTD) return(NULL);
6083
6084 /*
6085 * Check if there is a default declaration in the internal
6086 * or external subsets
6087 */
6088 doc = node->doc;
6089 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006090 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00006091 xmlAttributePtr attrDecl;
6092
Owen Taylor3473f882001-02-23 17:55:21 +00006093 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6094 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6095 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
6096
6097 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
6098 /*
6099 * The DTD declaration only allows a prefix search
6100 */
6101 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00006102 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00006103 return(xmlStrdup(attrDecl->defaultValue));
6104 }
6105 }
6106 }
6107 return(NULL);
6108}
6109
Daniel Veillard652327a2003-09-29 18:02:38 +00006110#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00006111/**
6112 * xmlSetProp:
6113 * @node: the node
6114 * @name: the attribute name
6115 * @value: the attribute value
6116 *
6117 * Set (or reset) an attribute carried by a node.
6118 * Returns the attribute pointer.
6119 */
6120xmlAttrPtr
6121xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006122 xmlAttrPtr prop;
6123 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00006124
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006125 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006126 return(NULL);
6127 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006128 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00006129 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006130 if ((xmlStrEqual(prop->name, name)) &&
6131 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006132 xmlNodePtr oldprop = prop->children;
6133
Owen Taylor3473f882001-02-23 17:55:21 +00006134 prop->children = NULL;
6135 prop->last = NULL;
6136 if (value != NULL) {
6137 xmlChar *buffer;
6138 xmlNodePtr tmp;
6139
6140 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6141 prop->children = xmlStringGetNodeList(node->doc, buffer);
6142 prop->last = NULL;
6143 prop->doc = doc;
6144 tmp = prop->children;
6145 while (tmp != NULL) {
6146 tmp->parent = (xmlNodePtr) prop;
6147 tmp->doc = doc;
6148 if (tmp->next == NULL)
6149 prop->last = tmp;
6150 tmp = tmp->next;
6151 }
6152 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00006153 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006154 if (oldprop != NULL)
6155 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00006156 return(prop);
6157 }
6158 prop = prop->next;
6159 }
6160 prop = xmlNewProp(node, name, value);
6161 return(prop);
6162}
6163
6164/**
Daniel Veillard75bea542001-05-11 17:41:21 +00006165 * xmlUnsetProp:
6166 * @node: the node
6167 * @name: the attribute name
6168 *
6169 * Remove an attribute carried by a node.
6170 * Returns 0 if successful, -1 if not found
6171 */
6172int
6173xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Daniel Veillard814a76d2003-01-23 18:24:20 +00006174 xmlAttrPtr prop, prev = NULL;;
Daniel Veillard75bea542001-05-11 17:41:21 +00006175
6176 if ((node == NULL) || (name == NULL))
6177 return(-1);
Daniel Veillard814a76d2003-01-23 18:24:20 +00006178 prop = node->properties;
Daniel Veillard75bea542001-05-11 17:41:21 +00006179 while (prop != NULL) {
6180 if ((xmlStrEqual(prop->name, name)) &&
6181 (prop->ns == NULL)) {
6182 if (prev == NULL)
6183 node->properties = prop->next;
6184 else
6185 prev->next = prop->next;
6186 xmlFreeProp(prop);
6187 return(0);
6188 }
6189 prev = prop;
6190 prop = prop->next;
6191 }
6192 return(-1);
6193}
6194
6195/**
Owen Taylor3473f882001-02-23 17:55:21 +00006196 * xmlSetNsProp:
6197 * @node: the node
6198 * @ns: the namespace definition
6199 * @name: the attribute name
6200 * @value: the attribute value
6201 *
6202 * Set (or reset) an attribute carried by a node.
6203 * The ns structure must be in scope, this is not checked.
6204 *
6205 * Returns the attribute pointer.
6206 */
6207xmlAttrPtr
6208xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
6209 const xmlChar *value) {
6210 xmlAttrPtr prop;
6211
6212 if ((node == NULL) || (name == NULL))
6213 return(NULL);
6214
6215 if (ns == NULL)
6216 return(xmlSetProp(node, name, value));
6217 if (ns->href == NULL)
6218 return(NULL);
6219 prop = node->properties;
6220
6221 while (prop != NULL) {
6222 /*
6223 * One need to have
6224 * - same attribute names
6225 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006226 */
6227 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00006228 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006229 if (prop->children != NULL)
6230 xmlFreeNodeList(prop->children);
6231 prop->children = NULL;
6232 prop->last = NULL;
6233 prop->ns = ns;
6234 if (value != NULL) {
6235 xmlChar *buffer;
6236 xmlNodePtr tmp;
6237
6238 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6239 prop->children = xmlStringGetNodeList(node->doc, buffer);
6240 prop->last = NULL;
6241 tmp = prop->children;
6242 while (tmp != NULL) {
6243 tmp->parent = (xmlNodePtr) prop;
6244 if (tmp->next == NULL)
6245 prop->last = tmp;
6246 tmp = tmp->next;
6247 }
6248 xmlFree(buffer);
6249 }
6250 return(prop);
6251 }
6252 prop = prop->next;
6253 }
6254 prop = xmlNewNsProp(node, ns, name, value);
6255 return(prop);
6256}
6257
6258/**
Daniel Veillard75bea542001-05-11 17:41:21 +00006259 * xmlUnsetNsProp:
6260 * @node: the node
6261 * @ns: the namespace definition
6262 * @name: the attribute name
6263 *
6264 * Remove an attribute carried by a node.
6265 * Returns 0 if successful, -1 if not found
6266 */
6267int
6268xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
6269 xmlAttrPtr prop = node->properties, prev = NULL;;
6270
6271 if ((node == NULL) || (name == NULL))
6272 return(-1);
6273 if (ns == NULL)
6274 return(xmlUnsetProp(node, name));
6275 if (ns->href == NULL)
6276 return(-1);
6277 while (prop != NULL) {
6278 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00006279 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006280 if (prev == NULL)
6281 node->properties = prop->next;
6282 else
6283 prev->next = prop->next;
6284 xmlFreeProp(prop);
6285 return(0);
6286 }
6287 prev = prop;
6288 prop = prop->next;
6289 }
6290 return(-1);
6291}
Daniel Veillard652327a2003-09-29 18:02:38 +00006292#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006293
6294/**
Owen Taylor3473f882001-02-23 17:55:21 +00006295 * xmlNodeIsText:
6296 * @node: the node
6297 *
6298 * Is this node a Text node ?
6299 * Returns 1 yes, 0 no
6300 */
6301int
6302xmlNodeIsText(xmlNodePtr node) {
6303 if (node == NULL) return(0);
6304
6305 if (node->type == XML_TEXT_NODE) return(1);
6306 return(0);
6307}
6308
6309/**
6310 * xmlIsBlankNode:
6311 * @node: the node
6312 *
6313 * Checks whether this node is an empty or whitespace only
6314 * (and possibly ignorable) text-node.
6315 *
6316 * Returns 1 yes, 0 no
6317 */
6318int
6319xmlIsBlankNode(xmlNodePtr node) {
6320 const xmlChar *cur;
6321 if (node == NULL) return(0);
6322
Daniel Veillard7db37732001-07-12 01:20:08 +00006323 if ((node->type != XML_TEXT_NODE) &&
6324 (node->type != XML_CDATA_SECTION_NODE))
6325 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006326 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006327 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006328 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006329 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006330 cur++;
6331 }
6332
6333 return(1);
6334}
6335
6336/**
6337 * xmlTextConcat:
6338 * @node: the node
6339 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006340 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006341 *
6342 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006343 *
6344 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006345 */
6346
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006347int
Owen Taylor3473f882001-02-23 17:55:21 +00006348xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006349 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006350
6351 if ((node->type != XML_TEXT_NODE) &&
6352 (node->type != XML_CDATA_SECTION_NODE)) {
6353#ifdef DEBUG_TREE
6354 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006355 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006356#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006357 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006358 }
Owen Taylor3473f882001-02-23 17:55:21 +00006359 node->content = xmlStrncat(node->content, content, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006360 if (node->content == NULL)
6361 return(-1);
6362 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006363}
6364
6365/************************************************************************
6366 * *
6367 * Output : to a FILE or in memory *
6368 * *
6369 ************************************************************************/
6370
Owen Taylor3473f882001-02-23 17:55:21 +00006371/**
6372 * xmlBufferCreate:
6373 *
6374 * routine to create an XML buffer.
6375 * returns the new structure.
6376 */
6377xmlBufferPtr
6378xmlBufferCreate(void) {
6379 xmlBufferPtr ret;
6380
6381 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6382 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006383 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006384 return(NULL);
6385 }
6386 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006387 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006388 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006389 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006390 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006391 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006392 xmlFree(ret);
6393 return(NULL);
6394 }
6395 ret->content[0] = 0;
6396 return(ret);
6397}
6398
6399/**
6400 * xmlBufferCreateSize:
6401 * @size: initial size of buffer
6402 *
6403 * routine to create an XML buffer.
6404 * returns the new structure.
6405 */
6406xmlBufferPtr
6407xmlBufferCreateSize(size_t size) {
6408 xmlBufferPtr ret;
6409
6410 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6411 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006412 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006413 return(NULL);
6414 }
6415 ret->use = 0;
6416 ret->alloc = xmlBufferAllocScheme;
6417 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6418 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006419 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006420 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006421 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006422 xmlFree(ret);
6423 return(NULL);
6424 }
6425 ret->content[0] = 0;
6426 } else
6427 ret->content = NULL;
6428 return(ret);
6429}
6430
6431/**
Daniel Veillard53350552003-09-18 13:35:51 +00006432 * xmlBufferCreateStatic:
6433 * @mem: the memory area
6434 * @size: the size in byte
6435 *
MST 2003 John Flecka0e7e932003-12-19 03:13:47 +00006436 * routine to create an XML buffer from an immutable memory area.
6437 * The area won't be modified nor copied, and is expected to be
Daniel Veillard53350552003-09-18 13:35:51 +00006438 * present until the end of the buffer lifetime.
6439 *
6440 * returns the new structure.
6441 */
6442xmlBufferPtr
6443xmlBufferCreateStatic(void *mem, size_t size) {
6444 xmlBufferPtr ret;
6445
6446 if ((mem == NULL) || (size == 0))
6447 return(NULL);
6448
6449 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6450 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006451 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00006452 return(NULL);
6453 }
6454 ret->use = size;
6455 ret->size = size;
6456 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6457 ret->content = (xmlChar *) mem;
6458 return(ret);
6459}
6460
6461/**
Owen Taylor3473f882001-02-23 17:55:21 +00006462 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006463 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006464 * @scheme: allocation scheme to use
6465 *
6466 * Sets the allocation scheme for this buffer
6467 */
6468void
6469xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6470 xmlBufferAllocationScheme scheme) {
6471 if (buf == NULL) {
6472#ifdef DEBUG_BUFFER
6473 xmlGenericError(xmlGenericErrorContext,
6474 "xmlBufferSetAllocationScheme: buf == NULL\n");
6475#endif
6476 return;
6477 }
Daniel Veillard53350552003-09-18 13:35:51 +00006478 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006479
6480 buf->alloc = scheme;
6481}
6482
6483/**
6484 * xmlBufferFree:
6485 * @buf: the buffer to free
6486 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006487 * Frees an XML buffer. It frees both the content and the structure which
6488 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006489 */
6490void
6491xmlBufferFree(xmlBufferPtr buf) {
6492 if (buf == NULL) {
6493#ifdef DEBUG_BUFFER
6494 xmlGenericError(xmlGenericErrorContext,
6495 "xmlBufferFree: buf == NULL\n");
6496#endif
6497 return;
6498 }
Daniel Veillard53350552003-09-18 13:35:51 +00006499
6500 if ((buf->content != NULL) &&
6501 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006502 xmlFree(buf->content);
6503 }
Owen Taylor3473f882001-02-23 17:55:21 +00006504 xmlFree(buf);
6505}
6506
6507/**
6508 * xmlBufferEmpty:
6509 * @buf: the buffer
6510 *
6511 * empty a buffer.
6512 */
6513void
6514xmlBufferEmpty(xmlBufferPtr buf) {
6515 if (buf->content == NULL) return;
6516 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006517 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00006518 buf->content = BAD_CAST "";
Daniel Veillard53350552003-09-18 13:35:51 +00006519 } else {
6520 memset(buf->content, 0, buf->size);
6521 }
Owen Taylor3473f882001-02-23 17:55:21 +00006522}
6523
6524/**
6525 * xmlBufferShrink:
6526 * @buf: the buffer to dump
6527 * @len: the number of xmlChar to remove
6528 *
6529 * Remove the beginning of an XML buffer.
6530 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006531 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006532 */
6533int
6534xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
6535 if (len == 0) return(0);
6536 if (len > buf->use) return(-1);
6537
6538 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006539 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6540 buf->content += len;
6541 } else {
6542 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6543 buf->content[buf->use] = 0;
6544 }
Owen Taylor3473f882001-02-23 17:55:21 +00006545 return(len);
6546}
6547
6548/**
6549 * xmlBufferGrow:
6550 * @buf: the buffer
6551 * @len: the minimum free size to allocate
6552 *
6553 * Grow the available space of an XML buffer.
6554 *
6555 * Returns the new available space or -1 in case of error
6556 */
6557int
6558xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6559 int size;
6560 xmlChar *newbuf;
6561
Daniel Veillard53350552003-09-18 13:35:51 +00006562 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006563 if (len + buf->use < buf->size) return(0);
6564
6565 size = buf->use + len + 100;
6566
6567 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006568 if (newbuf == NULL) {
6569 xmlTreeErrMemory("growing buffer");
6570 return(-1);
6571 }
Owen Taylor3473f882001-02-23 17:55:21 +00006572 buf->content = newbuf;
6573 buf->size = size;
6574 return(buf->size - buf->use);
6575}
6576
6577/**
6578 * xmlBufferDump:
6579 * @file: the file output
6580 * @buf: the buffer to dump
6581 *
6582 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006583 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006584 */
6585int
6586xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6587 int ret;
6588
6589 if (buf == NULL) {
6590#ifdef DEBUG_BUFFER
6591 xmlGenericError(xmlGenericErrorContext,
6592 "xmlBufferDump: buf == NULL\n");
6593#endif
6594 return(0);
6595 }
6596 if (buf->content == NULL) {
6597#ifdef DEBUG_BUFFER
6598 xmlGenericError(xmlGenericErrorContext,
6599 "xmlBufferDump: buf->content == NULL\n");
6600#endif
6601 return(0);
6602 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006603 if (file == NULL)
6604 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006605 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6606 return(ret);
6607}
6608
6609/**
6610 * xmlBufferContent:
6611 * @buf: the buffer
6612 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006613 * Function to extract the content of a buffer
6614 *
Owen Taylor3473f882001-02-23 17:55:21 +00006615 * Returns the internal content
6616 */
6617
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006618const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006619xmlBufferContent(const xmlBufferPtr buf)
6620{
6621 if(!buf)
6622 return NULL;
6623
6624 return buf->content;
6625}
6626
6627/**
6628 * xmlBufferLength:
6629 * @buf: the buffer
6630 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006631 * Function to get the length of a buffer
6632 *
Owen Taylor3473f882001-02-23 17:55:21 +00006633 * Returns the length of data in the internal content
6634 */
6635
6636int
6637xmlBufferLength(const xmlBufferPtr buf)
6638{
6639 if(!buf)
6640 return 0;
6641
6642 return buf->use;
6643}
6644
6645/**
6646 * xmlBufferResize:
6647 * @buf: the buffer to resize
6648 * @size: the desired size
6649 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006650 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006651 *
6652 * Returns 0 in case of problems, 1 otherwise
6653 */
6654int
6655xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6656{
6657 unsigned int newSize;
6658 xmlChar* rebuf = NULL;
6659
Daniel Veillard53350552003-09-18 13:35:51 +00006660 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6661
Owen Taylor3473f882001-02-23 17:55:21 +00006662 /*take care of empty case*/
6663 newSize = (buf->size ? buf->size*2 : size);
6664
6665 /* Don't resize if we don't have to */
6666 if (size < buf->size)
6667 return 1;
6668
6669 /* figure out new size */
6670 switch (buf->alloc){
6671 case XML_BUFFER_ALLOC_DOUBLEIT:
6672 while (size > newSize) newSize *= 2;
6673 break;
6674 case XML_BUFFER_ALLOC_EXACT:
6675 newSize = size+10;
6676 break;
6677 default:
6678 newSize = size+10;
6679 break;
6680 }
6681
6682 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006683 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006684 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006685 rebuf = (xmlChar *) xmlRealloc(buf->content,
6686 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006687 } else {
6688 /*
6689 * if we are reallocating a buffer far from being full, it's
6690 * better to make a new allocation and copy only the used range
6691 * and free the old one.
6692 */
6693 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6694 if (rebuf != NULL) {
6695 memcpy(rebuf, buf->content, buf->use);
6696 xmlFree(buf->content);
6697 }
Daniel Veillarde5984082003-08-19 22:21:13 +00006698 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006699 }
Owen Taylor3473f882001-02-23 17:55:21 +00006700 if (rebuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006701 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006702 return 0;
6703 }
6704 buf->content = rebuf;
6705 buf->size = newSize;
6706
6707 return 1;
6708}
6709
6710/**
6711 * xmlBufferAdd:
6712 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006713 * @str: the #xmlChar string
6714 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006715 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006716 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006717 * str is recomputed.
6718 */
6719void
6720xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6721 unsigned int needSize;
6722
6723 if (str == NULL) {
6724#ifdef DEBUG_BUFFER
6725 xmlGenericError(xmlGenericErrorContext,
6726 "xmlBufferAdd: str == NULL\n");
6727#endif
6728 return;
6729 }
Daniel Veillard53350552003-09-18 13:35:51 +00006730 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006731 if (len < -1) {
6732#ifdef DEBUG_BUFFER
6733 xmlGenericError(xmlGenericErrorContext,
6734 "xmlBufferAdd: len < 0\n");
6735#endif
6736 return;
6737 }
6738 if (len == 0) return;
6739
6740 if (len < 0)
6741 len = xmlStrlen(str);
6742
6743 if (len <= 0) return;
6744
6745 needSize = buf->use + len + 2;
6746 if (needSize > buf->size){
6747 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006748 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006749 return;
6750 }
6751 }
6752
6753 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6754 buf->use += len;
6755 buf->content[buf->use] = 0;
6756}
6757
6758/**
6759 * xmlBufferAddHead:
6760 * @buf: the buffer
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 *
6764 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006765 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00006766 */
6767void
6768xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6769 unsigned int needSize;
6770
Daniel Veillard53350552003-09-18 13:35:51 +00006771 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006772 if (str == NULL) {
6773#ifdef DEBUG_BUFFER
6774 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006775 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006776#endif
6777 return;
6778 }
6779 if (len < -1) {
6780#ifdef DEBUG_BUFFER
6781 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006782 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006783#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[len], &buf->content[0], buf->use * sizeof(xmlChar));
6802 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6803 buf->use += len;
6804 buf->content[buf->use] = 0;
6805}
6806
6807/**
6808 * xmlBufferCat:
6809 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006810 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006811 *
6812 * Append a zero terminated string to an XML buffer.
6813 */
6814void
6815xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillard53350552003-09-18 13:35:51 +00006816 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006817 if (str != NULL)
6818 xmlBufferAdd(buf, str, -1);
6819}
6820
6821/**
6822 * xmlBufferCCat:
6823 * @buf: the buffer to dump
6824 * @str: the C char string
6825 *
6826 * Append a zero terminated C string to an XML buffer.
6827 */
6828void
6829xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6830 const char *cur;
6831
Daniel Veillard53350552003-09-18 13:35:51 +00006832 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006833 if (str == NULL) {
6834#ifdef DEBUG_BUFFER
6835 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006836 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006837#endif
6838 return;
6839 }
6840 for (cur = str;*cur != 0;cur++) {
6841 if (buf->use + 10 >= buf->size) {
6842 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006843 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006844 return;
6845 }
6846 }
6847 buf->content[buf->use++] = *cur;
6848 }
6849 buf->content[buf->use] = 0;
6850}
6851
6852/**
6853 * xmlBufferWriteCHAR:
6854 * @buf: the XML buffer
6855 * @string: the string to add
6856 *
6857 * routine which manages and grows an output buffer. This one adds
6858 * xmlChars at the end of the buffer.
6859 */
6860void
Daniel Veillard53350552003-09-18 13:35:51 +00006861xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
6862 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006863 xmlBufferCat(buf, string);
6864}
6865
6866/**
6867 * xmlBufferWriteChar:
6868 * @buf: the XML buffer output
6869 * @string: the string to add
6870 *
6871 * routine which manage and grows an output buffer. This one add
6872 * C chars at the end of the array.
6873 */
6874void
6875xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillard53350552003-09-18 13:35:51 +00006876 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006877 xmlBufferCCat(buf, string);
6878}
6879
6880
6881/**
6882 * xmlBufferWriteQuotedString:
6883 * @buf: the XML buffer output
6884 * @string: the string to add
6885 *
6886 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00006887 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00006888 * quote or double-quotes internally
6889 */
6890void
6891xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00006892 const xmlChar *cur, *base;
Daniel Veillard53350552003-09-18 13:35:51 +00006893 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00006894 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00006895 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00006896#ifdef DEBUG_BUFFER
6897 xmlGenericError(xmlGenericErrorContext,
6898 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
6899#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00006900 xmlBufferCCat(buf, "\"");
6901 base = cur = string;
6902 while(*cur != 0){
6903 if(*cur == '"'){
6904 if (base != cur)
6905 xmlBufferAdd(buf, base, cur - base);
6906 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6907 cur++;
6908 base = cur;
6909 }
6910 else {
6911 cur++;
6912 }
6913 }
6914 if (base != cur)
6915 xmlBufferAdd(buf, base, cur - base);
6916 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006917 }
Daniel Veillard39057f42003-08-04 01:33:43 +00006918 else{
6919 xmlBufferCCat(buf, "\'");
6920 xmlBufferCat(buf, string);
6921 xmlBufferCCat(buf, "\'");
6922 }
Owen Taylor3473f882001-02-23 17:55:21 +00006923 } else {
6924 xmlBufferCCat(buf, "\"");
6925 xmlBufferCat(buf, string);
6926 xmlBufferCCat(buf, "\"");
6927 }
6928}
6929
6930
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00006931#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00006932/************************************************************************
6933 * *
Daniel Veillarde2238d52003-10-09 13:14:55 +00006934 * Output error handlers *
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006935 * *
6936 ************************************************************************/
6937/**
6938 * xmlSaveErrMemory:
6939 * @extra: extra informations
6940 *
6941 * Handle an out of memory condition
6942 */
6943static void
6944xmlSaveErrMemory(const char *extra)
6945{
6946 __xmlSimpleError(XML_FROM_OUTPUT, XML_ERR_NO_MEMORY, NULL, NULL, extra);
6947}
6948
6949/**
6950 * xmlSaveErr:
6951 * @code: the error number
6952 * @node: the location of the error.
6953 * @extra: extra informations
6954 *
6955 * Handle an out of memory condition
6956 */
6957static void
6958xmlSaveErr(int code, xmlNodePtr node, const char *extra)
6959{
6960 const char *msg = NULL;
6961
6962 switch(code) {
6963 case XML_SAVE_NOT_UTF8:
6964 msg = "string is not in UTF-8";
6965 break;
6966 case XML_SAVE_CHAR_INVALID:
6967 msg = "invalid character value";
6968 break;
6969 case XML_SAVE_UNKNOWN_ENCODING:
6970 msg = "unknown encoding %s";
6971 break;
Daniel Veillarde2238d52003-10-09 13:14:55 +00006972 case XML_SAVE_NO_DOCTYPE:
6973 msg = "document has no DOCTYPE";
6974 break;
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006975 default:
6976 msg = "unexpected error number";
6977 }
Daniel Veillarde2238d52003-10-09 13:14:55 +00006978 __xmlSimpleError(XML_FROM_OUTPUT, code, node, msg, extra);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006979}
6980/************************************************************************
6981 * *
Owen Taylor3473f882001-02-23 17:55:21 +00006982 * Dumping XML tree content to a simple buffer *
6983 * *
6984 ************************************************************************/
6985
Owen Taylor3473f882001-02-23 17:55:21 +00006986/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00006987 * xmlAttrSerializeContent:
6988 * @buf: the XML buffer output
6989 * @doc: the document
6990 * @attr: the attribute pointer
6991 *
6992 * Serialize the attribute in the buffer
6993 */
6994static void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006995xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr)
6996{
Daniel Veillarda6d05382002-02-13 13:07:41 +00006997 const xmlChar *cur, *base;
6998 xmlNodePtr children;
6999
7000 children = attr->children;
7001 while (children != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007002 switch (children->type) {
7003 case XML_TEXT_NODE:
7004 base = cur = children->content;
7005 while (*cur != 0) {
7006 if (*cur == '\n') {
7007 if (base != cur)
7008 xmlBufferAdd(buf, base, cur - base);
7009 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
7010 cur++;
7011 base = cur;
Daniel Veillard0046c0f2003-02-23 13:52:30 +00007012 } else if (*cur == '\r') {
7013 if (base != cur)
7014 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00007015 xmlBufferAdd(buf, BAD_CAST "&#13;", 5);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00007016 cur++;
7017 base = cur;
7018 } else if (*cur == '\t') {
7019 if (base != cur)
7020 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00007021 xmlBufferAdd(buf, BAD_CAST "&#9;", 4);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00007022 cur++;
7023 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00007024#if 0
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007025 } else if (*cur == '\'') {
7026 if (base != cur)
7027 xmlBufferAdd(buf, base, cur - base);
7028 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
7029 cur++;
7030 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00007031#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007032 } else if (*cur == '"') {
7033 if (base != cur)
7034 xmlBufferAdd(buf, base, cur - base);
7035 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7036 cur++;
7037 base = cur;
7038 } else if (*cur == '<') {
7039 if (base != cur)
7040 xmlBufferAdd(buf, base, cur - base);
7041 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
7042 cur++;
7043 base = cur;
7044 } else if (*cur == '>') {
7045 if (base != cur)
7046 xmlBufferAdd(buf, base, cur - base);
7047 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
7048 cur++;
7049 base = cur;
7050 } else if (*cur == '&') {
7051 if (base != cur)
7052 xmlBufferAdd(buf, base, cur - base);
7053 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
7054 cur++;
7055 base = cur;
7056 } else if ((*cur >= 0x80) && ((doc == NULL) ||
7057 (doc->encoding ==
7058 NULL))) {
7059 /*
7060 * We assume we have UTF-8 content.
7061 */
7062 char tmp[10];
7063 int val = 0, l = 1;
Daniel Veillarda6d05382002-02-13 13:07:41 +00007064
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007065 if (base != cur)
7066 xmlBufferAdd(buf, base, cur - base);
7067 if (*cur < 0xC0) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007068 xmlSaveErr(XML_SAVE_NOT_UTF8, (xmlNodePtr) attr,
7069 NULL);
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007070 if (doc != NULL)
7071 doc->encoding =
7072 xmlStrdup(BAD_CAST "ISO-8859-1");
7073 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
7074 tmp[sizeof(tmp) - 1] = 0;
7075 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
7076 cur++;
7077 base = cur;
7078 continue;
7079 } else if (*cur < 0xE0) {
7080 val = (cur[0]) & 0x1F;
7081 val <<= 6;
7082 val |= (cur[1]) & 0x3F;
7083 l = 2;
7084 } else if (*cur < 0xF0) {
7085 val = (cur[0]) & 0x0F;
7086 val <<= 6;
7087 val |= (cur[1]) & 0x3F;
7088 val <<= 6;
7089 val |= (cur[2]) & 0x3F;
7090 l = 3;
7091 } else if (*cur < 0xF8) {
7092 val = (cur[0]) & 0x07;
7093 val <<= 6;
7094 val |= (cur[1]) & 0x3F;
7095 val <<= 6;
7096 val |= (cur[2]) & 0x3F;
7097 val <<= 6;
7098 val |= (cur[3]) & 0x3F;
7099 l = 4;
7100 }
7101 if ((l == 1) || (!IS_CHAR(val))) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007102 xmlSaveErr(XML_SAVE_CHAR_INVALID, (xmlNodePtr) attr,
7103 NULL);
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007104 if (doc != NULL)
7105 doc->encoding =
7106 xmlStrdup(BAD_CAST "ISO-8859-1");
7107 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
7108 tmp[sizeof(tmp) - 1] = 0;
7109 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
7110 cur++;
7111 base = cur;
7112 continue;
7113 }
7114 /*
7115 * We could do multiple things here. Just save
7116 * as a char ref
7117 */
7118 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
7119 tmp[sizeof(tmp) - 1] = 0;
7120 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
7121 cur += l;
7122 base = cur;
7123 } else {
7124 cur++;
7125 }
7126 }
7127 if (base != cur)
7128 xmlBufferAdd(buf, base, cur - base);
7129 break;
7130 case XML_ENTITY_REF_NODE:
7131 xmlBufferAdd(buf, BAD_CAST "&", 1);
7132 xmlBufferAdd(buf, children->name,
7133 xmlStrlen(children->name));
7134 xmlBufferAdd(buf, BAD_CAST ";", 1);
7135 break;
7136 default:
7137 /* should not happen unless we have a badly built tree */
7138 break;
7139 }
7140 children = children->next;
Owen Taylor3473f882001-02-23 17:55:21 +00007141 }
7142}
7143
7144/**
7145 * xmlNodeDump:
7146 * @buf: the XML buffer output
7147 * @doc: the document
7148 * @cur: the current node
7149 * @level: the imbrication level for indenting
7150 * @format: is formatting allowed
7151 *
7152 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007153 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007154 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007155 *
7156 * Returns the number of bytes written to the buffer or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00007157 */
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007158int
Owen Taylor3473f882001-02-23 17:55:21 +00007159xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007160 int format)
7161{
7162 unsigned int use;
7163 int ret;
7164 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00007165
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007166 xmlInitParser();
7167
Owen Taylor3473f882001-02-23 17:55:21 +00007168 if (cur == NULL) {
7169#ifdef DEBUG_TREE
7170 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007171 "xmlNodeDump : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007172#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007173 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007174 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007175 if (buf == NULL) {
7176#ifdef DEBUG_TREE
7177 xmlGenericError(xmlGenericErrorContext,
7178 "xmlNodeDump : buf == NULL\n");
7179#endif
7180 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007181 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007182 outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
7183 if (outbuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007184 xmlSaveErrMemory("creating buffer");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007185 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007186 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007187 memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
7188 outbuf->buffer = buf;
7189 outbuf->encoder = NULL;
7190 outbuf->writecallback = NULL;
7191 outbuf->closecallback = NULL;
7192 outbuf->context = NULL;
7193 outbuf->written = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007194
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007195 use = buf->use;
7196 xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
7197 xmlFree(outbuf);
7198 ret = buf->use - use;
7199 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00007200}
7201
7202/**
7203 * xmlElemDump:
7204 * @f: the FILE * for the output
7205 * @doc: the document
7206 * @cur: the current node
7207 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007208 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00007209 */
7210void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007211xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur)
7212{
7213 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00007214
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007215 xmlInitParser();
7216
Owen Taylor3473f882001-02-23 17:55:21 +00007217 if (cur == NULL) {
7218#ifdef DEBUG_TREE
7219 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007220 "xmlElemDump : cur == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007221#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007222 return;
Owen Taylor3473f882001-02-23 17:55:21 +00007223 }
Owen Taylor3473f882001-02-23 17:55:21 +00007224#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007225 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00007226 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007227 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007228 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007229#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007230
7231 outbuf = xmlOutputBufferCreateFile(f, NULL);
7232 if (outbuf == NULL)
7233 return;
7234 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007235#ifdef LIBXML_HTML_ENABLED
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007236 htmlNodeDumpOutput(outbuf, doc, cur, NULL);
7237#else
Daniel Veillard2189b592003-10-21 00:08:42 +00007238 xmlSaveErr(XML_ERR_INTERNAL_ERROR, cur, "HTML support not compiled in\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007239#endif /* LIBXML_HTML_ENABLED */
7240 } else
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007241 xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL);
7242 xmlOutputBufferClose(outbuf);
Owen Taylor3473f882001-02-23 17:55:21 +00007243}
7244
7245/************************************************************************
7246 * *
7247 * Dumping XML tree content to an I/O output buffer *
7248 * *
7249 ************************************************************************/
7250
Daniel Veillard4432df22003-09-28 18:58:27 +00007251#ifdef LIBXML_HTML_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00007252static void
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007253xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7254 int level, int format, const char *encoding);
Daniel Veillard4432df22003-09-28 18:58:27 +00007255#endif
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007256static void
Owen Taylor3473f882001-02-23 17:55:21 +00007257xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7258 int level, int format, const char *encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007259static void
7260xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
7261 xmlNodePtr cur, int level, int format, const char *encoding);
7262
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00007263void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
7264
Owen Taylor3473f882001-02-23 17:55:21 +00007265/**
7266 * xmlNsDumpOutput:
7267 * @buf: the XML buffer output
7268 * @cur: a namespace
7269 *
7270 * Dump a local Namespace definition.
7271 * Should be called in the context of attributes dumps.
7272 */
7273static void
7274xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
7275 if (cur == NULL) {
7276#ifdef DEBUG_TREE
7277 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007278 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007279#endif
7280 return;
7281 }
7282 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00007283 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
7284 return;
7285
Owen Taylor3473f882001-02-23 17:55:21 +00007286 /* Within the context of an element attributes */
7287 if (cur->prefix != NULL) {
7288 xmlOutputBufferWriteString(buf, " xmlns:");
7289 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
7290 } else
7291 xmlOutputBufferWriteString(buf, " xmlns");
7292 xmlOutputBufferWriteString(buf, "=");
7293 xmlBufferWriteQuotedString(buf->buffer, cur->href);
7294 }
7295}
7296
7297/**
7298 * xmlNsListDumpOutput:
7299 * @buf: the XML buffer output
7300 * @cur: the first namespace
7301 *
7302 * Dump a list of local Namespace definitions.
7303 * Should be called in the context of attributes dumps.
7304 */
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00007305void
Owen Taylor3473f882001-02-23 17:55:21 +00007306xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
7307 while (cur != NULL) {
7308 xmlNsDumpOutput(buf, cur);
7309 cur = cur->next;
7310 }
7311}
7312
7313/**
7314 * xmlDtdDumpOutput:
7315 * @buf: the XML buffer output
7316 * @doc: the document
7317 * @encoding: an optional encoding string
7318 *
7319 * Dump the XML document DTD, if any.
7320 */
7321static void
7322xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
7323 if (dtd == NULL) {
7324#ifdef DEBUG_TREE
7325 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007326 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007327#endif
7328 return;
7329 }
7330 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
7331 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
7332 if (dtd->ExternalID != NULL) {
7333 xmlOutputBufferWriteString(buf, " PUBLIC ");
7334 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
7335 xmlOutputBufferWriteString(buf, " ");
7336 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
7337 } else if (dtd->SystemID != NULL) {
7338 xmlOutputBufferWriteString(buf, " SYSTEM ");
7339 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
7340 }
7341 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
7342 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
7343 xmlOutputBufferWriteString(buf, ">");
7344 return;
7345 }
7346 xmlOutputBufferWriteString(buf, " [\n");
7347 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
7348 xmlOutputBufferWriteString(buf, "]>");
7349}
7350
7351/**
7352 * xmlAttrDumpOutput:
7353 * @buf: the XML buffer output
7354 * @doc: the document
7355 * @cur: the attribute pointer
7356 * @encoding: an optional encoding string
7357 *
7358 * Dump an XML attribute
7359 */
7360static void
7361xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00007362 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00007363 if (cur == NULL) {
7364#ifdef DEBUG_TREE
7365 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007366 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007367#endif
7368 return;
7369 }
7370 xmlOutputBufferWriteString(buf, " ");
7371 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7372 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7373 xmlOutputBufferWriteString(buf, ":");
7374 }
7375 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00007376 xmlOutputBufferWriteString(buf, "=\"");
7377 xmlAttrSerializeContent(buf->buffer, doc, cur);
7378 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007379}
7380
7381/**
7382 * xmlAttrListDumpOutput:
7383 * @buf: the XML buffer output
7384 * @doc: the document
7385 * @cur: the first attribute pointer
7386 * @encoding: an optional encoding string
7387 *
7388 * Dump a list of XML attributes
7389 */
7390static void
7391xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7392 xmlAttrPtr cur, const char *encoding) {
7393 if (cur == NULL) {
7394#ifdef DEBUG_TREE
7395 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007396 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007397#endif
7398 return;
7399 }
7400 while (cur != NULL) {
7401 xmlAttrDumpOutput(buf, doc, cur, encoding);
7402 cur = cur->next;
7403 }
7404}
7405
7406
7407
7408/**
7409 * xmlNodeListDumpOutput:
7410 * @buf: the XML buffer output
7411 * @doc: the document
7412 * @cur: the first node
7413 * @level: the imbrication level for indenting
7414 * @format: is formatting allowed
7415 * @encoding: an optional encoding string
7416 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007417 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007418 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007419 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007420 */
7421static void
7422xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7423 xmlNodePtr cur, int level, int format, const char *encoding) {
7424 int i;
7425
7426 if (cur == NULL) {
7427#ifdef DEBUG_TREE
7428 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007429 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007430#endif
7431 return;
7432 }
7433 while (cur != NULL) {
7434 if ((format) && (xmlIndentTreeOutput) &&
7435 (cur->type == XML_ELEMENT_NODE))
7436 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007437 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007438 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007439 if (format) {
7440 xmlOutputBufferWriteString(buf, "\n");
7441 }
7442 cur = cur->next;
7443 }
7444}
7445
7446/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007447 * xmlNodeDumpOutputInternal:
Owen Taylor3473f882001-02-23 17:55:21 +00007448 * @buf: the XML buffer output
7449 * @doc: the document
7450 * @cur: the current node
7451 * @level: the imbrication level for indenting
7452 * @format: is formatting allowed
7453 * @encoding: an optional encoding string
7454 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007455 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007456 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007457 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007458 */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007459static void
7460xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
7461 xmlNodePtr cur, int level, int format, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007462 int i;
7463 xmlNodePtr tmp;
Daniel Veillard9475a352003-09-26 12:47:50 +00007464 xmlChar *start, *end;
Owen Taylor3473f882001-02-23 17:55:21 +00007465
7466 if (cur == NULL) {
7467#ifdef DEBUG_TREE
7468 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007469 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007470#endif
7471 return;
7472 }
7473 if (cur->type == XML_XINCLUDE_START)
7474 return;
7475 if (cur->type == XML_XINCLUDE_END)
7476 return;
7477 if (cur->type == XML_DTD_NODE) {
7478 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7479 return;
7480 }
Daniel Veillardcec50a62003-10-28 13:26:51 +00007481 if (cur->type == XML_DOCUMENT_FRAG_NODE) {
7482 xmlNodeListDumpOutput(buf, doc, cur->children, level, format, encoding);
7483 return;
7484 }
Owen Taylor3473f882001-02-23 17:55:21 +00007485 if (cur->type == XML_ELEMENT_DECL) {
7486 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7487 return;
7488 }
7489 if (cur->type == XML_ATTRIBUTE_DECL) {
7490 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7491 return;
7492 }
7493 if (cur->type == XML_ENTITY_DECL) {
7494 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7495 return;
7496 }
7497 if (cur->type == XML_TEXT_NODE) {
7498 if (cur->content != NULL) {
7499 if ((cur->name == xmlStringText) ||
7500 (cur->name != xmlStringTextNoenc)) {
7501 xmlChar *buffer;
7502
Owen Taylor3473f882001-02-23 17:55:21 +00007503 if (encoding == NULL)
7504 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7505 else
7506 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007507 if (buffer != NULL) {
7508 xmlOutputBufferWriteString(buf, (const char *)buffer);
7509 xmlFree(buffer);
7510 }
7511 } else {
7512 /*
7513 * Disable escaping, needed for XSLT
7514 */
Owen Taylor3473f882001-02-23 17:55:21 +00007515 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007516 }
7517 }
7518
7519 return;
7520 }
7521 if (cur->type == XML_PI_NODE) {
7522 if (cur->content != NULL) {
7523 xmlOutputBufferWriteString(buf, "<?");
7524 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7525 if (cur->content != NULL) {
7526 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00007527 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007528 }
7529 xmlOutputBufferWriteString(buf, "?>");
7530 } else {
7531 xmlOutputBufferWriteString(buf, "<?");
7532 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7533 xmlOutputBufferWriteString(buf, "?>");
7534 }
7535 return;
7536 }
7537 if (cur->type == XML_COMMENT_NODE) {
7538 if (cur->content != NULL) {
7539 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00007540 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007541 xmlOutputBufferWriteString(buf, "-->");
7542 }
7543 return;
7544 }
7545 if (cur->type == XML_ENTITY_REF_NODE) {
7546 xmlOutputBufferWriteString(buf, "&");
7547 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7548 xmlOutputBufferWriteString(buf, ";");
7549 return;
7550 }
7551 if (cur->type == XML_CDATA_SECTION_NODE) {
Daniel Veillard9475a352003-09-26 12:47:50 +00007552 start = end = cur->content;
7553 while (*end != '\0') {
7554 if ((*end == ']') && (*(end + 1) == ']') && (*(end + 2) == '>')) {
7555 end = end + 2;
7556 xmlOutputBufferWriteString(buf, "<![CDATA[");
7557 xmlOutputBufferWrite(buf, end - start, (const char *)start);
7558 xmlOutputBufferWriteString(buf, "]]>");
7559 start = end;
7560 }
7561 end++;
7562 }
7563 if (start != end) {
7564 xmlOutputBufferWriteString(buf, "<![CDATA[");
7565 xmlOutputBufferWriteString(buf, (const char *)start);
7566 xmlOutputBufferWriteString(buf, "]]>");
7567 }
Owen Taylor3473f882001-02-23 17:55:21 +00007568 return;
7569 }
Daniel Veillard7b72ee52003-02-27 23:24:53 +00007570 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillarda1a9d042003-03-18 16:53:17 +00007571 xmlAttrDumpOutput(buf,doc, (xmlAttrPtr) cur,encoding);
Daniel Veillard7b72ee52003-02-27 23:24:53 +00007572 return;
7573 }
Daniel Veillard6aa2f602003-02-10 00:01:56 +00007574 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007575 xmlNsDumpOutput(buf, (xmlNsPtr) cur);
Daniel Veillard6aa2f602003-02-10 00:01:56 +00007576 return;
7577 }
Owen Taylor3473f882001-02-23 17:55:21 +00007578
7579 if (format == 1) {
7580 tmp = cur->children;
7581 while (tmp != NULL) {
William M. Brack9ca682f2003-10-19 10:01:59 +00007582 if ((tmp->type == XML_TEXT_NODE) ||
7583 (tmp->type == XML_CDATA_SECTION_NODE) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007584 (tmp->type == XML_ENTITY_REF_NODE)) {
7585 format = 0;
7586 break;
7587 }
7588 tmp = tmp->next;
7589 }
7590 }
7591 xmlOutputBufferWriteString(buf, "<");
7592 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7593 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7594 xmlOutputBufferWriteString(buf, ":");
7595 }
7596
7597 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7598 if (cur->nsDef)
7599 xmlNsListDumpOutput(buf, cur->nsDef);
7600 if (cur->properties != NULL)
7601 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7602
Daniel Veillard7db37732001-07-12 01:20:08 +00007603 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
7604 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007605 xmlOutputBufferWriteString(buf, "/>");
7606 return;
7607 }
7608 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00007609 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007610 xmlChar *buffer;
7611
Owen Taylor3473f882001-02-23 17:55:21 +00007612 if (encoding == NULL)
7613 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7614 else
7615 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007616 if (buffer != NULL) {
7617 xmlOutputBufferWriteString(buf, (const char *)buffer);
7618 xmlFree(buffer);
7619 }
7620 }
7621 if (cur->children != NULL) {
7622 if (format) xmlOutputBufferWriteString(buf, "\n");
7623 xmlNodeListDumpOutput(buf, doc, cur->children,
7624 (level >= 0?level+1:-1), format, encoding);
7625 if ((xmlIndentTreeOutput) && (format))
7626 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007627 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00007628 }
7629 xmlOutputBufferWriteString(buf, "</");
7630 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7631 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7632 xmlOutputBufferWriteString(buf, ":");
7633 }
7634
7635 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7636 xmlOutputBufferWriteString(buf, ">");
7637}
7638
7639/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007640 * xmlNodeDumpOutput:
7641 * @buf: the XML buffer output
7642 * @doc: the document
7643 * @cur: the current node
7644 * @level: the imbrication level for indenting
7645 * @format: is formatting allowed
7646 * @encoding: an optional encoding string
7647 *
7648 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007649 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007650 * or xmlKeepBlanksDefault(0) was called
7651 */
7652void
7653xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007654 int level, int format, const char *encoding)
7655{
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007656#ifdef LIBXML_HTML_ENABLED
7657 xmlDtdPtr dtd;
7658 int is_xhtml = 0;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007659#endif
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007660
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007661 xmlInitParser();
7662
7663#ifdef LIBXML_HTML_ENABLED
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007664 dtd = xmlGetIntSubset(doc);
7665 if (dtd != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007666 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7667 if (is_xhtml < 0)
7668 is_xhtml = 0;
7669 if ((is_xhtml) && (cur->parent == (xmlNodePtr) doc) &&
7670 (cur->type == XML_ELEMENT_NODE) &&
7671 (xmlStrEqual(cur->name, BAD_CAST "html"))) {
7672 if (encoding != NULL)
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007673 htmlSetMetaEncoding((htmlDocPtr) doc,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007674 (const xmlChar *) encoding);
7675 else
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007676 htmlSetMetaEncoding((htmlDocPtr) doc, BAD_CAST "UTF-8");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007677 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007678 }
7679
7680 if (is_xhtml)
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007681 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007682 else
7683#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007684 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007685}
7686
7687/**
Owen Taylor3473f882001-02-23 17:55:21 +00007688 * xmlDocContentDumpOutput:
7689 * @buf: the XML buffer output
7690 * @cur: the document
7691 * @encoding: an optional encoding string
7692 * @format: should formatting spaces been added
7693 *
7694 * Dump an XML document.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007695 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007696 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007697 */
7698static void
7699xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
7700 const char *encoding, int format) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007701#ifdef LIBXML_HTML_ENABLED
7702 xmlDtdPtr dtd;
7703 int is_xhtml = 0;
7704#endif
Daniel Veillard2f6ff812003-12-08 12:11:14 +00007705 const xmlChar *oldenc = cur->encoding;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007706
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007707 xmlInitParser();
7708
Daniel Veillard2f6ff812003-12-08 12:11:14 +00007709 if (encoding != NULL)
7710 cur->encoding = BAD_CAST encoding;
7711
Owen Taylor3473f882001-02-23 17:55:21 +00007712 xmlOutputBufferWriteString(buf, "<?xml version=");
7713 if (cur->version != NULL)
7714 xmlBufferWriteQuotedString(buf->buffer, cur->version);
7715 else
7716 xmlOutputBufferWriteString(buf, "\"1.0\"");
7717 if (encoding == NULL) {
7718 if (cur->encoding != NULL)
7719 encoding = (const char *) cur->encoding;
7720 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
7721 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
7722 }
7723 if (encoding != NULL) {
7724 xmlOutputBufferWriteString(buf, " encoding=");
7725 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
7726 }
7727 switch (cur->standalone) {
7728 case 0:
7729 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
7730 break;
7731 case 1:
7732 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
7733 break;
7734 }
7735 xmlOutputBufferWriteString(buf, "?>\n");
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007736
7737#ifdef LIBXML_HTML_ENABLED
7738 dtd = xmlGetIntSubset(cur);
7739 if (dtd != NULL) {
7740 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7741 if (is_xhtml < 0) is_xhtml = 0;
7742 }
7743 if (is_xhtml) {
7744 if (encoding != NULL)
7745 htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
7746 else
7747 htmlSetMetaEncoding(cur, BAD_CAST "UTF-8");
7748 }
7749#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007750 if (cur->children != NULL) {
7751 xmlNodePtr child = cur->children;
7752
7753 while (child != NULL) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007754#ifdef LIBXML_HTML_ENABLED
7755 if (is_xhtml)
7756 xhtmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
7757 else
7758#endif
7759 xmlNodeDumpOutputInternal(buf, cur, child, 0, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007760 xmlOutputBufferWriteString(buf, "\n");
7761 child = child->next;
7762 }
7763 }
Daniel Veillard2f6ff812003-12-08 12:11:14 +00007764 if (encoding != NULL)
7765 cur->encoding = oldenc;
Owen Taylor3473f882001-02-23 17:55:21 +00007766}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007767#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00007768
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007769#ifdef LIBXML_HTML_ENABLED
7770/************************************************************************
7771 * *
7772 * Functions specific to XHTML serialization *
7773 * *
7774 ************************************************************************/
7775
7776#define XHTML_STRICT_PUBLIC_ID BAD_CAST \
7777 "-//W3C//DTD XHTML 1.0 Strict//EN"
7778#define XHTML_STRICT_SYSTEM_ID BAD_CAST \
7779 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
7780#define XHTML_FRAME_PUBLIC_ID BAD_CAST \
7781 "-//W3C//DTD XHTML 1.0 Frameset//EN"
7782#define XHTML_FRAME_SYSTEM_ID BAD_CAST \
7783 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
7784#define XHTML_TRANS_PUBLIC_ID BAD_CAST \
7785 "-//W3C//DTD XHTML 1.0 Transitional//EN"
7786#define XHTML_TRANS_SYSTEM_ID BAD_CAST \
7787 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
7788
7789#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
7790/**
7791 * xmlIsXHTML:
7792 * @systemID: the system identifier
7793 * @publicID: the public identifier
7794 *
7795 * Try to find if the document correspond to an XHTML DTD
7796 *
7797 * Returns 1 if true, 0 if not and -1 in case of error
7798 */
7799int
7800xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) {
7801 if ((systemID == NULL) && (publicID == NULL))
7802 return(-1);
7803 if (publicID != NULL) {
7804 if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1);
7805 if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1);
7806 if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1);
7807 }
7808 if (systemID != NULL) {
7809 if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1);
7810 if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1);
7811 if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1);
7812 }
7813 return(0);
7814}
7815
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007816#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007817/**
7818 * xhtmlIsEmpty:
7819 * @node: the node
7820 *
7821 * Check if a node is an empty xhtml node
7822 *
7823 * Returns 1 if the node is an empty node, 0 if not and -1 in case of error
7824 */
7825static int
7826xhtmlIsEmpty(xmlNodePtr node) {
7827 if (node == NULL)
7828 return(-1);
7829 if (node->type != XML_ELEMENT_NODE)
7830 return(0);
7831 if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME)))
7832 return(0);
7833 if (node->children != NULL)
7834 return(0);
7835 switch (node->name[0]) {
7836 case 'a':
7837 if (xmlStrEqual(node->name, BAD_CAST "area"))
7838 return(1);
7839 return(0);
7840 case 'b':
7841 if (xmlStrEqual(node->name, BAD_CAST "br"))
7842 return(1);
7843 if (xmlStrEqual(node->name, BAD_CAST "base"))
7844 return(1);
7845 if (xmlStrEqual(node->name, BAD_CAST "basefont"))
7846 return(1);
7847 return(0);
7848 case 'c':
7849 if (xmlStrEqual(node->name, BAD_CAST "col"))
7850 return(1);
7851 return(0);
7852 case 'f':
7853 if (xmlStrEqual(node->name, BAD_CAST "frame"))
7854 return(1);
7855 return(0);
7856 case 'h':
7857 if (xmlStrEqual(node->name, BAD_CAST "hr"))
7858 return(1);
7859 return(0);
7860 case 'i':
7861 if (xmlStrEqual(node->name, BAD_CAST "img"))
7862 return(1);
7863 if (xmlStrEqual(node->name, BAD_CAST "input"))
7864 return(1);
7865 if (xmlStrEqual(node->name, BAD_CAST "isindex"))
7866 return(1);
7867 return(0);
7868 case 'l':
7869 if (xmlStrEqual(node->name, BAD_CAST "link"))
7870 return(1);
7871 return(0);
7872 case 'm':
7873 if (xmlStrEqual(node->name, BAD_CAST "meta"))
7874 return(1);
7875 return(0);
7876 case 'p':
7877 if (xmlStrEqual(node->name, BAD_CAST "param"))
7878 return(1);
7879 return(0);
7880 }
7881 return(0);
7882}
7883
7884/**
7885 * xhtmlAttrListDumpOutput:
7886 * @buf: the XML buffer output
7887 * @doc: the document
7888 * @cur: the first attribute pointer
7889 * @encoding: an optional encoding string
7890 *
7891 * Dump a list of XML attributes
7892 */
7893static void
7894xhtmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7895 xmlAttrPtr cur, const char *encoding) {
7896 xmlAttrPtr xml_lang = NULL;
7897 xmlAttrPtr lang = NULL;
7898 xmlAttrPtr name = NULL;
7899 xmlAttrPtr id = NULL;
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007900 xmlNodePtr parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007901
7902 if (cur == NULL) {
7903#ifdef DEBUG_TREE
7904 xmlGenericError(xmlGenericErrorContext,
7905 "xmlAttrListDumpOutput : property == NULL\n");
7906#endif
7907 return;
7908 }
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007909 parent = cur->parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007910 while (cur != NULL) {
7911 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id")))
7912 id = cur;
7913 else
7914 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name")))
7915 name = cur;
7916 else
7917 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")))
7918 lang = cur;
7919 else
7920 if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) &&
7921 (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml")))
7922 xml_lang = cur;
7923 else if ((cur->ns == NULL) &&
7924 ((cur->children == NULL) ||
7925 (cur->children->content == NULL) ||
7926 (cur->children->content[0] == 0)) &&
7927 (htmlIsBooleanAttr(cur->name))) {
7928 if (cur->children != NULL)
7929 xmlFreeNode(cur->children);
7930 cur->children = xmlNewText(cur->name);
7931 if (cur->children != NULL)
7932 cur->children->parent = (xmlNodePtr) cur;
7933 }
7934 xmlAttrDumpOutput(buf, doc, cur, encoding);
7935 cur = cur->next;
7936 }
7937 /*
7938 * C.8
7939 */
7940 if ((name != NULL) && (id == NULL)) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007941 if ((parent != NULL) && (parent->name != NULL) &&
7942 ((xmlStrEqual(parent->name, BAD_CAST "a")) ||
7943 (xmlStrEqual(parent->name, BAD_CAST "p")) ||
7944 (xmlStrEqual(parent->name, BAD_CAST "div")) ||
7945 (xmlStrEqual(parent->name, BAD_CAST "img")) ||
7946 (xmlStrEqual(parent->name, BAD_CAST "map")) ||
7947 (xmlStrEqual(parent->name, BAD_CAST "applet")) ||
7948 (xmlStrEqual(parent->name, BAD_CAST "form")) ||
7949 (xmlStrEqual(parent->name, BAD_CAST "frame")) ||
7950 (xmlStrEqual(parent->name, BAD_CAST "iframe")))) {
7951 xmlOutputBufferWriteString(buf, " id=\"");
7952 xmlAttrSerializeContent(buf->buffer, doc, name);
7953 xmlOutputBufferWriteString(buf, "\"");
7954 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007955 }
7956 /*
7957 * C.7.
7958 */
7959 if ((lang != NULL) && (xml_lang == NULL)) {
7960 xmlOutputBufferWriteString(buf, " xml:lang=\"");
7961 xmlAttrSerializeContent(buf->buffer, doc, lang);
7962 xmlOutputBufferWriteString(buf, "\"");
7963 } else
7964 if ((xml_lang != NULL) && (lang == NULL)) {
7965 xmlOutputBufferWriteString(buf, " lang=\"");
7966 xmlAttrSerializeContent(buf->buffer, doc, xml_lang);
7967 xmlOutputBufferWriteString(buf, "\"");
7968 }
7969}
7970
7971/**
7972 * xhtmlNodeListDumpOutput:
7973 * @buf: the XML buffer output
7974 * @doc: the XHTML document
7975 * @cur: the first node
7976 * @level: the imbrication level for indenting
7977 * @format: is formatting allowed
7978 * @encoding: an optional encoding string
7979 *
7980 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007981 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007982 * or xmlKeepBlanksDefault(0) was called
7983 */
7984static void
7985xhtmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7986 xmlNodePtr cur, int level, int format, const char *encoding) {
7987 int i;
7988
7989 if (cur == NULL) {
7990#ifdef DEBUG_TREE
7991 xmlGenericError(xmlGenericErrorContext,
7992 "xhtmlNodeListDumpOutput : node == NULL\n");
7993#endif
7994 return;
7995 }
7996 while (cur != NULL) {
7997 if ((format) && (xmlIndentTreeOutput) &&
7998 (cur->type == XML_ELEMENT_NODE))
7999 for (i = 0;i < level;i++)
8000 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
8001 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
8002 if (format) {
8003 xmlOutputBufferWriteString(buf, "\n");
8004 }
8005 cur = cur->next;
8006 }
8007}
8008
8009/**
8010 * xhtmlNodeDumpOutput:
8011 * @buf: the XML buffer output
8012 * @doc: the XHTML document
8013 * @cur: the current node
8014 * @level: the imbrication level for indenting
8015 * @format: is formatting allowed
8016 * @encoding: an optional encoding string
8017 *
8018 * Dump an XHTML node, 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
8023xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
8024 int level, int format, const char *encoding) {
8025 int i;
8026 xmlNodePtr tmp;
Daniel Veillard9475a352003-09-26 12:47:50 +00008027 xmlChar *start, *end;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00008028
8029 if (cur == NULL) {
8030#ifdef DEBUG_TREE
8031 xmlGenericError(xmlGenericErrorContext,
8032 "xmlNodeDumpOutput : node == NULL\n");
8033#endif
8034 return;
8035 }
8036 if (cur->type == XML_XINCLUDE_START)
8037 return;
8038 if (cur->type == XML_XINCLUDE_END)
8039 return;
8040 if (cur->type == XML_DTD_NODE) {
8041 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
8042 return;
8043 }
8044 if (cur->type == XML_ELEMENT_DECL) {
8045 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
8046 return;
8047 }
8048 if (cur->type == XML_ATTRIBUTE_DECL) {
8049 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
8050 return;
8051 }
8052 if (cur->type == XML_ENTITY_DECL) {
8053 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
8054 return;
8055 }
8056 if (cur->type == XML_TEXT_NODE) {
8057 if (cur->content != NULL) {
8058 if ((cur->name == xmlStringText) ||
8059 (cur->name != xmlStringTextNoenc)) {
8060 xmlChar *buffer;
8061
8062 if (encoding == NULL)
8063 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
8064 else
8065 buffer = xmlEncodeSpecialChars(doc, cur->content);
8066 if (buffer != NULL) {
8067 xmlOutputBufferWriteString(buf, (const char *)buffer);
8068 xmlFree(buffer);
8069 }
8070 } else {
8071 /*
8072 * Disable escaping, needed for XSLT
8073 */
8074 xmlOutputBufferWriteString(buf, (const char *) cur->content);
8075 }
8076 }
8077
8078 return;
8079 }
8080 if (cur->type == XML_PI_NODE) {
8081 if (cur->content != NULL) {
8082 xmlOutputBufferWriteString(buf, "<?");
8083 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8084 if (cur->content != NULL) {
8085 xmlOutputBufferWriteString(buf, " ");
8086 xmlOutputBufferWriteString(buf, (const char *)cur->content);
8087 }
8088 xmlOutputBufferWriteString(buf, "?>");
8089 } else {
8090 xmlOutputBufferWriteString(buf, "<?");
8091 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8092 xmlOutputBufferWriteString(buf, "?>");
8093 }
8094 return;
8095 }
8096 if (cur->type == XML_COMMENT_NODE) {
8097 if (cur->content != NULL) {
8098 xmlOutputBufferWriteString(buf, "<!--");
8099 xmlOutputBufferWriteString(buf, (const char *)cur->content);
8100 xmlOutputBufferWriteString(buf, "-->");
8101 }
8102 return;
8103 }
8104 if (cur->type == XML_ENTITY_REF_NODE) {
8105 xmlOutputBufferWriteString(buf, "&");
8106 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8107 xmlOutputBufferWriteString(buf, ";");
8108 return;
8109 }
8110 if (cur->type == XML_CDATA_SECTION_NODE) {
Daniel Veillard9475a352003-09-26 12:47:50 +00008111 start = end = cur->content;
8112 while (*end != '\0') {
8113 if (*end == ']' && *(end + 1) == ']' && *(end + 2) == '>') {
8114 end = end + 2;
8115 xmlOutputBufferWriteString(buf, "<![CDATA[");
8116 xmlOutputBufferWrite(buf, end - start, (const char *)start);
8117 xmlOutputBufferWriteString(buf, "]]>");
8118 start = end;
8119 }
8120 end++;
8121 }
8122 if (start != end) {
8123 xmlOutputBufferWriteString(buf, "<![CDATA[");
8124 xmlOutputBufferWriteString(buf, (const char *)start);
8125 xmlOutputBufferWriteString(buf, "]]>");
8126 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00008127 return;
8128 }
8129
8130 if (format == 1) {
8131 tmp = cur->children;
8132 while (tmp != NULL) {
8133 if ((tmp->type == XML_TEXT_NODE) ||
8134 (tmp->type == XML_ENTITY_REF_NODE)) {
8135 format = 0;
8136 break;
8137 }
8138 tmp = tmp->next;
8139 }
8140 }
8141 xmlOutputBufferWriteString(buf, "<");
8142 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
8143 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
8144 xmlOutputBufferWriteString(buf, ":");
8145 }
8146
8147 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8148 if (cur->nsDef)
8149 xmlNsListDumpOutput(buf, cur->nsDef);
8150 if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
8151 (cur->ns == NULL) && (cur->nsDef == NULL))) {
8152 /*
8153 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
8154 */
8155 xmlOutputBufferWriteString(buf,
8156 " xmlns=\"http://www.w3.org/1999/xhtml\"");
8157 }
8158 if (cur->properties != NULL)
8159 xhtmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
8160
8161 if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) {
8162 if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
8163 (xhtmlIsEmpty(cur) == 1)) {
8164 /*
8165 * C.2. Empty Elements
8166 */
8167 xmlOutputBufferWriteString(buf, " />");
8168 } else {
8169 /*
8170 * C.3. Element Minimization and Empty Element Content
8171 */
8172 xmlOutputBufferWriteString(buf, "></");
8173 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
8174 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
8175 xmlOutputBufferWriteString(buf, ":");
8176 }
8177 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8178 xmlOutputBufferWriteString(buf, ">");
8179 }
8180 return;
8181 }
8182 xmlOutputBufferWriteString(buf, ">");
8183 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
8184 xmlChar *buffer;
8185
8186 if (encoding == NULL)
8187 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
8188 else
8189 buffer = xmlEncodeSpecialChars(doc, cur->content);
8190 if (buffer != NULL) {
8191 xmlOutputBufferWriteString(buf, (const char *)buffer);
8192 xmlFree(buffer);
8193 }
8194 }
8195
8196 /*
8197 * 4.8. Script and Style elements
8198 */
8199 if ((cur->type == XML_ELEMENT_NODE) &&
8200 ((xmlStrEqual(cur->name, BAD_CAST "script")) ||
8201 (xmlStrEqual(cur->name, BAD_CAST "style"))) &&
8202 ((cur->ns == NULL) ||
8203 (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) {
8204 xmlNodePtr child = cur->children;
8205
8206 while (child != NULL) {
8207 if ((child->type == XML_TEXT_NODE) ||
8208 (child->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard64b35282002-12-04 15:10:40 +00008209 /*
8210 * Apparently CDATA escaping for style just break on IE,
8211 * mozilla and galeon, so ...
8212 */
8213 if (xmlStrEqual(cur->name, BAD_CAST "style") &&
8214 (xmlStrchr(child->content, '<') == NULL) &&
8215 (xmlStrchr(child->content, '>') == NULL) &&
8216 (xmlStrchr(child->content, '&') == NULL)) {
8217 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
8218 } else {
Daniel Veillard9475a352003-09-26 12:47:50 +00008219 start = end = child->content;
8220 while (*end != '\0') {
8221 if (*end == ']' &&
8222 *(end + 1) == ']' &&
8223 *(end + 2) == '>') {
8224 end = end + 2;
8225 xmlOutputBufferWriteString(buf, "<![CDATA[");
8226 xmlOutputBufferWrite(buf, end - start,
8227 (const char *)start);
8228 xmlOutputBufferWriteString(buf, "]]>");
8229 start = end;
8230 }
8231 end++;
8232 }
8233 if (start != end) {
8234 xmlOutputBufferWriteString(buf, "<![CDATA[");
8235 xmlOutputBufferWriteString(buf, (const char *)start);
8236 xmlOutputBufferWriteString(buf, "]]>");
8237 }
Daniel Veillard64b35282002-12-04 15:10:40 +00008238 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00008239 } else {
8240 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
8241 }
8242 child = child->next;
8243 }
8244 } else if (cur->children != NULL) {
8245 if (format) xmlOutputBufferWriteString(buf, "\n");
8246 xhtmlNodeListDumpOutput(buf, doc, cur->children,
8247 (level >= 0?level+1:-1), format, encoding);
8248 if ((xmlIndentTreeOutput) && (format))
8249 for (i = 0;i < level;i++)
8250 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
8251 }
8252 xmlOutputBufferWriteString(buf, "</");
8253 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
8254 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
8255 xmlOutputBufferWriteString(buf, ":");
8256 }
8257
8258 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8259 xmlOutputBufferWriteString(buf, ">");
8260}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00008261#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00008262#endif
8263
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00008264#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00008265/************************************************************************
8266 * *
8267 * Saving functions front-ends *
8268 * *
8269 ************************************************************************/
8270
8271/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00008272 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00008273 * @out_doc: Document to generate XML text from
8274 * @doc_txt_ptr: Memory pointer for allocated XML text
8275 * @doc_txt_len: Length of the generated XML text
8276 * @txt_encoding: Character encoding to use when generating XML text
8277 * @format: should formatting spaces been added
8278 *
8279 * Dump the current DOM tree into memory using the character encoding specified
8280 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008281 * allocated memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00008282 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00008283 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008284 */
8285
8286void
8287xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008288 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008289 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00008290 int dummy = 0;
8291
Owen Taylor3473f882001-02-23 17:55:21 +00008292 xmlOutputBufferPtr out_buff = NULL;
8293 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
8294
8295 if (doc_txt_len == NULL) {
8296 doc_txt_len = &dummy; /* Continue, caller just won't get length */
8297 }
8298
8299 if (doc_txt_ptr == NULL) {
8300 *doc_txt_len = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008301 return;
8302 }
8303
8304 *doc_txt_ptr = NULL;
8305 *doc_txt_len = 0;
8306
8307 if (out_doc == NULL) {
8308 /* No document, no output */
Owen Taylor3473f882001-02-23 17:55:21 +00008309 return;
8310 }
8311
8312 /*
8313 * Validate the encoding value, if provided.
8314 * This logic is copied from xmlSaveFileEnc.
8315 */
8316
8317 if (txt_encoding == NULL)
8318 txt_encoding = (const char *) out_doc->encoding;
8319 if (txt_encoding != NULL) {
Daniel Veillarde1326112003-06-05 09:32:20 +00008320 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00008321 if ( conv_hdlr == NULL ) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00008322 xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, (xmlNodePtr) out_doc,
8323 txt_encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00008324 return;
8325 }
8326 }
Owen Taylor3473f882001-02-23 17:55:21 +00008327
8328 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00008329 xmlSaveErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00008330 return;
8331 }
8332
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008333 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008334 xmlOutputBufferFlush(out_buff);
8335 if (out_buff->conv != NULL) {
8336 *doc_txt_len = out_buff->conv->use;
8337 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
8338 } else {
8339 *doc_txt_len = out_buff->buffer->use;
8340 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
8341 }
8342 (void)xmlOutputBufferClose(out_buff);
8343
8344 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
8345 *doc_txt_len = 0;
Daniel Veillard18ec16e2003-10-07 23:16:40 +00008346 xmlSaveErrMemory("creating output");
Owen Taylor3473f882001-02-23 17:55:21 +00008347 }
8348
8349 return;
8350}
8351
8352/**
8353 * xmlDocDumpMemory:
8354 * @cur: the document
8355 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00008356 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00008357 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008358 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008359 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00008360 */
8361void
8362xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
8363 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
8364}
8365
8366/**
8367 * xmlDocDumpFormatMemory:
8368 * @cur: the document
8369 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00008370 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00008371 * @format: should formatting spaces been added
8372 *
8373 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008374 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008375 * It's up to the caller to free the memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00008376 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00008377 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008378 */
8379void
8380xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
8381 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
8382}
8383
8384/**
8385 * xmlDocDumpMemoryEnc:
8386 * @out_doc: Document to generate XML text from
8387 * @doc_txt_ptr: Memory pointer for allocated XML text
8388 * @doc_txt_len: Length of the generated XML text
8389 * @txt_encoding: Character encoding to use when generating XML text
8390 *
8391 * Dump the current DOM tree into memory using the character encoding specified
8392 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008393 * allocated memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00008394 */
8395
8396void
8397xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
8398 int * doc_txt_len, const char * txt_encoding) {
8399 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008400 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008401}
8402
8403/**
Daniel Veillard9e412302002-06-10 15:59:44 +00008404 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00008405 * @f: the FILE*
8406 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00008407 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00008408 *
8409 * Dump an XML document to an open FILE.
8410 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008411 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008412 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8413 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008414 */
8415int
Daniel Veillard9e412302002-06-10 15:59:44 +00008416xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00008417 xmlOutputBufferPtr buf;
8418 const char * encoding;
8419 xmlCharEncodingHandlerPtr handler = NULL;
8420 int ret;
8421
8422 if (cur == NULL) {
8423#ifdef DEBUG_TREE
8424 xmlGenericError(xmlGenericErrorContext,
8425 "xmlDocDump : document == NULL\n");
8426#endif
8427 return(-1);
8428 }
8429 encoding = (const char *) cur->encoding;
8430
8431 if (encoding != NULL) {
Daniel Veillarde1326112003-06-05 09:32:20 +00008432 handler = xmlFindCharEncodingHandler(encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00008433 if (handler == NULL) {
8434 xmlFree((char *) cur->encoding);
8435 cur->encoding = NULL;
8436 }
8437 }
Owen Taylor3473f882001-02-23 17:55:21 +00008438 buf = xmlOutputBufferCreateFile(f, handler);
8439 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00008440 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008441
8442 ret = xmlOutputBufferClose(buf);
8443 return(ret);
8444}
8445
8446/**
Daniel Veillard9e412302002-06-10 15:59:44 +00008447 * xmlDocDump:
8448 * @f: the FILE*
8449 * @cur: the document
8450 *
8451 * Dump an XML document to an open FILE.
8452 *
8453 * returns: the number of bytes written or -1 in case of failure.
8454 */
8455int
8456xmlDocDump(FILE *f, xmlDocPtr cur) {
Daniel Veillard828ce832003-10-08 19:19:10 +00008457 return(xmlDocFormatDump (f, cur, 0));
Daniel Veillard9e412302002-06-10 15:59:44 +00008458}
8459
8460/**
Owen Taylor3473f882001-02-23 17:55:21 +00008461 * xmlSaveFileTo:
8462 * @buf: an output I/O buffer
8463 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00008464 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00008465 *
8466 * Dump an XML document to an I/O buffer.
8467 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008468 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008469 */
8470int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00008471xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00008472 int ret;
8473
8474 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008475 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008476 ret = xmlOutputBufferClose(buf);
8477 return(ret);
8478}
8479
8480/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00008481 * xmlSaveFormatFileTo:
8482 * @buf: an output I/O buffer
8483 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00008484 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00008485 * @format: should formatting spaces been added
8486 *
8487 * Dump an XML document to an I/O buffer.
8488 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008489 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008490 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8491 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardeefd4492001-04-28 16:55:50 +00008492 */
8493int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00008494xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00008495 int ret;
8496
8497 if (buf == NULL) return(0);
8498 xmlDocContentDumpOutput(buf, cur, encoding, format);
8499 ret = xmlOutputBufferClose(buf);
8500 return(ret);
8501}
8502
8503/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00008504 * xmlSaveFormatFileEnc:
Daniel Veillardf012a642001-07-23 19:10:52 +00008505 * @filename: the filename or URL to output
8506 * @cur: the document being saved
8507 * @encoding: the name of the encoding to use or NULL.
8508 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00008509 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00008510 * Dump an XML document to a file or an URL.
8511 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008512 * Returns the number of bytes written or -1 in case of error.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008513 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8514 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008515 */
8516int
Daniel Veillardf012a642001-07-23 19:10:52 +00008517xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
8518 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00008519 xmlOutputBufferPtr buf;
8520 xmlCharEncodingHandlerPtr handler = NULL;
8521 int ret;
8522
Daniel Veillard4dbe77a2003-01-14 00:17:42 +00008523 if (cur == NULL)
8524 return(-1);
8525
Daniel Veillardfb25a512002-01-13 20:32:08 +00008526 if (encoding == NULL)
8527 encoding = (const char *) cur->encoding;
8528
Owen Taylor3473f882001-02-23 17:55:21 +00008529 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00008530
Owen Taylor3473f882001-02-23 17:55:21 +00008531 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00008532 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00008533 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00008534 }
8535
Daniel Veillardf012a642001-07-23 19:10:52 +00008536#ifdef HAVE_ZLIB_H
8537 if (cur->compression < 0) cur->compression = xmlCompressMode;
8538#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008539 /*
8540 * save the content to a temp buffer.
8541 */
Daniel Veillardf012a642001-07-23 19:10:52 +00008542 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00008543 if (buf == NULL) return(-1);
8544
Daniel Veillardf012a642001-07-23 19:10:52 +00008545 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008546
8547 ret = xmlOutputBufferClose(buf);
8548 return(ret);
8549}
8550
Daniel Veillardf012a642001-07-23 19:10:52 +00008551
8552/**
8553 * xmlSaveFileEnc:
8554 * @filename: the filename (or URL)
8555 * @cur: the document
8556 * @encoding: the name of an encoding (or NULL)
8557 *
8558 * Dump an XML document, converting it to the given encoding
8559 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008560 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00008561 */
8562int
8563xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
8564 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
8565}
8566
Owen Taylor3473f882001-02-23 17:55:21 +00008567/**
Daniel Veillard67fee942001-04-26 18:59:03 +00008568 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00008569 * @filename: the filename (or URL)
8570 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00008571 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00008572 *
8573 * Dump an XML document to a file. Will use compression if
8574 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00008575 * used. If @format is set then the document will be indented on output.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008576 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8577 * or xmlKeepBlanksDefault(0) was called
Daniel Veillard67fee942001-04-26 18:59:03 +00008578 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008579 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008580 */
8581int
Daniel Veillard67fee942001-04-26 18:59:03 +00008582xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008583 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00008584}
8585
Daniel Veillard67fee942001-04-26 18:59:03 +00008586/**
8587 * xmlSaveFile:
8588 * @filename: the filename (or URL)
8589 * @cur: the document
8590 *
8591 * Dump an XML document to a file. Will use compression if
8592 * compiled in and enabled. If @filename is "-" the stdout file is
8593 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00008594 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00008595 */
8596int
8597xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008598 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00008599}
8600
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00008601#endif /* LIBXML_OUTPUT_ENABLED */
8602
8603/**
8604 * xmlGetDocCompressMode:
8605 * @doc: the document
8606 *
8607 * get the compression ratio for a document, ZLIB based
8608 * Returns 0 (uncompressed) to 9 (max compression)
8609 */
8610int
8611xmlGetDocCompressMode (xmlDocPtr doc) {
8612 if (doc == NULL) return(-1);
8613 return(doc->compression);
8614}
8615
8616/**
8617 * xmlSetDocCompressMode:
8618 * @doc: the document
8619 * @mode: the compression ratio
8620 *
8621 * set the compression ratio for a document, ZLIB based
8622 * Correct values: 0 (uncompressed) to 9 (max compression)
8623 */
8624void
8625xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
8626 if (doc == NULL) return;
8627 if (mode < 0) doc->compression = 0;
8628 else if (mode > 9) doc->compression = 9;
8629 else doc->compression = mode;
8630}
8631
8632/**
8633 * xmlGetCompressMode:
8634 *
8635 * get the default compression mode used, ZLIB based.
8636 * Returns 0 (uncompressed) to 9 (max compression)
8637 */
8638int
8639xmlGetCompressMode(void)
8640{
8641 return (xmlCompressMode);
8642}
8643
8644/**
8645 * xmlSetCompressMode:
8646 * @mode: the compression ratio
8647 *
8648 * set the default compression mode used, ZLIB based
8649 * Correct values: 0 (uncompressed) to 9 (max compression)
8650 */
8651void
8652xmlSetCompressMode(int mode) {
8653 if (mode < 0) xmlCompressMode = 0;
8654 else if (mode > 9) xmlCompressMode = 9;
8655 else xmlCompressMode = mode;
8656}
8657