blob: 59faab7e16c9ac4cac0ff4d184bfc458c1f97416 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002 * tree.c : implementation of access function for an XML tree.
Owen Taylor3473f882001-02-23 17:55:21 +00003 *
Daniel Veillardd5c2f922002-11-21 14:10:52 +00004 * References:
5 * XHTML 1.0 W3C REC: http://www.w3.org/TR/2002/REC-xhtml1-20020801/
6 *
Owen Taylor3473f882001-02-23 17:55:21 +00007 * See Copyright for the status of this software.
8 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00009 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000010 *
Owen Taylor3473f882001-02-23 17:55:21 +000011 */
12
Daniel Veillard34ce8be2002-03-18 19:37:11 +000013#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000014#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000015
Owen Taylor3473f882001-02-23 17:55:21 +000016#include <string.h> /* for memset() only ! */
17
18#ifdef HAVE_CTYPE_H
19#include <ctype.h>
20#endif
21#ifdef HAVE_STDLIB_H
22#include <stdlib.h>
23#endif
24#ifdef HAVE_ZLIB_H
25#include <zlib.h>
26#endif
27
28#include <libxml/xmlmemory.h>
29#include <libxml/tree.h>
30#include <libxml/parser.h>
Daniel Veillardb8c9be92001-07-09 16:01:19 +000031#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000032#include <libxml/entities.h>
33#include <libxml/valid.h>
34#include <libxml/xmlerror.h>
Daniel Veillardbdb9ba72001-04-11 11:28:06 +000035#include <libxml/parserInternals.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000036#include <libxml/globals.h>
Daniel Veillardd5c2f922002-11-21 14:10:52 +000037#ifdef LIBXML_HTML_ENABLED
38#include <libxml/HTMLtree.h>
39#endif
Owen Taylor3473f882001-02-23 17:55:21 +000040
Daniel Veillarda880b122003-04-21 21:36:41 +000041int __xmlRegisterCallbacks = 0;
42
Daniel Veillard56a4cb82001-03-24 17:00:36 +000043xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
44
45/************************************************************************
46 * *
Daniel Veillard18ec16e2003-10-07 23:16:40 +000047 * Tree memory error handler *
48 * *
49 ************************************************************************/
50/**
51 * xmlTreeErrMemory:
52 * @extra: extra informations
53 *
54 * Handle an out of memory condition
55 */
56static void
57xmlTreeErrMemory(const char *extra)
58{
59 __xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra);
60}
61
62/**
63 * xmlTreeErr:
64 * @code: the error number
65 * @extra: extra informations
66 *
67 * Handle an out of memory condition
68 */
69static void
70xmlTreeErr(int code, xmlNodePtr node, const char *extra)
71{
72 const char *msg = NULL;
73
74 switch(code) {
75 case XML_TREE_INVALID_HEX:
76 msg = "invalid hexadecimal character value";
77 break;
78 case XML_TREE_INVALID_DEC:
79 msg = "invalid decimal character value";
80 break;
81 case XML_TREE_UNTERMINATED_ENTITY:
82 msg = "unterminated entity reference %15s";
83 break;
84 default:
85 msg = "unexpected error number";
86 }
87 __xmlSimpleError(XML_FROM_TREE, code, node, msg, extra);
88}
89
90/************************************************************************
91 * *
Daniel Veillard56a4cb82001-03-24 17:00:36 +000092 * A few static variables and macros *
93 * *
94 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +000095/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +000096const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000097/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +000098const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +000099 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +0000100/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +0000101const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
102
Owen Taylor3473f882001-02-23 17:55:21 +0000103static int xmlCompressMode = 0;
104static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000105
Owen Taylor3473f882001-02-23 17:55:21 +0000106#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
107 xmlNodePtr ulccur = (n)->children; \
108 if (ulccur == NULL) { \
109 (n)->last = NULL; \
110 } else { \
111 while (ulccur->next != NULL) { \
112 ulccur->parent = (n); \
113 ulccur = ulccur->next; \
114 } \
115 ulccur->parent = (n); \
116 (n)->last = ulccur; \
117}}
118
119/* #define DEBUG_BUFFER */
120/* #define DEBUG_TREE */
121
122/************************************************************************
123 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000124 * Functions to move to entities.c once the *
125 * API freeze is smoothen and they can be made public. *
126 * *
127 ************************************************************************/
128#include <libxml/hash.h>
129
Daniel Veillard652327a2003-09-29 18:02:38 +0000130#ifdef LIBXML_TREE_ENABLED
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000131/**
132 * xmlGetEntityFromDtd:
133 * @dtd: A pointer to the DTD to search
134 * @name: The entity name
135 *
136 * Do an entity lookup in the DTD entity hash table and
137 * return the corresponding entity, if found.
138 *
139 * Returns A pointer to the entity structure or NULL if not found.
140 */
141static xmlEntityPtr
142xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
143 xmlEntitiesTablePtr table;
144
145 if((dtd != NULL) && (dtd->entities != NULL)) {
146 table = (xmlEntitiesTablePtr) dtd->entities;
147 return((xmlEntityPtr) xmlHashLookup(table, name));
148 /* return(xmlGetEntityFromTable(table, name)); */
149 }
150 return(NULL);
151}
152/**
153 * xmlGetParameterEntityFromDtd:
154 * @dtd: A pointer to the DTD to search
155 * @name: The entity name
156 *
157 * Do an entity lookup in the DTD pararmeter entity hash table and
158 * return the corresponding entity, if found.
159 *
160 * Returns A pointer to the entity structure or NULL if not found.
161 */
162static xmlEntityPtr
163xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
164 xmlEntitiesTablePtr table;
165
166 if ((dtd != NULL) && (dtd->pentities != NULL)) {
167 table = (xmlEntitiesTablePtr) dtd->pentities;
168 return((xmlEntityPtr) xmlHashLookup(table, name));
169 /* return(xmlGetEntityFromTable(table, name)); */
170 }
171 return(NULL);
172}
Daniel Veillard652327a2003-09-29 18:02:38 +0000173#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000174
175/************************************************************************
176 * *
Daniel Veillardc00cda82003-04-07 10:22:39 +0000177 * QName handling helper *
178 * *
179 ************************************************************************/
180
181/**
182 * xmlBuildQName:
183 * @ncname: the Name
184 * @prefix: the prefix
185 * @memory: preallocated memory
186 * @len: preallocated memory length
187 *
188 * Builds the QName @prefix:@ncname in @memory if there is enough space
189 * and prefix is not NULL nor empty, otherwise allocate a new string.
190 * If prefix is NULL or empty it returns ncname.
191 *
192 * Returns the new string which must be freed by the caller if different from
193 * @memory and @ncname or NULL in case of error
194 */
195xmlChar *
196xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix,
197 xmlChar *memory, int len) {
198 int lenn, lenp;
199 xmlChar *ret;
200
Daniel Veillard3b7840c2003-09-11 23:42:01 +0000201 if (ncname == NULL) return(NULL);
202 if (prefix == NULL) return((xmlChar *) ncname);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000203
204 lenn = strlen((char *) ncname);
205 lenp = strlen((char *) prefix);
206
207 if ((memory == NULL) || (len < lenn + lenp + 2)) {
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000208 ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000209 if (ret == NULL) {
210 xmlTreeErrMemory("building QName");
211 return(NULL);
212 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000213 } else {
214 ret = memory;
215 }
216 memcpy(&ret[0], prefix, lenp);
217 ret[lenp] = ':';
218 memcpy(&ret[lenp + 1], ncname, lenn);
219 ret[lenn + lenp + 1] = 0;
220 return(ret);
221}
222
223/**
224 * xmlSplitQName2:
225 * @name: the full QName
226 * @prefix: a xmlChar **
227 *
228 * parse an XML qualified name string
229 *
230 * [NS 5] QName ::= (Prefix ':')? LocalPart
231 *
232 * [NS 6] Prefix ::= NCName
233 *
234 * [NS 7] LocalPart ::= NCName
235 *
236 * Returns NULL if not a QName, otherwise the local part, and prefix
237 * is updated to get the Prefix if any.
238 */
239
240xmlChar *
241xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
242 int len = 0;
243 xmlChar *ret = NULL;
244
245 *prefix = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000246 if (name == NULL) return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000247
248#ifndef XML_XML_NAMESPACE
249 /* xml: prefix is not really a namespace */
250 if ((name[0] == 'x') && (name[1] == 'm') &&
251 (name[2] == 'l') && (name[3] == ':'))
252 return(NULL);
253#endif
254
255 /* nasty but valid */
256 if (name[0] == ':')
257 return(NULL);
258
259 /*
260 * we are not trying to validate but just to cut, and yes it will
261 * work even if this is as set of UTF-8 encoded chars
262 */
263 while ((name[len] != 0) && (name[len] != ':'))
264 len++;
265
266 if (name[len] == 0)
267 return(NULL);
268
269 *prefix = xmlStrndup(name, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000270 if (*prefix == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000271 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000272 return(NULL);
273 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000274 ret = xmlStrdup(&name[len + 1]);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000275 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000276 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000277 if (*prefix != NULL) {
278 xmlFree(*prefix);
279 *prefix = NULL;
280 }
281 return(NULL);
282 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000283
284 return(ret);
285}
286
Daniel Veillard8d73bcb2003-08-04 01:06:15 +0000287/**
288 * xmlSplitQName3:
289 * @name: the full QName
290 * @len: an int *
291 *
292 * parse an XML qualified name string,i
293 *
294 * returns NULL if it is not a Qualified Name, otherwise, update len
295 * with the lenght in byte of the prefix and return a pointer
296 */
297
298const xmlChar *
299xmlSplitQName3(const xmlChar *name, int *len) {
300 int l = 0;
301
302 if (name == NULL) return(NULL);
303 if (len == NULL) return(NULL);
304
305 /* nasty but valid */
306 if (name[0] == ':')
307 return(NULL);
308
309 /*
310 * we are not trying to validate but just to cut, and yes it will
311 * work even if this is as set of UTF-8 encoded chars
312 */
313 while ((name[l] != 0) && (name[l] != ':'))
314 l++;
315
316 if (name[l] == 0)
317 return(NULL);
318
319 *len = l;
320
321 return(&name[l+1]);
322}
323
Daniel Veillard652327a2003-09-29 18:02:38 +0000324#ifdef LIBXML_TREE_ENABLED
Daniel Veillardc00cda82003-04-07 10:22:39 +0000325/************************************************************************
326 * *
Daniel Veillardd2298792003-02-14 16:54:11 +0000327 * Check Name, NCName and QName strings *
328 * *
329 ************************************************************************/
330
331#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
332
333/**
334 * xmlValidateNCName:
335 * @value: the value to check
336 * @space: allow spaces in front and end of the string
337 *
338 * Check that a value conforms to the lexical space of NCName
339 *
340 * Returns 0 if this validates, a positive error code number otherwise
341 * and -1 in case of internal or API error.
342 */
343int
344xmlValidateNCName(const xmlChar *value, int space) {
345 const xmlChar *cur = value;
346 int c,l;
347
348 /*
349 * First quick algorithm for ASCII range
350 */
351 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000352 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000353 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
354 (*cur == '_'))
355 cur++;
356 else
357 goto try_complex;
358 while (((*cur >= 'a') && (*cur <= 'z')) ||
359 ((*cur >= 'A') && (*cur <= 'Z')) ||
360 ((*cur >= '0') && (*cur <= '9')) ||
361 (*cur == '_') || (*cur == '-') || (*cur == '.'))
362 cur++;
363 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000364 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000365 if (*cur == 0)
366 return(0);
367
368try_complex:
369 /*
370 * Second check for chars outside the ASCII range
371 */
372 cur = value;
373 c = CUR_SCHAR(cur, l);
374 if (space) {
375 while (IS_BLANK(c)) {
376 cur += l;
377 c = CUR_SCHAR(cur, l);
378 }
379 }
William M. Brack871611b2003-10-18 04:53:14 +0000380 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000381 return(1);
382 cur += l;
383 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000384 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
385 (c == '-') || (c == '_') || IS_COMBINING(c) ||
386 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000387 cur += l;
388 c = CUR_SCHAR(cur, l);
389 }
390 if (space) {
391 while (IS_BLANK(c)) {
392 cur += l;
393 c = CUR_SCHAR(cur, l);
394 }
395 }
396 if (c != 0)
397 return(1);
398
399 return(0);
400}
401
402/**
403 * xmlValidateQName:
404 * @value: the value to check
405 * @space: allow spaces in front and end of the string
406 *
407 * Check that a value conforms to the lexical space of QName
408 *
409 * Returns 0 if this validates, a positive error code number otherwise
410 * and -1 in case of internal or API error.
411 */
412int
413xmlValidateQName(const xmlChar *value, int space) {
414 const xmlChar *cur = value;
415 int c,l;
416
417 /*
418 * First quick algorithm for ASCII range
419 */
420 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000421 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000422 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
423 (*cur == '_'))
424 cur++;
425 else
426 goto try_complex;
427 while (((*cur >= 'a') && (*cur <= 'z')) ||
428 ((*cur >= 'A') && (*cur <= 'Z')) ||
429 ((*cur >= '0') && (*cur <= '9')) ||
430 (*cur == '_') || (*cur == '-') || (*cur == '.'))
431 cur++;
432 if (*cur == ':') {
433 cur++;
434 if (((*cur >= 'a') && (*cur <= 'z')) ||
435 ((*cur >= 'A') && (*cur <= 'Z')) ||
436 (*cur == '_'))
437 cur++;
438 else
439 goto try_complex;
440 while (((*cur >= 'a') && (*cur <= 'z')) ||
441 ((*cur >= 'A') && (*cur <= 'Z')) ||
442 ((*cur >= '0') && (*cur <= '9')) ||
443 (*cur == '_') || (*cur == '-') || (*cur == '.'))
444 cur++;
445 }
446 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000447 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000448 if (*cur == 0)
449 return(0);
450
451try_complex:
452 /*
453 * Second check for chars outside the ASCII range
454 */
455 cur = value;
456 c = CUR_SCHAR(cur, l);
457 if (space) {
458 while (IS_BLANK(c)) {
459 cur += l;
460 c = CUR_SCHAR(cur, l);
461 }
462 }
William M. Brack871611b2003-10-18 04:53:14 +0000463 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000464 return(1);
465 cur += l;
466 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000467 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
468 (c == '-') || (c == '_') || IS_COMBINING(c) ||
469 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000470 cur += l;
471 c = CUR_SCHAR(cur, l);
472 }
473 if (c == ':') {
474 cur += l;
475 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000476 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000477 return(1);
478 cur += l;
479 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000480 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
481 (c == '-') || (c == '_') || IS_COMBINING(c) ||
482 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000483 cur += l;
484 c = CUR_SCHAR(cur, l);
485 }
486 }
487 if (space) {
488 while (IS_BLANK(c)) {
489 cur += l;
490 c = CUR_SCHAR(cur, l);
491 }
492 }
493 if (c != 0)
494 return(1);
495 return(0);
496}
497
498/**
499 * xmlValidateName:
500 * @value: the value to check
501 * @space: allow spaces in front and end of the string
502 *
503 * Check that a value conforms to the lexical space of Name
504 *
505 * Returns 0 if this validates, a positive error code number otherwise
506 * and -1 in case of internal or API error.
507 */
508int
509xmlValidateName(const xmlChar *value, int space) {
510 const xmlChar *cur = value;
511 int c,l;
512
513 /*
514 * First quick algorithm for ASCII range
515 */
516 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000517 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000518 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
519 (*cur == '_') || (*cur == ':'))
520 cur++;
521 else
522 goto try_complex;
523 while (((*cur >= 'a') && (*cur <= 'z')) ||
524 ((*cur >= 'A') && (*cur <= 'Z')) ||
525 ((*cur >= '0') && (*cur <= '9')) ||
526 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
527 cur++;
528 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000529 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000530 if (*cur == 0)
531 return(0);
532
533try_complex:
534 /*
535 * Second check for chars outside the ASCII range
536 */
537 cur = value;
538 c = CUR_SCHAR(cur, l);
539 if (space) {
540 while (IS_BLANK(c)) {
541 cur += l;
542 c = CUR_SCHAR(cur, l);
543 }
544 }
William M. Brack871611b2003-10-18 04:53:14 +0000545 if ((!IS_LETTER(c)) && (c != '_') && (c != ':'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000546 return(1);
547 cur += l;
548 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000549 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
550 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000551 cur += l;
552 c = CUR_SCHAR(cur, l);
553 }
554 if (space) {
555 while (IS_BLANK(c)) {
556 cur += l;
557 c = CUR_SCHAR(cur, l);
558 }
559 }
560 if (c != 0)
561 return(1);
562 return(0);
563}
564
Daniel Veillardd4310742003-02-18 21:12:46 +0000565/**
566 * xmlValidateNMToken:
567 * @value: the value to check
568 * @space: allow spaces in front and end of the string
569 *
570 * Check that a value conforms to the lexical space of NMToken
571 *
572 * Returns 0 if this validates, a positive error code number otherwise
573 * and -1 in case of internal or API error.
574 */
575int
576xmlValidateNMToken(const xmlChar *value, int space) {
577 const xmlChar *cur = value;
578 int c,l;
579
580 /*
581 * First quick algorithm for ASCII range
582 */
583 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000584 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000585 if (((*cur >= 'a') && (*cur <= 'z')) ||
586 ((*cur >= 'A') && (*cur <= 'Z')) ||
587 ((*cur >= '0') && (*cur <= '9')) ||
588 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
589 cur++;
590 else
591 goto try_complex;
592 while (((*cur >= 'a') && (*cur <= 'z')) ||
593 ((*cur >= 'A') && (*cur <= 'Z')) ||
594 ((*cur >= '0') && (*cur <= '9')) ||
595 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
596 cur++;
597 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000598 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000599 if (*cur == 0)
600 return(0);
601
602try_complex:
603 /*
604 * Second check for chars outside the ASCII range
605 */
606 cur = value;
607 c = CUR_SCHAR(cur, l);
608 if (space) {
609 while (IS_BLANK(c)) {
610 cur += l;
611 c = CUR_SCHAR(cur, l);
612 }
613 }
William M. Brack871611b2003-10-18 04:53:14 +0000614 if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
615 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)))
Daniel Veillardd4310742003-02-18 21:12:46 +0000616 return(1);
617 cur += l;
618 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000619 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
620 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd4310742003-02-18 21:12:46 +0000621 cur += l;
622 c = CUR_SCHAR(cur, l);
623 }
624 if (space) {
625 while (IS_BLANK(c)) {
626 cur += l;
627 c = CUR_SCHAR(cur, l);
628 }
629 }
630 if (c != 0)
631 return(1);
632 return(0);
633}
Daniel Veillard652327a2003-09-29 18:02:38 +0000634#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardd4310742003-02-18 21:12:46 +0000635
Daniel Veillardd2298792003-02-14 16:54:11 +0000636/************************************************************************
637 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000638 * Allocation and deallocation of basic structures *
639 * *
640 ************************************************************************/
641
642/**
643 * xmlSetBufferAllocationScheme:
644 * @scheme: allocation method to use
645 *
646 * Set the buffer allocation method. Types are
647 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
648 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
649 * improves performance
650 */
651void
652xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
653 xmlBufferAllocScheme = scheme;
654}
655
656/**
657 * xmlGetBufferAllocationScheme:
658 *
659 * Types are
660 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
661 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
662 * improves performance
663 *
664 * Returns the current allocation scheme
665 */
666xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000667xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000668 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000669}
670
671/**
672 * xmlNewNs:
673 * @node: the element carrying the namespace
674 * @href: the URI associated
675 * @prefix: the prefix for the namespace
676 *
677 * Creation of a new Namespace. This function will refuse to create
678 * a namespace with a similar prefix than an existing one present on this
679 * node.
680 * We use href==NULL in the case of an element creation where the namespace
681 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000682 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000683 */
684xmlNsPtr
685xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
686 xmlNsPtr cur;
687
688 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
689 return(NULL);
690
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000691 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
692 return(NULL);
693
Owen Taylor3473f882001-02-23 17:55:21 +0000694 /*
695 * Allocate a new Namespace and fill the fields.
696 */
697 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
698 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000699 xmlTreeErrMemory("building namespace");
Owen Taylor3473f882001-02-23 17:55:21 +0000700 return(NULL);
701 }
702 memset(cur, 0, sizeof(xmlNs));
703 cur->type = XML_LOCAL_NAMESPACE;
704
705 if (href != NULL)
706 cur->href = xmlStrdup(href);
707 if (prefix != NULL)
708 cur->prefix = xmlStrdup(prefix);
709
710 /*
711 * Add it at the end to preserve parsing order ...
712 * and checks for existing use of the prefix
713 */
714 if (node != NULL) {
715 if (node->nsDef == NULL) {
716 node->nsDef = cur;
717 } else {
718 xmlNsPtr prev = node->nsDef;
719
720 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
721 (xmlStrEqual(prev->prefix, cur->prefix))) {
722 xmlFreeNs(cur);
723 return(NULL);
724 }
725 while (prev->next != NULL) {
726 prev = prev->next;
727 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
728 (xmlStrEqual(prev->prefix, cur->prefix))) {
729 xmlFreeNs(cur);
730 return(NULL);
731 }
732 }
733 prev->next = cur;
734 }
735 }
736 return(cur);
737}
738
739/**
740 * xmlSetNs:
741 * @node: a node in the document
742 * @ns: a namespace pointer
743 *
744 * Associate a namespace to a node, a posteriori.
745 */
746void
747xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
748 if (node == NULL) {
749#ifdef DEBUG_TREE
750 xmlGenericError(xmlGenericErrorContext,
751 "xmlSetNs: node == NULL\n");
752#endif
753 return;
754 }
755 node->ns = ns;
756}
757
758/**
759 * xmlFreeNs:
760 * @cur: the namespace pointer
761 *
762 * Free up the structures associated to a namespace
763 */
764void
765xmlFreeNs(xmlNsPtr cur) {
766 if (cur == NULL) {
767#ifdef DEBUG_TREE
768 xmlGenericError(xmlGenericErrorContext,
769 "xmlFreeNs : ns == NULL\n");
770#endif
771 return;
772 }
773 if (cur->href != NULL) xmlFree((char *) cur->href);
774 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000775 xmlFree(cur);
776}
777
778/**
779 * xmlFreeNsList:
780 * @cur: the first namespace pointer
781 *
782 * Free up all the structures associated to the chained namespaces.
783 */
784void
785xmlFreeNsList(xmlNsPtr cur) {
786 xmlNsPtr next;
787 if (cur == NULL) {
788#ifdef DEBUG_TREE
789 xmlGenericError(xmlGenericErrorContext,
790 "xmlFreeNsList : ns == NULL\n");
791#endif
792 return;
793 }
794 while (cur != NULL) {
795 next = cur->next;
796 xmlFreeNs(cur);
797 cur = next;
798 }
799}
800
801/**
802 * xmlNewDtd:
803 * @doc: the document pointer
804 * @name: the DTD name
805 * @ExternalID: the external ID
806 * @SystemID: the system ID
807 *
808 * Creation of a new DTD for the external subset. To create an
809 * internal subset, use xmlCreateIntSubset().
810 *
811 * Returns a pointer to the new DTD structure
812 */
813xmlDtdPtr
814xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
815 const xmlChar *ExternalID, const xmlChar *SystemID) {
816 xmlDtdPtr cur;
817
818 if ((doc != NULL) && (doc->extSubset != NULL)) {
819#ifdef DEBUG_TREE
820 xmlGenericError(xmlGenericErrorContext,
821 "xmlNewDtd(%s): document %s already have a DTD %s\n",
822 /* !!! */ (char *) name, doc->name,
823 /* !!! */ (char *)doc->extSubset->name);
824#endif
825 return(NULL);
826 }
827
828 /*
829 * Allocate a new DTD and fill the fields.
830 */
831 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
832 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000833 xmlTreeErrMemory("building DTD");
Owen Taylor3473f882001-02-23 17:55:21 +0000834 return(NULL);
835 }
836 memset(cur, 0 , sizeof(xmlDtd));
837 cur->type = XML_DTD_NODE;
838
839 if (name != NULL)
840 cur->name = xmlStrdup(name);
841 if (ExternalID != NULL)
842 cur->ExternalID = xmlStrdup(ExternalID);
843 if (SystemID != NULL)
844 cur->SystemID = xmlStrdup(SystemID);
845 if (doc != NULL)
846 doc->extSubset = cur;
847 cur->doc = doc;
848
Daniel Veillarda880b122003-04-21 21:36:41 +0000849 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000850 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000851 return(cur);
852}
853
854/**
855 * xmlGetIntSubset:
856 * @doc: the document pointer
857 *
858 * Get the internal subset of a document
859 * Returns a pointer to the DTD structure or NULL if not found
860 */
861
862xmlDtdPtr
863xmlGetIntSubset(xmlDocPtr doc) {
864 xmlNodePtr cur;
865
866 if (doc == NULL)
867 return(NULL);
868 cur = doc->children;
869 while (cur != NULL) {
870 if (cur->type == XML_DTD_NODE)
871 return((xmlDtdPtr) cur);
872 cur = cur->next;
873 }
874 return((xmlDtdPtr) doc->intSubset);
875}
876
877/**
878 * xmlCreateIntSubset:
879 * @doc: the document pointer
880 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000881 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000882 * @SystemID: the system ID
883 *
884 * Create the internal subset of a document
885 * Returns a pointer to the new DTD structure
886 */
887xmlDtdPtr
888xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
889 const xmlChar *ExternalID, const xmlChar *SystemID) {
890 xmlDtdPtr cur;
891
892 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
893#ifdef DEBUG_TREE
894 xmlGenericError(xmlGenericErrorContext,
895
896 "xmlCreateIntSubset(): document %s already have an internal subset\n",
897 doc->name);
898#endif
899 return(NULL);
900 }
901
902 /*
903 * Allocate a new DTD and fill the fields.
904 */
905 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
906 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000907 xmlTreeErrMemory("building internal subset");
Owen Taylor3473f882001-02-23 17:55:21 +0000908 return(NULL);
909 }
910 memset(cur, 0, sizeof(xmlDtd));
911 cur->type = XML_DTD_NODE;
912
913 if (name != NULL)
914 cur->name = xmlStrdup(name);
915 if (ExternalID != NULL)
916 cur->ExternalID = xmlStrdup(ExternalID);
917 if (SystemID != NULL)
918 cur->SystemID = xmlStrdup(SystemID);
919 if (doc != NULL) {
920 doc->intSubset = cur;
921 cur->parent = doc;
922 cur->doc = doc;
923 if (doc->children == NULL) {
924 doc->children = (xmlNodePtr) cur;
925 doc->last = (xmlNodePtr) cur;
926 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000927 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000928 xmlNodePtr prev;
929
Owen Taylor3473f882001-02-23 17:55:21 +0000930 prev = doc->children;
931 prev->prev = (xmlNodePtr) cur;
932 cur->next = prev;
933 doc->children = (xmlNodePtr) cur;
934 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000935 xmlNodePtr next;
936
937 next = doc->children;
938 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
939 next = next->next;
940 if (next == NULL) {
941 cur->prev = doc->last;
942 cur->prev->next = (xmlNodePtr) cur;
943 cur->next = NULL;
944 doc->last = (xmlNodePtr) cur;
945 } else {
946 cur->next = next;
947 cur->prev = next->prev;
948 if (cur->prev == NULL)
949 doc->children = (xmlNodePtr) cur;
950 else
951 cur->prev->next = (xmlNodePtr) cur;
952 next->prev = (xmlNodePtr) cur;
953 }
Owen Taylor3473f882001-02-23 17:55:21 +0000954 }
955 }
956 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000957
Daniel Veillarda880b122003-04-21 21:36:41 +0000958 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000959 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000960 return(cur);
961}
962
963/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000964 * DICT_FREE:
965 * @str: a string
966 *
967 * Free a string if it is not owned by the "dict" dictionnary in the
968 * current scope
969 */
970#define DICT_FREE(str) \
971 if ((str) && ((!dict) || \
972 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
973 xmlFree((char *)(str));
974
975/**
Owen Taylor3473f882001-02-23 17:55:21 +0000976 * xmlFreeDtd:
977 * @cur: the DTD structure to free up
978 *
979 * Free a DTD structure.
980 */
981void
982xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000983 xmlDictPtr dict = NULL;
984
Owen Taylor3473f882001-02-23 17:55:21 +0000985 if (cur == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000986 return;
987 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000988 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +0000989
Daniel Veillarda880b122003-04-21 21:36:41 +0000990 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000991 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
992
Owen Taylor3473f882001-02-23 17:55:21 +0000993 if (cur->children != NULL) {
994 xmlNodePtr next, c = cur->children;
995
996 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000997 * Cleanup all the DTD comments they are not in the DTD
Owen Taylor3473f882001-02-23 17:55:21 +0000998 * indexes.
999 */
1000 while (c != NULL) {
1001 next = c->next;
Daniel Veillardd72c7e32003-05-12 21:55:03 +00001002 if ((c->type == XML_COMMENT_NODE) || (c->type == XML_PI_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001003 xmlUnlinkNode(c);
1004 xmlFreeNode(c);
1005 }
1006 c = next;
1007 }
1008 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001009 DICT_FREE(cur->name)
1010 DICT_FREE(cur->SystemID)
1011 DICT_FREE(cur->ExternalID)
Owen Taylor3473f882001-02-23 17:55:21 +00001012 /* TODO !!! */
1013 if (cur->notations != NULL)
1014 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
1015
1016 if (cur->elements != NULL)
1017 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
1018 if (cur->attributes != NULL)
1019 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
1020 if (cur->entities != NULL)
1021 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
1022 if (cur->pentities != NULL)
1023 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
1024
Owen Taylor3473f882001-02-23 17:55:21 +00001025 xmlFree(cur);
1026}
1027
1028/**
1029 * xmlNewDoc:
1030 * @version: xmlChar string giving the version of XML "1.0"
1031 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001032 * Creates a new XML document
1033 *
Owen Taylor3473f882001-02-23 17:55:21 +00001034 * Returns a new document
1035 */
1036xmlDocPtr
1037xmlNewDoc(const xmlChar *version) {
1038 xmlDocPtr cur;
1039
1040 if (version == NULL)
1041 version = (const xmlChar *) "1.0";
1042
1043 /*
1044 * Allocate a new document and fill the fields.
1045 */
1046 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
1047 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001048 xmlTreeErrMemory("building doc");
Owen Taylor3473f882001-02-23 17:55:21 +00001049 return(NULL);
1050 }
1051 memset(cur, 0, sizeof(xmlDoc));
1052 cur->type = XML_DOCUMENT_NODE;
1053
1054 cur->version = xmlStrdup(version);
1055 cur->standalone = -1;
1056 cur->compression = -1; /* not initialized */
1057 cur->doc = cur;
Daniel Veillarda6874ca2003-07-29 16:47:24 +00001058 /*
1059 * The in memory encoding is always UTF8
1060 * This field will never change and would
1061 * be obsolete if not for binary compatibility.
1062 */
Daniel Veillardd2f3ec72001-04-11 07:50:02 +00001063 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001064
Daniel Veillarda880b122003-04-21 21:36:41 +00001065 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001066 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001067 return(cur);
1068}
1069
1070/**
1071 * xmlFreeDoc:
1072 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +00001073 *
1074 * Free up all the structures used by a document, tree included.
1075 */
1076void
1077xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +00001078 xmlDtdPtr extSubset, intSubset;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001079 xmlDictPtr dict = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001080
Owen Taylor3473f882001-02-23 17:55:21 +00001081 if (cur == NULL) {
1082#ifdef DEBUG_TREE
1083 xmlGenericError(xmlGenericErrorContext,
1084 "xmlFreeDoc : document == NULL\n");
1085#endif
1086 return;
1087 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001088 if (cur != NULL) dict = cur->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001089
Daniel Veillarda880b122003-04-21 21:36:41 +00001090 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001091 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1092
Daniel Veillard76d66f42001-05-16 21:05:17 +00001093 /*
1094 * Do this before freeing the children list to avoid ID lookups
1095 */
1096 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1097 cur->ids = NULL;
1098 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1099 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001100 extSubset = cur->extSubset;
1101 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +00001102 if (intSubset == extSubset)
1103 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001104 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001105 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001106 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001107 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001108 }
Daniel Veillarda9142e72001-06-19 11:07:54 +00001109 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001110 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001111 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001112 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001113 }
1114
1115 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001116 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001117
1118 DICT_FREE(cur->version)
1119 DICT_FREE(cur->name)
1120 DICT_FREE(cur->encoding)
1121 DICT_FREE(cur->URL)
Owen Taylor3473f882001-02-23 17:55:21 +00001122 xmlFree(cur);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001123 if (dict) xmlDictFree(dict);
Owen Taylor3473f882001-02-23 17:55:21 +00001124}
1125
1126/**
1127 * xmlStringLenGetNodeList:
1128 * @doc: the document
1129 * @value: the value of the text
1130 * @len: the length of the string value
1131 *
1132 * Parse the value string and build the node list associated. Should
1133 * produce a flat tree with only TEXTs and ENTITY_REFs.
1134 * Returns a pointer to the first child
1135 */
1136xmlNodePtr
1137xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1138 xmlNodePtr ret = NULL, last = NULL;
1139 xmlNodePtr node;
1140 xmlChar *val;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001141 const xmlChar *cur = value, *end = cur + len;
Owen Taylor3473f882001-02-23 17:55:21 +00001142 const xmlChar *q;
1143 xmlEntityPtr ent;
1144
1145 if (value == NULL) return(NULL);
1146
1147 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001148 while ((cur < end) && (*cur != 0)) {
1149 if (cur[0] == '&') {
1150 int charval = 0;
1151 xmlChar tmp;
1152
Owen Taylor3473f882001-02-23 17:55:21 +00001153 /*
1154 * Save the current text.
1155 */
1156 if (cur != q) {
1157 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1158 xmlNodeAddContentLen(last, q, cur - q);
1159 } else {
1160 node = xmlNewDocTextLen(doc, q, cur - q);
1161 if (node == NULL) return(ret);
1162 if (last == NULL)
1163 last = ret = node;
1164 else {
1165 last->next = node;
1166 node->prev = last;
1167 last = node;
1168 }
1169 }
1170 }
Owen Taylor3473f882001-02-23 17:55:21 +00001171 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001172 if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
1173 cur += 3;
1174 if (cur < end)
1175 tmp = *cur;
1176 else
1177 tmp = 0;
1178 while (tmp != ';') { /* Non input consuming loop */
1179 if ((tmp >= '0') && (tmp <= '9'))
1180 charval = charval * 16 + (tmp - '0');
1181 else if ((tmp >= 'a') && (tmp <= 'f'))
1182 charval = charval * 16 + (tmp - 'a') + 10;
1183 else if ((tmp >= 'A') && (tmp <= 'F'))
1184 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001185 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001186 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1187 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001188 charval = 0;
1189 break;
1190 }
1191 cur++;
1192 if (cur < end)
1193 tmp = *cur;
1194 else
1195 tmp = 0;
1196 }
1197 if (tmp == ';')
1198 cur++;
1199 q = cur;
1200 } else if ((cur + 1 < end) && (cur[1] == '#')) {
1201 cur += 2;
1202 if (cur < end)
1203 tmp = *cur;
1204 else
1205 tmp = 0;
1206 while (tmp != ';') { /* Non input consuming loops */
1207 if ((tmp >= '0') && (tmp <= '9'))
1208 charval = charval * 10 + (tmp - '0');
1209 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001210 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1211 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001212 charval = 0;
1213 break;
1214 }
1215 cur++;
1216 if (cur < end)
1217 tmp = *cur;
1218 else
1219 tmp = 0;
1220 }
1221 if (tmp == ';')
1222 cur++;
1223 q = cur;
1224 } else {
1225 /*
1226 * Read the entity string
1227 */
1228 cur++;
1229 q = cur;
1230 while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1231 if ((cur >= end) || (*cur == 0)) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001232 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc,
1233 (const char *) q);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001234 return(ret);
1235 }
1236 if (cur != q) {
1237 /*
1238 * Predefined entities don't generate nodes
1239 */
1240 val = xmlStrndup(q, cur - q);
1241 ent = xmlGetDocEntity(doc, val);
1242 if ((ent != NULL) &&
1243 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1244 if (last == NULL) {
1245 node = xmlNewDocText(doc, ent->content);
1246 last = ret = node;
1247 } else if (last->type != XML_TEXT_NODE) {
1248 node = xmlNewDocText(doc, ent->content);
1249 last = xmlAddNextSibling(last, node);
1250 } else
1251 xmlNodeAddContent(last, ent->content);
1252
1253 } else {
1254 /*
1255 * Create a new REFERENCE_REF node
1256 */
1257 node = xmlNewReference(doc, val);
1258 if (node == NULL) {
1259 if (val != NULL) xmlFree(val);
1260 return(ret);
1261 }
1262 else if ((ent != NULL) && (ent->children == NULL)) {
1263 xmlNodePtr temp;
1264
1265 ent->children = xmlStringGetNodeList(doc,
1266 (const xmlChar*)node->content);
1267 ent->owner = 1;
1268 temp = ent->children;
1269 while (temp) {
1270 temp->parent = (xmlNodePtr)ent;
1271 temp = temp->next;
1272 }
1273 }
1274 if (last == NULL) {
1275 last = ret = node;
1276 } else {
1277 last = xmlAddNextSibling(last, node);
1278 }
1279 }
1280 xmlFree(val);
1281 }
1282 cur++;
1283 q = cur;
1284 }
1285 if (charval != 0) {
1286 xmlChar buf[10];
1287 int l;
1288
1289 l = xmlCopyCharMultiByte(buf, charval);
1290 buf[l] = 0;
1291 node = xmlNewDocText(doc, buf);
1292 if (node != NULL) {
1293 if (last == NULL) {
1294 last = ret = node;
1295 } else {
1296 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001297 }
1298 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001299 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001300 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001301 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001302 cur++;
1303 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001304 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001305 /*
1306 * Handle the last piece of text.
1307 */
1308 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1309 xmlNodeAddContentLen(last, q, cur - q);
1310 } else {
1311 node = xmlNewDocTextLen(doc, q, cur - q);
1312 if (node == NULL) return(ret);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001313 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001314 last = ret = node;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001315 } else {
1316 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001317 }
1318 }
1319 }
1320 return(ret);
1321}
1322
1323/**
1324 * xmlStringGetNodeList:
1325 * @doc: the document
1326 * @value: the value of the attribute
1327 *
1328 * Parse the value string and build the node list associated. Should
1329 * produce a flat tree with only TEXTs and ENTITY_REFs.
1330 * Returns a pointer to the first child
1331 */
1332xmlNodePtr
1333xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1334 xmlNodePtr ret = NULL, last = NULL;
1335 xmlNodePtr node;
1336 xmlChar *val;
1337 const xmlChar *cur = value;
1338 const xmlChar *q;
1339 xmlEntityPtr ent;
1340
1341 if (value == NULL) return(NULL);
1342
1343 q = cur;
1344 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001345 if (cur[0] == '&') {
1346 int charval = 0;
1347 xmlChar tmp;
1348
Owen Taylor3473f882001-02-23 17:55:21 +00001349 /*
1350 * Save the current text.
1351 */
1352 if (cur != q) {
1353 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1354 xmlNodeAddContentLen(last, q, cur - q);
1355 } else {
1356 node = xmlNewDocTextLen(doc, q, cur - q);
1357 if (node == NULL) return(ret);
1358 if (last == NULL)
1359 last = ret = node;
1360 else {
1361 last->next = node;
1362 node->prev = last;
1363 last = node;
1364 }
1365 }
1366 }
Owen Taylor3473f882001-02-23 17:55:21 +00001367 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001368 if ((cur[1] == '#') && (cur[2] == 'x')) {
1369 cur += 3;
1370 tmp = *cur;
1371 while (tmp != ';') { /* Non input consuming loop */
1372 if ((tmp >= '0') && (tmp <= '9'))
1373 charval = charval * 16 + (tmp - '0');
1374 else if ((tmp >= 'a') && (tmp <= 'f'))
1375 charval = charval * 16 + (tmp - 'a') + 10;
1376 else if ((tmp >= 'A') && (tmp <= 'F'))
1377 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001378 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001379 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1380 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001381 charval = 0;
1382 break;
1383 }
1384 cur++;
1385 tmp = *cur;
1386 }
1387 if (tmp == ';')
1388 cur++;
1389 q = cur;
1390 } else if (cur[1] == '#') {
1391 cur += 2;
1392 tmp = *cur;
1393 while (tmp != ';') { /* Non input consuming loops */
1394 if ((tmp >= '0') && (tmp <= '9'))
1395 charval = charval * 10 + (tmp - '0');
1396 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001397 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1398 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001399 charval = 0;
1400 break;
1401 }
1402 cur++;
1403 tmp = *cur;
1404 }
1405 if (tmp == ';')
1406 cur++;
1407 q = cur;
1408 } else {
1409 /*
1410 * Read the entity string
1411 */
1412 cur++;
1413 q = cur;
1414 while ((*cur != 0) && (*cur != ';')) cur++;
1415 if (*cur == 0) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001416 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY,
1417 (xmlNodePtr) doc, (const char *) q);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001418 return(ret);
1419 }
1420 if (cur != q) {
1421 /*
1422 * Predefined entities don't generate nodes
1423 */
1424 val = xmlStrndup(q, cur - q);
1425 ent = xmlGetDocEntity(doc, val);
1426 if ((ent != NULL) &&
1427 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1428 if (last == NULL) {
1429 node = xmlNewDocText(doc, ent->content);
1430 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001431 } else if (last->type != XML_TEXT_NODE) {
1432 node = xmlNewDocText(doc, ent->content);
1433 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001434 } else
1435 xmlNodeAddContent(last, ent->content);
1436
1437 } else {
1438 /*
1439 * Create a new REFERENCE_REF node
1440 */
1441 node = xmlNewReference(doc, val);
1442 if (node == NULL) {
1443 if (val != NULL) xmlFree(val);
1444 return(ret);
1445 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001446 else if ((ent != NULL) && (ent->children == NULL)) {
1447 xmlNodePtr temp;
1448
1449 ent->children = xmlStringGetNodeList(doc,
1450 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001451 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001452 temp = ent->children;
1453 while (temp) {
1454 temp->parent = (xmlNodePtr)ent;
1455 temp = temp->next;
1456 }
1457 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001458 if (last == NULL) {
1459 last = ret = node;
1460 } else {
1461 last = xmlAddNextSibling(last, node);
1462 }
1463 }
1464 xmlFree(val);
1465 }
1466 cur++;
1467 q = cur;
1468 }
1469 if (charval != 0) {
1470 xmlChar buf[10];
1471 int len;
1472
1473 len = xmlCopyCharMultiByte(buf, charval);
1474 buf[len] = 0;
1475 node = xmlNewDocText(doc, buf);
1476 if (node != NULL) {
1477 if (last == NULL) {
1478 last = ret = node;
1479 } else {
1480 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001481 }
1482 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001483
1484 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001485 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001486 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001487 cur++;
1488 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001489 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001490 /*
1491 * Handle the last piece of text.
1492 */
1493 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1494 xmlNodeAddContentLen(last, q, cur - q);
1495 } else {
1496 node = xmlNewDocTextLen(doc, q, cur - q);
1497 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001498 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001499 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001500 } else {
1501 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001502 }
1503 }
1504 }
1505 return(ret);
1506}
1507
1508/**
1509 * xmlNodeListGetString:
1510 * @doc: the document
1511 * @list: a Node list
1512 * @inLine: should we replace entity contents or show their external form
1513 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001514 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001515 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001516 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001517 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001518 */
1519xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001520xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1521{
Owen Taylor3473f882001-02-23 17:55:21 +00001522 xmlNodePtr node = list;
1523 xmlChar *ret = NULL;
1524 xmlEntityPtr ent;
1525
Daniel Veillard7646b182002-04-20 06:41:40 +00001526 if (list == NULL)
1527 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001528
1529 while (node != NULL) {
1530 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001531 (node->type == XML_CDATA_SECTION_NODE)) {
1532 if (inLine) {
1533 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001534 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001535 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001536
Daniel Veillard7646b182002-04-20 06:41:40 +00001537 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1538 if (buffer != NULL) {
1539 ret = xmlStrcat(ret, buffer);
1540 xmlFree(buffer);
1541 }
1542 }
1543 } else if (node->type == XML_ENTITY_REF_NODE) {
1544 if (inLine) {
1545 ent = xmlGetDocEntity(doc, node->name);
1546 if (ent != NULL) {
1547 xmlChar *buffer;
1548
1549 /* an entity content can be any "well balanced chunk",
1550 * i.e. the result of the content [43] production:
1551 * http://www.w3.org/TR/REC-xml#NT-content.
1552 * So it can contain text, CDATA section or nested
1553 * entity reference nodes (among others).
1554 * -> we recursive call xmlNodeListGetString()
1555 * which handles these types */
1556 buffer = xmlNodeListGetString(doc, ent->children, 1);
1557 if (buffer != NULL) {
1558 ret = xmlStrcat(ret, buffer);
1559 xmlFree(buffer);
1560 }
1561 } else {
1562 ret = xmlStrcat(ret, node->content);
1563 }
1564 } else {
1565 xmlChar buf[2];
1566
1567 buf[0] = '&';
1568 buf[1] = 0;
1569 ret = xmlStrncat(ret, buf, 1);
1570 ret = xmlStrcat(ret, node->name);
1571 buf[0] = ';';
1572 buf[1] = 0;
1573 ret = xmlStrncat(ret, buf, 1);
1574 }
1575 }
1576#if 0
1577 else {
1578 xmlGenericError(xmlGenericErrorContext,
1579 "xmlGetNodeListString : invalid node type %d\n",
1580 node->type);
1581 }
1582#endif
1583 node = node->next;
1584 }
1585 return (ret);
1586}
Daniel Veillard652327a2003-09-29 18:02:38 +00001587
1588#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001589/**
1590 * xmlNodeListGetRawString:
1591 * @doc: the document
1592 * @list: a Node list
1593 * @inLine: should we replace entity contents or show their external form
1594 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001595 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001596 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1597 * this function doesn't do any character encoding handling.
1598 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001599 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001600 */
1601xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001602xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1603{
Owen Taylor3473f882001-02-23 17:55:21 +00001604 xmlNodePtr node = list;
1605 xmlChar *ret = NULL;
1606 xmlEntityPtr ent;
1607
Daniel Veillard7646b182002-04-20 06:41:40 +00001608 if (list == NULL)
1609 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001610
1611 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001612 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001613 (node->type == XML_CDATA_SECTION_NODE)) {
1614 if (inLine) {
1615 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001616 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001617 xmlChar *buffer;
1618
1619 buffer = xmlEncodeSpecialChars(doc, node->content);
1620 if (buffer != NULL) {
1621 ret = xmlStrcat(ret, buffer);
1622 xmlFree(buffer);
1623 }
1624 }
1625 } else if (node->type == XML_ENTITY_REF_NODE) {
1626 if (inLine) {
1627 ent = xmlGetDocEntity(doc, node->name);
1628 if (ent != NULL) {
1629 xmlChar *buffer;
1630
1631 /* an entity content can be any "well balanced chunk",
1632 * i.e. the result of the content [43] production:
1633 * http://www.w3.org/TR/REC-xml#NT-content.
1634 * So it can contain text, CDATA section or nested
1635 * entity reference nodes (among others).
1636 * -> we recursive call xmlNodeListGetRawString()
1637 * which handles these types */
1638 buffer =
1639 xmlNodeListGetRawString(doc, ent->children, 1);
1640 if (buffer != NULL) {
1641 ret = xmlStrcat(ret, buffer);
1642 xmlFree(buffer);
1643 }
1644 } else {
1645 ret = xmlStrcat(ret, node->content);
1646 }
1647 } else {
1648 xmlChar buf[2];
1649
1650 buf[0] = '&';
1651 buf[1] = 0;
1652 ret = xmlStrncat(ret, buf, 1);
1653 ret = xmlStrcat(ret, node->name);
1654 buf[0] = ';';
1655 buf[1] = 0;
1656 ret = xmlStrncat(ret, buf, 1);
1657 }
1658 }
Owen Taylor3473f882001-02-23 17:55:21 +00001659#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001660 else {
1661 xmlGenericError(xmlGenericErrorContext,
1662 "xmlGetNodeListString : invalid node type %d\n",
1663 node->type);
1664 }
Owen Taylor3473f882001-02-23 17:55:21 +00001665#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001666 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001667 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001668 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001669}
Daniel Veillard652327a2003-09-29 18:02:38 +00001670#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001671
Daniel Veillard652327a2003-09-29 18:02:38 +00001672#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001673/**
1674 * xmlNewProp:
1675 * @node: the holding node
1676 * @name: the name of the attribute
1677 * @value: the value of the attribute
1678 *
1679 * Create a new property carried by a node.
1680 * Returns a pointer to the attribute
1681 */
1682xmlAttrPtr
1683xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1684 xmlAttrPtr cur;
1685 xmlDocPtr doc = NULL;
1686
1687 if (name == NULL) {
1688#ifdef DEBUG_TREE
1689 xmlGenericError(xmlGenericErrorContext,
1690 "xmlNewProp : name == NULL\n");
1691#endif
1692 return(NULL);
1693 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00001694 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
1695 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001696
1697 /*
1698 * Allocate a new property and fill the fields.
1699 */
1700 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1701 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001702 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001703 return(NULL);
1704 }
1705 memset(cur, 0, sizeof(xmlAttr));
1706 cur->type = XML_ATTRIBUTE_NODE;
1707
1708 cur->parent = node;
1709 if (node != NULL) {
1710 doc = node->doc;
1711 cur->doc = doc;
1712 }
1713 cur->name = xmlStrdup(name);
1714 if (value != NULL) {
1715 xmlChar *buffer;
1716 xmlNodePtr tmp;
1717
1718 buffer = xmlEncodeEntitiesReentrant(doc, value);
1719 cur->children = xmlStringGetNodeList(doc, buffer);
1720 cur->last = NULL;
1721 tmp = cur->children;
1722 while (tmp != NULL) {
1723 tmp->parent = (xmlNodePtr) cur;
1724 tmp->doc = doc;
1725 if (tmp->next == NULL)
1726 cur->last = tmp;
1727 tmp = tmp->next;
1728 }
1729 xmlFree(buffer);
1730 }
1731
1732 /*
1733 * Add it at the end to preserve parsing order ...
1734 */
1735 if (node != NULL) {
1736 if (node->properties == NULL) {
1737 node->properties = cur;
1738 } else {
1739 xmlAttrPtr prev = node->properties;
1740
1741 while (prev->next != NULL) prev = prev->next;
1742 prev->next = cur;
1743 cur->prev = prev;
1744 }
1745 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001746
Daniel Veillarda880b122003-04-21 21:36:41 +00001747 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001748 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001749 return(cur);
1750}
Daniel Veillard652327a2003-09-29 18:02:38 +00001751#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001752
1753/**
1754 * xmlNewNsProp:
1755 * @node: the holding node
1756 * @ns: the namespace
1757 * @name: the name of the attribute
1758 * @value: the value of the attribute
1759 *
1760 * Create a new property tagged with a namespace and carried by a node.
1761 * Returns a pointer to the attribute
1762 */
1763xmlAttrPtr
1764xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1765 const xmlChar *value) {
1766 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001767 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001768
1769 if (name == NULL) {
1770#ifdef DEBUG_TREE
1771 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001772 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001773#endif
1774 return(NULL);
1775 }
1776
1777 /*
1778 * Allocate a new property and fill the fields.
1779 */
1780 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1781 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001782 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001783 return(NULL);
1784 }
1785 memset(cur, 0, sizeof(xmlAttr));
1786 cur->type = XML_ATTRIBUTE_NODE;
1787
1788 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001789 if (node != NULL) {
1790 doc = node->doc;
1791 cur->doc = doc;
1792 }
Owen Taylor3473f882001-02-23 17:55:21 +00001793 cur->ns = ns;
1794 cur->name = xmlStrdup(name);
1795 if (value != NULL) {
1796 xmlChar *buffer;
1797 xmlNodePtr tmp;
1798
Daniel Veillarda682b212001-06-07 19:59:42 +00001799 buffer = xmlEncodeEntitiesReentrant(doc, value);
1800 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001801 cur->last = NULL;
1802 tmp = cur->children;
1803 while (tmp != NULL) {
1804 tmp->parent = (xmlNodePtr) cur;
1805 if (tmp->next == NULL)
1806 cur->last = tmp;
1807 tmp = tmp->next;
1808 }
1809 xmlFree(buffer);
1810 }
1811
1812 /*
1813 * Add it at the end to preserve parsing order ...
1814 */
1815 if (node != NULL) {
1816 if (node->properties == NULL) {
1817 node->properties = cur;
1818 } else {
1819 xmlAttrPtr prev = node->properties;
1820
1821 while (prev->next != NULL) prev = prev->next;
1822 prev->next = cur;
1823 cur->prev = prev;
1824 }
1825 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001826
Daniel Veillarda880b122003-04-21 21:36:41 +00001827 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001828 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001829 return(cur);
1830}
1831
1832/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001833 * xmlNewNsPropEatName:
1834 * @node: the holding node
1835 * @ns: the namespace
1836 * @name: the name of the attribute
1837 * @value: the value of the attribute
1838 *
1839 * Create a new property tagged with a namespace and carried by a node.
1840 * Returns a pointer to the attribute
1841 */
1842xmlAttrPtr
1843xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1844 const xmlChar *value) {
1845 xmlAttrPtr cur;
1846 xmlDocPtr doc = NULL;
1847
1848 if (name == NULL) {
1849#ifdef DEBUG_TREE
1850 xmlGenericError(xmlGenericErrorContext,
1851 "xmlNewNsPropEatName : name == NULL\n");
1852#endif
1853 return(NULL);
1854 }
1855
1856 /*
1857 * Allocate a new property and fill the fields.
1858 */
1859 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1860 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001861 xmlTreeErrMemory("building attribute");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001862 xmlFree(name);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001863 return(NULL);
1864 }
1865 memset(cur, 0, sizeof(xmlAttr));
1866 cur->type = XML_ATTRIBUTE_NODE;
1867
1868 cur->parent = node;
1869 if (node != NULL) {
1870 doc = node->doc;
1871 cur->doc = doc;
1872 }
1873 cur->ns = ns;
1874 cur->name = name;
1875 if (value != NULL) {
1876 xmlChar *buffer;
1877 xmlNodePtr tmp;
1878
1879 buffer = xmlEncodeEntitiesReentrant(doc, value);
1880 cur->children = xmlStringGetNodeList(doc, buffer);
1881 cur->last = NULL;
1882 tmp = cur->children;
1883 while (tmp != NULL) {
1884 tmp->parent = (xmlNodePtr) cur;
1885 if (tmp->next == NULL)
1886 cur->last = tmp;
1887 tmp = tmp->next;
1888 }
1889 xmlFree(buffer);
1890 }
1891
1892 /*
1893 * Add it at the end to preserve parsing order ...
1894 */
1895 if (node != NULL) {
1896 if (node->properties == NULL) {
1897 node->properties = cur;
1898 } else {
1899 xmlAttrPtr prev = node->properties;
1900
1901 while (prev->next != NULL) prev = prev->next;
1902 prev->next = cur;
1903 cur->prev = prev;
1904 }
1905 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001906
Daniel Veillarda880b122003-04-21 21:36:41 +00001907 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001908 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001909 return(cur);
1910}
1911
1912/**
Owen Taylor3473f882001-02-23 17:55:21 +00001913 * xmlNewDocProp:
1914 * @doc: the document
1915 * @name: the name of the attribute
1916 * @value: the value of the attribute
1917 *
1918 * Create a new property carried by a document.
1919 * Returns a pointer to the attribute
1920 */
1921xmlAttrPtr
1922xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1923 xmlAttrPtr cur;
1924
1925 if (name == NULL) {
1926#ifdef DEBUG_TREE
1927 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001928 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001929#endif
1930 return(NULL);
1931 }
1932
1933 /*
1934 * Allocate a new property and fill the fields.
1935 */
1936 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1937 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001938 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001939 return(NULL);
1940 }
1941 memset(cur, 0, sizeof(xmlAttr));
1942 cur->type = XML_ATTRIBUTE_NODE;
1943
1944 cur->name = xmlStrdup(name);
1945 cur->doc = doc;
1946 if (value != NULL) {
1947 xmlNodePtr tmp;
1948
1949 cur->children = xmlStringGetNodeList(doc, value);
1950 cur->last = NULL;
1951
1952 tmp = cur->children;
1953 while (tmp != NULL) {
1954 tmp->parent = (xmlNodePtr) cur;
1955 if (tmp->next == NULL)
1956 cur->last = tmp;
1957 tmp = tmp->next;
1958 }
1959 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001960
Daniel Veillarda880b122003-04-21 21:36:41 +00001961 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001962 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001963 return(cur);
1964}
1965
1966/**
1967 * xmlFreePropList:
1968 * @cur: the first property in the list
1969 *
1970 * Free a property and all its siblings, all the children are freed too.
1971 */
1972void
1973xmlFreePropList(xmlAttrPtr cur) {
1974 xmlAttrPtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001975 if (cur == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001976 while (cur != NULL) {
1977 next = cur->next;
1978 xmlFreeProp(cur);
1979 cur = next;
1980 }
1981}
1982
1983/**
1984 * xmlFreeProp:
1985 * @cur: an attribute
1986 *
1987 * Free one attribute, all the content is freed too
1988 */
1989void
1990xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001991 xmlDictPtr dict = NULL;
1992 if (cur == NULL) return;
1993
1994 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001995
Daniel Veillarda880b122003-04-21 21:36:41 +00001996 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001997 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1998
Owen Taylor3473f882001-02-23 17:55:21 +00001999 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00002000 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
2001 ((cur->parent->doc->intSubset != NULL) ||
2002 (cur->parent->doc->extSubset != NULL))) {
2003 if (xmlIsID(cur->parent->doc, cur->parent, cur))
2004 xmlRemoveID(cur->parent->doc, cur);
2005 }
Owen Taylor3473f882001-02-23 17:55:21 +00002006 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002007 DICT_FREE(cur->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002008 xmlFree(cur);
2009}
2010
Daniel Veillard652327a2003-09-29 18:02:38 +00002011#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002012/**
2013 * xmlRemoveProp:
2014 * @cur: an attribute
2015 *
2016 * Unlink and free one attribute, all the content is freed too
2017 * Note this doesn't work for namespace definition attributes
2018 *
2019 * Returns 0 if success and -1 in case of error.
2020 */
2021int
2022xmlRemoveProp(xmlAttrPtr cur) {
2023 xmlAttrPtr tmp;
2024 if (cur == NULL) {
2025#ifdef DEBUG_TREE
2026 xmlGenericError(xmlGenericErrorContext,
2027 "xmlRemoveProp : cur == NULL\n");
2028#endif
2029 return(-1);
2030 }
2031 if (cur->parent == NULL) {
2032#ifdef DEBUG_TREE
2033 xmlGenericError(xmlGenericErrorContext,
2034 "xmlRemoveProp : cur->parent == NULL\n");
2035#endif
2036 return(-1);
2037 }
2038 tmp = cur->parent->properties;
2039 if (tmp == cur) {
2040 cur->parent->properties = cur->next;
2041 xmlFreeProp(cur);
2042 return(0);
2043 }
2044 while (tmp != NULL) {
2045 if (tmp->next == cur) {
2046 tmp->next = cur->next;
2047 if (tmp->next != NULL)
2048 tmp->next->prev = tmp;
2049 xmlFreeProp(cur);
2050 return(0);
2051 }
2052 tmp = tmp->next;
2053 }
2054#ifdef DEBUG_TREE
2055 xmlGenericError(xmlGenericErrorContext,
2056 "xmlRemoveProp : attribute not owned by its node\n");
2057#endif
2058 return(-1);
2059}
Daniel Veillard652327a2003-09-29 18:02:38 +00002060#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002061
2062/**
2063 * xmlNewPI:
2064 * @name: the processing instruction name
2065 * @content: the PI content
2066 *
2067 * Creation of a processing instruction element.
2068 * Returns a pointer to the new node object.
2069 */
2070xmlNodePtr
2071xmlNewPI(const xmlChar *name, const xmlChar *content) {
2072 xmlNodePtr cur;
2073
2074 if (name == NULL) {
2075#ifdef DEBUG_TREE
2076 xmlGenericError(xmlGenericErrorContext,
2077 "xmlNewPI : name == NULL\n");
2078#endif
2079 return(NULL);
2080 }
2081
2082 /*
2083 * Allocate a new node and fill the fields.
2084 */
2085 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2086 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002087 xmlTreeErrMemory("building PI");
Owen Taylor3473f882001-02-23 17:55:21 +00002088 return(NULL);
2089 }
2090 memset(cur, 0, sizeof(xmlNode));
2091 cur->type = XML_PI_NODE;
2092
2093 cur->name = xmlStrdup(name);
2094 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002095 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002096 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002097
Daniel Veillarda880b122003-04-21 21:36:41 +00002098 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002099 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002100 return(cur);
2101}
2102
2103/**
2104 * xmlNewNode:
2105 * @ns: namespace if any
2106 * @name: the node name
2107 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002108 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002109 *
2110 * Returns a pointer to the new node object.
2111 */
2112xmlNodePtr
2113xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2114 xmlNodePtr cur;
2115
2116 if (name == NULL) {
2117#ifdef DEBUG_TREE
2118 xmlGenericError(xmlGenericErrorContext,
2119 "xmlNewNode : name == NULL\n");
2120#endif
2121 return(NULL);
2122 }
2123
2124 /*
2125 * Allocate a new node and fill the fields.
2126 */
2127 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2128 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002129 xmlTreeErrMemory("building node");
Owen Taylor3473f882001-02-23 17:55:21 +00002130 return(NULL);
2131 }
2132 memset(cur, 0, sizeof(xmlNode));
2133 cur->type = XML_ELEMENT_NODE;
2134
2135 cur->name = xmlStrdup(name);
2136 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002137
Daniel Veillarda880b122003-04-21 21:36:41 +00002138 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002139 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002140 return(cur);
2141}
2142
2143/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00002144 * xmlNewNodeEatName:
2145 * @ns: namespace if any
2146 * @name: the node name
2147 *
2148 * Creation of a new node element. @ns is optional (NULL).
2149 *
2150 * Returns a pointer to the new node object.
2151 */
2152xmlNodePtr
2153xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2154 xmlNodePtr cur;
2155
2156 if (name == NULL) {
2157#ifdef DEBUG_TREE
2158 xmlGenericError(xmlGenericErrorContext,
2159 "xmlNewNode : name == NULL\n");
2160#endif
2161 return(NULL);
2162 }
2163
2164 /*
2165 * Allocate a new node and fill the fields.
2166 */
2167 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2168 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002169 xmlTreeErrMemory("building node");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00002170 xmlFree(name);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002171 return(NULL);
2172 }
2173 memset(cur, 0, sizeof(xmlNode));
2174 cur->type = XML_ELEMENT_NODE;
2175
2176 cur->name = name;
2177 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002178
Daniel Veillarda880b122003-04-21 21:36:41 +00002179 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002180 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002181 return(cur);
2182}
2183
2184/**
Owen Taylor3473f882001-02-23 17:55:21 +00002185 * xmlNewDocNode:
2186 * @doc: the document
2187 * @ns: namespace if any
2188 * @name: the node name
2189 * @content: the XML text content if any
2190 *
2191 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002192 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002193 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2194 * references, but XML special chars need to be escaped first by using
2195 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2196 * need entities support.
2197 *
2198 * Returns a pointer to the new node object.
2199 */
2200xmlNodePtr
2201xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2202 const xmlChar *name, const xmlChar *content) {
2203 xmlNodePtr cur;
2204
2205 cur = xmlNewNode(ns, name);
2206 if (cur != NULL) {
2207 cur->doc = doc;
2208 if (content != NULL) {
2209 cur->children = xmlStringGetNodeList(doc, content);
2210 UPDATE_LAST_CHILD_AND_PARENT(cur)
2211 }
2212 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002213
Owen Taylor3473f882001-02-23 17:55:21 +00002214 return(cur);
2215}
2216
Daniel Veillard46de64e2002-05-29 08:21:33 +00002217/**
2218 * xmlNewDocNodeEatName:
2219 * @doc: the document
2220 * @ns: namespace if any
2221 * @name: the node name
2222 * @content: the XML text content if any
2223 *
2224 * Creation of a new node element within a document. @ns and @content
2225 * are optional (NULL).
2226 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2227 * references, but XML special chars need to be escaped first by using
2228 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2229 * need entities support.
2230 *
2231 * Returns a pointer to the new node object.
2232 */
2233xmlNodePtr
2234xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2235 xmlChar *name, const xmlChar *content) {
2236 xmlNodePtr cur;
2237
2238 cur = xmlNewNodeEatName(ns, name);
2239 if (cur != NULL) {
2240 cur->doc = doc;
2241 if (content != NULL) {
2242 cur->children = xmlStringGetNodeList(doc, content);
2243 UPDATE_LAST_CHILD_AND_PARENT(cur)
2244 }
2245 }
2246 return(cur);
2247}
2248
Daniel Veillard652327a2003-09-29 18:02:38 +00002249#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002250/**
2251 * xmlNewDocRawNode:
2252 * @doc: the document
2253 * @ns: namespace if any
2254 * @name: the node name
2255 * @content: the text content if any
2256 *
2257 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002258 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002259 *
2260 * Returns a pointer to the new node object.
2261 */
2262xmlNodePtr
2263xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2264 const xmlChar *name, const xmlChar *content) {
2265 xmlNodePtr cur;
2266
2267 cur = xmlNewNode(ns, name);
2268 if (cur != NULL) {
2269 cur->doc = doc;
2270 if (content != NULL) {
2271 cur->children = xmlNewDocText(doc, content);
2272 UPDATE_LAST_CHILD_AND_PARENT(cur)
2273 }
2274 }
2275 return(cur);
2276}
2277
2278/**
2279 * xmlNewDocFragment:
2280 * @doc: the document owning the fragment
2281 *
2282 * Creation of a new Fragment node.
2283 * Returns a pointer to the new node object.
2284 */
2285xmlNodePtr
2286xmlNewDocFragment(xmlDocPtr doc) {
2287 xmlNodePtr cur;
2288
2289 /*
2290 * Allocate a new DocumentFragment node and fill the fields.
2291 */
2292 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2293 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002294 xmlTreeErrMemory("building fragment");
Owen Taylor3473f882001-02-23 17:55:21 +00002295 return(NULL);
2296 }
2297 memset(cur, 0, sizeof(xmlNode));
2298 cur->type = XML_DOCUMENT_FRAG_NODE;
2299
2300 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002301
Daniel Veillarda880b122003-04-21 21:36:41 +00002302 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002303 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002304 return(cur);
2305}
Daniel Veillard652327a2003-09-29 18:02:38 +00002306#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002307
2308/**
2309 * xmlNewText:
2310 * @content: the text content
2311 *
2312 * Creation of a new text node.
2313 * Returns a pointer to the new node object.
2314 */
2315xmlNodePtr
2316xmlNewText(const xmlChar *content) {
2317 xmlNodePtr cur;
2318
2319 /*
2320 * Allocate a new node and fill the fields.
2321 */
2322 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2323 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002324 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002325 return(NULL);
2326 }
2327 memset(cur, 0, sizeof(xmlNode));
2328 cur->type = XML_TEXT_NODE;
2329
2330 cur->name = xmlStringText;
2331 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002332 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002333 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002334
Daniel Veillarda880b122003-04-21 21:36:41 +00002335 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002336 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002337 return(cur);
2338}
2339
Daniel Veillard652327a2003-09-29 18:02:38 +00002340#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002341/**
2342 * xmlNewTextChild:
2343 * @parent: the parent node
2344 * @ns: a namespace if any
2345 * @name: the name of the child
2346 * @content: the text content of the child if any.
2347 *
2348 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002349 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002350 * a child TEXT node will be created containing the string content.
2351 *
2352 * Returns a pointer to the new node object.
2353 */
2354xmlNodePtr
2355xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2356 const xmlChar *name, const xmlChar *content) {
2357 xmlNodePtr cur, prev;
2358
2359 if (parent == NULL) {
2360#ifdef DEBUG_TREE
2361 xmlGenericError(xmlGenericErrorContext,
2362 "xmlNewTextChild : parent == NULL\n");
2363#endif
2364 return(NULL);
2365 }
2366
2367 if (name == NULL) {
2368#ifdef DEBUG_TREE
2369 xmlGenericError(xmlGenericErrorContext,
2370 "xmlNewTextChild : name == NULL\n");
2371#endif
2372 return(NULL);
2373 }
2374
2375 /*
2376 * Allocate a new node
2377 */
Daniel Veillard254b1262003-11-01 17:04:58 +00002378 if (parent->type == XML_ELEMENT_NODE) {
2379 if (ns == NULL)
2380 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2381 else
2382 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2383 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2384 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2385 if (ns == NULL)
2386 cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2387 else
2388 cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2389 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2390 cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2391 } else {
2392 return(NULL);
2393 }
Owen Taylor3473f882001-02-23 17:55:21 +00002394 if (cur == NULL) return(NULL);
2395
2396 /*
2397 * add the new element at the end of the children list.
2398 */
2399 cur->type = XML_ELEMENT_NODE;
2400 cur->parent = parent;
2401 cur->doc = parent->doc;
2402 if (parent->children == NULL) {
2403 parent->children = cur;
2404 parent->last = cur;
2405 } else {
2406 prev = parent->last;
2407 prev->next = cur;
2408 cur->prev = prev;
2409 parent->last = cur;
2410 }
2411
2412 return(cur);
2413}
Daniel Veillard652327a2003-09-29 18:02:38 +00002414#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002415
2416/**
2417 * xmlNewCharRef:
2418 * @doc: the document
2419 * @name: the char ref string, starting with # or "&# ... ;"
2420 *
2421 * Creation of a new character reference node.
2422 * Returns a pointer to the new node object.
2423 */
2424xmlNodePtr
2425xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2426 xmlNodePtr cur;
2427
2428 /*
2429 * Allocate a new node and fill the fields.
2430 */
2431 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2432 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002433 xmlTreeErrMemory("building character reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002434 return(NULL);
2435 }
2436 memset(cur, 0, sizeof(xmlNode));
2437 cur->type = XML_ENTITY_REF_NODE;
2438
2439 cur->doc = doc;
2440 if (name[0] == '&') {
2441 int len;
2442 name++;
2443 len = xmlStrlen(name);
2444 if (name[len - 1] == ';')
2445 cur->name = xmlStrndup(name, len - 1);
2446 else
2447 cur->name = xmlStrndup(name, len);
2448 } else
2449 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002450
Daniel Veillarda880b122003-04-21 21:36:41 +00002451 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002452 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002453 return(cur);
2454}
2455
2456/**
2457 * xmlNewReference:
2458 * @doc: the document
2459 * @name: the reference name, or the reference string with & and ;
2460 *
2461 * Creation of a new reference node.
2462 * Returns a pointer to the new node object.
2463 */
2464xmlNodePtr
2465xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2466 xmlNodePtr cur;
2467 xmlEntityPtr ent;
2468
2469 /*
2470 * Allocate a new node and fill the fields.
2471 */
2472 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2473 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002474 xmlTreeErrMemory("building reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002475 return(NULL);
2476 }
2477 memset(cur, 0, sizeof(xmlNode));
2478 cur->type = XML_ENTITY_REF_NODE;
2479
2480 cur->doc = doc;
2481 if (name[0] == '&') {
2482 int len;
2483 name++;
2484 len = xmlStrlen(name);
2485 if (name[len - 1] == ';')
2486 cur->name = xmlStrndup(name, len - 1);
2487 else
2488 cur->name = xmlStrndup(name, len);
2489 } else
2490 cur->name = xmlStrdup(name);
2491
2492 ent = xmlGetDocEntity(doc, cur->name);
2493 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002494 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002495 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002496 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002497 * updated. Not sure if this is 100% correct.
2498 * -George
2499 */
2500 cur->children = (xmlNodePtr) ent;
2501 cur->last = (xmlNodePtr) ent;
2502 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002503
Daniel Veillarda880b122003-04-21 21:36:41 +00002504 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002505 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002506 return(cur);
2507}
2508
2509/**
2510 * xmlNewDocText:
2511 * @doc: the document
2512 * @content: the text content
2513 *
2514 * Creation of a new text node within a document.
2515 * Returns a pointer to the new node object.
2516 */
2517xmlNodePtr
2518xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2519 xmlNodePtr cur;
2520
2521 cur = xmlNewText(content);
2522 if (cur != NULL) cur->doc = doc;
2523 return(cur);
2524}
2525
2526/**
2527 * xmlNewTextLen:
2528 * @content: the text content
2529 * @len: the text len.
2530 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002531 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002532 * Returns a pointer to the new node object.
2533 */
2534xmlNodePtr
2535xmlNewTextLen(const xmlChar *content, int len) {
2536 xmlNodePtr cur;
2537
2538 /*
2539 * Allocate a new node and fill the fields.
2540 */
2541 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2542 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002543 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002544 return(NULL);
2545 }
2546 memset(cur, 0, sizeof(xmlNode));
2547 cur->type = XML_TEXT_NODE;
2548
2549 cur->name = xmlStringText;
2550 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002551 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002552 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002553
Daniel Veillarda880b122003-04-21 21:36:41 +00002554 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002555 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002556 return(cur);
2557}
2558
2559/**
2560 * xmlNewDocTextLen:
2561 * @doc: the document
2562 * @content: the text content
2563 * @len: the text len.
2564 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002565 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002566 * text node pertain to a given document.
2567 * Returns a pointer to the new node object.
2568 */
2569xmlNodePtr
2570xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2571 xmlNodePtr cur;
2572
2573 cur = xmlNewTextLen(content, len);
2574 if (cur != NULL) cur->doc = doc;
2575 return(cur);
2576}
2577
2578/**
2579 * xmlNewComment:
2580 * @content: the comment content
2581 *
2582 * Creation of a new node containing a comment.
2583 * Returns a pointer to the new node object.
2584 */
2585xmlNodePtr
2586xmlNewComment(const xmlChar *content) {
2587 xmlNodePtr cur;
2588
2589 /*
2590 * Allocate a new node and fill the fields.
2591 */
2592 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2593 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002594 xmlTreeErrMemory("building comment");
Owen Taylor3473f882001-02-23 17:55:21 +00002595 return(NULL);
2596 }
2597 memset(cur, 0, sizeof(xmlNode));
2598 cur->type = XML_COMMENT_NODE;
2599
2600 cur->name = xmlStringComment;
2601 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002602 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002603 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002604
Daniel Veillarda880b122003-04-21 21:36:41 +00002605 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002606 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002607 return(cur);
2608}
2609
2610/**
2611 * xmlNewCDataBlock:
2612 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002613 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002614 * @len: the length of the block
2615 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002616 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002617 * Returns a pointer to the new node object.
2618 */
2619xmlNodePtr
2620xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2621 xmlNodePtr cur;
2622
2623 /*
2624 * Allocate a new node and fill the fields.
2625 */
2626 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2627 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002628 xmlTreeErrMemory("building CDATA");
Owen Taylor3473f882001-02-23 17:55:21 +00002629 return(NULL);
2630 }
2631 memset(cur, 0, sizeof(xmlNode));
2632 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002633 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002634
2635 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002636 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002637 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002638
Daniel Veillarda880b122003-04-21 21:36:41 +00002639 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002640 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002641 return(cur);
2642}
2643
2644/**
2645 * xmlNewDocComment:
2646 * @doc: the document
2647 * @content: the comment content
2648 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002649 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002650 * Returns a pointer to the new node object.
2651 */
2652xmlNodePtr
2653xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2654 xmlNodePtr cur;
2655
2656 cur = xmlNewComment(content);
2657 if (cur != NULL) cur->doc = doc;
2658 return(cur);
2659}
2660
2661/**
2662 * xmlSetTreeDoc:
2663 * @tree: the top element
2664 * @doc: the document
2665 *
2666 * update all nodes under the tree to point to the right document
2667 */
2668void
2669xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002670 xmlAttrPtr prop;
2671
Owen Taylor3473f882001-02-23 17:55:21 +00002672 if (tree == NULL)
2673 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002674 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002675 if(tree->type == XML_ELEMENT_NODE) {
2676 prop = tree->properties;
2677 while (prop != NULL) {
2678 prop->doc = doc;
2679 xmlSetListDoc(prop->children, doc);
2680 prop = prop->next;
2681 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002682 }
Owen Taylor3473f882001-02-23 17:55:21 +00002683 if (tree->children != NULL)
2684 xmlSetListDoc(tree->children, doc);
2685 tree->doc = doc;
2686 }
2687}
2688
2689/**
2690 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002691 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002692 * @doc: the document
2693 *
2694 * update all nodes in the list to point to the right document
2695 */
2696void
2697xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2698 xmlNodePtr cur;
2699
2700 if (list == NULL)
2701 return;
2702 cur = list;
2703 while (cur != NULL) {
2704 if (cur->doc != doc)
2705 xmlSetTreeDoc(cur, doc);
2706 cur = cur->next;
2707 }
2708}
2709
Daniel Veillard652327a2003-09-29 18:02:38 +00002710#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002711/**
2712 * xmlNewChild:
2713 * @parent: the parent node
2714 * @ns: a namespace if any
2715 * @name: the name of the child
2716 * @content: the XML content of the child if any.
2717 *
2718 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002719 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002720 * a child list containing the TEXTs and ENTITY_REFs node will be created.
2721 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2722 * references, but XML special chars need to be escaped first by using
2723 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
2724 * support is not needed.
2725 *
2726 * Returns a pointer to the new node object.
2727 */
2728xmlNodePtr
2729xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2730 const xmlChar *name, const xmlChar *content) {
2731 xmlNodePtr cur, prev;
2732
2733 if (parent == NULL) {
2734#ifdef DEBUG_TREE
2735 xmlGenericError(xmlGenericErrorContext,
2736 "xmlNewChild : parent == NULL\n");
2737#endif
2738 return(NULL);
2739 }
2740
2741 if (name == NULL) {
2742#ifdef DEBUG_TREE
2743 xmlGenericError(xmlGenericErrorContext,
2744 "xmlNewChild : name == NULL\n");
2745#endif
2746 return(NULL);
2747 }
2748
2749 /*
2750 * Allocate a new node
2751 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002752 if (parent->type == XML_ELEMENT_NODE) {
2753 if (ns == NULL)
2754 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2755 else
2756 cur = xmlNewDocNode(parent->doc, ns, name, content);
2757 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2758 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2759 if (ns == NULL)
2760 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2761 else
2762 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002763 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2764 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002765 } else {
2766 return(NULL);
2767 }
Owen Taylor3473f882001-02-23 17:55:21 +00002768 if (cur == NULL) return(NULL);
2769
2770 /*
2771 * add the new element at the end of the children list.
2772 */
2773 cur->type = XML_ELEMENT_NODE;
2774 cur->parent = parent;
2775 cur->doc = parent->doc;
2776 if (parent->children == NULL) {
2777 parent->children = cur;
2778 parent->last = cur;
2779 } else {
2780 prev = parent->last;
2781 prev->next = cur;
2782 cur->prev = prev;
2783 parent->last = cur;
2784 }
2785
2786 return(cur);
2787}
Daniel Veillard652327a2003-09-29 18:02:38 +00002788#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002789
2790/**
2791 * xmlAddNextSibling:
2792 * @cur: the child node
2793 * @elem: the new node
2794 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002795 * Add a new node @elem as the next sibling of @cur
2796 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002797 * first unlinked from its existing context.
2798 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002799 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2800 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002801 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002802 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002803 */
2804xmlNodePtr
2805xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2806 if (cur == NULL) {
2807#ifdef DEBUG_TREE
2808 xmlGenericError(xmlGenericErrorContext,
2809 "xmlAddNextSibling : cur == NULL\n");
2810#endif
2811 return(NULL);
2812 }
2813 if (elem == NULL) {
2814#ifdef DEBUG_TREE
2815 xmlGenericError(xmlGenericErrorContext,
2816 "xmlAddNextSibling : elem == NULL\n");
2817#endif
2818 return(NULL);
2819 }
2820
2821 xmlUnlinkNode(elem);
2822
2823 if (elem->type == XML_TEXT_NODE) {
2824 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002825 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002826 xmlFreeNode(elem);
2827 return(cur);
2828 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002829 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2830 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002831 xmlChar *tmp;
2832
2833 tmp = xmlStrdup(elem->content);
2834 tmp = xmlStrcat(tmp, cur->next->content);
2835 xmlNodeSetContent(cur->next, tmp);
2836 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002837 xmlFreeNode(elem);
2838 return(cur->next);
2839 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002840 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2841 /* check if an attribute with the same name exists */
2842 xmlAttrPtr attr;
2843
2844 if (elem->ns == NULL)
2845 attr = xmlHasProp(cur->parent, elem->name);
2846 else
2847 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2848 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2849 /* different instance, destroy it (attributes must be unique) */
2850 xmlFreeProp(attr);
2851 }
Owen Taylor3473f882001-02-23 17:55:21 +00002852 }
2853
2854 if (elem->doc != cur->doc) {
2855 xmlSetTreeDoc(elem, cur->doc);
2856 }
2857 elem->parent = cur->parent;
2858 elem->prev = cur;
2859 elem->next = cur->next;
2860 cur->next = elem;
2861 if (elem->next != NULL)
2862 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002863 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002864 elem->parent->last = elem;
2865 return(elem);
2866}
2867
Daniel Veillard652327a2003-09-29 18:02:38 +00002868#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002869/**
2870 * xmlAddPrevSibling:
2871 * @cur: the child node
2872 * @elem: the new node
2873 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002874 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002875 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002876 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002877 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002878 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2879 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002880 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002881 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002882 */
2883xmlNodePtr
2884xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2885 if (cur == NULL) {
2886#ifdef DEBUG_TREE
2887 xmlGenericError(xmlGenericErrorContext,
2888 "xmlAddPrevSibling : cur == NULL\n");
2889#endif
2890 return(NULL);
2891 }
2892 if (elem == NULL) {
2893#ifdef DEBUG_TREE
2894 xmlGenericError(xmlGenericErrorContext,
2895 "xmlAddPrevSibling : elem == NULL\n");
2896#endif
2897 return(NULL);
2898 }
2899
2900 xmlUnlinkNode(elem);
2901
2902 if (elem->type == XML_TEXT_NODE) {
2903 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002904 xmlChar *tmp;
2905
2906 tmp = xmlStrdup(elem->content);
2907 tmp = xmlStrcat(tmp, cur->content);
2908 xmlNodeSetContent(cur, tmp);
2909 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002910 xmlFreeNode(elem);
2911 return(cur);
2912 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002913 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2914 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002915 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002916 xmlFreeNode(elem);
2917 return(cur->prev);
2918 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002919 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2920 /* check if an attribute with the same name exists */
2921 xmlAttrPtr attr;
2922
2923 if (elem->ns == NULL)
2924 attr = xmlHasProp(cur->parent, elem->name);
2925 else
2926 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2927 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2928 /* different instance, destroy it (attributes must be unique) */
2929 xmlFreeProp(attr);
2930 }
Owen Taylor3473f882001-02-23 17:55:21 +00002931 }
2932
2933 if (elem->doc != cur->doc) {
2934 xmlSetTreeDoc(elem, cur->doc);
2935 }
2936 elem->parent = cur->parent;
2937 elem->next = cur;
2938 elem->prev = cur->prev;
2939 cur->prev = elem;
2940 if (elem->prev != NULL)
2941 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002942 if (elem->parent != NULL) {
2943 if (elem->type == XML_ATTRIBUTE_NODE) {
2944 if (elem->parent->properties == (xmlAttrPtr) cur) {
2945 elem->parent->properties = (xmlAttrPtr) elem;
2946 }
2947 } else {
2948 if (elem->parent->children == cur) {
2949 elem->parent->children = elem;
2950 }
2951 }
2952 }
Owen Taylor3473f882001-02-23 17:55:21 +00002953 return(elem);
2954}
Daniel Veillard652327a2003-09-29 18:02:38 +00002955#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002956
2957/**
2958 * xmlAddSibling:
2959 * @cur: the child node
2960 * @elem: the new node
2961 *
2962 * Add a new element @elem to the list of siblings of @cur
2963 * merging adjacent TEXT nodes (@elem may be freed)
2964 * If the new element was already inserted in a document it is
2965 * first unlinked from its existing context.
2966 *
2967 * Returns the new element or NULL in case of error.
2968 */
2969xmlNodePtr
2970xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2971 xmlNodePtr parent;
2972
2973 if (cur == NULL) {
2974#ifdef DEBUG_TREE
2975 xmlGenericError(xmlGenericErrorContext,
2976 "xmlAddSibling : cur == NULL\n");
2977#endif
2978 return(NULL);
2979 }
2980
2981 if (elem == NULL) {
2982#ifdef DEBUG_TREE
2983 xmlGenericError(xmlGenericErrorContext,
2984 "xmlAddSibling : elem == NULL\n");
2985#endif
2986 return(NULL);
2987 }
2988
2989 /*
2990 * Constant time is we can rely on the ->parent->last to find
2991 * the last sibling.
2992 */
2993 if ((cur->parent != NULL) &&
2994 (cur->parent->children != NULL) &&
2995 (cur->parent->last != NULL) &&
2996 (cur->parent->last->next == NULL)) {
2997 cur = cur->parent->last;
2998 } else {
2999 while (cur->next != NULL) cur = cur->next;
3000 }
3001
3002 xmlUnlinkNode(elem);
3003
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003004 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3005 (cur->name == elem->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003006 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003007 xmlFreeNode(elem);
3008 return(cur);
3009 }
3010
3011 if (elem->doc != cur->doc) {
3012 xmlSetTreeDoc(elem, cur->doc);
3013 }
3014 parent = cur->parent;
3015 elem->prev = cur;
3016 elem->next = NULL;
3017 elem->parent = parent;
3018 cur->next = elem;
3019 if (parent != NULL)
3020 parent->last = elem;
3021
3022 return(elem);
3023}
3024
3025/**
3026 * xmlAddChildList:
3027 * @parent: the parent node
3028 * @cur: the first node in the list
3029 *
3030 * Add a list of node at the end of the child list of the parent
3031 * merging adjacent TEXT nodes (@cur may be freed)
3032 *
3033 * Returns the last child or NULL in case of error.
3034 */
3035xmlNodePtr
3036xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3037 xmlNodePtr prev;
3038
3039 if (parent == NULL) {
3040#ifdef DEBUG_TREE
3041 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003042 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003043#endif
3044 return(NULL);
3045 }
3046
3047 if (cur == NULL) {
3048#ifdef DEBUG_TREE
3049 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003050 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003051#endif
3052 return(NULL);
3053 }
3054
3055 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3056 (cur->doc != parent->doc)) {
3057#ifdef DEBUG_TREE
3058 xmlGenericError(xmlGenericErrorContext,
3059 "Elements moved to a different document\n");
3060#endif
3061 }
3062
3063 /*
3064 * add the first element at the end of the children list.
3065 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003066
Owen Taylor3473f882001-02-23 17:55:21 +00003067 if (parent->children == NULL) {
3068 parent->children = cur;
3069 } else {
3070 /*
3071 * If cur and parent->last both are TEXT nodes, then merge them.
3072 */
3073 if ((cur->type == XML_TEXT_NODE) &&
3074 (parent->last->type == XML_TEXT_NODE) &&
3075 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003076 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003077 /*
3078 * if it's the only child, nothing more to be done.
3079 */
3080 if (cur->next == NULL) {
3081 xmlFreeNode(cur);
3082 return(parent->last);
3083 }
3084 prev = cur;
3085 cur = cur->next;
3086 xmlFreeNode(prev);
3087 }
3088 prev = parent->last;
3089 prev->next = cur;
3090 cur->prev = prev;
3091 }
3092 while (cur->next != NULL) {
3093 cur->parent = parent;
3094 if (cur->doc != parent->doc) {
3095 xmlSetTreeDoc(cur, parent->doc);
3096 }
3097 cur = cur->next;
3098 }
3099 cur->parent = parent;
3100 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
3101 parent->last = cur;
3102
3103 return(cur);
3104}
3105
3106/**
3107 * xmlAddChild:
3108 * @parent: the parent node
3109 * @cur: the child node
3110 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003111 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003112 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003113 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3114 * If there is an attribute with equal name, it is first destroyed.
3115 *
Owen Taylor3473f882001-02-23 17:55:21 +00003116 * Returns the child or NULL in case of error.
3117 */
3118xmlNodePtr
3119xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3120 xmlNodePtr prev;
3121
3122 if (parent == NULL) {
3123#ifdef DEBUG_TREE
3124 xmlGenericError(xmlGenericErrorContext,
3125 "xmlAddChild : parent == NULL\n");
3126#endif
3127 return(NULL);
3128 }
3129
3130 if (cur == NULL) {
3131#ifdef DEBUG_TREE
3132 xmlGenericError(xmlGenericErrorContext,
3133 "xmlAddChild : child == NULL\n");
3134#endif
3135 return(NULL);
3136 }
3137
Owen Taylor3473f882001-02-23 17:55:21 +00003138 /*
3139 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003140 * cur is then freed.
3141 */
3142 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003143 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003144 (parent->content != NULL) &&
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003145 (parent->name == cur->name) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003146 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003147 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003148 xmlFreeNode(cur);
3149 return(parent);
3150 }
3151 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003152 (parent->last->name == cur->name) &&
3153 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003154 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003155 xmlFreeNode(cur);
3156 return(parent->last);
3157 }
3158 }
3159
3160 /*
3161 * add the new element at the end of the children list.
3162 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003163 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003164 cur->parent = parent;
3165 if (cur->doc != parent->doc) {
3166 xmlSetTreeDoc(cur, parent->doc);
3167 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003168 /* this check prevents a loop on tree-traversions if a developer
3169 * tries to add a node to its parent multiple times
3170 */
3171 if (prev == parent)
3172 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003173
3174 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003175 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003176 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003177 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003178 (parent->content != NULL) &&
3179 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003180 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003181 xmlFreeNode(cur);
3182 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003183 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003184 if (cur->type == XML_ATTRIBUTE_NODE) {
3185 if (parent->properties == NULL) {
3186 parent->properties = (xmlAttrPtr) cur;
3187 } else {
3188 /* check if an attribute with the same name exists */
3189 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003190
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003191 if (cur->ns == NULL)
3192 lastattr = xmlHasProp(parent, cur->name);
3193 else
3194 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3195 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
3196 /* different instance, destroy it (attributes must be unique) */
3197 xmlFreeProp(lastattr);
3198 }
3199 /* find the end */
3200 lastattr = parent->properties;
3201 while (lastattr->next != NULL) {
3202 lastattr = lastattr->next;
3203 }
3204 lastattr->next = (xmlAttrPtr) cur;
3205 ((xmlAttrPtr) cur)->prev = lastattr;
3206 }
3207 } else {
3208 if (parent->children == NULL) {
3209 parent->children = cur;
3210 parent->last = cur;
3211 } else {
3212 prev = parent->last;
3213 prev->next = cur;
3214 cur->prev = prev;
3215 parent->last = cur;
3216 }
3217 }
Owen Taylor3473f882001-02-23 17:55:21 +00003218 return(cur);
3219}
3220
3221/**
3222 * xmlGetLastChild:
3223 * @parent: the parent node
3224 *
3225 * Search the last child of a node.
3226 * Returns the last child or NULL if none.
3227 */
3228xmlNodePtr
3229xmlGetLastChild(xmlNodePtr parent) {
3230 if (parent == NULL) {
3231#ifdef DEBUG_TREE
3232 xmlGenericError(xmlGenericErrorContext,
3233 "xmlGetLastChild : parent == NULL\n");
3234#endif
3235 return(NULL);
3236 }
3237 return(parent->last);
3238}
3239
3240/**
3241 * xmlFreeNodeList:
3242 * @cur: the first node in the list
3243 *
3244 * Free a node and all its siblings, this is a recursive behaviour, all
3245 * the children are freed too.
3246 */
3247void
3248xmlFreeNodeList(xmlNodePtr cur) {
3249 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003250 xmlDictPtr dict = NULL;
3251
3252 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003253 if (cur->type == XML_NAMESPACE_DECL) {
3254 xmlFreeNsList((xmlNsPtr) cur);
3255 return;
3256 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003257 if ((cur->type == XML_DOCUMENT_NODE) ||
3258#ifdef LIBXML_DOCB_ENABLED
3259 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003260#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003261 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003262 xmlFreeDoc((xmlDocPtr) cur);
3263 return;
3264 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003265 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003266 while (cur != NULL) {
3267 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003268 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003269
Daniel Veillarda880b122003-04-21 21:36:41 +00003270 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003271 xmlDeregisterNodeDefaultValue(cur);
3272
Daniel Veillard02141ea2001-04-30 11:46:40 +00003273 if ((cur->children != NULL) &&
3274 (cur->type != XML_ENTITY_REF_NODE))
3275 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003276 if (((cur->type == XML_ELEMENT_NODE) ||
3277 (cur->type == XML_XINCLUDE_START) ||
3278 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003279 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003280 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003281 if ((cur->type != XML_ELEMENT_NODE) &&
3282 (cur->type != XML_XINCLUDE_START) &&
3283 (cur->type != XML_XINCLUDE_END) &&
3284 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003285 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003286 }
3287 if (((cur->type == XML_ELEMENT_NODE) ||
3288 (cur->type == XML_XINCLUDE_START) ||
3289 (cur->type == XML_XINCLUDE_END)) &&
3290 (cur->nsDef != NULL))
3291 xmlFreeNsList(cur->nsDef);
3292
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003293 /*
3294 * When a node is a text node or a comment, it uses a global static
3295 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003296 * Otherwise the node name might come from the document's
3297 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003298 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003299 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003300 (cur->type != XML_TEXT_NODE) &&
3301 (cur->type != XML_COMMENT_NODE))
3302 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003303 xmlFree(cur);
3304 }
Owen Taylor3473f882001-02-23 17:55:21 +00003305 cur = next;
3306 }
3307}
3308
3309/**
3310 * xmlFreeNode:
3311 * @cur: the node
3312 *
3313 * Free a node, this is a recursive behaviour, all the children are freed too.
3314 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3315 */
3316void
3317xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003318 xmlDictPtr dict = NULL;
3319
3320 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003321
Daniel Veillard02141ea2001-04-30 11:46:40 +00003322 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003323 if (cur->type == XML_DTD_NODE) {
3324 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003325 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003326 }
3327 if (cur->type == XML_NAMESPACE_DECL) {
3328 xmlFreeNs((xmlNsPtr) cur);
3329 return;
3330 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003331 if (cur->type == XML_ATTRIBUTE_NODE) {
3332 xmlFreeProp((xmlAttrPtr) cur);
3333 return;
3334 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003335
Daniel Veillarda880b122003-04-21 21:36:41 +00003336 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003337 xmlDeregisterNodeDefaultValue(cur);
3338
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003339 if (cur->doc != NULL) dict = cur->doc->dict;
3340
Owen Taylor3473f882001-02-23 17:55:21 +00003341 if ((cur->children != NULL) &&
3342 (cur->type != XML_ENTITY_REF_NODE))
3343 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003344 if (((cur->type == XML_ELEMENT_NODE) ||
3345 (cur->type == XML_XINCLUDE_START) ||
3346 (cur->type == XML_XINCLUDE_END)) &&
3347 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003348 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003349 if ((cur->type != XML_ELEMENT_NODE) &&
3350 (cur->content != NULL) &&
3351 (cur->type != XML_ENTITY_REF_NODE) &&
3352 (cur->type != XML_XINCLUDE_END) &&
3353 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003354 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003355 }
3356
Daniel Veillardacd370f2001-06-09 17:17:51 +00003357 /*
3358 * When a node is a text node or a comment, it uses a global static
3359 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003360 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003361 */
Owen Taylor3473f882001-02-23 17:55:21 +00003362 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003363 (cur->type != XML_TEXT_NODE) &&
3364 (cur->type != XML_COMMENT_NODE))
3365 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003366
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003367 if (((cur->type == XML_ELEMENT_NODE) ||
3368 (cur->type == XML_XINCLUDE_START) ||
3369 (cur->type == XML_XINCLUDE_END)) &&
3370 (cur->nsDef != NULL))
3371 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003372 xmlFree(cur);
3373}
3374
3375/**
3376 * xmlUnlinkNode:
3377 * @cur: the node
3378 *
3379 * Unlink a node from it's current context, the node is not freed
3380 */
3381void
3382xmlUnlinkNode(xmlNodePtr cur) {
3383 if (cur == NULL) {
3384#ifdef DEBUG_TREE
3385 xmlGenericError(xmlGenericErrorContext,
3386 "xmlUnlinkNode : node == NULL\n");
3387#endif
3388 return;
3389 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003390 if (cur->type == XML_DTD_NODE) {
3391 xmlDocPtr doc;
3392 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003393 if (doc != NULL) {
3394 if (doc->intSubset == (xmlDtdPtr) cur)
3395 doc->intSubset = NULL;
3396 if (doc->extSubset == (xmlDtdPtr) cur)
3397 doc->extSubset = NULL;
3398 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003399 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003400 if (cur->parent != NULL) {
3401 xmlNodePtr parent;
3402 parent = cur->parent;
3403 if (cur->type == XML_ATTRIBUTE_NODE) {
3404 if (parent->properties == (xmlAttrPtr) cur)
3405 parent->properties = ((xmlAttrPtr) cur)->next;
3406 } else {
3407 if (parent->children == cur)
3408 parent->children = cur->next;
3409 if (parent->last == cur)
3410 parent->last = cur->prev;
3411 }
3412 cur->parent = NULL;
3413 }
Owen Taylor3473f882001-02-23 17:55:21 +00003414 if (cur->next != NULL)
3415 cur->next->prev = cur->prev;
3416 if (cur->prev != NULL)
3417 cur->prev->next = cur->next;
3418 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003419}
3420
Daniel Veillard652327a2003-09-29 18:02:38 +00003421#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003422/**
3423 * xmlReplaceNode:
3424 * @old: the old node
3425 * @cur: the node
3426 *
3427 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003428 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003429 * first unlinked from its existing context.
3430 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003431 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003432 */
3433xmlNodePtr
3434xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3435 if (old == NULL) {
3436#ifdef DEBUG_TREE
3437 xmlGenericError(xmlGenericErrorContext,
3438 "xmlReplaceNode : old == NULL\n");
3439#endif
3440 return(NULL);
3441 }
3442 if (cur == NULL) {
3443 xmlUnlinkNode(old);
3444 return(old);
3445 }
3446 if (cur == old) {
3447 return(old);
3448 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003449 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3450#ifdef DEBUG_TREE
3451 xmlGenericError(xmlGenericErrorContext,
3452 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3453#endif
3454 return(old);
3455 }
3456 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3457#ifdef DEBUG_TREE
3458 xmlGenericError(xmlGenericErrorContext,
3459 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3460#endif
3461 return(old);
3462 }
Owen Taylor3473f882001-02-23 17:55:21 +00003463 xmlUnlinkNode(cur);
3464 cur->doc = old->doc;
3465 cur->parent = old->parent;
3466 cur->next = old->next;
3467 if (cur->next != NULL)
3468 cur->next->prev = cur;
3469 cur->prev = old->prev;
3470 if (cur->prev != NULL)
3471 cur->prev->next = cur;
3472 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003473 if (cur->type == XML_ATTRIBUTE_NODE) {
3474 if (cur->parent->properties == (xmlAttrPtr)old)
3475 cur->parent->properties = ((xmlAttrPtr) cur);
3476 } else {
3477 if (cur->parent->children == old)
3478 cur->parent->children = cur;
3479 if (cur->parent->last == old)
3480 cur->parent->last = cur;
3481 }
Owen Taylor3473f882001-02-23 17:55:21 +00003482 }
3483 old->next = old->prev = NULL;
3484 old->parent = NULL;
3485 return(old);
3486}
Daniel Veillard652327a2003-09-29 18:02:38 +00003487#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003488
3489/************************************************************************
3490 * *
3491 * Copy operations *
3492 * *
3493 ************************************************************************/
3494
3495/**
3496 * xmlCopyNamespace:
3497 * @cur: the namespace
3498 *
3499 * Do a copy of the namespace.
3500 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003501 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003502 */
3503xmlNsPtr
3504xmlCopyNamespace(xmlNsPtr cur) {
3505 xmlNsPtr ret;
3506
3507 if (cur == NULL) return(NULL);
3508 switch (cur->type) {
3509 case XML_LOCAL_NAMESPACE:
3510 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3511 break;
3512 default:
3513#ifdef DEBUG_TREE
3514 xmlGenericError(xmlGenericErrorContext,
3515 "xmlCopyNamespace: invalid type %d\n", cur->type);
3516#endif
3517 return(NULL);
3518 }
3519 return(ret);
3520}
3521
3522/**
3523 * xmlCopyNamespaceList:
3524 * @cur: the first namespace
3525 *
3526 * Do a copy of an namespace list.
3527 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003528 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003529 */
3530xmlNsPtr
3531xmlCopyNamespaceList(xmlNsPtr cur) {
3532 xmlNsPtr ret = NULL;
3533 xmlNsPtr p = NULL,q;
3534
3535 while (cur != NULL) {
3536 q = xmlCopyNamespace(cur);
3537 if (p == NULL) {
3538 ret = p = q;
3539 } else {
3540 p->next = q;
3541 p = q;
3542 }
3543 cur = cur->next;
3544 }
3545 return(ret);
3546}
3547
3548static xmlNodePtr
3549xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3550/**
3551 * xmlCopyProp:
3552 * @target: the element where the attribute will be grafted
3553 * @cur: the attribute
3554 *
3555 * Do a copy of the attribute.
3556 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003557 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003558 */
3559xmlAttrPtr
3560xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3561 xmlAttrPtr ret;
3562
3563 if (cur == NULL) return(NULL);
3564 if (target != NULL)
3565 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3566 else if (cur->parent != NULL)
3567 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3568 else if (cur->children != NULL)
3569 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3570 else
3571 ret = xmlNewDocProp(NULL, cur->name, NULL);
3572 if (ret == NULL) return(NULL);
3573 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003574
Owen Taylor3473f882001-02-23 17:55:21 +00003575 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003576 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003577
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003578 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3579 if (ns == NULL) {
3580 /*
3581 * Humm, we are copying an element whose namespace is defined
3582 * out of the new tree scope. Search it in the original tree
3583 * and add it at the top of the new tree
3584 */
3585 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3586 if (ns != NULL) {
3587 xmlNodePtr root = target;
3588 xmlNodePtr pred = NULL;
3589
3590 while (root->parent != NULL) {
3591 pred = root;
3592 root = root->parent;
3593 }
3594 if (root == (xmlNodePtr) target->doc) {
3595 /* correct possibly cycling above the document elt */
3596 root = pred;
3597 }
3598 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3599 }
3600 } else {
3601 /*
3602 * we have to find something appropriate here since
3603 * we cant be sure, that the namespce we found is identified
3604 * by the prefix
3605 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003606 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003607 /* this is the nice case */
3608 ret->ns = ns;
3609 } else {
3610 /*
3611 * we are in trouble: we need a new reconcilied namespace.
3612 * This is expensive
3613 */
3614 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3615 }
3616 }
3617
Owen Taylor3473f882001-02-23 17:55:21 +00003618 } else
3619 ret->ns = NULL;
3620
3621 if (cur->children != NULL) {
3622 xmlNodePtr tmp;
3623
3624 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3625 ret->last = NULL;
3626 tmp = ret->children;
3627 while (tmp != NULL) {
3628 /* tmp->parent = (xmlNodePtr)ret; */
3629 if (tmp->next == NULL)
3630 ret->last = tmp;
3631 tmp = tmp->next;
3632 }
3633 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003634 /*
3635 * Try to handle IDs
3636 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003637 if ((target!= NULL) && (cur!= NULL) &&
3638 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003639 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3640 if (xmlIsID(cur->doc, cur->parent, cur)) {
3641 xmlChar *id;
3642
3643 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3644 if (id != NULL) {
3645 xmlAddID(NULL, target->doc, id, ret);
3646 xmlFree(id);
3647 }
3648 }
3649 }
Owen Taylor3473f882001-02-23 17:55:21 +00003650 return(ret);
3651}
3652
3653/**
3654 * xmlCopyPropList:
3655 * @target: the element where the attributes will be grafted
3656 * @cur: the first attribute
3657 *
3658 * Do a copy of an attribute list.
3659 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003660 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003661 */
3662xmlAttrPtr
3663xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3664 xmlAttrPtr ret = NULL;
3665 xmlAttrPtr p = NULL,q;
3666
3667 while (cur != NULL) {
3668 q = xmlCopyProp(target, cur);
3669 if (p == NULL) {
3670 ret = p = q;
3671 } else {
3672 p->next = q;
3673 q->prev = p;
3674 p = q;
3675 }
3676 cur = cur->next;
3677 }
3678 return(ret);
3679}
3680
3681/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003682 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003683 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003684 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003685 * tricky reason: namespaces. Doing a direct copy of a node
3686 * say RPM:Copyright without changing the namespace pointer to
3687 * something else can produce stale links. One way to do it is
3688 * to keep a reference counter but this doesn't work as soon
3689 * as one move the element or the subtree out of the scope of
3690 * the existing namespace. The actual solution seems to add
3691 * a copy of the namespace at the top of the copied tree if
3692 * not available in the subtree.
3693 * Hence two functions, the public front-end call the inner ones
3694 */
3695
3696static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003697xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003698 int recursive) {
3699 xmlNodePtr ret;
3700
3701 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003702 switch (node->type) {
3703 case XML_TEXT_NODE:
3704 case XML_CDATA_SECTION_NODE:
3705 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003706 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003707 case XML_ENTITY_REF_NODE:
3708 case XML_ENTITY_NODE:
3709 case XML_PI_NODE:
3710 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003711 case XML_XINCLUDE_START:
3712 case XML_XINCLUDE_END:
3713 break;
3714 case XML_ATTRIBUTE_NODE:
3715 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3716 case XML_NAMESPACE_DECL:
3717 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3718
Daniel Veillard39196eb2001-06-19 18:09:42 +00003719 case XML_DOCUMENT_NODE:
3720 case XML_HTML_DOCUMENT_NODE:
3721#ifdef LIBXML_DOCB_ENABLED
3722 case XML_DOCB_DOCUMENT_NODE:
3723#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00003724#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003725 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard652327a2003-09-29 18:02:38 +00003726#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00003727 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003728 case XML_NOTATION_NODE:
3729 case XML_DTD_NODE:
3730 case XML_ELEMENT_DECL:
3731 case XML_ATTRIBUTE_DECL:
3732 case XML_ENTITY_DECL:
3733 return(NULL);
3734 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003735
Owen Taylor3473f882001-02-23 17:55:21 +00003736 /*
3737 * Allocate a new node and fill the fields.
3738 */
3739 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3740 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00003741 xmlTreeErrMemory("copying node");
Owen Taylor3473f882001-02-23 17:55:21 +00003742 return(NULL);
3743 }
3744 memset(ret, 0, sizeof(xmlNode));
3745 ret->type = node->type;
3746
3747 ret->doc = doc;
3748 ret->parent = parent;
3749 if (node->name == xmlStringText)
3750 ret->name = xmlStringText;
3751 else if (node->name == xmlStringTextNoenc)
3752 ret->name = xmlStringTextNoenc;
3753 else if (node->name == xmlStringComment)
3754 ret->name = xmlStringComment;
3755 else if (node->name != NULL)
3756 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003757 if ((node->type != XML_ELEMENT_NODE) &&
3758 (node->content != NULL) &&
3759 (node->type != XML_ENTITY_REF_NODE) &&
3760 (node->type != XML_XINCLUDE_END) &&
3761 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003762 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003763 }else{
3764 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00003765 ret->line = node->line;
Owen Taylor3473f882001-02-23 17:55:21 +00003766 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003767 if (parent != NULL) {
3768 xmlNodePtr tmp;
3769
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003770 /*
3771 * this is a tricky part for the node register thing:
3772 * in case ret does get coalesced in xmlAddChild
3773 * the deregister-node callback is called; so we register ret now already
3774 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003775 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003776 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3777
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003778 tmp = xmlAddChild(parent, ret);
3779 /* node could have coalesced */
3780 if (tmp != ret)
3781 return(tmp);
3782 }
Owen Taylor3473f882001-02-23 17:55:21 +00003783
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003784 if (!recursive)
3785 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003786 if (node->nsDef != NULL)
3787 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3788
3789 if (node->ns != NULL) {
3790 xmlNsPtr ns;
3791
3792 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3793 if (ns == NULL) {
3794 /*
3795 * Humm, we are copying an element whose namespace is defined
3796 * out of the new tree scope. Search it in the original tree
3797 * and add it at the top of the new tree
3798 */
3799 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3800 if (ns != NULL) {
3801 xmlNodePtr root = ret;
3802
3803 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003804 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003805 }
3806 } else {
3807 /*
3808 * reference the existing namespace definition in our own tree.
3809 */
3810 ret->ns = ns;
3811 }
3812 }
3813 if (node->properties != NULL)
3814 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003815 if (node->type == XML_ENTITY_REF_NODE) {
3816 if ((doc == NULL) || (node->doc != doc)) {
3817 /*
3818 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003819 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003820 * we cannot keep the reference. Try to find it in the
3821 * target document.
3822 */
3823 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3824 } else {
3825 ret->children = node->children;
3826 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003827 ret->last = ret->children;
3828 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003829 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003830 UPDATE_LAST_CHILD_AND_PARENT(ret)
3831 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003832
3833out:
3834 /* if parent != NULL we already registered the node above */
3835 if (parent == NULL && xmlRegisterNodeDefaultValue)
3836 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003837 return(ret);
3838}
3839
3840static xmlNodePtr
3841xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3842 xmlNodePtr ret = NULL;
3843 xmlNodePtr p = NULL,q;
3844
3845 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00003846#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003847 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003848 if (doc == NULL) {
3849 node = node->next;
3850 continue;
3851 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003852 if (doc->intSubset == NULL) {
3853 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3854 q->doc = doc;
3855 q->parent = parent;
3856 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003857 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003858 } else {
3859 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003860 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003861 }
3862 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00003863#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00003864 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003865 if (ret == NULL) {
3866 q->prev = NULL;
3867 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003868 } else if (p != q) {
3869 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003870 p->next = q;
3871 q->prev = p;
3872 p = q;
3873 }
3874 node = node->next;
3875 }
3876 return(ret);
3877}
3878
3879/**
3880 * xmlCopyNode:
3881 * @node: the node
3882 * @recursive: if 1 do a recursive copy.
3883 *
3884 * Do a copy of the node.
3885 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003886 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003887 */
3888xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003889xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003890 xmlNodePtr ret;
3891
3892 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3893 return(ret);
3894}
3895
3896/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003897 * xmlDocCopyNode:
3898 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003899 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003900 * @recursive: if 1 do a recursive copy.
3901 *
3902 * Do a copy of the node to a given document.
3903 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003904 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003905 */
3906xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003907xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003908 xmlNodePtr ret;
3909
3910 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3911 return(ret);
3912}
3913
3914/**
Owen Taylor3473f882001-02-23 17:55:21 +00003915 * xmlCopyNodeList:
3916 * @node: the first node in the list.
3917 *
3918 * Do a recursive copy of the node list.
3919 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003920 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003921 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003922xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003923 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3924 return(ret);
3925}
3926
Daniel Veillard652327a2003-09-29 18:02:38 +00003927#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003928/**
Owen Taylor3473f882001-02-23 17:55:21 +00003929 * xmlCopyDtd:
3930 * @dtd: the dtd
3931 *
3932 * Do a copy of the dtd.
3933 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003934 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003935 */
3936xmlDtdPtr
3937xmlCopyDtd(xmlDtdPtr dtd) {
3938 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003939 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003940
3941 if (dtd == NULL) return(NULL);
3942 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3943 if (ret == NULL) return(NULL);
3944 if (dtd->entities != NULL)
3945 ret->entities = (void *) xmlCopyEntitiesTable(
3946 (xmlEntitiesTablePtr) dtd->entities);
3947 if (dtd->notations != NULL)
3948 ret->notations = (void *) xmlCopyNotationTable(
3949 (xmlNotationTablePtr) dtd->notations);
3950 if (dtd->elements != NULL)
3951 ret->elements = (void *) xmlCopyElementTable(
3952 (xmlElementTablePtr) dtd->elements);
3953 if (dtd->attributes != NULL)
3954 ret->attributes = (void *) xmlCopyAttributeTable(
3955 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003956 if (dtd->pentities != NULL)
3957 ret->pentities = (void *) xmlCopyEntitiesTable(
3958 (xmlEntitiesTablePtr) dtd->pentities);
3959
3960 cur = dtd->children;
3961 while (cur != NULL) {
3962 q = NULL;
3963
3964 if (cur->type == XML_ENTITY_DECL) {
3965 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3966 switch (tmp->etype) {
3967 case XML_INTERNAL_GENERAL_ENTITY:
3968 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3969 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3970 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3971 break;
3972 case XML_INTERNAL_PARAMETER_ENTITY:
3973 case XML_EXTERNAL_PARAMETER_ENTITY:
3974 q = (xmlNodePtr)
3975 xmlGetParameterEntityFromDtd(ret, tmp->name);
3976 break;
3977 case XML_INTERNAL_PREDEFINED_ENTITY:
3978 break;
3979 }
3980 } else if (cur->type == XML_ELEMENT_DECL) {
3981 xmlElementPtr tmp = (xmlElementPtr) cur;
3982 q = (xmlNodePtr)
3983 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3984 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3985 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3986 q = (xmlNodePtr)
3987 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3988 } else if (cur->type == XML_COMMENT_NODE) {
3989 q = xmlCopyNode(cur, 0);
3990 }
3991
3992 if (q == NULL) {
3993 cur = cur->next;
3994 continue;
3995 }
3996
3997 if (p == NULL)
3998 ret->children = q;
3999 else
4000 p->next = q;
4001
4002 q->prev = p;
4003 q->parent = (xmlNodePtr) ret;
4004 q->next = NULL;
4005 ret->last = q;
4006 p = q;
4007 cur = cur->next;
4008 }
4009
Owen Taylor3473f882001-02-23 17:55:21 +00004010 return(ret);
4011}
4012
4013/**
4014 * xmlCopyDoc:
4015 * @doc: the document
4016 * @recursive: if 1 do a recursive copy.
4017 *
4018 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004019 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004020 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004021 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004022 */
4023xmlDocPtr
4024xmlCopyDoc(xmlDocPtr doc, int recursive) {
4025 xmlDocPtr ret;
4026
4027 if (doc == NULL) return(NULL);
4028 ret = xmlNewDoc(doc->version);
4029 if (ret == NULL) return(NULL);
4030 if (doc->name != NULL)
4031 ret->name = xmlMemStrdup(doc->name);
4032 if (doc->encoding != NULL)
4033 ret->encoding = xmlStrdup(doc->encoding);
4034 ret->charset = doc->charset;
4035 ret->compression = doc->compression;
4036 ret->standalone = doc->standalone;
4037 if (!recursive) return(ret);
4038
Daniel Veillardb33c2012001-04-25 12:59:04 +00004039 ret->last = NULL;
4040 ret->children = NULL;
4041 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004042 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004043 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004044 ret->intSubset->parent = ret;
4045 }
Owen Taylor3473f882001-02-23 17:55:21 +00004046 if (doc->oldNs != NULL)
4047 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4048 if (doc->children != NULL) {
4049 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00004050
4051 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4052 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004053 ret->last = NULL;
4054 tmp = ret->children;
4055 while (tmp != NULL) {
4056 if (tmp->next == NULL)
4057 ret->last = tmp;
4058 tmp = tmp->next;
4059 }
4060 }
4061 return(ret);
4062}
Daniel Veillard652327a2003-09-29 18:02:38 +00004063#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004064
4065/************************************************************************
4066 * *
4067 * Content access functions *
4068 * *
4069 ************************************************************************/
4070
4071/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004072 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004073 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004074 *
4075 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004076 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004077 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004078 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004079 */
4080long
4081xmlGetLineNo(xmlNodePtr node)
4082{
4083 long result = -1;
4084
4085 if (!node)
4086 return result;
4087 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004088 result = (long) node->line;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004089 else if ((node->prev != NULL) &&
4090 ((node->prev->type == XML_ELEMENT_NODE) ||
4091 (node->prev->type == XML_TEXT_NODE)))
4092 result = xmlGetLineNo(node->prev);
4093 else if ((node->parent != NULL) &&
4094 ((node->parent->type == XML_ELEMENT_NODE) ||
4095 (node->parent->type == XML_TEXT_NODE)))
4096 result = xmlGetLineNo(node->parent);
4097
4098 return result;
4099}
4100
Daniel Veillard652327a2003-09-29 18:02:38 +00004101#ifdef LIBXML_TREE_ENABLED
Daniel Veillard8faa7832001-11-26 15:58:08 +00004102/**
4103 * xmlGetNodePath:
4104 * @node: a node
4105 *
4106 * Build a structure based Path for the given node
4107 *
4108 * Returns the new path or NULL in case of error. The caller must free
4109 * the returned string
4110 */
4111xmlChar *
4112xmlGetNodePath(xmlNodePtr node)
4113{
4114 xmlNodePtr cur, tmp, next;
4115 xmlChar *buffer = NULL, *temp;
4116 size_t buf_len;
4117 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004118 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004119 const char *name;
4120 char nametemp[100];
4121 int occur = 0;
4122
4123 if (node == NULL)
4124 return (NULL);
4125
4126 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004127 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004128 if (buffer == NULL) {
4129 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004130 return (NULL);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004131 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004132 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004133 if (buf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004134 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004135 xmlFree(buffer);
4136 return (NULL);
4137 }
4138
4139 buffer[0] = 0;
4140 cur = node;
4141 do {
4142 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004143 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004144 occur = 0;
4145 if ((cur->type == XML_DOCUMENT_NODE) ||
4146 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4147 if (buffer[0] == '/')
4148 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004149 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004150 next = NULL;
4151 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004152 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004153 name = (const char *) cur->name;
4154 if (cur->ns) {
4155 snprintf(nametemp, sizeof(nametemp) - 1,
4156 "%s:%s", cur->ns->prefix, cur->name);
4157 nametemp[sizeof(nametemp) - 1] = 0;
4158 name = nametemp;
4159 }
4160 next = cur->parent;
4161
4162 /*
4163 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004164 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004165 */
4166 tmp = cur->prev;
4167 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004168 if ((tmp->type == XML_ELEMENT_NODE) &&
4169 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004170 occur++;
4171 tmp = tmp->prev;
4172 }
4173 if (occur == 0) {
4174 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004175 while (tmp != NULL && occur == 0) {
4176 if ((tmp->type == XML_ELEMENT_NODE) &&
4177 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004178 occur++;
4179 tmp = tmp->next;
4180 }
4181 if (occur != 0)
4182 occur = 1;
4183 } else
4184 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004185 } else if (cur->type == XML_COMMENT_NODE) {
4186 sep = "/";
4187 name = "comment()";
4188 next = cur->parent;
4189
4190 /*
4191 * Thumbler index computation
4192 */
4193 tmp = cur->prev;
4194 while (tmp != NULL) {
4195 if (tmp->type == XML_COMMENT_NODE)
4196 occur++;
4197 tmp = tmp->prev;
4198 }
4199 if (occur == 0) {
4200 tmp = cur->next;
4201 while (tmp != NULL && occur == 0) {
4202 if (tmp->type == XML_COMMENT_NODE)
4203 occur++;
4204 tmp = tmp->next;
4205 }
4206 if (occur != 0)
4207 occur = 1;
4208 } else
4209 occur++;
4210 } else if ((cur->type == XML_TEXT_NODE) ||
4211 (cur->type == XML_CDATA_SECTION_NODE)) {
4212 sep = "/";
4213 name = "text()";
4214 next = cur->parent;
4215
4216 /*
4217 * Thumbler index computation
4218 */
4219 tmp = cur->prev;
4220 while (tmp != NULL) {
4221 if ((cur->type == XML_TEXT_NODE) ||
4222 (cur->type == XML_CDATA_SECTION_NODE))
4223 occur++;
4224 tmp = tmp->prev;
4225 }
4226 if (occur == 0) {
4227 tmp = cur->next;
4228 while (tmp != NULL && occur == 0) {
4229 if ((cur->type == XML_TEXT_NODE) ||
4230 (cur->type == XML_CDATA_SECTION_NODE))
4231 occur++;
4232 tmp = tmp->next;
4233 }
4234 if (occur != 0)
4235 occur = 1;
4236 } else
4237 occur++;
4238 } else if (cur->type == XML_PI_NODE) {
4239 sep = "/";
4240 snprintf(nametemp, sizeof(nametemp) - 1,
4241 "processing-instruction('%s')", cur->name);
4242 nametemp[sizeof(nametemp) - 1] = 0;
4243 name = nametemp;
4244
4245 next = cur->parent;
4246
4247 /*
4248 * Thumbler index computation
4249 */
4250 tmp = cur->prev;
4251 while (tmp != NULL) {
4252 if ((tmp->type == XML_PI_NODE) &&
4253 (xmlStrEqual(cur->name, tmp->name)))
4254 occur++;
4255 tmp = tmp->prev;
4256 }
4257 if (occur == 0) {
4258 tmp = cur->next;
4259 while (tmp != NULL && occur == 0) {
4260 if ((tmp->type == XML_PI_NODE) &&
4261 (xmlStrEqual(cur->name, tmp->name)))
4262 occur++;
4263 tmp = tmp->next;
4264 }
4265 if (occur != 0)
4266 occur = 1;
4267 } else
4268 occur++;
4269
Daniel Veillard8faa7832001-11-26 15:58:08 +00004270 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004271 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004272 name = (const char *) (((xmlAttrPtr) cur)->name);
4273 next = ((xmlAttrPtr) cur)->parent;
4274 } else {
4275 next = cur->parent;
4276 }
4277
4278 /*
4279 * Make sure there is enough room
4280 */
4281 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4282 buf_len =
4283 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4284 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4285 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004286 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004287 xmlFree(buf);
4288 xmlFree(buffer);
4289 return (NULL);
4290 }
4291 buffer = temp;
4292 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4293 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004294 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004295 xmlFree(buf);
4296 xmlFree(buffer);
4297 return (NULL);
4298 }
4299 buf = temp;
4300 }
4301 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004302 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004303 sep, name, (char *) buffer);
4304 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004305 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004306 sep, name, occur, (char *) buffer);
4307 snprintf((char *) buffer, buf_len, "%s", buf);
4308 cur = next;
4309 } while (cur != NULL);
4310 xmlFree(buf);
4311 return (buffer);
4312}
Daniel Veillard652327a2003-09-29 18:02:38 +00004313#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004314
4315/**
Owen Taylor3473f882001-02-23 17:55:21 +00004316 * xmlDocGetRootElement:
4317 * @doc: the document
4318 *
4319 * Get the root element of the document (doc->children is a list
4320 * containing possibly comments, PIs, etc ...).
4321 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004322 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004323 */
4324xmlNodePtr
4325xmlDocGetRootElement(xmlDocPtr doc) {
4326 xmlNodePtr ret;
4327
4328 if (doc == NULL) return(NULL);
4329 ret = doc->children;
4330 while (ret != NULL) {
4331 if (ret->type == XML_ELEMENT_NODE)
4332 return(ret);
4333 ret = ret->next;
4334 }
4335 return(ret);
4336}
4337
Daniel Veillard652327a2003-09-29 18:02:38 +00004338#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004339/**
4340 * xmlDocSetRootElement:
4341 * @doc: the document
4342 * @root: the new document root element
4343 *
4344 * Set the root element of the document (doc->children is a list
4345 * containing possibly comments, PIs, etc ...).
4346 *
4347 * Returns the old root element if any was found
4348 */
4349xmlNodePtr
4350xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4351 xmlNodePtr old = NULL;
4352
4353 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004354 if (root == NULL)
4355 return(NULL);
4356 xmlUnlinkNode(root);
4357 root->doc = doc;
4358 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004359 old = doc->children;
4360 while (old != NULL) {
4361 if (old->type == XML_ELEMENT_NODE)
4362 break;
4363 old = old->next;
4364 }
4365 if (old == NULL) {
4366 if (doc->children == NULL) {
4367 doc->children = root;
4368 doc->last = root;
4369 } else {
4370 xmlAddSibling(doc->children, root);
4371 }
4372 } else {
4373 xmlReplaceNode(old, root);
4374 }
4375 return(old);
4376}
4377
4378/**
4379 * xmlNodeSetLang:
4380 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004381 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004382 *
4383 * Set the language of a node, i.e. the values of the xml:lang
4384 * attribute.
4385 */
4386void
4387xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004388 xmlNsPtr ns;
4389
Owen Taylor3473f882001-02-23 17:55:21 +00004390 if (cur == NULL) return;
4391 switch(cur->type) {
4392 case XML_TEXT_NODE:
4393 case XML_CDATA_SECTION_NODE:
4394 case XML_COMMENT_NODE:
4395 case XML_DOCUMENT_NODE:
4396 case XML_DOCUMENT_TYPE_NODE:
4397 case XML_DOCUMENT_FRAG_NODE:
4398 case XML_NOTATION_NODE:
4399 case XML_HTML_DOCUMENT_NODE:
4400 case XML_DTD_NODE:
4401 case XML_ELEMENT_DECL:
4402 case XML_ATTRIBUTE_DECL:
4403 case XML_ENTITY_DECL:
4404 case XML_PI_NODE:
4405 case XML_ENTITY_REF_NODE:
4406 case XML_ENTITY_NODE:
4407 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004408#ifdef LIBXML_DOCB_ENABLED
4409 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004410#endif
4411 case XML_XINCLUDE_START:
4412 case XML_XINCLUDE_END:
4413 return;
4414 case XML_ELEMENT_NODE:
4415 case XML_ATTRIBUTE_NODE:
4416 break;
4417 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004418 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4419 if (ns == NULL)
4420 return;
4421 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004422}
Daniel Veillard652327a2003-09-29 18:02:38 +00004423#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004424
4425/**
4426 * xmlNodeGetLang:
4427 * @cur: the node being checked
4428 *
4429 * Searches the language of a node, i.e. the values of the xml:lang
4430 * attribute or the one carried by the nearest ancestor.
4431 *
4432 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004433 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004434 */
4435xmlChar *
4436xmlNodeGetLang(xmlNodePtr cur) {
4437 xmlChar *lang;
4438
4439 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004440 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004441 if (lang != NULL)
4442 return(lang);
4443 cur = cur->parent;
4444 }
4445 return(NULL);
4446}
4447
4448
Daniel Veillard652327a2003-09-29 18:02:38 +00004449#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004450/**
4451 * xmlNodeSetSpacePreserve:
4452 * @cur: the node being changed
4453 * @val: the xml:space value ("0": default, 1: "preserve")
4454 *
4455 * Set (or reset) the space preserving behaviour of a node, i.e. the
4456 * value of the xml:space attribute.
4457 */
4458void
4459xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004460 xmlNsPtr ns;
4461
Owen Taylor3473f882001-02-23 17:55:21 +00004462 if (cur == NULL) return;
4463 switch(cur->type) {
4464 case XML_TEXT_NODE:
4465 case XML_CDATA_SECTION_NODE:
4466 case XML_COMMENT_NODE:
4467 case XML_DOCUMENT_NODE:
4468 case XML_DOCUMENT_TYPE_NODE:
4469 case XML_DOCUMENT_FRAG_NODE:
4470 case XML_NOTATION_NODE:
4471 case XML_HTML_DOCUMENT_NODE:
4472 case XML_DTD_NODE:
4473 case XML_ELEMENT_DECL:
4474 case XML_ATTRIBUTE_DECL:
4475 case XML_ENTITY_DECL:
4476 case XML_PI_NODE:
4477 case XML_ENTITY_REF_NODE:
4478 case XML_ENTITY_NODE:
4479 case XML_NAMESPACE_DECL:
4480 case XML_XINCLUDE_START:
4481 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004482#ifdef LIBXML_DOCB_ENABLED
4483 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004484#endif
4485 return;
4486 case XML_ELEMENT_NODE:
4487 case XML_ATTRIBUTE_NODE:
4488 break;
4489 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004490 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4491 if (ns == NULL)
4492 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004493 switch (val) {
4494 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004495 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004496 break;
4497 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004498 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004499 break;
4500 }
4501}
Daniel Veillard652327a2003-09-29 18:02:38 +00004502#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004503
4504/**
4505 * xmlNodeGetSpacePreserve:
4506 * @cur: the node being checked
4507 *
4508 * Searches the space preserving behaviour of a node, i.e. the values
4509 * of the xml:space attribute or the one carried by the nearest
4510 * ancestor.
4511 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004512 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004513 */
4514int
4515xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4516 xmlChar *space;
4517
4518 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004519 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004520 if (space != NULL) {
4521 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4522 xmlFree(space);
4523 return(1);
4524 }
4525 if (xmlStrEqual(space, BAD_CAST "default")) {
4526 xmlFree(space);
4527 return(0);
4528 }
4529 xmlFree(space);
4530 }
4531 cur = cur->parent;
4532 }
4533 return(-1);
4534}
4535
Daniel Veillard652327a2003-09-29 18:02:38 +00004536#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004537/**
4538 * xmlNodeSetName:
4539 * @cur: the node being changed
4540 * @name: the new tag name
4541 *
4542 * Set (or reset) the name of a node.
4543 */
4544void
4545xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
4546 if (cur == NULL) return;
4547 if (name == NULL) return;
4548 switch(cur->type) {
4549 case XML_TEXT_NODE:
4550 case XML_CDATA_SECTION_NODE:
4551 case XML_COMMENT_NODE:
4552 case XML_DOCUMENT_TYPE_NODE:
4553 case XML_DOCUMENT_FRAG_NODE:
4554 case XML_NOTATION_NODE:
4555 case XML_HTML_DOCUMENT_NODE:
4556 case XML_NAMESPACE_DECL:
4557 case XML_XINCLUDE_START:
4558 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004559#ifdef LIBXML_DOCB_ENABLED
4560 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004561#endif
4562 return;
4563 case XML_ELEMENT_NODE:
4564 case XML_ATTRIBUTE_NODE:
4565 case XML_PI_NODE:
4566 case XML_ENTITY_REF_NODE:
4567 case XML_ENTITY_NODE:
4568 case XML_DTD_NODE:
4569 case XML_DOCUMENT_NODE:
4570 case XML_ELEMENT_DECL:
4571 case XML_ATTRIBUTE_DECL:
4572 case XML_ENTITY_DECL:
4573 break;
4574 }
4575 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4576 cur->name = xmlStrdup(name);
4577}
4578
4579/**
4580 * xmlNodeSetBase:
4581 * @cur: the node being changed
4582 * @uri: the new base URI
4583 *
4584 * Set (or reset) the base URI of a node, i.e. the value of the
4585 * xml:base attribute.
4586 */
4587void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00004588xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004589 xmlNsPtr ns;
4590
Owen Taylor3473f882001-02-23 17:55:21 +00004591 if (cur == NULL) return;
4592 switch(cur->type) {
4593 case XML_TEXT_NODE:
4594 case XML_CDATA_SECTION_NODE:
4595 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004596 case XML_DOCUMENT_TYPE_NODE:
4597 case XML_DOCUMENT_FRAG_NODE:
4598 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004599 case XML_DTD_NODE:
4600 case XML_ELEMENT_DECL:
4601 case XML_ATTRIBUTE_DECL:
4602 case XML_ENTITY_DECL:
4603 case XML_PI_NODE:
4604 case XML_ENTITY_REF_NODE:
4605 case XML_ENTITY_NODE:
4606 case XML_NAMESPACE_DECL:
4607 case XML_XINCLUDE_START:
4608 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004609 return;
4610 case XML_ELEMENT_NODE:
4611 case XML_ATTRIBUTE_NODE:
4612 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004613 case XML_DOCUMENT_NODE:
4614#ifdef LIBXML_DOCB_ENABLED
4615 case XML_DOCB_DOCUMENT_NODE:
4616#endif
4617 case XML_HTML_DOCUMENT_NODE: {
4618 xmlDocPtr doc = (xmlDocPtr) cur;
4619
4620 if (doc->URL != NULL)
4621 xmlFree((xmlChar *) doc->URL);
4622 if (uri == NULL)
4623 doc->URL = NULL;
4624 else
4625 doc->URL = xmlStrdup(uri);
4626 return;
4627 }
Owen Taylor3473f882001-02-23 17:55:21 +00004628 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004629
4630 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4631 if (ns == NULL)
4632 return;
4633 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004634}
Daniel Veillard652327a2003-09-29 18:02:38 +00004635#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004636
4637/**
Owen Taylor3473f882001-02-23 17:55:21 +00004638 * xmlNodeGetBase:
4639 * @doc: the document the node pertains to
4640 * @cur: the node being checked
4641 *
4642 * Searches for the BASE URL. The code should work on both XML
4643 * and HTML document even if base mechanisms are completely different.
4644 * It returns the base as defined in RFC 2396 sections
4645 * 5.1.1. Base URI within Document Content
4646 * and
4647 * 5.1.2. Base URI from the Encapsulating Entity
4648 * However it does not return the document base (5.1.3), use
4649 * xmlDocumentGetBase() for this
4650 *
4651 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004652 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004653 */
4654xmlChar *
4655xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004656 xmlChar *oldbase = NULL;
4657 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004658
4659 if ((cur == NULL) && (doc == NULL))
4660 return(NULL);
4661 if (doc == NULL) doc = cur->doc;
4662 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4663 cur = doc->children;
4664 while ((cur != NULL) && (cur->name != NULL)) {
4665 if (cur->type != XML_ELEMENT_NODE) {
4666 cur = cur->next;
4667 continue;
4668 }
4669 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4670 cur = cur->children;
4671 continue;
4672 }
4673 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4674 cur = cur->children;
4675 continue;
4676 }
4677 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4678 return(xmlGetProp(cur, BAD_CAST "href"));
4679 }
4680 cur = cur->next;
4681 }
4682 return(NULL);
4683 }
4684 while (cur != NULL) {
4685 if (cur->type == XML_ENTITY_DECL) {
4686 xmlEntityPtr ent = (xmlEntityPtr) cur;
4687 return(xmlStrdup(ent->URI));
4688 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004689 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004690 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004691 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004692 if (oldbase != NULL) {
4693 newbase = xmlBuildURI(oldbase, base);
4694 if (newbase != NULL) {
4695 xmlFree(oldbase);
4696 xmlFree(base);
4697 oldbase = newbase;
4698 } else {
4699 xmlFree(oldbase);
4700 xmlFree(base);
4701 return(NULL);
4702 }
4703 } else {
4704 oldbase = base;
4705 }
4706 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4707 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4708 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4709 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004710 }
4711 }
Owen Taylor3473f882001-02-23 17:55:21 +00004712 cur = cur->parent;
4713 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004714 if ((doc != NULL) && (doc->URL != NULL)) {
4715 if (oldbase == NULL)
4716 return(xmlStrdup(doc->URL));
4717 newbase = xmlBuildURI(oldbase, doc->URL);
4718 xmlFree(oldbase);
4719 return(newbase);
4720 }
4721 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004722}
4723
4724/**
Daniel Veillard78697292003-10-19 20:44:43 +00004725 * xmlNodeBufGetContent:
4726 * @buffer: a buffer
4727 * @cur: the node being read
4728 *
4729 * Read the value of a node @cur, this can be either the text carried
4730 * directly by this node if it's a TEXT node or the aggregate string
4731 * of the values carried by this node child's (TEXT and ENTITY_REF).
4732 * Entity references are substituted.
4733 * Fills up the buffer @buffer with this value
4734 *
4735 * Returns 0 in case of success and -1 in case of error.
4736 */
4737int
4738xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
4739{
4740 if ((cur == NULL) || (buffer == NULL)) return(-1);
4741 switch (cur->type) {
4742 case XML_CDATA_SECTION_NODE:
4743 case XML_TEXT_NODE:
4744 xmlBufferCat(buffer, cur->content);
4745 break;
4746 case XML_DOCUMENT_FRAG_NODE:
4747 case XML_ELEMENT_NODE:{
4748 xmlNodePtr tmp = cur;
4749
4750 while (tmp != NULL) {
4751 switch (tmp->type) {
4752 case XML_CDATA_SECTION_NODE:
4753 case XML_TEXT_NODE:
4754 if (tmp->content != NULL)
4755 xmlBufferCat(buffer, tmp->content);
4756 break;
4757 case XML_ENTITY_REF_NODE:
4758 xmlNodeBufGetContent(buffer, tmp->children);
4759 break;
4760 default:
4761 break;
4762 }
4763 /*
4764 * Skip to next node
4765 */
4766 if (tmp->children != NULL) {
4767 if (tmp->children->type != XML_ENTITY_DECL) {
4768 tmp = tmp->children;
4769 continue;
4770 }
4771 }
4772 if (tmp == cur)
4773 break;
4774
4775 if (tmp->next != NULL) {
4776 tmp = tmp->next;
4777 continue;
4778 }
4779
4780 do {
4781 tmp = tmp->parent;
4782 if (tmp == NULL)
4783 break;
4784 if (tmp == cur) {
4785 tmp = NULL;
4786 break;
4787 }
4788 if (tmp->next != NULL) {
4789 tmp = tmp->next;
4790 break;
4791 }
4792 } while (tmp != NULL);
4793 }
4794 break;
4795 }
4796 case XML_ATTRIBUTE_NODE:{
4797 xmlAttrPtr attr = (xmlAttrPtr) cur;
4798 xmlNodePtr tmp = attr->children;
4799
4800 while (tmp != NULL) {
4801 if (tmp->type == XML_TEXT_NODE)
4802 xmlBufferCat(buffer, tmp->content);
4803 else
4804 xmlNodeBufGetContent(buffer, tmp);
4805 tmp = tmp->next;
4806 }
4807 break;
4808 }
4809 case XML_COMMENT_NODE:
4810 case XML_PI_NODE:
4811 xmlBufferCat(buffer, cur->content);
4812 break;
4813 case XML_ENTITY_REF_NODE:{
4814 xmlEntityPtr ent;
4815 xmlNodePtr tmp;
4816
4817 /* lookup entity declaration */
4818 ent = xmlGetDocEntity(cur->doc, cur->name);
4819 if (ent == NULL)
4820 return(-1);
4821
4822 /* an entity content can be any "well balanced chunk",
4823 * i.e. the result of the content [43] production:
4824 * http://www.w3.org/TR/REC-xml#NT-content
4825 * -> we iterate through child nodes and recursive call
4826 * xmlNodeGetContent() which handles all possible node types */
4827 tmp = ent->children;
4828 while (tmp) {
4829 xmlNodeBufGetContent(buffer, tmp);
4830 tmp = tmp->next;
4831 }
4832 break;
4833 }
4834 case XML_ENTITY_NODE:
4835 case XML_DOCUMENT_TYPE_NODE:
4836 case XML_NOTATION_NODE:
4837 case XML_DTD_NODE:
4838 case XML_XINCLUDE_START:
4839 case XML_XINCLUDE_END:
4840 break;
4841 case XML_DOCUMENT_NODE:
4842#ifdef LIBXML_DOCB_ENABLED
4843 case XML_DOCB_DOCUMENT_NODE:
4844#endif
4845 case XML_HTML_DOCUMENT_NODE:
4846 cur = cur->children;
4847 while (cur!= NULL) {
4848 if ((cur->type == XML_ELEMENT_NODE) ||
4849 (cur->type == XML_TEXT_NODE) ||
4850 (cur->type == XML_CDATA_SECTION_NODE)) {
4851 xmlNodeBufGetContent(buffer, cur);
4852 }
4853 cur = cur->next;
4854 }
4855 break;
4856 case XML_NAMESPACE_DECL:
4857 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
4858 break;
4859 case XML_ELEMENT_DECL:
4860 case XML_ATTRIBUTE_DECL:
4861 case XML_ENTITY_DECL:
4862 break;
4863 }
4864 return(0);
4865}
4866/**
Owen Taylor3473f882001-02-23 17:55:21 +00004867 * xmlNodeGetContent:
4868 * @cur: the node being read
4869 *
4870 * Read the value of a node, this can be either the text carried
4871 * directly by this node if it's a TEXT node or the aggregate string
4872 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004873 * Entity references are substituted.
4874 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004875 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004876 */
4877xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004878xmlNodeGetContent(xmlNodePtr cur)
4879{
4880 if (cur == NULL)
4881 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004882 switch (cur->type) {
4883 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004884 case XML_ELEMENT_NODE:{
Daniel Veillard7646b182002-04-20 06:41:40 +00004885 xmlBufferPtr buffer;
4886 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004887
Daniel Veillard814a76d2003-01-23 18:24:20 +00004888 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004889 if (buffer == NULL)
4890 return (NULL);
Daniel Veillardc4696922003-10-19 21:47:14 +00004891 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00004892 ret = buffer->content;
4893 buffer->content = NULL;
4894 xmlBufferFree(buffer);
4895 return (ret);
4896 }
4897 case XML_ATTRIBUTE_NODE:{
4898 xmlAttrPtr attr = (xmlAttrPtr) cur;
4899
4900 if (attr->parent != NULL)
4901 return (xmlNodeListGetString
4902 (attr->parent->doc, attr->children, 1));
4903 else
4904 return (xmlNodeListGetString(NULL, attr->children, 1));
4905 break;
4906 }
Owen Taylor3473f882001-02-23 17:55:21 +00004907 case XML_COMMENT_NODE:
4908 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004909 if (cur->content != NULL)
4910 return (xmlStrdup(cur->content));
4911 return (NULL);
4912 case XML_ENTITY_REF_NODE:{
4913 xmlEntityPtr ent;
Daniel Veillard7646b182002-04-20 06:41:40 +00004914 xmlBufferPtr buffer;
4915 xmlChar *ret;
4916
4917 /* lookup entity declaration */
4918 ent = xmlGetDocEntity(cur->doc, cur->name);
4919 if (ent == NULL)
4920 return (NULL);
4921
4922 buffer = xmlBufferCreate();
4923 if (buffer == NULL)
4924 return (NULL);
4925
Daniel Veillardc4696922003-10-19 21:47:14 +00004926 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00004927
4928 ret = buffer->content;
4929 buffer->content = NULL;
4930 xmlBufferFree(buffer);
4931 return (ret);
4932 }
Owen Taylor3473f882001-02-23 17:55:21 +00004933 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004934 case XML_DOCUMENT_TYPE_NODE:
4935 case XML_NOTATION_NODE:
4936 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004937 case XML_XINCLUDE_START:
4938 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00004939 return (NULL);
4940 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004941#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004942 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004943#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00004944 case XML_HTML_DOCUMENT_NODE: {
Daniel Veillardc4696922003-10-19 21:47:14 +00004945 xmlBufferPtr buffer;
4946 xmlChar *ret;
Daniel Veillard9adc0462003-03-24 18:39:54 +00004947
Daniel Veillardc4696922003-10-19 21:47:14 +00004948 buffer = xmlBufferCreate();
4949 if (buffer == NULL)
4950 return (NULL);
4951
4952 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
4953
4954 ret = buffer->content;
4955 buffer->content = NULL;
4956 xmlBufferFree(buffer);
4957 return (ret);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004958 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004959 case XML_NAMESPACE_DECL: {
4960 xmlChar *tmp;
4961
4962 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4963 return (tmp);
4964 }
Owen Taylor3473f882001-02-23 17:55:21 +00004965 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004966 /* TODO !!! */
4967 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004968 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004969 /* TODO !!! */
4970 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004971 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004972 /* TODO !!! */
4973 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004974 case XML_CDATA_SECTION_NODE:
4975 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004976 if (cur->content != NULL)
4977 return (xmlStrdup(cur->content));
4978 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004979 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004980 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004981}
Daniel Veillard652327a2003-09-29 18:02:38 +00004982
Owen Taylor3473f882001-02-23 17:55:21 +00004983/**
4984 * xmlNodeSetContent:
4985 * @cur: the node being modified
4986 * @content: the new value of the content
4987 *
4988 * Replace the content of a node.
4989 */
4990void
4991xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4992 if (cur == NULL) {
4993#ifdef DEBUG_TREE
4994 xmlGenericError(xmlGenericErrorContext,
4995 "xmlNodeSetContent : node == NULL\n");
4996#endif
4997 return;
4998 }
4999 switch (cur->type) {
5000 case XML_DOCUMENT_FRAG_NODE:
5001 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005002 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005003 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5004 cur->children = xmlStringGetNodeList(cur->doc, content);
5005 UPDATE_LAST_CHILD_AND_PARENT(cur)
5006 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005007 case XML_TEXT_NODE:
5008 case XML_CDATA_SECTION_NODE:
5009 case XML_ENTITY_REF_NODE:
5010 case XML_ENTITY_NODE:
5011 case XML_PI_NODE:
5012 case XML_COMMENT_NODE:
5013 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005014 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005015 }
5016 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5017 cur->last = cur->children = NULL;
5018 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005019 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00005020 } else
5021 cur->content = NULL;
5022 break;
5023 case XML_DOCUMENT_NODE:
5024 case XML_HTML_DOCUMENT_NODE:
5025 case XML_DOCUMENT_TYPE_NODE:
5026 case XML_XINCLUDE_START:
5027 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005028#ifdef LIBXML_DOCB_ENABLED
5029 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005030#endif
5031 break;
5032 case XML_NOTATION_NODE:
5033 break;
5034 case XML_DTD_NODE:
5035 break;
5036 case XML_NAMESPACE_DECL:
5037 break;
5038 case XML_ELEMENT_DECL:
5039 /* TODO !!! */
5040 break;
5041 case XML_ATTRIBUTE_DECL:
5042 /* TODO !!! */
5043 break;
5044 case XML_ENTITY_DECL:
5045 /* TODO !!! */
5046 break;
5047 }
5048}
5049
Daniel Veillard652327a2003-09-29 18:02:38 +00005050#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005051/**
5052 * xmlNodeSetContentLen:
5053 * @cur: the node being modified
5054 * @content: the new value of the content
5055 * @len: the size of @content
5056 *
5057 * Replace the content of a node.
5058 */
5059void
5060xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5061 if (cur == NULL) {
5062#ifdef DEBUG_TREE
5063 xmlGenericError(xmlGenericErrorContext,
5064 "xmlNodeSetContentLen : node == NULL\n");
5065#endif
5066 return;
5067 }
5068 switch (cur->type) {
5069 case XML_DOCUMENT_FRAG_NODE:
5070 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005071 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005072 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5073 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5074 UPDATE_LAST_CHILD_AND_PARENT(cur)
5075 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005076 case XML_TEXT_NODE:
5077 case XML_CDATA_SECTION_NODE:
5078 case XML_ENTITY_REF_NODE:
5079 case XML_ENTITY_NODE:
5080 case XML_PI_NODE:
5081 case XML_COMMENT_NODE:
5082 case XML_NOTATION_NODE:
5083 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005084 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005085 }
5086 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5087 cur->children = cur->last = NULL;
5088 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005089 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005090 } else
5091 cur->content = NULL;
5092 break;
5093 case XML_DOCUMENT_NODE:
5094 case XML_DTD_NODE:
5095 case XML_HTML_DOCUMENT_NODE:
5096 case XML_DOCUMENT_TYPE_NODE:
5097 case XML_NAMESPACE_DECL:
5098 case XML_XINCLUDE_START:
5099 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005100#ifdef LIBXML_DOCB_ENABLED
5101 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005102#endif
5103 break;
5104 case XML_ELEMENT_DECL:
5105 /* TODO !!! */
5106 break;
5107 case XML_ATTRIBUTE_DECL:
5108 /* TODO !!! */
5109 break;
5110 case XML_ENTITY_DECL:
5111 /* TODO !!! */
5112 break;
5113 }
5114}
Daniel Veillard652327a2003-09-29 18:02:38 +00005115#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005116
5117/**
5118 * xmlNodeAddContentLen:
5119 * @cur: the node being modified
5120 * @content: extra content
5121 * @len: the size of @content
5122 *
5123 * Append the extra substring to the node content.
5124 */
5125void
5126xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5127 if (cur == NULL) {
5128#ifdef DEBUG_TREE
5129 xmlGenericError(xmlGenericErrorContext,
5130 "xmlNodeAddContentLen : node == NULL\n");
5131#endif
5132 return;
5133 }
5134 if (len <= 0) return;
5135 switch (cur->type) {
5136 case XML_DOCUMENT_FRAG_NODE:
5137 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005138 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005139
Daniel Veillard7db37732001-07-12 01:20:08 +00005140 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005141 newNode = xmlNewTextLen(content, len);
5142 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005143 tmp = xmlAddChild(cur, newNode);
5144 if (tmp != newNode)
5145 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005146 if ((last != NULL) && (last->next == newNode)) {
5147 xmlTextMerge(last, newNode);
5148 }
5149 }
5150 break;
5151 }
5152 case XML_ATTRIBUTE_NODE:
5153 break;
5154 case XML_TEXT_NODE:
5155 case XML_CDATA_SECTION_NODE:
5156 case XML_ENTITY_REF_NODE:
5157 case XML_ENTITY_NODE:
5158 case XML_PI_NODE:
5159 case XML_COMMENT_NODE:
5160 case XML_NOTATION_NODE:
5161 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005162 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005163 }
5164 case XML_DOCUMENT_NODE:
5165 case XML_DTD_NODE:
5166 case XML_HTML_DOCUMENT_NODE:
5167 case XML_DOCUMENT_TYPE_NODE:
5168 case XML_NAMESPACE_DECL:
5169 case XML_XINCLUDE_START:
5170 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005171#ifdef LIBXML_DOCB_ENABLED
5172 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005173#endif
5174 break;
5175 case XML_ELEMENT_DECL:
5176 case XML_ATTRIBUTE_DECL:
5177 case XML_ENTITY_DECL:
5178 break;
5179 }
5180}
5181
5182/**
5183 * xmlNodeAddContent:
5184 * @cur: the node being modified
5185 * @content: extra content
5186 *
5187 * Append the extra substring to the node content.
5188 */
5189void
5190xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5191 int len;
5192
5193 if (cur == NULL) {
5194#ifdef DEBUG_TREE
5195 xmlGenericError(xmlGenericErrorContext,
5196 "xmlNodeAddContent : node == NULL\n");
5197#endif
5198 return;
5199 }
5200 if (content == NULL) return;
5201 len = xmlStrlen(content);
5202 xmlNodeAddContentLen(cur, content, len);
5203}
5204
5205/**
5206 * xmlTextMerge:
5207 * @first: the first text node
5208 * @second: the second text node being merged
5209 *
5210 * Merge two text nodes into one
5211 * Returns the first text node augmented
5212 */
5213xmlNodePtr
5214xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5215 if (first == NULL) return(second);
5216 if (second == NULL) return(first);
5217 if (first->type != XML_TEXT_NODE) return(first);
5218 if (second->type != XML_TEXT_NODE) return(first);
5219 if (second->name != first->name)
5220 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005221 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005222 xmlUnlinkNode(second);
5223 xmlFreeNode(second);
5224 return(first);
5225}
5226
Daniel Veillard652327a2003-09-29 18:02:38 +00005227#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005228/**
5229 * xmlGetNsList:
5230 * @doc: the document
5231 * @node: the current node
5232 *
5233 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005234 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005235 * that need to be freed by the caller or NULL if no
5236 * namespace if defined
5237 */
5238xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005239xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5240{
Owen Taylor3473f882001-02-23 17:55:21 +00005241 xmlNsPtr cur;
5242 xmlNsPtr *ret = NULL;
5243 int nbns = 0;
5244 int maxns = 10;
5245 int i;
5246
5247 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005248 if (node->type == XML_ELEMENT_NODE) {
5249 cur = node->nsDef;
5250 while (cur != NULL) {
5251 if (ret == NULL) {
5252 ret =
5253 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5254 sizeof(xmlNsPtr));
5255 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005256 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005257 return (NULL);
5258 }
5259 ret[nbns] = NULL;
5260 }
5261 for (i = 0; i < nbns; i++) {
5262 if ((cur->prefix == ret[i]->prefix) ||
5263 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5264 break;
5265 }
5266 if (i >= nbns) {
5267 if (nbns >= maxns) {
5268 maxns *= 2;
5269 ret = (xmlNsPtr *) xmlRealloc(ret,
5270 (maxns +
5271 1) *
5272 sizeof(xmlNsPtr));
5273 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005274 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005275 return (NULL);
5276 }
5277 }
5278 ret[nbns++] = cur;
5279 ret[nbns] = NULL;
5280 }
Owen Taylor3473f882001-02-23 17:55:21 +00005281
Daniel Veillard77044732001-06-29 21:31:07 +00005282 cur = cur->next;
5283 }
5284 }
5285 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005286 }
Daniel Veillard77044732001-06-29 21:31:07 +00005287 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005288}
Daniel Veillard652327a2003-09-29 18:02:38 +00005289#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005290
5291/**
5292 * xmlSearchNs:
5293 * @doc: the document
5294 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005295 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005296 *
5297 * Search a Ns registered under a given name space for a document.
5298 * recurse on the parents until it finds the defined namespace
5299 * or return NULL otherwise.
5300 * @nameSpace can be NULL, this is a search for the default namespace.
5301 * We don't allow to cross entities boundaries. If you don't declare
5302 * the namespace within those you will be in troubles !!! A warning
5303 * is generated to cover this case.
5304 *
5305 * Returns the namespace pointer or NULL.
5306 */
5307xmlNsPtr
5308xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillardf4e56292003-10-28 14:27:41 +00005309
Owen Taylor3473f882001-02-23 17:55:21 +00005310 xmlNsPtr cur;
Daniel Veillardf4e56292003-10-28 14:27:41 +00005311 xmlNodePtr orig = node;
Owen Taylor3473f882001-02-23 17:55:21 +00005312
5313 if (node == NULL) return(NULL);
5314 if ((nameSpace != NULL) &&
5315 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005316 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5317 /*
5318 * The XML-1.0 namespace is normally held on the root
5319 * element. In this case exceptionally create it on the
5320 * node element.
5321 */
5322 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5323 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005324 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005325 return(NULL);
5326 }
5327 memset(cur, 0, sizeof(xmlNs));
5328 cur->type = XML_LOCAL_NAMESPACE;
5329 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5330 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5331 cur->next = node->nsDef;
5332 node->nsDef = cur;
5333 return(cur);
5334 }
Owen Taylor3473f882001-02-23 17:55:21 +00005335 if (doc->oldNs == NULL) {
5336 /*
5337 * Allocate a new Namespace and fill the fields.
5338 */
5339 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5340 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005341 xmlTreeErrMemory("searching namespace");
Owen Taylor3473f882001-02-23 17:55:21 +00005342 return(NULL);
5343 }
5344 memset(doc->oldNs, 0, sizeof(xmlNs));
5345 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5346
5347 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5348 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5349 }
5350 return(doc->oldNs);
5351 }
5352 while (node != NULL) {
5353 if ((node->type == XML_ENTITY_REF_NODE) ||
5354 (node->type == XML_ENTITY_NODE) ||
5355 (node->type == XML_ENTITY_DECL))
5356 return(NULL);
5357 if (node->type == XML_ELEMENT_NODE) {
5358 cur = node->nsDef;
5359 while (cur != NULL) {
5360 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5361 (cur->href != NULL))
5362 return(cur);
5363 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5364 (cur->href != NULL) &&
5365 (xmlStrEqual(cur->prefix, nameSpace)))
5366 return(cur);
5367 cur = cur->next;
5368 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005369 if (orig != node) {
5370 cur = node->ns;
5371 if (cur != NULL) {
5372 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5373 (cur->href != NULL))
5374 return(cur);
5375 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5376 (cur->href != NULL) &&
5377 (xmlStrEqual(cur->prefix, nameSpace)))
5378 return(cur);
5379 }
5380 }
Owen Taylor3473f882001-02-23 17:55:21 +00005381 }
5382 node = node->parent;
5383 }
5384 return(NULL);
5385}
5386
5387/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005388 * xmlNsInScope:
5389 * @doc: the document
5390 * @node: the current node
5391 * @ancestor: the ancestor carrying the namespace
5392 * @prefix: the namespace prefix
5393 *
5394 * Verify that the given namespace held on @ancestor is still in scope
5395 * on node.
5396 *
5397 * Returns 1 if true, 0 if false and -1 in case of error.
5398 */
5399static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005400xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5401 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005402{
5403 xmlNsPtr tst;
5404
5405 while ((node != NULL) && (node != ancestor)) {
5406 if ((node->type == XML_ENTITY_REF_NODE) ||
5407 (node->type == XML_ENTITY_NODE) ||
5408 (node->type == XML_ENTITY_DECL))
5409 return (-1);
5410 if (node->type == XML_ELEMENT_NODE) {
5411 tst = node->nsDef;
5412 while (tst != NULL) {
5413 if ((tst->prefix == NULL)
5414 && (prefix == NULL))
5415 return (0);
5416 if ((tst->prefix != NULL)
5417 && (prefix != NULL)
5418 && (xmlStrEqual(tst->prefix, prefix)))
5419 return (0);
5420 tst = tst->next;
5421 }
5422 }
5423 node = node->parent;
5424 }
5425 if (node != ancestor)
5426 return (-1);
5427 return (1);
5428}
5429
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005430/**
Owen Taylor3473f882001-02-23 17:55:21 +00005431 * xmlSearchNsByHref:
5432 * @doc: the document
5433 * @node: the current node
5434 * @href: the namespace value
5435 *
5436 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5437 * the defined namespace or return NULL otherwise.
5438 * Returns the namespace pointer or NULL.
5439 */
5440xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005441xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5442{
Owen Taylor3473f882001-02-23 17:55:21 +00005443 xmlNsPtr cur;
5444 xmlNodePtr orig = node;
5445
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005446 if ((node == NULL) || (href == NULL))
5447 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005448 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005449 /*
5450 * Only the document can hold the XML spec namespace.
5451 */
5452 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5453 /*
5454 * The XML-1.0 namespace is normally held on the root
5455 * element. In this case exceptionally create it on the
5456 * node element.
5457 */
5458 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5459 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005460 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005461 return (NULL);
5462 }
5463 memset(cur, 0, sizeof(xmlNs));
5464 cur->type = XML_LOCAL_NAMESPACE;
5465 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5466 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5467 cur->next = node->nsDef;
5468 node->nsDef = cur;
5469 return (cur);
5470 }
5471 if (doc->oldNs == NULL) {
5472 /*
5473 * Allocate a new Namespace and fill the fields.
5474 */
5475 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5476 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005477 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005478 return (NULL);
5479 }
5480 memset(doc->oldNs, 0, sizeof(xmlNs));
5481 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005482
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005483 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5484 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5485 }
5486 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005487 }
5488 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005489 if ((node->type == XML_ENTITY_REF_NODE) ||
5490 (node->type == XML_ENTITY_NODE) ||
5491 (node->type == XML_ENTITY_DECL))
5492 return (NULL);
5493 if (node->type == XML_ELEMENT_NODE) {
5494 cur = node->nsDef;
5495 while (cur != NULL) {
5496 if ((cur->href != NULL) && (href != NULL) &&
5497 (xmlStrEqual(cur->href, href))) {
5498 if (xmlNsInScope(doc, orig, node, cur->href) == 1)
5499 return (cur);
5500 }
5501 cur = cur->next;
5502 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005503 if (orig != node) {
5504 cur = node->ns;
5505 if (cur != NULL) {
5506 if ((cur->href != NULL) && (href != NULL) &&
5507 (xmlStrEqual(cur->href, href))) {
5508 if (xmlNsInScope(doc, orig, node, cur->href) == 1)
5509 return (cur);
5510 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005511 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005512 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005513 }
5514 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005515 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005516 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005517}
5518
5519/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005520 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005521 * @doc: the document
5522 * @tree: a node expected to hold the new namespace
5523 * @ns: the original namespace
5524 *
5525 * This function tries to locate a namespace definition in a tree
5526 * ancestors, or create a new namespace definition node similar to
5527 * @ns trying to reuse the same prefix. However if the given prefix is
5528 * null (default namespace) or reused within the subtree defined by
5529 * @tree or on one of its ancestors then a new prefix is generated.
5530 * Returns the (new) namespace definition or NULL in case of error
5531 */
5532xmlNsPtr
5533xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5534 xmlNsPtr def;
5535 xmlChar prefix[50];
5536 int counter = 1;
5537
5538 if (tree == NULL) {
5539#ifdef DEBUG_TREE
5540 xmlGenericError(xmlGenericErrorContext,
5541 "xmlNewReconciliedNs : tree == NULL\n");
5542#endif
5543 return(NULL);
5544 }
5545 if (ns == NULL) {
5546#ifdef DEBUG_TREE
5547 xmlGenericError(xmlGenericErrorContext,
5548 "xmlNewReconciliedNs : ns == NULL\n");
5549#endif
5550 return(NULL);
5551 }
5552 /*
5553 * Search an existing namespace definition inherited.
5554 */
5555 def = xmlSearchNsByHref(doc, tree, ns->href);
5556 if (def != NULL)
5557 return(def);
5558
5559 /*
5560 * Find a close prefix which is not already in use.
5561 * Let's strip namespace prefixes longer than 20 chars !
5562 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005563 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005564 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005565 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005566 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005567
Owen Taylor3473f882001-02-23 17:55:21 +00005568 def = xmlSearchNs(doc, tree, prefix);
5569 while (def != NULL) {
5570 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005571 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005572 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005573 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005574 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005575 def = xmlSearchNs(doc, tree, prefix);
5576 }
5577
5578 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005579 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005580 */
5581 def = xmlNewNs(tree, ns->href, prefix);
5582 return(def);
5583}
5584
Daniel Veillard652327a2003-09-29 18:02:38 +00005585#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005586/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005587 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005588 * @doc: the document
5589 * @tree: a node defining the subtree to reconciliate
5590 *
5591 * This function checks that all the namespaces declared within the given
5592 * tree are properly declared. This is needed for example after Copy or Cut
5593 * and then paste operations. The subtree may still hold pointers to
5594 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005595 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005596 * the new environment. If not possible the new namespaces are redeclared
5597 * on @tree at the top of the given subtree.
5598 * Returns the number of namespace declarations created or -1 in case of error.
5599 */
5600int
5601xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5602 xmlNsPtr *oldNs = NULL;
5603 xmlNsPtr *newNs = NULL;
5604 int sizeCache = 0;
5605 int nbCache = 0;
5606
5607 xmlNsPtr n;
5608 xmlNodePtr node = tree;
5609 xmlAttrPtr attr;
5610 int ret = 0, i;
5611
5612 while (node != NULL) {
5613 /*
5614 * Reconciliate the node namespace
5615 */
5616 if (node->ns != NULL) {
5617 /*
5618 * initialize the cache if needed
5619 */
5620 if (sizeCache == 0) {
5621 sizeCache = 10;
5622 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5623 sizeof(xmlNsPtr));
5624 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005625 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005626 return(-1);
5627 }
5628 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5629 sizeof(xmlNsPtr));
5630 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005631 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005632 xmlFree(oldNs);
5633 return(-1);
5634 }
5635 }
5636 for (i = 0;i < nbCache;i++) {
5637 if (oldNs[i] == node->ns) {
5638 node->ns = newNs[i];
5639 break;
5640 }
5641 }
5642 if (i == nbCache) {
5643 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005644 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005645 */
5646 n = xmlNewReconciliedNs(doc, tree, node->ns);
5647 if (n != NULL) { /* :-( what if else ??? */
5648 /*
5649 * check if we need to grow the cache buffers.
5650 */
5651 if (sizeCache <= nbCache) {
5652 sizeCache *= 2;
5653 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5654 sizeof(xmlNsPtr));
5655 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005656 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005657 xmlFree(newNs);
5658 return(-1);
5659 }
5660 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5661 sizeof(xmlNsPtr));
5662 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005663 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005664 xmlFree(oldNs);
5665 return(-1);
5666 }
5667 }
5668 newNs[nbCache] = n;
5669 oldNs[nbCache++] = node->ns;
5670 node->ns = n;
5671 }
5672 }
5673 }
5674 /*
5675 * now check for namespace hold by attributes on the node.
5676 */
5677 attr = node->properties;
5678 while (attr != NULL) {
5679 if (attr->ns != NULL) {
5680 /*
5681 * initialize the cache if needed
5682 */
5683 if (sizeCache == 0) {
5684 sizeCache = 10;
5685 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5686 sizeof(xmlNsPtr));
5687 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005688 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005689 return(-1);
5690 }
5691 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5692 sizeof(xmlNsPtr));
5693 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005694 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005695 xmlFree(oldNs);
5696 return(-1);
5697 }
5698 }
5699 for (i = 0;i < nbCache;i++) {
5700 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005701 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005702 break;
5703 }
5704 }
5705 if (i == nbCache) {
5706 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005707 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005708 */
5709 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5710 if (n != NULL) { /* :-( what if else ??? */
5711 /*
5712 * check if we need to grow the cache buffers.
5713 */
5714 if (sizeCache <= nbCache) {
5715 sizeCache *= 2;
5716 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5717 sizeof(xmlNsPtr));
5718 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005719 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005720 xmlFree(newNs);
5721 return(-1);
5722 }
5723 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5724 sizeof(xmlNsPtr));
5725 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005726 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005727 xmlFree(oldNs);
5728 return(-1);
5729 }
5730 }
5731 newNs[nbCache] = n;
5732 oldNs[nbCache++] = attr->ns;
5733 attr->ns = n;
5734 }
5735 }
5736 }
5737 attr = attr->next;
5738 }
5739
5740 /*
5741 * Browse the full subtree, deep first
5742 */
5743 if (node->children != NULL) {
5744 /* deep first */
5745 node = node->children;
5746 } else if ((node != tree) && (node->next != NULL)) {
5747 /* then siblings */
5748 node = node->next;
5749 } else if (node != tree) {
5750 /* go up to parents->next if needed */
5751 while (node != tree) {
5752 if (node->parent != NULL)
5753 node = node->parent;
5754 if ((node != tree) && (node->next != NULL)) {
5755 node = node->next;
5756 break;
5757 }
5758 if (node->parent == NULL) {
5759 node = NULL;
5760 break;
5761 }
5762 }
5763 /* exit condition */
5764 if (node == tree)
5765 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005766 } else
5767 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005768 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005769 if (oldNs != NULL)
5770 xmlFree(oldNs);
5771 if (newNs != NULL)
5772 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005773 return(ret);
5774}
Daniel Veillard652327a2003-09-29 18:02:38 +00005775#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005776
5777/**
5778 * xmlHasProp:
5779 * @node: the node
5780 * @name: the attribute name
5781 *
5782 * Search an attribute associated to a node
5783 * This function also looks in DTD attribute declaration for #FIXED or
5784 * default declaration values unless DTD use has been turned off.
5785 *
5786 * Returns the attribute or the attribute declaration or NULL if
5787 * neither was found.
5788 */
5789xmlAttrPtr
5790xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5791 xmlAttrPtr prop;
5792 xmlDocPtr doc;
5793
5794 if ((node == NULL) || (name == NULL)) return(NULL);
5795 /*
5796 * Check on the properties attached to the node
5797 */
5798 prop = node->properties;
5799 while (prop != NULL) {
5800 if (xmlStrEqual(prop->name, name)) {
5801 return(prop);
5802 }
5803 prop = prop->next;
5804 }
5805 if (!xmlCheckDTD) return(NULL);
5806
5807 /*
5808 * Check if there is a default declaration in the internal
5809 * or external subsets
5810 */
5811 doc = node->doc;
5812 if (doc != NULL) {
5813 xmlAttributePtr attrDecl;
5814 if (doc->intSubset != NULL) {
5815 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5816 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5817 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005818 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5819 /* return attribute declaration only if a default value is given
5820 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005821 return((xmlAttrPtr) attrDecl);
5822 }
5823 }
5824 return(NULL);
5825}
5826
5827/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005828 * xmlHasNsProp:
5829 * @node: the node
5830 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005831 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005832 *
5833 * Search for an attribute associated to a node
5834 * This attribute has to be anchored in the namespace specified.
5835 * This does the entity substitution.
5836 * This function looks in DTD attribute declaration for #FIXED or
5837 * default declaration values unless DTD use has been turned off.
5838 *
5839 * Returns the attribute or the attribute declaration or NULL
5840 * if neither was found.
5841 */
5842xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005843xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005844 xmlAttrPtr prop;
Daniel Veillard652327a2003-09-29 18:02:38 +00005845#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005846 xmlDocPtr doc;
Daniel Veillard652327a2003-09-29 18:02:38 +00005847#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005848
5849 if (node == NULL)
5850 return(NULL);
5851
5852 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005853 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005854 return(xmlHasProp(node, name));
5855 while (prop != NULL) {
5856 /*
5857 * One need to have
5858 * - same attribute names
5859 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005860 */
5861 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005862 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5863 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005864 }
5865 prop = prop->next;
5866 }
5867 if (!xmlCheckDTD) return(NULL);
5868
Daniel Veillard652327a2003-09-29 18:02:38 +00005869#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005870 /*
5871 * Check if there is a default declaration in the internal
5872 * or external subsets
5873 */
5874 doc = node->doc;
5875 if (doc != NULL) {
5876 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005877 xmlAttributePtr attrDecl = NULL;
5878 xmlNsPtr *nsList, *cur;
5879 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005880
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005881 nsList = xmlGetNsList(node->doc, node);
5882 if (nsList == NULL)
5883 return(NULL);
5884 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5885 ename = xmlStrdup(node->ns->prefix);
5886 ename = xmlStrcat(ename, BAD_CAST ":");
5887 ename = xmlStrcat(ename, node->name);
5888 } else {
5889 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005890 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005891 if (ename == NULL) {
5892 xmlFree(nsList);
5893 return(NULL);
5894 }
5895
5896 cur = nsList;
5897 while (*cur != NULL) {
5898 if (xmlStrEqual((*cur)->href, nameSpace)) {
5899 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5900 name, (*cur)->prefix);
5901 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5902 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5903 name, (*cur)->prefix);
5904 }
5905 cur++;
5906 }
5907 xmlFree(nsList);
5908 xmlFree(ename);
5909 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005910 }
5911 }
Daniel Veillard652327a2003-09-29 18:02:38 +00005912#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005913 return(NULL);
5914}
5915
5916/**
Owen Taylor3473f882001-02-23 17:55:21 +00005917 * xmlGetProp:
5918 * @node: the node
5919 * @name: the attribute name
5920 *
5921 * Search and get the value of an attribute associated to a node
5922 * This does the entity substitution.
5923 * This function looks in DTD attribute declaration for #FIXED or
5924 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00005925 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00005926 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
5927 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00005928 *
5929 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005930 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005931 */
5932xmlChar *
5933xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5934 xmlAttrPtr prop;
5935 xmlDocPtr doc;
5936
5937 if ((node == NULL) || (name == NULL)) return(NULL);
5938 /*
5939 * Check on the properties attached to the node
5940 */
5941 prop = node->properties;
5942 while (prop != NULL) {
5943 if (xmlStrEqual(prop->name, name)) {
5944 xmlChar *ret;
5945
5946 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5947 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5948 return(ret);
5949 }
5950 prop = prop->next;
5951 }
5952 if (!xmlCheckDTD) return(NULL);
5953
5954 /*
5955 * Check if there is a default declaration in the internal
5956 * or external subsets
5957 */
5958 doc = node->doc;
5959 if (doc != NULL) {
5960 xmlAttributePtr attrDecl;
5961 if (doc->intSubset != NULL) {
5962 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5963 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5964 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005965 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5966 /* return attribute declaration only if a default value is given
5967 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005968 return(xmlStrdup(attrDecl->defaultValue));
5969 }
5970 }
5971 return(NULL);
5972}
5973
5974/**
Daniel Veillard71531f32003-02-05 13:19:53 +00005975 * xmlGetNoNsProp:
5976 * @node: the node
5977 * @name: the attribute name
5978 *
5979 * Search and get the value of an attribute associated to a node
5980 * This does the entity substitution.
5981 * This function looks in DTD attribute declaration for #FIXED or
5982 * default declaration values unless DTD use has been turned off.
5983 * This function is similar to xmlGetProp except it will accept only
5984 * an attribute in no namespace.
5985 *
5986 * Returns the attribute value or NULL if not found.
5987 * It's up to the caller to free the memory with xmlFree().
5988 */
5989xmlChar *
5990xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
5991 xmlAttrPtr prop;
5992 xmlDocPtr doc;
5993
5994 if ((node == NULL) || (name == NULL)) return(NULL);
5995 /*
5996 * Check on the properties attached to the node
5997 */
5998 prop = node->properties;
5999 while (prop != NULL) {
6000 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
6001 xmlChar *ret;
6002
6003 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6004 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6005 return(ret);
6006 }
6007 prop = prop->next;
6008 }
6009 if (!xmlCheckDTD) return(NULL);
6010
6011 /*
6012 * Check if there is a default declaration in the internal
6013 * or external subsets
6014 */
6015 doc = node->doc;
6016 if (doc != NULL) {
6017 xmlAttributePtr attrDecl;
6018 if (doc->intSubset != NULL) {
6019 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6020 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6021 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006022 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6023 /* return attribute declaration only if a default value is given
6024 (that includes #FIXED declarations) */
Daniel Veillard71531f32003-02-05 13:19:53 +00006025 return(xmlStrdup(attrDecl->defaultValue));
6026 }
6027 }
6028 return(NULL);
6029}
6030
6031/**
Owen Taylor3473f882001-02-23 17:55:21 +00006032 * xmlGetNsProp:
6033 * @node: the node
6034 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006035 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006036 *
6037 * Search and get the value of an attribute associated to a node
6038 * This attribute has to be anchored in the namespace specified.
6039 * This does the entity substitution.
6040 * This function looks in DTD attribute declaration for #FIXED or
6041 * default declaration values unless DTD use has been turned off.
6042 *
6043 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006044 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006045 */
6046xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006047xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006048 xmlAttrPtr prop;
6049 xmlDocPtr doc;
6050 xmlNsPtr ns;
6051
6052 if (node == NULL)
6053 return(NULL);
6054
6055 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00006056 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00006057 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00006058 while (prop != NULL) {
6059 /*
6060 * One need to have
6061 * - same attribute names
6062 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006063 */
6064 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00006065 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00006066 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006067 xmlChar *ret;
6068
6069 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6070 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6071 return(ret);
6072 }
6073 prop = prop->next;
6074 }
6075 if (!xmlCheckDTD) return(NULL);
6076
6077 /*
6078 * Check if there is a default declaration in the internal
6079 * or external subsets
6080 */
6081 doc = node->doc;
6082 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006083 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00006084 xmlAttributePtr attrDecl;
6085
Owen Taylor3473f882001-02-23 17:55:21 +00006086 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6087 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6088 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
6089
6090 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
6091 /*
6092 * The DTD declaration only allows a prefix search
6093 */
6094 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00006095 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00006096 return(xmlStrdup(attrDecl->defaultValue));
6097 }
6098 }
6099 }
6100 return(NULL);
6101}
6102
Daniel Veillard652327a2003-09-29 18:02:38 +00006103#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00006104/**
6105 * xmlSetProp:
6106 * @node: the node
6107 * @name: the attribute name
6108 * @value: the attribute value
6109 *
6110 * Set (or reset) an attribute carried by a node.
6111 * Returns the attribute pointer.
6112 */
6113xmlAttrPtr
6114xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006115 xmlAttrPtr prop;
6116 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00006117
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006118 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006119 return(NULL);
6120 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006121 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00006122 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006123 if ((xmlStrEqual(prop->name, name)) &&
6124 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006125 xmlNodePtr oldprop = prop->children;
6126
Owen Taylor3473f882001-02-23 17:55:21 +00006127 prop->children = NULL;
6128 prop->last = NULL;
6129 if (value != NULL) {
6130 xmlChar *buffer;
6131 xmlNodePtr tmp;
6132
6133 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6134 prop->children = xmlStringGetNodeList(node->doc, buffer);
6135 prop->last = NULL;
6136 prop->doc = doc;
6137 tmp = prop->children;
6138 while (tmp != NULL) {
6139 tmp->parent = (xmlNodePtr) prop;
6140 tmp->doc = doc;
6141 if (tmp->next == NULL)
6142 prop->last = tmp;
6143 tmp = tmp->next;
6144 }
6145 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00006146 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006147 if (oldprop != NULL)
6148 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00006149 return(prop);
6150 }
6151 prop = prop->next;
6152 }
6153 prop = xmlNewProp(node, name, value);
6154 return(prop);
6155}
6156
6157/**
Daniel Veillard75bea542001-05-11 17:41:21 +00006158 * xmlUnsetProp:
6159 * @node: the node
6160 * @name: the attribute name
6161 *
6162 * Remove an attribute carried by a node.
6163 * Returns 0 if successful, -1 if not found
6164 */
6165int
6166xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Daniel Veillard814a76d2003-01-23 18:24:20 +00006167 xmlAttrPtr prop, prev = NULL;;
Daniel Veillard75bea542001-05-11 17:41:21 +00006168
6169 if ((node == NULL) || (name == NULL))
6170 return(-1);
Daniel Veillard814a76d2003-01-23 18:24:20 +00006171 prop = node->properties;
Daniel Veillard75bea542001-05-11 17:41:21 +00006172 while (prop != NULL) {
6173 if ((xmlStrEqual(prop->name, name)) &&
6174 (prop->ns == NULL)) {
6175 if (prev == NULL)
6176 node->properties = prop->next;
6177 else
6178 prev->next = prop->next;
6179 xmlFreeProp(prop);
6180 return(0);
6181 }
6182 prev = prop;
6183 prop = prop->next;
6184 }
6185 return(-1);
6186}
6187
6188/**
Owen Taylor3473f882001-02-23 17:55:21 +00006189 * xmlSetNsProp:
6190 * @node: the node
6191 * @ns: the namespace definition
6192 * @name: the attribute name
6193 * @value: the attribute value
6194 *
6195 * Set (or reset) an attribute carried by a node.
6196 * The ns structure must be in scope, this is not checked.
6197 *
6198 * Returns the attribute pointer.
6199 */
6200xmlAttrPtr
6201xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
6202 const xmlChar *value) {
6203 xmlAttrPtr prop;
6204
6205 if ((node == NULL) || (name == NULL))
6206 return(NULL);
6207
6208 if (ns == NULL)
6209 return(xmlSetProp(node, name, value));
6210 if (ns->href == NULL)
6211 return(NULL);
6212 prop = node->properties;
6213
6214 while (prop != NULL) {
6215 /*
6216 * One need to have
6217 * - same attribute names
6218 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006219 */
6220 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00006221 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006222 if (prop->children != NULL)
6223 xmlFreeNodeList(prop->children);
6224 prop->children = NULL;
6225 prop->last = NULL;
6226 prop->ns = ns;
6227 if (value != NULL) {
6228 xmlChar *buffer;
6229 xmlNodePtr tmp;
6230
6231 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6232 prop->children = xmlStringGetNodeList(node->doc, buffer);
6233 prop->last = NULL;
6234 tmp = prop->children;
6235 while (tmp != NULL) {
6236 tmp->parent = (xmlNodePtr) prop;
6237 if (tmp->next == NULL)
6238 prop->last = tmp;
6239 tmp = tmp->next;
6240 }
6241 xmlFree(buffer);
6242 }
6243 return(prop);
6244 }
6245 prop = prop->next;
6246 }
6247 prop = xmlNewNsProp(node, ns, name, value);
6248 return(prop);
6249}
6250
6251/**
Daniel Veillard75bea542001-05-11 17:41:21 +00006252 * xmlUnsetNsProp:
6253 * @node: the node
6254 * @ns: the namespace definition
6255 * @name: the attribute name
6256 *
6257 * Remove an attribute carried by a node.
6258 * Returns 0 if successful, -1 if not found
6259 */
6260int
6261xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
6262 xmlAttrPtr prop = node->properties, prev = NULL;;
6263
6264 if ((node == NULL) || (name == NULL))
6265 return(-1);
6266 if (ns == NULL)
6267 return(xmlUnsetProp(node, name));
6268 if (ns->href == NULL)
6269 return(-1);
6270 while (prop != NULL) {
6271 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00006272 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006273 if (prev == NULL)
6274 node->properties = prop->next;
6275 else
6276 prev->next = prop->next;
6277 xmlFreeProp(prop);
6278 return(0);
6279 }
6280 prev = prop;
6281 prop = prop->next;
6282 }
6283 return(-1);
6284}
Daniel Veillard652327a2003-09-29 18:02:38 +00006285#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006286
6287/**
Owen Taylor3473f882001-02-23 17:55:21 +00006288 * xmlNodeIsText:
6289 * @node: the node
6290 *
6291 * Is this node a Text node ?
6292 * Returns 1 yes, 0 no
6293 */
6294int
6295xmlNodeIsText(xmlNodePtr node) {
6296 if (node == NULL) return(0);
6297
6298 if (node->type == XML_TEXT_NODE) return(1);
6299 return(0);
6300}
6301
6302/**
6303 * xmlIsBlankNode:
6304 * @node: the node
6305 *
6306 * Checks whether this node is an empty or whitespace only
6307 * (and possibly ignorable) text-node.
6308 *
6309 * Returns 1 yes, 0 no
6310 */
6311int
6312xmlIsBlankNode(xmlNodePtr node) {
6313 const xmlChar *cur;
6314 if (node == NULL) return(0);
6315
Daniel Veillard7db37732001-07-12 01:20:08 +00006316 if ((node->type != XML_TEXT_NODE) &&
6317 (node->type != XML_CDATA_SECTION_NODE))
6318 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006319 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006320 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006321 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006322 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006323 cur++;
6324 }
6325
6326 return(1);
6327}
6328
6329/**
6330 * xmlTextConcat:
6331 * @node: the node
6332 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006333 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006334 *
6335 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006336 *
6337 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006338 */
6339
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006340int
Owen Taylor3473f882001-02-23 17:55:21 +00006341xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006342 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006343
6344 if ((node->type != XML_TEXT_NODE) &&
6345 (node->type != XML_CDATA_SECTION_NODE)) {
6346#ifdef DEBUG_TREE
6347 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006348 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006349#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006350 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006351 }
Owen Taylor3473f882001-02-23 17:55:21 +00006352 node->content = xmlStrncat(node->content, content, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006353 if (node->content == NULL)
6354 return(-1);
6355 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006356}
6357
6358/************************************************************************
6359 * *
6360 * Output : to a FILE or in memory *
6361 * *
6362 ************************************************************************/
6363
Owen Taylor3473f882001-02-23 17:55:21 +00006364/**
6365 * xmlBufferCreate:
6366 *
6367 * routine to create an XML buffer.
6368 * returns the new structure.
6369 */
6370xmlBufferPtr
6371xmlBufferCreate(void) {
6372 xmlBufferPtr ret;
6373
6374 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6375 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006376 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006377 return(NULL);
6378 }
6379 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006380 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006381 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006382 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006383 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006384 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006385 xmlFree(ret);
6386 return(NULL);
6387 }
6388 ret->content[0] = 0;
6389 return(ret);
6390}
6391
6392/**
6393 * xmlBufferCreateSize:
6394 * @size: initial size of buffer
6395 *
6396 * routine to create an XML buffer.
6397 * returns the new structure.
6398 */
6399xmlBufferPtr
6400xmlBufferCreateSize(size_t size) {
6401 xmlBufferPtr ret;
6402
6403 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6404 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006405 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006406 return(NULL);
6407 }
6408 ret->use = 0;
6409 ret->alloc = xmlBufferAllocScheme;
6410 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6411 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006412 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006413 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006414 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006415 xmlFree(ret);
6416 return(NULL);
6417 }
6418 ret->content[0] = 0;
6419 } else
6420 ret->content = NULL;
6421 return(ret);
6422}
6423
6424/**
Daniel Veillard53350552003-09-18 13:35:51 +00006425 * xmlBufferCreateStatic:
6426 * @mem: the memory area
6427 * @size: the size in byte
6428 *
6429 * routine to create an XML buffer from an immutable memory area,
6430 * The are won't be modified nor copied, and is expected to be
6431 * present until the end of the buffer lifetime.
6432 *
6433 * returns the new structure.
6434 */
6435xmlBufferPtr
6436xmlBufferCreateStatic(void *mem, size_t size) {
6437 xmlBufferPtr ret;
6438
6439 if ((mem == NULL) || (size == 0))
6440 return(NULL);
6441
6442 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6443 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006444 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00006445 return(NULL);
6446 }
6447 ret->use = size;
6448 ret->size = size;
6449 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6450 ret->content = (xmlChar *) mem;
6451 return(ret);
6452}
6453
6454/**
Owen Taylor3473f882001-02-23 17:55:21 +00006455 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006456 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006457 * @scheme: allocation scheme to use
6458 *
6459 * Sets the allocation scheme for this buffer
6460 */
6461void
6462xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6463 xmlBufferAllocationScheme scheme) {
6464 if (buf == NULL) {
6465#ifdef DEBUG_BUFFER
6466 xmlGenericError(xmlGenericErrorContext,
6467 "xmlBufferSetAllocationScheme: buf == NULL\n");
6468#endif
6469 return;
6470 }
Daniel Veillard53350552003-09-18 13:35:51 +00006471 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006472
6473 buf->alloc = scheme;
6474}
6475
6476/**
6477 * xmlBufferFree:
6478 * @buf: the buffer to free
6479 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006480 * Frees an XML buffer. It frees both the content and the structure which
6481 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006482 */
6483void
6484xmlBufferFree(xmlBufferPtr buf) {
6485 if (buf == NULL) {
6486#ifdef DEBUG_BUFFER
6487 xmlGenericError(xmlGenericErrorContext,
6488 "xmlBufferFree: buf == NULL\n");
6489#endif
6490 return;
6491 }
Daniel Veillard53350552003-09-18 13:35:51 +00006492
6493 if ((buf->content != NULL) &&
6494 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006495 xmlFree(buf->content);
6496 }
Owen Taylor3473f882001-02-23 17:55:21 +00006497 xmlFree(buf);
6498}
6499
6500/**
6501 * xmlBufferEmpty:
6502 * @buf: the buffer
6503 *
6504 * empty a buffer.
6505 */
6506void
6507xmlBufferEmpty(xmlBufferPtr buf) {
6508 if (buf->content == NULL) return;
6509 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006510 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00006511 buf->content = BAD_CAST "";
Daniel Veillard53350552003-09-18 13:35:51 +00006512 } else {
6513 memset(buf->content, 0, buf->size);
6514 }
Owen Taylor3473f882001-02-23 17:55:21 +00006515}
6516
6517/**
6518 * xmlBufferShrink:
6519 * @buf: the buffer to dump
6520 * @len: the number of xmlChar to remove
6521 *
6522 * Remove the beginning of an XML buffer.
6523 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006524 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006525 */
6526int
6527xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
6528 if (len == 0) return(0);
6529 if (len > buf->use) return(-1);
6530
6531 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006532 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6533 buf->content += len;
6534 } else {
6535 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6536 buf->content[buf->use] = 0;
6537 }
Owen Taylor3473f882001-02-23 17:55:21 +00006538 return(len);
6539}
6540
6541/**
6542 * xmlBufferGrow:
6543 * @buf: the buffer
6544 * @len: the minimum free size to allocate
6545 *
6546 * Grow the available space of an XML buffer.
6547 *
6548 * Returns the new available space or -1 in case of error
6549 */
6550int
6551xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6552 int size;
6553 xmlChar *newbuf;
6554
Daniel Veillard53350552003-09-18 13:35:51 +00006555 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006556 if (len + buf->use < buf->size) return(0);
6557
6558 size = buf->use + len + 100;
6559
6560 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006561 if (newbuf == NULL) {
6562 xmlTreeErrMemory("growing buffer");
6563 return(-1);
6564 }
Owen Taylor3473f882001-02-23 17:55:21 +00006565 buf->content = newbuf;
6566 buf->size = size;
6567 return(buf->size - buf->use);
6568}
6569
6570/**
6571 * xmlBufferDump:
6572 * @file: the file output
6573 * @buf: the buffer to dump
6574 *
6575 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006576 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006577 */
6578int
6579xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6580 int ret;
6581
6582 if (buf == NULL) {
6583#ifdef DEBUG_BUFFER
6584 xmlGenericError(xmlGenericErrorContext,
6585 "xmlBufferDump: buf == NULL\n");
6586#endif
6587 return(0);
6588 }
6589 if (buf->content == NULL) {
6590#ifdef DEBUG_BUFFER
6591 xmlGenericError(xmlGenericErrorContext,
6592 "xmlBufferDump: buf->content == NULL\n");
6593#endif
6594 return(0);
6595 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006596 if (file == NULL)
6597 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006598 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6599 return(ret);
6600}
6601
6602/**
6603 * xmlBufferContent:
6604 * @buf: the buffer
6605 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006606 * Function to extract the content of a buffer
6607 *
Owen Taylor3473f882001-02-23 17:55:21 +00006608 * Returns the internal content
6609 */
6610
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006611const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006612xmlBufferContent(const xmlBufferPtr buf)
6613{
6614 if(!buf)
6615 return NULL;
6616
6617 return buf->content;
6618}
6619
6620/**
6621 * xmlBufferLength:
6622 * @buf: the buffer
6623 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006624 * Function to get the length of a buffer
6625 *
Owen Taylor3473f882001-02-23 17:55:21 +00006626 * Returns the length of data in the internal content
6627 */
6628
6629int
6630xmlBufferLength(const xmlBufferPtr buf)
6631{
6632 if(!buf)
6633 return 0;
6634
6635 return buf->use;
6636}
6637
6638/**
6639 * xmlBufferResize:
6640 * @buf: the buffer to resize
6641 * @size: the desired size
6642 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006643 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006644 *
6645 * Returns 0 in case of problems, 1 otherwise
6646 */
6647int
6648xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6649{
6650 unsigned int newSize;
6651 xmlChar* rebuf = NULL;
6652
Daniel Veillard53350552003-09-18 13:35:51 +00006653 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6654
Owen Taylor3473f882001-02-23 17:55:21 +00006655 /*take care of empty case*/
6656 newSize = (buf->size ? buf->size*2 : size);
6657
6658 /* Don't resize if we don't have to */
6659 if (size < buf->size)
6660 return 1;
6661
6662 /* figure out new size */
6663 switch (buf->alloc){
6664 case XML_BUFFER_ALLOC_DOUBLEIT:
6665 while (size > newSize) newSize *= 2;
6666 break;
6667 case XML_BUFFER_ALLOC_EXACT:
6668 newSize = size+10;
6669 break;
6670 default:
6671 newSize = size+10;
6672 break;
6673 }
6674
6675 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006676 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006677 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006678 rebuf = (xmlChar *) xmlRealloc(buf->content,
6679 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006680 } else {
6681 /*
6682 * if we are reallocating a buffer far from being full, it's
6683 * better to make a new allocation and copy only the used range
6684 * and free the old one.
6685 */
6686 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6687 if (rebuf != NULL) {
6688 memcpy(rebuf, buf->content, buf->use);
6689 xmlFree(buf->content);
6690 }
Daniel Veillarde5984082003-08-19 22:21:13 +00006691 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006692 }
Owen Taylor3473f882001-02-23 17:55:21 +00006693 if (rebuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006694 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006695 return 0;
6696 }
6697 buf->content = rebuf;
6698 buf->size = newSize;
6699
6700 return 1;
6701}
6702
6703/**
6704 * xmlBufferAdd:
6705 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006706 * @str: the #xmlChar string
6707 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006708 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006709 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006710 * str is recomputed.
6711 */
6712void
6713xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6714 unsigned int needSize;
6715
6716 if (str == NULL) {
6717#ifdef DEBUG_BUFFER
6718 xmlGenericError(xmlGenericErrorContext,
6719 "xmlBufferAdd: str == NULL\n");
6720#endif
6721 return;
6722 }
Daniel Veillard53350552003-09-18 13:35:51 +00006723 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006724 if (len < -1) {
6725#ifdef DEBUG_BUFFER
6726 xmlGenericError(xmlGenericErrorContext,
6727 "xmlBufferAdd: len < 0\n");
6728#endif
6729 return;
6730 }
6731 if (len == 0) return;
6732
6733 if (len < 0)
6734 len = xmlStrlen(str);
6735
6736 if (len <= 0) return;
6737
6738 needSize = buf->use + len + 2;
6739 if (needSize > buf->size){
6740 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006741 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006742 return;
6743 }
6744 }
6745
6746 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6747 buf->use += len;
6748 buf->content[buf->use] = 0;
6749}
6750
6751/**
6752 * xmlBufferAddHead:
6753 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006754 * @str: the #xmlChar string
6755 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006756 *
6757 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006758 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00006759 */
6760void
6761xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6762 unsigned int needSize;
6763
Daniel Veillard53350552003-09-18 13:35:51 +00006764 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006765 if (str == NULL) {
6766#ifdef DEBUG_BUFFER
6767 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006768 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006769#endif
6770 return;
6771 }
6772 if (len < -1) {
6773#ifdef DEBUG_BUFFER
6774 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006775 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006776#endif
6777 return;
6778 }
6779 if (len == 0) return;
6780
6781 if (len < 0)
6782 len = xmlStrlen(str);
6783
6784 if (len <= 0) return;
6785
6786 needSize = buf->use + len + 2;
6787 if (needSize > buf->size){
6788 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006789 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006790 return;
6791 }
6792 }
6793
6794 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6795 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6796 buf->use += len;
6797 buf->content[buf->use] = 0;
6798}
6799
6800/**
6801 * xmlBufferCat:
6802 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006803 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006804 *
6805 * Append a zero terminated string to an XML buffer.
6806 */
6807void
6808xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillard53350552003-09-18 13:35:51 +00006809 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006810 if (str != NULL)
6811 xmlBufferAdd(buf, str, -1);
6812}
6813
6814/**
6815 * xmlBufferCCat:
6816 * @buf: the buffer to dump
6817 * @str: the C char string
6818 *
6819 * Append a zero terminated C string to an XML buffer.
6820 */
6821void
6822xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6823 const char *cur;
6824
Daniel Veillard53350552003-09-18 13:35:51 +00006825 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006826 if (str == NULL) {
6827#ifdef DEBUG_BUFFER
6828 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006829 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006830#endif
6831 return;
6832 }
6833 for (cur = str;*cur != 0;cur++) {
6834 if (buf->use + 10 >= buf->size) {
6835 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006836 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006837 return;
6838 }
6839 }
6840 buf->content[buf->use++] = *cur;
6841 }
6842 buf->content[buf->use] = 0;
6843}
6844
6845/**
6846 * xmlBufferWriteCHAR:
6847 * @buf: the XML buffer
6848 * @string: the string to add
6849 *
6850 * routine which manages and grows an output buffer. This one adds
6851 * xmlChars at the end of the buffer.
6852 */
6853void
Daniel Veillard53350552003-09-18 13:35:51 +00006854xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
6855 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006856 xmlBufferCat(buf, string);
6857}
6858
6859/**
6860 * xmlBufferWriteChar:
6861 * @buf: the XML buffer output
6862 * @string: the string to add
6863 *
6864 * routine which manage and grows an output buffer. This one add
6865 * C chars at the end of the array.
6866 */
6867void
6868xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillard53350552003-09-18 13:35:51 +00006869 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006870 xmlBufferCCat(buf, string);
6871}
6872
6873
6874/**
6875 * xmlBufferWriteQuotedString:
6876 * @buf: the XML buffer output
6877 * @string: the string to add
6878 *
6879 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00006880 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00006881 * quote or double-quotes internally
6882 */
6883void
6884xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00006885 const xmlChar *cur, *base;
Daniel Veillard53350552003-09-18 13:35:51 +00006886 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00006887 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00006888 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00006889#ifdef DEBUG_BUFFER
6890 xmlGenericError(xmlGenericErrorContext,
6891 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
6892#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00006893 xmlBufferCCat(buf, "\"");
6894 base = cur = string;
6895 while(*cur != 0){
6896 if(*cur == '"'){
6897 if (base != cur)
6898 xmlBufferAdd(buf, base, cur - base);
6899 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6900 cur++;
6901 base = cur;
6902 }
6903 else {
6904 cur++;
6905 }
6906 }
6907 if (base != cur)
6908 xmlBufferAdd(buf, base, cur - base);
6909 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006910 }
Daniel Veillard39057f42003-08-04 01:33:43 +00006911 else{
6912 xmlBufferCCat(buf, "\'");
6913 xmlBufferCat(buf, string);
6914 xmlBufferCCat(buf, "\'");
6915 }
Owen Taylor3473f882001-02-23 17:55:21 +00006916 } else {
6917 xmlBufferCCat(buf, "\"");
6918 xmlBufferCat(buf, string);
6919 xmlBufferCCat(buf, "\"");
6920 }
6921}
6922
6923
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00006924#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00006925/************************************************************************
6926 * *
Daniel Veillarde2238d52003-10-09 13:14:55 +00006927 * Output error handlers *
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006928 * *
6929 ************************************************************************/
6930/**
6931 * xmlSaveErrMemory:
6932 * @extra: extra informations
6933 *
6934 * Handle an out of memory condition
6935 */
6936static void
6937xmlSaveErrMemory(const char *extra)
6938{
6939 __xmlSimpleError(XML_FROM_OUTPUT, XML_ERR_NO_MEMORY, NULL, NULL, extra);
6940}
6941
6942/**
6943 * xmlSaveErr:
6944 * @code: the error number
6945 * @node: the location of the error.
6946 * @extra: extra informations
6947 *
6948 * Handle an out of memory condition
6949 */
6950static void
6951xmlSaveErr(int code, xmlNodePtr node, const char *extra)
6952{
6953 const char *msg = NULL;
6954
6955 switch(code) {
6956 case XML_SAVE_NOT_UTF8:
6957 msg = "string is not in UTF-8";
6958 break;
6959 case XML_SAVE_CHAR_INVALID:
6960 msg = "invalid character value";
6961 break;
6962 case XML_SAVE_UNKNOWN_ENCODING:
6963 msg = "unknown encoding %s";
6964 break;
Daniel Veillarde2238d52003-10-09 13:14:55 +00006965 case XML_SAVE_NO_DOCTYPE:
6966 msg = "document has no DOCTYPE";
6967 break;
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006968 default:
6969 msg = "unexpected error number";
6970 }
Daniel Veillarde2238d52003-10-09 13:14:55 +00006971 __xmlSimpleError(XML_FROM_OUTPUT, code, node, msg, extra);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006972}
6973/************************************************************************
6974 * *
Owen Taylor3473f882001-02-23 17:55:21 +00006975 * Dumping XML tree content to a simple buffer *
6976 * *
6977 ************************************************************************/
6978
Owen Taylor3473f882001-02-23 17:55:21 +00006979/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00006980 * xmlAttrSerializeContent:
6981 * @buf: the XML buffer output
6982 * @doc: the document
6983 * @attr: the attribute pointer
6984 *
6985 * Serialize the attribute in the buffer
6986 */
6987static void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006988xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr)
6989{
Daniel Veillarda6d05382002-02-13 13:07:41 +00006990 const xmlChar *cur, *base;
6991 xmlNodePtr children;
6992
6993 children = attr->children;
6994 while (children != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006995 switch (children->type) {
6996 case XML_TEXT_NODE:
6997 base = cur = children->content;
6998 while (*cur != 0) {
6999 if (*cur == '\n') {
7000 if (base != cur)
7001 xmlBufferAdd(buf, base, cur - base);
7002 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
7003 cur++;
7004 base = cur;
Daniel Veillard0046c0f2003-02-23 13:52:30 +00007005 } else if (*cur == '\r') {
7006 if (base != cur)
7007 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00007008 xmlBufferAdd(buf, BAD_CAST "&#13;", 5);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00007009 cur++;
7010 base = cur;
7011 } else if (*cur == '\t') {
7012 if (base != cur)
7013 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00007014 xmlBufferAdd(buf, BAD_CAST "&#9;", 4);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00007015 cur++;
7016 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00007017#if 0
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007018 } else if (*cur == '\'') {
7019 if (base != cur)
7020 xmlBufferAdd(buf, base, cur - base);
7021 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
7022 cur++;
7023 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00007024#endif
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 "&quot;", 6);
7029 cur++;
7030 base = cur;
7031 } else if (*cur == '<') {
7032 if (base != cur)
7033 xmlBufferAdd(buf, base, cur - base);
7034 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
7035 cur++;
7036 base = cur;
7037 } else if (*cur == '>') {
7038 if (base != cur)
7039 xmlBufferAdd(buf, base, cur - base);
7040 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
7041 cur++;
7042 base = cur;
7043 } else if (*cur == '&') {
7044 if (base != cur)
7045 xmlBufferAdd(buf, base, cur - base);
7046 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
7047 cur++;
7048 base = cur;
7049 } else if ((*cur >= 0x80) && ((doc == NULL) ||
7050 (doc->encoding ==
7051 NULL))) {
7052 /*
7053 * We assume we have UTF-8 content.
7054 */
7055 char tmp[10];
7056 int val = 0, l = 1;
Daniel Veillarda6d05382002-02-13 13:07:41 +00007057
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007058 if (base != cur)
7059 xmlBufferAdd(buf, base, cur - base);
7060 if (*cur < 0xC0) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007061 xmlSaveErr(XML_SAVE_NOT_UTF8, (xmlNodePtr) attr,
7062 NULL);
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007063 if (doc != NULL)
7064 doc->encoding =
7065 xmlStrdup(BAD_CAST "ISO-8859-1");
7066 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
7067 tmp[sizeof(tmp) - 1] = 0;
7068 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
7069 cur++;
7070 base = cur;
7071 continue;
7072 } else if (*cur < 0xE0) {
7073 val = (cur[0]) & 0x1F;
7074 val <<= 6;
7075 val |= (cur[1]) & 0x3F;
7076 l = 2;
7077 } else if (*cur < 0xF0) {
7078 val = (cur[0]) & 0x0F;
7079 val <<= 6;
7080 val |= (cur[1]) & 0x3F;
7081 val <<= 6;
7082 val |= (cur[2]) & 0x3F;
7083 l = 3;
7084 } else if (*cur < 0xF8) {
7085 val = (cur[0]) & 0x07;
7086 val <<= 6;
7087 val |= (cur[1]) & 0x3F;
7088 val <<= 6;
7089 val |= (cur[2]) & 0x3F;
7090 val <<= 6;
7091 val |= (cur[3]) & 0x3F;
7092 l = 4;
7093 }
7094 if ((l == 1) || (!IS_CHAR(val))) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007095 xmlSaveErr(XML_SAVE_CHAR_INVALID, (xmlNodePtr) attr,
7096 NULL);
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007097 if (doc != NULL)
7098 doc->encoding =
7099 xmlStrdup(BAD_CAST "ISO-8859-1");
7100 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
7101 tmp[sizeof(tmp) - 1] = 0;
7102 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
7103 cur++;
7104 base = cur;
7105 continue;
7106 }
7107 /*
7108 * We could do multiple things here. Just save
7109 * as a char ref
7110 */
7111 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
7112 tmp[sizeof(tmp) - 1] = 0;
7113 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
7114 cur += l;
7115 base = cur;
7116 } else {
7117 cur++;
7118 }
7119 }
7120 if (base != cur)
7121 xmlBufferAdd(buf, base, cur - base);
7122 break;
7123 case XML_ENTITY_REF_NODE:
7124 xmlBufferAdd(buf, BAD_CAST "&", 1);
7125 xmlBufferAdd(buf, children->name,
7126 xmlStrlen(children->name));
7127 xmlBufferAdd(buf, BAD_CAST ";", 1);
7128 break;
7129 default:
7130 /* should not happen unless we have a badly built tree */
7131 break;
7132 }
7133 children = children->next;
Owen Taylor3473f882001-02-23 17:55:21 +00007134 }
7135}
7136
7137/**
7138 * xmlNodeDump:
7139 * @buf: the XML buffer output
7140 * @doc: the document
7141 * @cur: the current node
7142 * @level: the imbrication level for indenting
7143 * @format: is formatting allowed
7144 *
7145 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007146 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007147 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007148 *
7149 * Returns the number of bytes written to the buffer or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00007150 */
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007151int
Owen Taylor3473f882001-02-23 17:55:21 +00007152xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007153 int format)
7154{
7155 unsigned int use;
7156 int ret;
7157 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00007158
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007159 xmlInitParser();
7160
Owen Taylor3473f882001-02-23 17:55:21 +00007161 if (cur == NULL) {
7162#ifdef DEBUG_TREE
7163 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007164 "xmlNodeDump : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007165#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007166 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007167 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007168 if (buf == NULL) {
7169#ifdef DEBUG_TREE
7170 xmlGenericError(xmlGenericErrorContext,
7171 "xmlNodeDump : buf == NULL\n");
7172#endif
7173 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007174 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007175 outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
7176 if (outbuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007177 xmlSaveErrMemory("creating buffer");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007178 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007179 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007180 memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
7181 outbuf->buffer = buf;
7182 outbuf->encoder = NULL;
7183 outbuf->writecallback = NULL;
7184 outbuf->closecallback = NULL;
7185 outbuf->context = NULL;
7186 outbuf->written = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007187
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007188 use = buf->use;
7189 xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
7190 xmlFree(outbuf);
7191 ret = buf->use - use;
7192 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00007193}
7194
7195/**
7196 * xmlElemDump:
7197 * @f: the FILE * for the output
7198 * @doc: the document
7199 * @cur: the current node
7200 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007201 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00007202 */
7203void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007204xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur)
7205{
7206 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00007207
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007208 xmlInitParser();
7209
Owen Taylor3473f882001-02-23 17:55:21 +00007210 if (cur == NULL) {
7211#ifdef DEBUG_TREE
7212 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007213 "xmlElemDump : cur == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007214#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007215 return;
Owen Taylor3473f882001-02-23 17:55:21 +00007216 }
Owen Taylor3473f882001-02-23 17:55:21 +00007217#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007218 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00007219 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007220 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007221 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007222#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007223
7224 outbuf = xmlOutputBufferCreateFile(f, NULL);
7225 if (outbuf == NULL)
7226 return;
7227 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007228#ifdef LIBXML_HTML_ENABLED
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007229 htmlNodeDumpOutput(outbuf, doc, cur, NULL);
7230#else
Daniel Veillard2189b592003-10-21 00:08:42 +00007231 xmlSaveErr(XML_ERR_INTERNAL_ERROR, cur, "HTML support not compiled in\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007232#endif /* LIBXML_HTML_ENABLED */
7233 } else
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007234 xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL);
7235 xmlOutputBufferClose(outbuf);
Owen Taylor3473f882001-02-23 17:55:21 +00007236}
7237
7238/************************************************************************
7239 * *
7240 * Dumping XML tree content to an I/O output buffer *
7241 * *
7242 ************************************************************************/
7243
Daniel Veillard4432df22003-09-28 18:58:27 +00007244#ifdef LIBXML_HTML_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00007245static void
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007246xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7247 int level, int format, const char *encoding);
Daniel Veillard4432df22003-09-28 18:58:27 +00007248#endif
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007249static void
Owen Taylor3473f882001-02-23 17:55:21 +00007250xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7251 int level, int format, const char *encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007252static void
7253xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
7254 xmlNodePtr cur, int level, int format, const char *encoding);
7255
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00007256void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
7257
Owen Taylor3473f882001-02-23 17:55:21 +00007258/**
7259 * xmlNsDumpOutput:
7260 * @buf: the XML buffer output
7261 * @cur: a namespace
7262 *
7263 * Dump a local Namespace definition.
7264 * Should be called in the context of attributes dumps.
7265 */
7266static void
7267xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
7268 if (cur == NULL) {
7269#ifdef DEBUG_TREE
7270 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007271 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007272#endif
7273 return;
7274 }
7275 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00007276 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
7277 return;
7278
Owen Taylor3473f882001-02-23 17:55:21 +00007279 /* Within the context of an element attributes */
7280 if (cur->prefix != NULL) {
7281 xmlOutputBufferWriteString(buf, " xmlns:");
7282 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
7283 } else
7284 xmlOutputBufferWriteString(buf, " xmlns");
7285 xmlOutputBufferWriteString(buf, "=");
7286 xmlBufferWriteQuotedString(buf->buffer, cur->href);
7287 }
7288}
7289
7290/**
7291 * xmlNsListDumpOutput:
7292 * @buf: the XML buffer output
7293 * @cur: the first namespace
7294 *
7295 * Dump a list of local Namespace definitions.
7296 * Should be called in the context of attributes dumps.
7297 */
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00007298void
Owen Taylor3473f882001-02-23 17:55:21 +00007299xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
7300 while (cur != NULL) {
7301 xmlNsDumpOutput(buf, cur);
7302 cur = cur->next;
7303 }
7304}
7305
7306/**
7307 * xmlDtdDumpOutput:
7308 * @buf: the XML buffer output
7309 * @doc: the document
7310 * @encoding: an optional encoding string
7311 *
7312 * Dump the XML document DTD, if any.
7313 */
7314static void
7315xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
7316 if (dtd == NULL) {
7317#ifdef DEBUG_TREE
7318 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007319 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007320#endif
7321 return;
7322 }
7323 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
7324 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
7325 if (dtd->ExternalID != NULL) {
7326 xmlOutputBufferWriteString(buf, " PUBLIC ");
7327 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
7328 xmlOutputBufferWriteString(buf, " ");
7329 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
7330 } else if (dtd->SystemID != NULL) {
7331 xmlOutputBufferWriteString(buf, " SYSTEM ");
7332 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
7333 }
7334 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
7335 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
7336 xmlOutputBufferWriteString(buf, ">");
7337 return;
7338 }
7339 xmlOutputBufferWriteString(buf, " [\n");
7340 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
7341 xmlOutputBufferWriteString(buf, "]>");
7342}
7343
7344/**
7345 * xmlAttrDumpOutput:
7346 * @buf: the XML buffer output
7347 * @doc: the document
7348 * @cur: the attribute pointer
7349 * @encoding: an optional encoding string
7350 *
7351 * Dump an XML attribute
7352 */
7353static void
7354xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00007355 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00007356 if (cur == NULL) {
7357#ifdef DEBUG_TREE
7358 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007359 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007360#endif
7361 return;
7362 }
7363 xmlOutputBufferWriteString(buf, " ");
7364 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7365 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7366 xmlOutputBufferWriteString(buf, ":");
7367 }
7368 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00007369 xmlOutputBufferWriteString(buf, "=\"");
7370 xmlAttrSerializeContent(buf->buffer, doc, cur);
7371 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007372}
7373
7374/**
7375 * xmlAttrListDumpOutput:
7376 * @buf: the XML buffer output
7377 * @doc: the document
7378 * @cur: the first attribute pointer
7379 * @encoding: an optional encoding string
7380 *
7381 * Dump a list of XML attributes
7382 */
7383static void
7384xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7385 xmlAttrPtr cur, const char *encoding) {
7386 if (cur == NULL) {
7387#ifdef DEBUG_TREE
7388 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007389 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007390#endif
7391 return;
7392 }
7393 while (cur != NULL) {
7394 xmlAttrDumpOutput(buf, doc, cur, encoding);
7395 cur = cur->next;
7396 }
7397}
7398
7399
7400
7401/**
7402 * xmlNodeListDumpOutput:
7403 * @buf: the XML buffer output
7404 * @doc: the document
7405 * @cur: the first node
7406 * @level: the imbrication level for indenting
7407 * @format: is formatting allowed
7408 * @encoding: an optional encoding string
7409 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007410 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007411 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007412 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007413 */
7414static void
7415xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7416 xmlNodePtr cur, int level, int format, const char *encoding) {
7417 int i;
7418
7419 if (cur == NULL) {
7420#ifdef DEBUG_TREE
7421 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007422 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007423#endif
7424 return;
7425 }
7426 while (cur != NULL) {
7427 if ((format) && (xmlIndentTreeOutput) &&
7428 (cur->type == XML_ELEMENT_NODE))
7429 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007430 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007431 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007432 if (format) {
7433 xmlOutputBufferWriteString(buf, "\n");
7434 }
7435 cur = cur->next;
7436 }
7437}
7438
7439/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007440 * xmlNodeDumpOutputInternal:
Owen Taylor3473f882001-02-23 17:55:21 +00007441 * @buf: the XML buffer output
7442 * @doc: the document
7443 * @cur: the current node
7444 * @level: the imbrication level for indenting
7445 * @format: is formatting allowed
7446 * @encoding: an optional encoding string
7447 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007448 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007449 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007450 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007451 */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007452static void
7453xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
7454 xmlNodePtr cur, int level, int format, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007455 int i;
7456 xmlNodePtr tmp;
Daniel Veillard9475a352003-09-26 12:47:50 +00007457 xmlChar *start, *end;
Owen Taylor3473f882001-02-23 17:55:21 +00007458
7459 if (cur == NULL) {
7460#ifdef DEBUG_TREE
7461 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007462 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007463#endif
7464 return;
7465 }
7466 if (cur->type == XML_XINCLUDE_START)
7467 return;
7468 if (cur->type == XML_XINCLUDE_END)
7469 return;
7470 if (cur->type == XML_DTD_NODE) {
7471 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7472 return;
7473 }
Daniel Veillardcec50a62003-10-28 13:26:51 +00007474 if (cur->type == XML_DOCUMENT_FRAG_NODE) {
7475 xmlNodeListDumpOutput(buf, doc, cur->children, level, format, encoding);
7476 return;
7477 }
Owen Taylor3473f882001-02-23 17:55:21 +00007478 if (cur->type == XML_ELEMENT_DECL) {
7479 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7480 return;
7481 }
7482 if (cur->type == XML_ATTRIBUTE_DECL) {
7483 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7484 return;
7485 }
7486 if (cur->type == XML_ENTITY_DECL) {
7487 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7488 return;
7489 }
7490 if (cur->type == XML_TEXT_NODE) {
7491 if (cur->content != NULL) {
7492 if ((cur->name == xmlStringText) ||
7493 (cur->name != xmlStringTextNoenc)) {
7494 xmlChar *buffer;
7495
Owen Taylor3473f882001-02-23 17:55:21 +00007496 if (encoding == NULL)
7497 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7498 else
7499 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007500 if (buffer != NULL) {
7501 xmlOutputBufferWriteString(buf, (const char *)buffer);
7502 xmlFree(buffer);
7503 }
7504 } else {
7505 /*
7506 * Disable escaping, needed for XSLT
7507 */
Owen Taylor3473f882001-02-23 17:55:21 +00007508 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007509 }
7510 }
7511
7512 return;
7513 }
7514 if (cur->type == XML_PI_NODE) {
7515 if (cur->content != NULL) {
7516 xmlOutputBufferWriteString(buf, "<?");
7517 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7518 if (cur->content != NULL) {
7519 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00007520 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007521 }
7522 xmlOutputBufferWriteString(buf, "?>");
7523 } else {
7524 xmlOutputBufferWriteString(buf, "<?");
7525 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7526 xmlOutputBufferWriteString(buf, "?>");
7527 }
7528 return;
7529 }
7530 if (cur->type == XML_COMMENT_NODE) {
7531 if (cur->content != NULL) {
7532 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00007533 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007534 xmlOutputBufferWriteString(buf, "-->");
7535 }
7536 return;
7537 }
7538 if (cur->type == XML_ENTITY_REF_NODE) {
7539 xmlOutputBufferWriteString(buf, "&");
7540 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7541 xmlOutputBufferWriteString(buf, ";");
7542 return;
7543 }
7544 if (cur->type == XML_CDATA_SECTION_NODE) {
Daniel Veillard9475a352003-09-26 12:47:50 +00007545 start = end = cur->content;
7546 while (*end != '\0') {
7547 if ((*end == ']') && (*(end + 1) == ']') && (*(end + 2) == '>')) {
7548 end = end + 2;
7549 xmlOutputBufferWriteString(buf, "<![CDATA[");
7550 xmlOutputBufferWrite(buf, end - start, (const char *)start);
7551 xmlOutputBufferWriteString(buf, "]]>");
7552 start = end;
7553 }
7554 end++;
7555 }
7556 if (start != end) {
7557 xmlOutputBufferWriteString(buf, "<![CDATA[");
7558 xmlOutputBufferWriteString(buf, (const char *)start);
7559 xmlOutputBufferWriteString(buf, "]]>");
7560 }
Owen Taylor3473f882001-02-23 17:55:21 +00007561 return;
7562 }
Daniel Veillard7b72ee52003-02-27 23:24:53 +00007563 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillarda1a9d042003-03-18 16:53:17 +00007564 xmlAttrDumpOutput(buf,doc, (xmlAttrPtr) cur,encoding);
Daniel Veillard7b72ee52003-02-27 23:24:53 +00007565 return;
7566 }
Daniel Veillard6aa2f602003-02-10 00:01:56 +00007567 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007568 xmlNsDumpOutput(buf, (xmlNsPtr) cur);
Daniel Veillard6aa2f602003-02-10 00:01:56 +00007569 return;
7570 }
Owen Taylor3473f882001-02-23 17:55:21 +00007571
7572 if (format == 1) {
7573 tmp = cur->children;
7574 while (tmp != NULL) {
William M. Brack9ca682f2003-10-19 10:01:59 +00007575 if ((tmp->type == XML_TEXT_NODE) ||
7576 (tmp->type == XML_CDATA_SECTION_NODE) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007577 (tmp->type == XML_ENTITY_REF_NODE)) {
7578 format = 0;
7579 break;
7580 }
7581 tmp = tmp->next;
7582 }
7583 }
7584 xmlOutputBufferWriteString(buf, "<");
7585 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7586 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7587 xmlOutputBufferWriteString(buf, ":");
7588 }
7589
7590 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7591 if (cur->nsDef)
7592 xmlNsListDumpOutput(buf, cur->nsDef);
7593 if (cur->properties != NULL)
7594 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7595
Daniel Veillard7db37732001-07-12 01:20:08 +00007596 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
7597 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007598 xmlOutputBufferWriteString(buf, "/>");
7599 return;
7600 }
7601 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00007602 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007603 xmlChar *buffer;
7604
Owen Taylor3473f882001-02-23 17:55:21 +00007605 if (encoding == NULL)
7606 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7607 else
7608 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007609 if (buffer != NULL) {
7610 xmlOutputBufferWriteString(buf, (const char *)buffer);
7611 xmlFree(buffer);
7612 }
7613 }
7614 if (cur->children != NULL) {
7615 if (format) xmlOutputBufferWriteString(buf, "\n");
7616 xmlNodeListDumpOutput(buf, doc, cur->children,
7617 (level >= 0?level+1:-1), format, encoding);
7618 if ((xmlIndentTreeOutput) && (format))
7619 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007620 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00007621 }
7622 xmlOutputBufferWriteString(buf, "</");
7623 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7624 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7625 xmlOutputBufferWriteString(buf, ":");
7626 }
7627
7628 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7629 xmlOutputBufferWriteString(buf, ">");
7630}
7631
7632/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007633 * xmlNodeDumpOutput:
7634 * @buf: the XML buffer output
7635 * @doc: the document
7636 * @cur: the current node
7637 * @level: the imbrication level for indenting
7638 * @format: is formatting allowed
7639 * @encoding: an optional encoding string
7640 *
7641 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007642 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007643 * or xmlKeepBlanksDefault(0) was called
7644 */
7645void
7646xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007647 int level, int format, const char *encoding)
7648{
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007649#ifdef LIBXML_HTML_ENABLED
7650 xmlDtdPtr dtd;
7651 int is_xhtml = 0;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007652#endif
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007653
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007654 xmlInitParser();
7655
7656#ifdef LIBXML_HTML_ENABLED
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007657 dtd = xmlGetIntSubset(doc);
7658 if (dtd != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007659 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7660 if (is_xhtml < 0)
7661 is_xhtml = 0;
7662 if ((is_xhtml) && (cur->parent == (xmlNodePtr) doc) &&
7663 (cur->type == XML_ELEMENT_NODE) &&
7664 (xmlStrEqual(cur->name, BAD_CAST "html"))) {
7665 if (encoding != NULL)
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007666 htmlSetMetaEncoding((htmlDocPtr) doc,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007667 (const xmlChar *) encoding);
7668 else
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007669 htmlSetMetaEncoding((htmlDocPtr) doc, BAD_CAST "UTF-8");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007670 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007671 }
7672
7673 if (is_xhtml)
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007674 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007675 else
7676#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007677 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007678}
7679
7680/**
Owen Taylor3473f882001-02-23 17:55:21 +00007681 * xmlDocContentDumpOutput:
7682 * @buf: the XML buffer output
7683 * @cur: the document
7684 * @encoding: an optional encoding string
7685 * @format: should formatting spaces been added
7686 *
7687 * Dump an XML document.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007688 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007689 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007690 */
7691static void
7692xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
7693 const char *encoding, int format) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007694#ifdef LIBXML_HTML_ENABLED
7695 xmlDtdPtr dtd;
7696 int is_xhtml = 0;
7697#endif
7698
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007699 xmlInitParser();
7700
Owen Taylor3473f882001-02-23 17:55:21 +00007701 xmlOutputBufferWriteString(buf, "<?xml version=");
7702 if (cur->version != NULL)
7703 xmlBufferWriteQuotedString(buf->buffer, cur->version);
7704 else
7705 xmlOutputBufferWriteString(buf, "\"1.0\"");
7706 if (encoding == NULL) {
7707 if (cur->encoding != NULL)
7708 encoding = (const char *) cur->encoding;
7709 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
7710 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
7711 }
7712 if (encoding != NULL) {
7713 xmlOutputBufferWriteString(buf, " encoding=");
7714 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
7715 }
7716 switch (cur->standalone) {
7717 case 0:
7718 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
7719 break;
7720 case 1:
7721 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
7722 break;
7723 }
7724 xmlOutputBufferWriteString(buf, "?>\n");
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007725
7726#ifdef LIBXML_HTML_ENABLED
7727 dtd = xmlGetIntSubset(cur);
7728 if (dtd != NULL) {
7729 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7730 if (is_xhtml < 0) is_xhtml = 0;
7731 }
7732 if (is_xhtml) {
7733 if (encoding != NULL)
7734 htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
7735 else
7736 htmlSetMetaEncoding(cur, BAD_CAST "UTF-8");
7737 }
7738#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007739 if (cur->children != NULL) {
7740 xmlNodePtr child = cur->children;
7741
7742 while (child != NULL) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007743#ifdef LIBXML_HTML_ENABLED
7744 if (is_xhtml)
7745 xhtmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
7746 else
7747#endif
7748 xmlNodeDumpOutputInternal(buf, cur, child, 0, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007749 xmlOutputBufferWriteString(buf, "\n");
7750 child = child->next;
7751 }
7752 }
7753}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007754#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00007755
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007756#ifdef LIBXML_HTML_ENABLED
7757/************************************************************************
7758 * *
7759 * Functions specific to XHTML serialization *
7760 * *
7761 ************************************************************************/
7762
7763#define XHTML_STRICT_PUBLIC_ID BAD_CAST \
7764 "-//W3C//DTD XHTML 1.0 Strict//EN"
7765#define XHTML_STRICT_SYSTEM_ID BAD_CAST \
7766 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
7767#define XHTML_FRAME_PUBLIC_ID BAD_CAST \
7768 "-//W3C//DTD XHTML 1.0 Frameset//EN"
7769#define XHTML_FRAME_SYSTEM_ID BAD_CAST \
7770 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
7771#define XHTML_TRANS_PUBLIC_ID BAD_CAST \
7772 "-//W3C//DTD XHTML 1.0 Transitional//EN"
7773#define XHTML_TRANS_SYSTEM_ID BAD_CAST \
7774 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
7775
7776#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
7777/**
7778 * xmlIsXHTML:
7779 * @systemID: the system identifier
7780 * @publicID: the public identifier
7781 *
7782 * Try to find if the document correspond to an XHTML DTD
7783 *
7784 * Returns 1 if true, 0 if not and -1 in case of error
7785 */
7786int
7787xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) {
7788 if ((systemID == NULL) && (publicID == NULL))
7789 return(-1);
7790 if (publicID != NULL) {
7791 if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1);
7792 if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1);
7793 if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1);
7794 }
7795 if (systemID != NULL) {
7796 if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1);
7797 if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1);
7798 if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1);
7799 }
7800 return(0);
7801}
7802
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007803#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007804/**
7805 * xhtmlIsEmpty:
7806 * @node: the node
7807 *
7808 * Check if a node is an empty xhtml node
7809 *
7810 * Returns 1 if the node is an empty node, 0 if not and -1 in case of error
7811 */
7812static int
7813xhtmlIsEmpty(xmlNodePtr node) {
7814 if (node == NULL)
7815 return(-1);
7816 if (node->type != XML_ELEMENT_NODE)
7817 return(0);
7818 if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME)))
7819 return(0);
7820 if (node->children != NULL)
7821 return(0);
7822 switch (node->name[0]) {
7823 case 'a':
7824 if (xmlStrEqual(node->name, BAD_CAST "area"))
7825 return(1);
7826 return(0);
7827 case 'b':
7828 if (xmlStrEqual(node->name, BAD_CAST "br"))
7829 return(1);
7830 if (xmlStrEqual(node->name, BAD_CAST "base"))
7831 return(1);
7832 if (xmlStrEqual(node->name, BAD_CAST "basefont"))
7833 return(1);
7834 return(0);
7835 case 'c':
7836 if (xmlStrEqual(node->name, BAD_CAST "col"))
7837 return(1);
7838 return(0);
7839 case 'f':
7840 if (xmlStrEqual(node->name, BAD_CAST "frame"))
7841 return(1);
7842 return(0);
7843 case 'h':
7844 if (xmlStrEqual(node->name, BAD_CAST "hr"))
7845 return(1);
7846 return(0);
7847 case 'i':
7848 if (xmlStrEqual(node->name, BAD_CAST "img"))
7849 return(1);
7850 if (xmlStrEqual(node->name, BAD_CAST "input"))
7851 return(1);
7852 if (xmlStrEqual(node->name, BAD_CAST "isindex"))
7853 return(1);
7854 return(0);
7855 case 'l':
7856 if (xmlStrEqual(node->name, BAD_CAST "link"))
7857 return(1);
7858 return(0);
7859 case 'm':
7860 if (xmlStrEqual(node->name, BAD_CAST "meta"))
7861 return(1);
7862 return(0);
7863 case 'p':
7864 if (xmlStrEqual(node->name, BAD_CAST "param"))
7865 return(1);
7866 return(0);
7867 }
7868 return(0);
7869}
7870
7871/**
7872 * xhtmlAttrListDumpOutput:
7873 * @buf: the XML buffer output
7874 * @doc: the document
7875 * @cur: the first attribute pointer
7876 * @encoding: an optional encoding string
7877 *
7878 * Dump a list of XML attributes
7879 */
7880static void
7881xhtmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7882 xmlAttrPtr cur, const char *encoding) {
7883 xmlAttrPtr xml_lang = NULL;
7884 xmlAttrPtr lang = NULL;
7885 xmlAttrPtr name = NULL;
7886 xmlAttrPtr id = NULL;
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007887 xmlNodePtr parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007888
7889 if (cur == NULL) {
7890#ifdef DEBUG_TREE
7891 xmlGenericError(xmlGenericErrorContext,
7892 "xmlAttrListDumpOutput : property == NULL\n");
7893#endif
7894 return;
7895 }
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007896 parent = cur->parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007897 while (cur != NULL) {
7898 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id")))
7899 id = cur;
7900 else
7901 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name")))
7902 name = cur;
7903 else
7904 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")))
7905 lang = cur;
7906 else
7907 if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) &&
7908 (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml")))
7909 xml_lang = cur;
7910 else if ((cur->ns == NULL) &&
7911 ((cur->children == NULL) ||
7912 (cur->children->content == NULL) ||
7913 (cur->children->content[0] == 0)) &&
7914 (htmlIsBooleanAttr(cur->name))) {
7915 if (cur->children != NULL)
7916 xmlFreeNode(cur->children);
7917 cur->children = xmlNewText(cur->name);
7918 if (cur->children != NULL)
7919 cur->children->parent = (xmlNodePtr) cur;
7920 }
7921 xmlAttrDumpOutput(buf, doc, cur, encoding);
7922 cur = cur->next;
7923 }
7924 /*
7925 * C.8
7926 */
7927 if ((name != NULL) && (id == NULL)) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007928 if ((parent != NULL) && (parent->name != NULL) &&
7929 ((xmlStrEqual(parent->name, BAD_CAST "a")) ||
7930 (xmlStrEqual(parent->name, BAD_CAST "p")) ||
7931 (xmlStrEqual(parent->name, BAD_CAST "div")) ||
7932 (xmlStrEqual(parent->name, BAD_CAST "img")) ||
7933 (xmlStrEqual(parent->name, BAD_CAST "map")) ||
7934 (xmlStrEqual(parent->name, BAD_CAST "applet")) ||
7935 (xmlStrEqual(parent->name, BAD_CAST "form")) ||
7936 (xmlStrEqual(parent->name, BAD_CAST "frame")) ||
7937 (xmlStrEqual(parent->name, BAD_CAST "iframe")))) {
7938 xmlOutputBufferWriteString(buf, " id=\"");
7939 xmlAttrSerializeContent(buf->buffer, doc, name);
7940 xmlOutputBufferWriteString(buf, "\"");
7941 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007942 }
7943 /*
7944 * C.7.
7945 */
7946 if ((lang != NULL) && (xml_lang == NULL)) {
7947 xmlOutputBufferWriteString(buf, " xml:lang=\"");
7948 xmlAttrSerializeContent(buf->buffer, doc, lang);
7949 xmlOutputBufferWriteString(buf, "\"");
7950 } else
7951 if ((xml_lang != NULL) && (lang == NULL)) {
7952 xmlOutputBufferWriteString(buf, " lang=\"");
7953 xmlAttrSerializeContent(buf->buffer, doc, xml_lang);
7954 xmlOutputBufferWriteString(buf, "\"");
7955 }
7956}
7957
7958/**
7959 * xhtmlNodeListDumpOutput:
7960 * @buf: the XML buffer output
7961 * @doc: the XHTML document
7962 * @cur: the first node
7963 * @level: the imbrication level for indenting
7964 * @format: is formatting allowed
7965 * @encoding: an optional encoding string
7966 *
7967 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007968 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007969 * or xmlKeepBlanksDefault(0) was called
7970 */
7971static void
7972xhtmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7973 xmlNodePtr cur, int level, int format, const char *encoding) {
7974 int i;
7975
7976 if (cur == NULL) {
7977#ifdef DEBUG_TREE
7978 xmlGenericError(xmlGenericErrorContext,
7979 "xhtmlNodeListDumpOutput : node == NULL\n");
7980#endif
7981 return;
7982 }
7983 while (cur != NULL) {
7984 if ((format) && (xmlIndentTreeOutput) &&
7985 (cur->type == XML_ELEMENT_NODE))
7986 for (i = 0;i < level;i++)
7987 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7988 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
7989 if (format) {
7990 xmlOutputBufferWriteString(buf, "\n");
7991 }
7992 cur = cur->next;
7993 }
7994}
7995
7996/**
7997 * xhtmlNodeDumpOutput:
7998 * @buf: the XML buffer output
7999 * @doc: the XHTML document
8000 * @cur: the current node
8001 * @level: the imbrication level for indenting
8002 * @format: is formatting allowed
8003 * @encoding: an optional encoding string
8004 *
8005 * Dump an XHTML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008006 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00008007 * or xmlKeepBlanksDefault(0) was called
8008 */
8009static void
8010xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
8011 int level, int format, const char *encoding) {
8012 int i;
8013 xmlNodePtr tmp;
Daniel Veillard9475a352003-09-26 12:47:50 +00008014 xmlChar *start, *end;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00008015
8016 if (cur == NULL) {
8017#ifdef DEBUG_TREE
8018 xmlGenericError(xmlGenericErrorContext,
8019 "xmlNodeDumpOutput : node == NULL\n");
8020#endif
8021 return;
8022 }
8023 if (cur->type == XML_XINCLUDE_START)
8024 return;
8025 if (cur->type == XML_XINCLUDE_END)
8026 return;
8027 if (cur->type == XML_DTD_NODE) {
8028 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
8029 return;
8030 }
8031 if (cur->type == XML_ELEMENT_DECL) {
8032 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
8033 return;
8034 }
8035 if (cur->type == XML_ATTRIBUTE_DECL) {
8036 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
8037 return;
8038 }
8039 if (cur->type == XML_ENTITY_DECL) {
8040 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
8041 return;
8042 }
8043 if (cur->type == XML_TEXT_NODE) {
8044 if (cur->content != NULL) {
8045 if ((cur->name == xmlStringText) ||
8046 (cur->name != xmlStringTextNoenc)) {
8047 xmlChar *buffer;
8048
8049 if (encoding == NULL)
8050 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
8051 else
8052 buffer = xmlEncodeSpecialChars(doc, cur->content);
8053 if (buffer != NULL) {
8054 xmlOutputBufferWriteString(buf, (const char *)buffer);
8055 xmlFree(buffer);
8056 }
8057 } else {
8058 /*
8059 * Disable escaping, needed for XSLT
8060 */
8061 xmlOutputBufferWriteString(buf, (const char *) cur->content);
8062 }
8063 }
8064
8065 return;
8066 }
8067 if (cur->type == XML_PI_NODE) {
8068 if (cur->content != NULL) {
8069 xmlOutputBufferWriteString(buf, "<?");
8070 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8071 if (cur->content != NULL) {
8072 xmlOutputBufferWriteString(buf, " ");
8073 xmlOutputBufferWriteString(buf, (const char *)cur->content);
8074 }
8075 xmlOutputBufferWriteString(buf, "?>");
8076 } else {
8077 xmlOutputBufferWriteString(buf, "<?");
8078 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8079 xmlOutputBufferWriteString(buf, "?>");
8080 }
8081 return;
8082 }
8083 if (cur->type == XML_COMMENT_NODE) {
8084 if (cur->content != NULL) {
8085 xmlOutputBufferWriteString(buf, "<!--");
8086 xmlOutputBufferWriteString(buf, (const char *)cur->content);
8087 xmlOutputBufferWriteString(buf, "-->");
8088 }
8089 return;
8090 }
8091 if (cur->type == XML_ENTITY_REF_NODE) {
8092 xmlOutputBufferWriteString(buf, "&");
8093 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8094 xmlOutputBufferWriteString(buf, ";");
8095 return;
8096 }
8097 if (cur->type == XML_CDATA_SECTION_NODE) {
Daniel Veillard9475a352003-09-26 12:47:50 +00008098 start = end = cur->content;
8099 while (*end != '\0') {
8100 if (*end == ']' && *(end + 1) == ']' && *(end + 2) == '>') {
8101 end = end + 2;
8102 xmlOutputBufferWriteString(buf, "<![CDATA[");
8103 xmlOutputBufferWrite(buf, end - start, (const char *)start);
8104 xmlOutputBufferWriteString(buf, "]]>");
8105 start = end;
8106 }
8107 end++;
8108 }
8109 if (start != end) {
8110 xmlOutputBufferWriteString(buf, "<![CDATA[");
8111 xmlOutputBufferWriteString(buf, (const char *)start);
8112 xmlOutputBufferWriteString(buf, "]]>");
8113 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00008114 return;
8115 }
8116
8117 if (format == 1) {
8118 tmp = cur->children;
8119 while (tmp != NULL) {
8120 if ((tmp->type == XML_TEXT_NODE) ||
8121 (tmp->type == XML_ENTITY_REF_NODE)) {
8122 format = 0;
8123 break;
8124 }
8125 tmp = tmp->next;
8126 }
8127 }
8128 xmlOutputBufferWriteString(buf, "<");
8129 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
8130 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
8131 xmlOutputBufferWriteString(buf, ":");
8132 }
8133
8134 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8135 if (cur->nsDef)
8136 xmlNsListDumpOutput(buf, cur->nsDef);
8137 if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
8138 (cur->ns == NULL) && (cur->nsDef == NULL))) {
8139 /*
8140 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
8141 */
8142 xmlOutputBufferWriteString(buf,
8143 " xmlns=\"http://www.w3.org/1999/xhtml\"");
8144 }
8145 if (cur->properties != NULL)
8146 xhtmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
8147
8148 if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) {
8149 if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
8150 (xhtmlIsEmpty(cur) == 1)) {
8151 /*
8152 * C.2. Empty Elements
8153 */
8154 xmlOutputBufferWriteString(buf, " />");
8155 } else {
8156 /*
8157 * C.3. Element Minimization and Empty Element Content
8158 */
8159 xmlOutputBufferWriteString(buf, "></");
8160 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
8161 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
8162 xmlOutputBufferWriteString(buf, ":");
8163 }
8164 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8165 xmlOutputBufferWriteString(buf, ">");
8166 }
8167 return;
8168 }
8169 xmlOutputBufferWriteString(buf, ">");
8170 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
8171 xmlChar *buffer;
8172
8173 if (encoding == NULL)
8174 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
8175 else
8176 buffer = xmlEncodeSpecialChars(doc, cur->content);
8177 if (buffer != NULL) {
8178 xmlOutputBufferWriteString(buf, (const char *)buffer);
8179 xmlFree(buffer);
8180 }
8181 }
8182
8183 /*
8184 * 4.8. Script and Style elements
8185 */
8186 if ((cur->type == XML_ELEMENT_NODE) &&
8187 ((xmlStrEqual(cur->name, BAD_CAST "script")) ||
8188 (xmlStrEqual(cur->name, BAD_CAST "style"))) &&
8189 ((cur->ns == NULL) ||
8190 (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) {
8191 xmlNodePtr child = cur->children;
8192
8193 while (child != NULL) {
8194 if ((child->type == XML_TEXT_NODE) ||
8195 (child->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard64b35282002-12-04 15:10:40 +00008196 /*
8197 * Apparently CDATA escaping for style just break on IE,
8198 * mozilla and galeon, so ...
8199 */
8200 if (xmlStrEqual(cur->name, BAD_CAST "style") &&
8201 (xmlStrchr(child->content, '<') == NULL) &&
8202 (xmlStrchr(child->content, '>') == NULL) &&
8203 (xmlStrchr(child->content, '&') == NULL)) {
8204 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
8205 } else {
Daniel Veillard9475a352003-09-26 12:47:50 +00008206 start = end = child->content;
8207 while (*end != '\0') {
8208 if (*end == ']' &&
8209 *(end + 1) == ']' &&
8210 *(end + 2) == '>') {
8211 end = end + 2;
8212 xmlOutputBufferWriteString(buf, "<![CDATA[");
8213 xmlOutputBufferWrite(buf, end - start,
8214 (const char *)start);
8215 xmlOutputBufferWriteString(buf, "]]>");
8216 start = end;
8217 }
8218 end++;
8219 }
8220 if (start != end) {
8221 xmlOutputBufferWriteString(buf, "<![CDATA[");
8222 xmlOutputBufferWriteString(buf, (const char *)start);
8223 xmlOutputBufferWriteString(buf, "]]>");
8224 }
Daniel Veillard64b35282002-12-04 15:10:40 +00008225 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00008226 } else {
8227 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
8228 }
8229 child = child->next;
8230 }
8231 } else if (cur->children != NULL) {
8232 if (format) xmlOutputBufferWriteString(buf, "\n");
8233 xhtmlNodeListDumpOutput(buf, doc, cur->children,
8234 (level >= 0?level+1:-1), format, encoding);
8235 if ((xmlIndentTreeOutput) && (format))
8236 for (i = 0;i < level;i++)
8237 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
8238 }
8239 xmlOutputBufferWriteString(buf, "</");
8240 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
8241 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
8242 xmlOutputBufferWriteString(buf, ":");
8243 }
8244
8245 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8246 xmlOutputBufferWriteString(buf, ">");
8247}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00008248#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00008249#endif
8250
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00008251#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00008252/************************************************************************
8253 * *
8254 * Saving functions front-ends *
8255 * *
8256 ************************************************************************/
8257
8258/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00008259 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00008260 * @out_doc: Document to generate XML text from
8261 * @doc_txt_ptr: Memory pointer for allocated XML text
8262 * @doc_txt_len: Length of the generated XML text
8263 * @txt_encoding: Character encoding to use when generating XML text
8264 * @format: should formatting spaces been added
8265 *
8266 * Dump the current DOM tree into memory using the character encoding specified
8267 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008268 * allocated memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00008269 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00008270 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008271 */
8272
8273void
8274xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008275 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008276 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00008277 int dummy = 0;
8278
Owen Taylor3473f882001-02-23 17:55:21 +00008279 xmlOutputBufferPtr out_buff = NULL;
8280 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
8281
8282 if (doc_txt_len == NULL) {
8283 doc_txt_len = &dummy; /* Continue, caller just won't get length */
8284 }
8285
8286 if (doc_txt_ptr == NULL) {
8287 *doc_txt_len = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008288 return;
8289 }
8290
8291 *doc_txt_ptr = NULL;
8292 *doc_txt_len = 0;
8293
8294 if (out_doc == NULL) {
8295 /* No document, no output */
Owen Taylor3473f882001-02-23 17:55:21 +00008296 return;
8297 }
8298
8299 /*
8300 * Validate the encoding value, if provided.
8301 * This logic is copied from xmlSaveFileEnc.
8302 */
8303
8304 if (txt_encoding == NULL)
8305 txt_encoding = (const char *) out_doc->encoding;
8306 if (txt_encoding != NULL) {
Daniel Veillarde1326112003-06-05 09:32:20 +00008307 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00008308 if ( conv_hdlr == NULL ) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00008309 xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, (xmlNodePtr) out_doc,
8310 txt_encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00008311 return;
8312 }
8313 }
Owen Taylor3473f882001-02-23 17:55:21 +00008314
8315 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00008316 xmlSaveErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00008317 return;
8318 }
8319
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008320 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008321 xmlOutputBufferFlush(out_buff);
8322 if (out_buff->conv != NULL) {
8323 *doc_txt_len = out_buff->conv->use;
8324 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
8325 } else {
8326 *doc_txt_len = out_buff->buffer->use;
8327 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
8328 }
8329 (void)xmlOutputBufferClose(out_buff);
8330
8331 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
8332 *doc_txt_len = 0;
Daniel Veillard18ec16e2003-10-07 23:16:40 +00008333 xmlSaveErrMemory("creating output");
Owen Taylor3473f882001-02-23 17:55:21 +00008334 }
8335
8336 return;
8337}
8338
8339/**
8340 * xmlDocDumpMemory:
8341 * @cur: the document
8342 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00008343 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00008344 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008345 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008346 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00008347 */
8348void
8349xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
8350 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
8351}
8352
8353/**
8354 * xmlDocDumpFormatMemory:
8355 * @cur: the document
8356 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00008357 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00008358 * @format: should formatting spaces been added
8359 *
8360 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008361 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008362 * It's up to the caller to free the memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00008363 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00008364 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008365 */
8366void
8367xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
8368 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
8369}
8370
8371/**
8372 * xmlDocDumpMemoryEnc:
8373 * @out_doc: Document to generate XML text from
8374 * @doc_txt_ptr: Memory pointer for allocated XML text
8375 * @doc_txt_len: Length of the generated XML text
8376 * @txt_encoding: Character encoding to use when generating XML text
8377 *
8378 * Dump the current DOM tree into memory using the character encoding specified
8379 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008380 * allocated memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00008381 */
8382
8383void
8384xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
8385 int * doc_txt_len, const char * txt_encoding) {
8386 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008387 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008388}
8389
8390/**
Daniel Veillard9e412302002-06-10 15:59:44 +00008391 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00008392 * @f: the FILE*
8393 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00008394 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00008395 *
8396 * Dump an XML document to an open FILE.
8397 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008398 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008399 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8400 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008401 */
8402int
Daniel Veillard9e412302002-06-10 15:59:44 +00008403xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00008404 xmlOutputBufferPtr buf;
8405 const char * encoding;
8406 xmlCharEncodingHandlerPtr handler = NULL;
8407 int ret;
8408
8409 if (cur == NULL) {
8410#ifdef DEBUG_TREE
8411 xmlGenericError(xmlGenericErrorContext,
8412 "xmlDocDump : document == NULL\n");
8413#endif
8414 return(-1);
8415 }
8416 encoding = (const char *) cur->encoding;
8417
8418 if (encoding != NULL) {
Daniel Veillarde1326112003-06-05 09:32:20 +00008419 handler = xmlFindCharEncodingHandler(encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00008420 if (handler == NULL) {
8421 xmlFree((char *) cur->encoding);
8422 cur->encoding = NULL;
8423 }
8424 }
Owen Taylor3473f882001-02-23 17:55:21 +00008425 buf = xmlOutputBufferCreateFile(f, handler);
8426 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00008427 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008428
8429 ret = xmlOutputBufferClose(buf);
8430 return(ret);
8431}
8432
8433/**
Daniel Veillard9e412302002-06-10 15:59:44 +00008434 * xmlDocDump:
8435 * @f: the FILE*
8436 * @cur: the document
8437 *
8438 * Dump an XML document to an open FILE.
8439 *
8440 * returns: the number of bytes written or -1 in case of failure.
8441 */
8442int
8443xmlDocDump(FILE *f, xmlDocPtr cur) {
Daniel Veillard828ce832003-10-08 19:19:10 +00008444 return(xmlDocFormatDump (f, cur, 0));
Daniel Veillard9e412302002-06-10 15:59:44 +00008445}
8446
8447/**
Owen Taylor3473f882001-02-23 17:55:21 +00008448 * xmlSaveFileTo:
8449 * @buf: an output I/O buffer
8450 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00008451 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00008452 *
8453 * Dump an XML document to an I/O buffer.
8454 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008455 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008456 */
8457int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00008458xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00008459 int ret;
8460
8461 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008462 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008463 ret = xmlOutputBufferClose(buf);
8464 return(ret);
8465}
8466
8467/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00008468 * xmlSaveFormatFileTo:
8469 * @buf: an output I/O buffer
8470 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00008471 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00008472 * @format: should formatting spaces been added
8473 *
8474 * Dump an XML document to an I/O buffer.
8475 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008476 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008477 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8478 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardeefd4492001-04-28 16:55:50 +00008479 */
8480int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00008481xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00008482 int ret;
8483
8484 if (buf == NULL) return(0);
8485 xmlDocContentDumpOutput(buf, cur, encoding, format);
8486 ret = xmlOutputBufferClose(buf);
8487 return(ret);
8488}
8489
8490/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00008491 * xmlSaveFormatFileEnc:
Daniel Veillardf012a642001-07-23 19:10:52 +00008492 * @filename: the filename or URL to output
8493 * @cur: the document being saved
8494 * @encoding: the name of the encoding to use or NULL.
8495 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00008496 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00008497 * Dump an XML document to a file or an URL.
8498 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008499 * Returns the number of bytes written or -1 in case of error.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008500 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8501 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008502 */
8503int
Daniel Veillardf012a642001-07-23 19:10:52 +00008504xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
8505 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00008506 xmlOutputBufferPtr buf;
8507 xmlCharEncodingHandlerPtr handler = NULL;
8508 int ret;
8509
Daniel Veillard4dbe77a2003-01-14 00:17:42 +00008510 if (cur == NULL)
8511 return(-1);
8512
Daniel Veillardfb25a512002-01-13 20:32:08 +00008513 if (encoding == NULL)
8514 encoding = (const char *) cur->encoding;
8515
Owen Taylor3473f882001-02-23 17:55:21 +00008516 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00008517
Owen Taylor3473f882001-02-23 17:55:21 +00008518 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00008519 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00008520 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00008521 }
8522
Daniel Veillardf012a642001-07-23 19:10:52 +00008523#ifdef HAVE_ZLIB_H
8524 if (cur->compression < 0) cur->compression = xmlCompressMode;
8525#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008526 /*
8527 * save the content to a temp buffer.
8528 */
Daniel Veillardf012a642001-07-23 19:10:52 +00008529 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00008530 if (buf == NULL) return(-1);
8531
Daniel Veillardf012a642001-07-23 19:10:52 +00008532 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008533
8534 ret = xmlOutputBufferClose(buf);
8535 return(ret);
8536}
8537
Daniel Veillardf012a642001-07-23 19:10:52 +00008538
8539/**
8540 * xmlSaveFileEnc:
8541 * @filename: the filename (or URL)
8542 * @cur: the document
8543 * @encoding: the name of an encoding (or NULL)
8544 *
8545 * Dump an XML document, converting it to the given encoding
8546 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008547 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00008548 */
8549int
8550xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
8551 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
8552}
8553
Owen Taylor3473f882001-02-23 17:55:21 +00008554/**
Daniel Veillard67fee942001-04-26 18:59:03 +00008555 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00008556 * @filename: the filename (or URL)
8557 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00008558 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00008559 *
8560 * Dump an XML document to a file. Will use compression if
8561 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00008562 * used. If @format is set then the document will be indented on output.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008563 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8564 * or xmlKeepBlanksDefault(0) was called
Daniel Veillard67fee942001-04-26 18:59:03 +00008565 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008566 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008567 */
8568int
Daniel Veillard67fee942001-04-26 18:59:03 +00008569xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008570 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00008571}
8572
Daniel Veillard67fee942001-04-26 18:59:03 +00008573/**
8574 * xmlSaveFile:
8575 * @filename: the filename (or URL)
8576 * @cur: the document
8577 *
8578 * Dump an XML document to a file. Will use compression if
8579 * compiled in and enabled. If @filename is "-" the stdout file is
8580 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00008581 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00008582 */
8583int
8584xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008585 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00008586}
8587
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00008588#endif /* LIBXML_OUTPUT_ENABLED */
8589
8590/**
8591 * xmlGetDocCompressMode:
8592 * @doc: the document
8593 *
8594 * get the compression ratio for a document, ZLIB based
8595 * Returns 0 (uncompressed) to 9 (max compression)
8596 */
8597int
8598xmlGetDocCompressMode (xmlDocPtr doc) {
8599 if (doc == NULL) return(-1);
8600 return(doc->compression);
8601}
8602
8603/**
8604 * xmlSetDocCompressMode:
8605 * @doc: the document
8606 * @mode: the compression ratio
8607 *
8608 * set the compression ratio for a document, ZLIB based
8609 * Correct values: 0 (uncompressed) to 9 (max compression)
8610 */
8611void
8612xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
8613 if (doc == NULL) return;
8614 if (mode < 0) doc->compression = 0;
8615 else if (mode > 9) doc->compression = 9;
8616 else doc->compression = mode;
8617}
8618
8619/**
8620 * xmlGetCompressMode:
8621 *
8622 * get the default compression mode used, ZLIB based.
8623 * Returns 0 (uncompressed) to 9 (max compression)
8624 */
8625int
8626xmlGetCompressMode(void)
8627{
8628 return (xmlCompressMode);
8629}
8630
8631/**
8632 * xmlSetCompressMode:
8633 * @mode: the compression ratio
8634 *
8635 * set the default compression mode used, ZLIB based
8636 * Correct values: 0 (uncompressed) to 9 (max compression)
8637 */
8638void
8639xmlSetCompressMode(int mode) {
8640 if (mode < 0) xmlCompressMode = 0;
8641 else if (mode > 9) xmlCompressMode = 9;
8642 else xmlCompressMode = mode;
8643}
8644