blob: ff28058aa33511d101eaf7b4a2b26d0fe06d8178 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002 * tree.c : implementation of access function for an XML tree.
Owen Taylor3473f882001-02-23 17:55:21 +00003 *
Daniel Veillardd5c2f922002-11-21 14:10:52 +00004 * References:
5 * XHTML 1.0 W3C REC: http://www.w3.org/TR/2002/REC-xhtml1-20020801/
6 *
Owen Taylor3473f882001-02-23 17:55:21 +00007 * See Copyright for the status of this software.
8 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00009 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000010 *
Owen Taylor3473f882001-02-23 17:55:21 +000011 */
12
Daniel Veillard34ce8be2002-03-18 19:37:11 +000013#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000014#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000015
Owen Taylor3473f882001-02-23 17:55:21 +000016#include <string.h> /* for memset() only ! */
17
18#ifdef HAVE_CTYPE_H
19#include <ctype.h>
20#endif
21#ifdef HAVE_STDLIB_H
22#include <stdlib.h>
23#endif
24#ifdef HAVE_ZLIB_H
25#include <zlib.h>
26#endif
27
28#include <libxml/xmlmemory.h>
29#include <libxml/tree.h>
30#include <libxml/parser.h>
Daniel Veillardb8c9be92001-07-09 16:01:19 +000031#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000032#include <libxml/entities.h>
33#include <libxml/valid.h>
34#include <libxml/xmlerror.h>
Daniel Veillardbdb9ba72001-04-11 11:28:06 +000035#include <libxml/parserInternals.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000036#include <libxml/globals.h>
Daniel Veillardd5c2f922002-11-21 14:10:52 +000037#ifdef LIBXML_HTML_ENABLED
38#include <libxml/HTMLtree.h>
39#endif
Owen Taylor3473f882001-02-23 17:55:21 +000040
Daniel Veillarda880b122003-04-21 21:36:41 +000041int __xmlRegisterCallbacks = 0;
42
Daniel Veillard56a4cb82001-03-24 17:00:36 +000043xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
44
45/************************************************************************
46 * *
Daniel Veillard18ec16e2003-10-07 23:16:40 +000047 * Tree memory error handler *
48 * *
49 ************************************************************************/
50/**
51 * xmlTreeErrMemory:
52 * @extra: extra informations
53 *
54 * Handle an out of memory condition
55 */
56static void
57xmlTreeErrMemory(const char *extra)
58{
59 __xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra);
60}
61
62/**
63 * xmlTreeErr:
64 * @code: the error number
65 * @extra: extra informations
66 *
67 * Handle an out of memory condition
68 */
69static void
70xmlTreeErr(int code, xmlNodePtr node, const char *extra)
71{
72 const char *msg = NULL;
73
74 switch(code) {
75 case XML_TREE_INVALID_HEX:
76 msg = "invalid hexadecimal character value";
77 break;
78 case XML_TREE_INVALID_DEC:
79 msg = "invalid decimal character value";
80 break;
81 case XML_TREE_UNTERMINATED_ENTITY:
82 msg = "unterminated entity reference %15s";
83 break;
84 default:
85 msg = "unexpected error number";
86 }
87 __xmlSimpleError(XML_FROM_TREE, code, node, msg, extra);
88}
89
90/************************************************************************
91 * *
Daniel Veillard56a4cb82001-03-24 17:00:36 +000092 * A few static variables and macros *
93 * *
94 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +000095/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +000096const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000097/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +000098const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +000099 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +0000100/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +0000101const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
102
Owen Taylor3473f882001-02-23 17:55:21 +0000103static int xmlCompressMode = 0;
104static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000105
Owen Taylor3473f882001-02-23 17:55:21 +0000106#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
107 xmlNodePtr ulccur = (n)->children; \
108 if (ulccur == NULL) { \
109 (n)->last = NULL; \
110 } else { \
111 while (ulccur->next != NULL) { \
112 ulccur->parent = (n); \
113 ulccur = ulccur->next; \
114 } \
115 ulccur->parent = (n); \
116 (n)->last = ulccur; \
117}}
118
119/* #define DEBUG_BUFFER */
120/* #define DEBUG_TREE */
121
122/************************************************************************
123 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000124 * Functions to move to entities.c once the *
125 * API freeze is smoothen and they can be made public. *
126 * *
127 ************************************************************************/
128#include <libxml/hash.h>
129
Daniel Veillard652327a2003-09-29 18:02:38 +0000130#ifdef LIBXML_TREE_ENABLED
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000131/**
132 * xmlGetEntityFromDtd:
133 * @dtd: A pointer to the DTD to search
134 * @name: The entity name
135 *
136 * Do an entity lookup in the DTD entity hash table and
137 * return the corresponding entity, if found.
138 *
139 * Returns A pointer to the entity structure or NULL if not found.
140 */
141static xmlEntityPtr
142xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
143 xmlEntitiesTablePtr table;
144
145 if((dtd != NULL) && (dtd->entities != NULL)) {
146 table = (xmlEntitiesTablePtr) dtd->entities;
147 return((xmlEntityPtr) xmlHashLookup(table, name));
148 /* return(xmlGetEntityFromTable(table, name)); */
149 }
150 return(NULL);
151}
152/**
153 * xmlGetParameterEntityFromDtd:
154 * @dtd: A pointer to the DTD to search
155 * @name: The entity name
156 *
157 * Do an entity lookup in the DTD pararmeter entity hash table and
158 * return the corresponding entity, if found.
159 *
160 * Returns A pointer to the entity structure or NULL if not found.
161 */
162static xmlEntityPtr
163xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
164 xmlEntitiesTablePtr table;
165
166 if ((dtd != NULL) && (dtd->pentities != NULL)) {
167 table = (xmlEntitiesTablePtr) dtd->pentities;
168 return((xmlEntityPtr) xmlHashLookup(table, name));
169 /* return(xmlGetEntityFromTable(table, name)); */
170 }
171 return(NULL);
172}
Daniel Veillard652327a2003-09-29 18:02:38 +0000173#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000174
175/************************************************************************
176 * *
Daniel Veillardc00cda82003-04-07 10:22:39 +0000177 * QName handling helper *
178 * *
179 ************************************************************************/
180
181/**
182 * xmlBuildQName:
183 * @ncname: the Name
184 * @prefix: the prefix
185 * @memory: preallocated memory
186 * @len: preallocated memory length
187 *
188 * Builds the QName @prefix:@ncname in @memory if there is enough space
189 * and prefix is not NULL nor empty, otherwise allocate a new string.
190 * If prefix is NULL or empty it returns ncname.
191 *
192 * Returns the new string which must be freed by the caller if different from
193 * @memory and @ncname or NULL in case of error
194 */
195xmlChar *
196xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix,
197 xmlChar *memory, int len) {
198 int lenn, lenp;
199 xmlChar *ret;
200
Daniel Veillard3b7840c2003-09-11 23:42:01 +0000201 if (ncname == NULL) return(NULL);
202 if (prefix == NULL) return((xmlChar *) ncname);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000203
204 lenn = strlen((char *) ncname);
205 lenp = strlen((char *) prefix);
206
207 if ((memory == NULL) || (len < lenn + lenp + 2)) {
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000208 ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000209 if (ret == NULL) {
210 xmlTreeErrMemory("building QName");
211 return(NULL);
212 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000213 } else {
214 ret = memory;
215 }
216 memcpy(&ret[0], prefix, lenp);
217 ret[lenp] = ':';
218 memcpy(&ret[lenp + 1], ncname, lenn);
219 ret[lenn + lenp + 1] = 0;
220 return(ret);
221}
222
223/**
224 * xmlSplitQName2:
225 * @name: the full QName
226 * @prefix: a xmlChar **
227 *
228 * parse an XML qualified name string
229 *
230 * [NS 5] QName ::= (Prefix ':')? LocalPart
231 *
232 * [NS 6] Prefix ::= NCName
233 *
234 * [NS 7] LocalPart ::= NCName
235 *
236 * Returns NULL if not a QName, otherwise the local part, and prefix
237 * is updated to get the Prefix if any.
238 */
239
240xmlChar *
241xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
242 int len = 0;
243 xmlChar *ret = NULL;
244
245 *prefix = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000246 if (name == NULL) return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000247
248#ifndef XML_XML_NAMESPACE
249 /* xml: prefix is not really a namespace */
250 if ((name[0] == 'x') && (name[1] == 'm') &&
251 (name[2] == 'l') && (name[3] == ':'))
252 return(NULL);
253#endif
254
255 /* nasty but valid */
256 if (name[0] == ':')
257 return(NULL);
258
259 /*
260 * we are not trying to validate but just to cut, and yes it will
261 * work even if this is as set of UTF-8 encoded chars
262 */
263 while ((name[len] != 0) && (name[len] != ':'))
264 len++;
265
266 if (name[len] == 0)
267 return(NULL);
268
269 *prefix = xmlStrndup(name, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000270 if (*prefix == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000271 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000272 return(NULL);
273 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000274 ret = xmlStrdup(&name[len + 1]);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000275 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000276 xmlTreeErrMemory("QName split");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000277 if (*prefix != NULL) {
278 xmlFree(*prefix);
279 *prefix = NULL;
280 }
281 return(NULL);
282 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000283
284 return(ret);
285}
286
Daniel Veillard8d73bcb2003-08-04 01:06:15 +0000287/**
288 * xmlSplitQName3:
289 * @name: the full QName
290 * @len: an int *
291 *
292 * parse an XML qualified name string,i
293 *
294 * returns NULL if it is not a Qualified Name, otherwise, update len
295 * with the lenght in byte of the prefix and return a pointer
296 */
297
298const xmlChar *
299xmlSplitQName3(const xmlChar *name, int *len) {
300 int l = 0;
301
302 if (name == NULL) return(NULL);
303 if (len == NULL) return(NULL);
304
305 /* nasty but valid */
306 if (name[0] == ':')
307 return(NULL);
308
309 /*
310 * we are not trying to validate but just to cut, and yes it will
311 * work even if this is as set of UTF-8 encoded chars
312 */
313 while ((name[l] != 0) && (name[l] != ':'))
314 l++;
315
316 if (name[l] == 0)
317 return(NULL);
318
319 *len = l;
320
321 return(&name[l+1]);
322}
323
Daniel Veillard652327a2003-09-29 18:02:38 +0000324#ifdef LIBXML_TREE_ENABLED
Daniel Veillardc00cda82003-04-07 10:22:39 +0000325/************************************************************************
326 * *
Daniel Veillardd2298792003-02-14 16:54:11 +0000327 * Check Name, NCName and QName strings *
328 * *
329 ************************************************************************/
330
331#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
332
333/**
334 * xmlValidateNCName:
335 * @value: the value to check
336 * @space: allow spaces in front and end of the string
337 *
338 * Check that a value conforms to the lexical space of NCName
339 *
340 * Returns 0 if this validates, a positive error code number otherwise
341 * and -1 in case of internal or API error.
342 */
343int
344xmlValidateNCName(const xmlChar *value, int space) {
345 const xmlChar *cur = value;
346 int c,l;
347
348 /*
349 * First quick algorithm for ASCII range
350 */
351 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000352 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000353 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
354 (*cur == '_'))
355 cur++;
356 else
357 goto try_complex;
358 while (((*cur >= 'a') && (*cur <= 'z')) ||
359 ((*cur >= 'A') && (*cur <= 'Z')) ||
360 ((*cur >= '0') && (*cur <= '9')) ||
361 (*cur == '_') || (*cur == '-') || (*cur == '.'))
362 cur++;
363 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000364 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000365 if (*cur == 0)
366 return(0);
367
368try_complex:
369 /*
370 * Second check for chars outside the ASCII range
371 */
372 cur = value;
373 c = CUR_SCHAR(cur, l);
374 if (space) {
375 while (IS_BLANK(c)) {
376 cur += l;
377 c = CUR_SCHAR(cur, l);
378 }
379 }
William M. Brack871611b2003-10-18 04:53:14 +0000380 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000381 return(1);
382 cur += l;
383 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000384 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
385 (c == '-') || (c == '_') || IS_COMBINING(c) ||
386 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000387 cur += l;
388 c = CUR_SCHAR(cur, l);
389 }
390 if (space) {
391 while (IS_BLANK(c)) {
392 cur += l;
393 c = CUR_SCHAR(cur, l);
394 }
395 }
396 if (c != 0)
397 return(1);
398
399 return(0);
400}
401
402/**
403 * xmlValidateQName:
404 * @value: the value to check
405 * @space: allow spaces in front and end of the string
406 *
407 * Check that a value conforms to the lexical space of QName
408 *
409 * Returns 0 if this validates, a positive error code number otherwise
410 * and -1 in case of internal or API error.
411 */
412int
413xmlValidateQName(const xmlChar *value, int space) {
414 const xmlChar *cur = value;
415 int c,l;
416
417 /*
418 * First quick algorithm for ASCII range
419 */
420 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000421 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000422 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
423 (*cur == '_'))
424 cur++;
425 else
426 goto try_complex;
427 while (((*cur >= 'a') && (*cur <= 'z')) ||
428 ((*cur >= 'A') && (*cur <= 'Z')) ||
429 ((*cur >= '0') && (*cur <= '9')) ||
430 (*cur == '_') || (*cur == '-') || (*cur == '.'))
431 cur++;
432 if (*cur == ':') {
433 cur++;
434 if (((*cur >= 'a') && (*cur <= 'z')) ||
435 ((*cur >= 'A') && (*cur <= 'Z')) ||
436 (*cur == '_'))
437 cur++;
438 else
439 goto try_complex;
440 while (((*cur >= 'a') && (*cur <= 'z')) ||
441 ((*cur >= 'A') && (*cur <= 'Z')) ||
442 ((*cur >= '0') && (*cur <= '9')) ||
443 (*cur == '_') || (*cur == '-') || (*cur == '.'))
444 cur++;
445 }
446 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000447 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000448 if (*cur == 0)
449 return(0);
450
451try_complex:
452 /*
453 * Second check for chars outside the ASCII range
454 */
455 cur = value;
456 c = CUR_SCHAR(cur, l);
457 if (space) {
458 while (IS_BLANK(c)) {
459 cur += l;
460 c = CUR_SCHAR(cur, l);
461 }
462 }
William M. Brack871611b2003-10-18 04:53:14 +0000463 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000464 return(1);
465 cur += l;
466 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000467 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
468 (c == '-') || (c == '_') || IS_COMBINING(c) ||
469 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000470 cur += l;
471 c = CUR_SCHAR(cur, l);
472 }
473 if (c == ':') {
474 cur += l;
475 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000476 if ((!IS_LETTER(c)) && (c != '_'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000477 return(1);
478 cur += l;
479 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000480 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
481 (c == '-') || (c == '_') || IS_COMBINING(c) ||
482 IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000483 cur += l;
484 c = CUR_SCHAR(cur, l);
485 }
486 }
487 if (space) {
488 while (IS_BLANK(c)) {
489 cur += l;
490 c = CUR_SCHAR(cur, l);
491 }
492 }
493 if (c != 0)
494 return(1);
495 return(0);
496}
497
498/**
499 * xmlValidateName:
500 * @value: the value to check
501 * @space: allow spaces in front and end of the string
502 *
503 * Check that a value conforms to the lexical space of Name
504 *
505 * Returns 0 if this validates, a positive error code number otherwise
506 * and -1 in case of internal or API error.
507 */
508int
509xmlValidateName(const xmlChar *value, int space) {
510 const xmlChar *cur = value;
511 int c,l;
512
513 /*
514 * First quick algorithm for ASCII range
515 */
516 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000517 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000518 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
519 (*cur == '_') || (*cur == ':'))
520 cur++;
521 else
522 goto try_complex;
523 while (((*cur >= 'a') && (*cur <= 'z')) ||
524 ((*cur >= 'A') && (*cur <= 'Z')) ||
525 ((*cur >= '0') && (*cur <= '9')) ||
526 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
527 cur++;
528 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000529 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +0000530 if (*cur == 0)
531 return(0);
532
533try_complex:
534 /*
535 * Second check for chars outside the ASCII range
536 */
537 cur = value;
538 c = CUR_SCHAR(cur, l);
539 if (space) {
540 while (IS_BLANK(c)) {
541 cur += l;
542 c = CUR_SCHAR(cur, l);
543 }
544 }
William M. Brack871611b2003-10-18 04:53:14 +0000545 if ((!IS_LETTER(c)) && (c != '_') && (c != ':'))
Daniel Veillardd2298792003-02-14 16:54:11 +0000546 return(1);
547 cur += l;
548 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000549 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
550 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd2298792003-02-14 16:54:11 +0000551 cur += l;
552 c = CUR_SCHAR(cur, l);
553 }
554 if (space) {
555 while (IS_BLANK(c)) {
556 cur += l;
557 c = CUR_SCHAR(cur, l);
558 }
559 }
560 if (c != 0)
561 return(1);
562 return(0);
563}
564
Daniel Veillardd4310742003-02-18 21:12:46 +0000565/**
566 * xmlValidateNMToken:
567 * @value: the value to check
568 * @space: allow spaces in front and end of the string
569 *
570 * Check that a value conforms to the lexical space of NMToken
571 *
572 * Returns 0 if this validates, a positive error code number otherwise
573 * and -1 in case of internal or API error.
574 */
575int
576xmlValidateNMToken(const xmlChar *value, int space) {
577 const xmlChar *cur = value;
578 int c,l;
579
580 /*
581 * First quick algorithm for ASCII range
582 */
583 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000584 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000585 if (((*cur >= 'a') && (*cur <= 'z')) ||
586 ((*cur >= 'A') && (*cur <= 'Z')) ||
587 ((*cur >= '0') && (*cur <= '9')) ||
588 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
589 cur++;
590 else
591 goto try_complex;
592 while (((*cur >= 'a') && (*cur <= 'z')) ||
593 ((*cur >= 'A') && (*cur <= 'Z')) ||
594 ((*cur >= '0') && (*cur <= '9')) ||
595 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
596 cur++;
597 if (space)
William M. Brack76e95df2003-10-18 16:20:14 +0000598 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardd4310742003-02-18 21:12:46 +0000599 if (*cur == 0)
600 return(0);
601
602try_complex:
603 /*
604 * Second check for chars outside the ASCII range
605 */
606 cur = value;
607 c = CUR_SCHAR(cur, l);
608 if (space) {
609 while (IS_BLANK(c)) {
610 cur += l;
611 c = CUR_SCHAR(cur, l);
612 }
613 }
William M. Brack871611b2003-10-18 04:53:14 +0000614 if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
615 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)))
Daniel Veillardd4310742003-02-18 21:12:46 +0000616 return(1);
617 cur += l;
618 c = CUR_SCHAR(cur, l);
William M. Brack871611b2003-10-18 04:53:14 +0000619 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
620 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
Daniel Veillardd4310742003-02-18 21:12:46 +0000621 cur += l;
622 c = CUR_SCHAR(cur, l);
623 }
624 if (space) {
625 while (IS_BLANK(c)) {
626 cur += l;
627 c = CUR_SCHAR(cur, l);
628 }
629 }
630 if (c != 0)
631 return(1);
632 return(0);
633}
Daniel Veillard652327a2003-09-29 18:02:38 +0000634#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardd4310742003-02-18 21:12:46 +0000635
Daniel Veillardd2298792003-02-14 16:54:11 +0000636/************************************************************************
637 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000638 * Allocation and deallocation of basic structures *
639 * *
640 ************************************************************************/
641
642/**
643 * xmlSetBufferAllocationScheme:
644 * @scheme: allocation method to use
645 *
646 * Set the buffer allocation method. Types are
647 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
648 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
649 * improves performance
650 */
651void
652xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
653 xmlBufferAllocScheme = scheme;
654}
655
656/**
657 * xmlGetBufferAllocationScheme:
658 *
659 * Types are
660 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
661 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
662 * improves performance
663 *
664 * Returns the current allocation scheme
665 */
666xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000667xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000668 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000669}
670
671/**
672 * xmlNewNs:
673 * @node: the element carrying the namespace
674 * @href: the URI associated
675 * @prefix: the prefix for the namespace
676 *
677 * Creation of a new Namespace. This function will refuse to create
678 * a namespace with a similar prefix than an existing one present on this
679 * node.
680 * We use href==NULL in the case of an element creation where the namespace
681 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000682 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000683 */
684xmlNsPtr
685xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
686 xmlNsPtr cur;
687
688 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
689 return(NULL);
690
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000691 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
692 return(NULL);
693
Owen Taylor3473f882001-02-23 17:55:21 +0000694 /*
695 * Allocate a new Namespace and fill the fields.
696 */
697 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
698 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000699 xmlTreeErrMemory("building namespace");
Owen Taylor3473f882001-02-23 17:55:21 +0000700 return(NULL);
701 }
702 memset(cur, 0, sizeof(xmlNs));
703 cur->type = XML_LOCAL_NAMESPACE;
704
705 if (href != NULL)
706 cur->href = xmlStrdup(href);
707 if (prefix != NULL)
708 cur->prefix = xmlStrdup(prefix);
709
710 /*
711 * Add it at the end to preserve parsing order ...
712 * and checks for existing use of the prefix
713 */
714 if (node != NULL) {
715 if (node->nsDef == NULL) {
716 node->nsDef = cur;
717 } else {
718 xmlNsPtr prev = node->nsDef;
719
720 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
721 (xmlStrEqual(prev->prefix, cur->prefix))) {
722 xmlFreeNs(cur);
723 return(NULL);
724 }
725 while (prev->next != NULL) {
726 prev = prev->next;
727 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
728 (xmlStrEqual(prev->prefix, cur->prefix))) {
729 xmlFreeNs(cur);
730 return(NULL);
731 }
732 }
733 prev->next = cur;
734 }
735 }
736 return(cur);
737}
738
739/**
740 * xmlSetNs:
741 * @node: a node in the document
742 * @ns: a namespace pointer
743 *
744 * Associate a namespace to a node, a posteriori.
745 */
746void
747xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
748 if (node == NULL) {
749#ifdef DEBUG_TREE
750 xmlGenericError(xmlGenericErrorContext,
751 "xmlSetNs: node == NULL\n");
752#endif
753 return;
754 }
755 node->ns = ns;
756}
757
758/**
759 * xmlFreeNs:
760 * @cur: the namespace pointer
761 *
762 * Free up the structures associated to a namespace
763 */
764void
765xmlFreeNs(xmlNsPtr cur) {
766 if (cur == NULL) {
767#ifdef DEBUG_TREE
768 xmlGenericError(xmlGenericErrorContext,
769 "xmlFreeNs : ns == NULL\n");
770#endif
771 return;
772 }
773 if (cur->href != NULL) xmlFree((char *) cur->href);
774 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000775 xmlFree(cur);
776}
777
778/**
779 * xmlFreeNsList:
780 * @cur: the first namespace pointer
781 *
782 * Free up all the structures associated to the chained namespaces.
783 */
784void
785xmlFreeNsList(xmlNsPtr cur) {
786 xmlNsPtr next;
787 if (cur == NULL) {
788#ifdef DEBUG_TREE
789 xmlGenericError(xmlGenericErrorContext,
790 "xmlFreeNsList : ns == NULL\n");
791#endif
792 return;
793 }
794 while (cur != NULL) {
795 next = cur->next;
796 xmlFreeNs(cur);
797 cur = next;
798 }
799}
800
801/**
802 * xmlNewDtd:
803 * @doc: the document pointer
804 * @name: the DTD name
805 * @ExternalID: the external ID
806 * @SystemID: the system ID
807 *
808 * Creation of a new DTD for the external subset. To create an
809 * internal subset, use xmlCreateIntSubset().
810 *
811 * Returns a pointer to the new DTD structure
812 */
813xmlDtdPtr
814xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
815 const xmlChar *ExternalID, const xmlChar *SystemID) {
816 xmlDtdPtr cur;
817
818 if ((doc != NULL) && (doc->extSubset != NULL)) {
819#ifdef DEBUG_TREE
820 xmlGenericError(xmlGenericErrorContext,
821 "xmlNewDtd(%s): document %s already have a DTD %s\n",
822 /* !!! */ (char *) name, doc->name,
823 /* !!! */ (char *)doc->extSubset->name);
824#endif
825 return(NULL);
826 }
827
828 /*
829 * Allocate a new DTD and fill the fields.
830 */
831 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
832 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000833 xmlTreeErrMemory("building DTD");
Owen Taylor3473f882001-02-23 17:55:21 +0000834 return(NULL);
835 }
836 memset(cur, 0 , sizeof(xmlDtd));
837 cur->type = XML_DTD_NODE;
838
839 if (name != NULL)
840 cur->name = xmlStrdup(name);
841 if (ExternalID != NULL)
842 cur->ExternalID = xmlStrdup(ExternalID);
843 if (SystemID != NULL)
844 cur->SystemID = xmlStrdup(SystemID);
845 if (doc != NULL)
846 doc->extSubset = cur;
847 cur->doc = doc;
848
Daniel Veillarda880b122003-04-21 21:36:41 +0000849 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000850 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000851 return(cur);
852}
853
854/**
855 * xmlGetIntSubset:
856 * @doc: the document pointer
857 *
858 * Get the internal subset of a document
859 * Returns a pointer to the DTD structure or NULL if not found
860 */
861
862xmlDtdPtr
863xmlGetIntSubset(xmlDocPtr doc) {
864 xmlNodePtr cur;
865
866 if (doc == NULL)
867 return(NULL);
868 cur = doc->children;
869 while (cur != NULL) {
870 if (cur->type == XML_DTD_NODE)
871 return((xmlDtdPtr) cur);
872 cur = cur->next;
873 }
874 return((xmlDtdPtr) doc->intSubset);
875}
876
877/**
878 * xmlCreateIntSubset:
879 * @doc: the document pointer
880 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000881 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000882 * @SystemID: the system ID
883 *
884 * Create the internal subset of a document
885 * Returns a pointer to the new DTD structure
886 */
887xmlDtdPtr
888xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
889 const xmlChar *ExternalID, const xmlChar *SystemID) {
890 xmlDtdPtr cur;
891
892 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
893#ifdef DEBUG_TREE
894 xmlGenericError(xmlGenericErrorContext,
895
896 "xmlCreateIntSubset(): document %s already have an internal subset\n",
897 doc->name);
898#endif
899 return(NULL);
900 }
901
902 /*
903 * Allocate a new DTD and fill the fields.
904 */
905 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
906 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +0000907 xmlTreeErrMemory("building internal subset");
Owen Taylor3473f882001-02-23 17:55:21 +0000908 return(NULL);
909 }
910 memset(cur, 0, sizeof(xmlDtd));
911 cur->type = XML_DTD_NODE;
912
913 if (name != NULL)
914 cur->name = xmlStrdup(name);
915 if (ExternalID != NULL)
916 cur->ExternalID = xmlStrdup(ExternalID);
917 if (SystemID != NULL)
918 cur->SystemID = xmlStrdup(SystemID);
919 if (doc != NULL) {
920 doc->intSubset = cur;
921 cur->parent = doc;
922 cur->doc = doc;
923 if (doc->children == NULL) {
924 doc->children = (xmlNodePtr) cur;
925 doc->last = (xmlNodePtr) cur;
926 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000927 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000928 xmlNodePtr prev;
929
Owen Taylor3473f882001-02-23 17:55:21 +0000930 prev = doc->children;
931 prev->prev = (xmlNodePtr) cur;
932 cur->next = prev;
933 doc->children = (xmlNodePtr) cur;
934 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000935 xmlNodePtr next;
936
937 next = doc->children;
938 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
939 next = next->next;
940 if (next == NULL) {
941 cur->prev = doc->last;
942 cur->prev->next = (xmlNodePtr) cur;
943 cur->next = NULL;
944 doc->last = (xmlNodePtr) cur;
945 } else {
946 cur->next = next;
947 cur->prev = next->prev;
948 if (cur->prev == NULL)
949 doc->children = (xmlNodePtr) cur;
950 else
951 cur->prev->next = (xmlNodePtr) cur;
952 next->prev = (xmlNodePtr) cur;
953 }
Owen Taylor3473f882001-02-23 17:55:21 +0000954 }
955 }
956 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000957
Daniel Veillarda880b122003-04-21 21:36:41 +0000958 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000959 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000960 return(cur);
961}
962
963/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000964 * DICT_FREE:
965 * @str: a string
966 *
967 * Free a string if it is not owned by the "dict" dictionnary in the
968 * current scope
969 */
970#define DICT_FREE(str) \
971 if ((str) && ((!dict) || \
972 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
973 xmlFree((char *)(str));
974
975/**
Owen Taylor3473f882001-02-23 17:55:21 +0000976 * xmlFreeDtd:
977 * @cur: the DTD structure to free up
978 *
979 * Free a DTD structure.
980 */
981void
982xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000983 xmlDictPtr dict = NULL;
984
Owen Taylor3473f882001-02-23 17:55:21 +0000985 if (cur == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000986 return;
987 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000988 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +0000989
Daniel Veillarda880b122003-04-21 21:36:41 +0000990 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000991 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
992
Owen Taylor3473f882001-02-23 17:55:21 +0000993 if (cur->children != NULL) {
994 xmlNodePtr next, c = cur->children;
995
996 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000997 * Cleanup all the DTD comments they are not in the DTD
Owen Taylor3473f882001-02-23 17:55:21 +0000998 * indexes.
999 */
1000 while (c != NULL) {
1001 next = c->next;
Daniel Veillardd72c7e32003-05-12 21:55:03 +00001002 if ((c->type == XML_COMMENT_NODE) || (c->type == XML_PI_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001003 xmlUnlinkNode(c);
1004 xmlFreeNode(c);
1005 }
1006 c = next;
1007 }
1008 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001009 DICT_FREE(cur->name)
1010 DICT_FREE(cur->SystemID)
1011 DICT_FREE(cur->ExternalID)
Owen Taylor3473f882001-02-23 17:55:21 +00001012 /* TODO !!! */
1013 if (cur->notations != NULL)
1014 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
1015
1016 if (cur->elements != NULL)
1017 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
1018 if (cur->attributes != NULL)
1019 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
1020 if (cur->entities != NULL)
1021 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
1022 if (cur->pentities != NULL)
1023 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
1024
Owen Taylor3473f882001-02-23 17:55:21 +00001025 xmlFree(cur);
1026}
1027
1028/**
1029 * xmlNewDoc:
1030 * @version: xmlChar string giving the version of XML "1.0"
1031 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001032 * Creates a new XML document
1033 *
Owen Taylor3473f882001-02-23 17:55:21 +00001034 * Returns a new document
1035 */
1036xmlDocPtr
1037xmlNewDoc(const xmlChar *version) {
1038 xmlDocPtr cur;
1039
1040 if (version == NULL)
1041 version = (const xmlChar *) "1.0";
1042
1043 /*
1044 * Allocate a new document and fill the fields.
1045 */
1046 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
1047 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001048 xmlTreeErrMemory("building doc");
Owen Taylor3473f882001-02-23 17:55:21 +00001049 return(NULL);
1050 }
1051 memset(cur, 0, sizeof(xmlDoc));
1052 cur->type = XML_DOCUMENT_NODE;
1053
1054 cur->version = xmlStrdup(version);
1055 cur->standalone = -1;
1056 cur->compression = -1; /* not initialized */
1057 cur->doc = cur;
Daniel Veillarda6874ca2003-07-29 16:47:24 +00001058 /*
1059 * The in memory encoding is always UTF8
1060 * This field will never change and would
1061 * be obsolete if not for binary compatibility.
1062 */
Daniel Veillardd2f3ec72001-04-11 07:50:02 +00001063 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001064
Daniel Veillarda880b122003-04-21 21:36:41 +00001065 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001066 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001067 return(cur);
1068}
1069
1070/**
1071 * xmlFreeDoc:
1072 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +00001073 *
1074 * Free up all the structures used by a document, tree included.
1075 */
1076void
1077xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +00001078 xmlDtdPtr extSubset, intSubset;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001079 xmlDictPtr dict = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001080
Owen Taylor3473f882001-02-23 17:55:21 +00001081 if (cur == NULL) {
1082#ifdef DEBUG_TREE
1083 xmlGenericError(xmlGenericErrorContext,
1084 "xmlFreeDoc : document == NULL\n");
1085#endif
1086 return;
1087 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001088 if (cur != NULL) dict = cur->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001089
Daniel Veillarda880b122003-04-21 21:36:41 +00001090 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001091 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1092
Daniel Veillard76d66f42001-05-16 21:05:17 +00001093 /*
1094 * Do this before freeing the children list to avoid ID lookups
1095 */
1096 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1097 cur->ids = NULL;
1098 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1099 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001100 extSubset = cur->extSubset;
1101 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +00001102 if (intSubset == extSubset)
1103 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001104 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001105 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001106 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001107 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001108 }
Daniel Veillarda9142e72001-06-19 11:07:54 +00001109 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001110 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001111 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001112 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001113 }
1114
1115 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001116 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001117
1118 DICT_FREE(cur->version)
1119 DICT_FREE(cur->name)
1120 DICT_FREE(cur->encoding)
1121 DICT_FREE(cur->URL)
Owen Taylor3473f882001-02-23 17:55:21 +00001122 xmlFree(cur);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001123 if (dict) xmlDictFree(dict);
Owen Taylor3473f882001-02-23 17:55:21 +00001124}
1125
1126/**
1127 * xmlStringLenGetNodeList:
1128 * @doc: the document
1129 * @value: the value of the text
1130 * @len: the length of the string value
1131 *
1132 * Parse the value string and build the node list associated. Should
1133 * produce a flat tree with only TEXTs and ENTITY_REFs.
1134 * Returns a pointer to the first child
1135 */
1136xmlNodePtr
1137xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1138 xmlNodePtr ret = NULL, last = NULL;
1139 xmlNodePtr node;
1140 xmlChar *val;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001141 const xmlChar *cur = value, *end = cur + len;
Owen Taylor3473f882001-02-23 17:55:21 +00001142 const xmlChar *q;
1143 xmlEntityPtr ent;
1144
1145 if (value == NULL) return(NULL);
1146
1147 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001148 while ((cur < end) && (*cur != 0)) {
1149 if (cur[0] == '&') {
1150 int charval = 0;
1151 xmlChar tmp;
1152
Owen Taylor3473f882001-02-23 17:55:21 +00001153 /*
1154 * Save the current text.
1155 */
1156 if (cur != q) {
1157 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1158 xmlNodeAddContentLen(last, q, cur - q);
1159 } else {
1160 node = xmlNewDocTextLen(doc, q, cur - q);
1161 if (node == NULL) return(ret);
1162 if (last == NULL)
1163 last = ret = node;
1164 else {
1165 last->next = node;
1166 node->prev = last;
1167 last = node;
1168 }
1169 }
1170 }
Owen Taylor3473f882001-02-23 17:55:21 +00001171 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001172 if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
1173 cur += 3;
1174 if (cur < end)
1175 tmp = *cur;
1176 else
1177 tmp = 0;
1178 while (tmp != ';') { /* Non input consuming loop */
1179 if ((tmp >= '0') && (tmp <= '9'))
1180 charval = charval * 16 + (tmp - '0');
1181 else if ((tmp >= 'a') && (tmp <= 'f'))
1182 charval = charval * 16 + (tmp - 'a') + 10;
1183 else if ((tmp >= 'A') && (tmp <= 'F'))
1184 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001185 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001186 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1187 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001188 charval = 0;
1189 break;
1190 }
1191 cur++;
1192 if (cur < end)
1193 tmp = *cur;
1194 else
1195 tmp = 0;
1196 }
1197 if (tmp == ';')
1198 cur++;
1199 q = cur;
1200 } else if ((cur + 1 < end) && (cur[1] == '#')) {
1201 cur += 2;
1202 if (cur < end)
1203 tmp = *cur;
1204 else
1205 tmp = 0;
1206 while (tmp != ';') { /* Non input consuming loops */
1207 if ((tmp >= '0') && (tmp <= '9'))
1208 charval = charval * 10 + (tmp - '0');
1209 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001210 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1211 NULL);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001212 charval = 0;
1213 break;
1214 }
1215 cur++;
1216 if (cur < end)
1217 tmp = *cur;
1218 else
1219 tmp = 0;
1220 }
1221 if (tmp == ';')
1222 cur++;
1223 q = cur;
1224 } else {
1225 /*
1226 * Read the entity string
1227 */
1228 cur++;
1229 q = cur;
1230 while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1231 if ((cur >= end) || (*cur == 0)) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001232 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc,
1233 (const char *) q);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001234 return(ret);
1235 }
1236 if (cur != q) {
1237 /*
1238 * Predefined entities don't generate nodes
1239 */
1240 val = xmlStrndup(q, cur - q);
1241 ent = xmlGetDocEntity(doc, val);
1242 if ((ent != NULL) &&
1243 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1244 if (last == NULL) {
1245 node = xmlNewDocText(doc, ent->content);
1246 last = ret = node;
1247 } else if (last->type != XML_TEXT_NODE) {
1248 node = xmlNewDocText(doc, ent->content);
1249 last = xmlAddNextSibling(last, node);
1250 } else
1251 xmlNodeAddContent(last, ent->content);
1252
1253 } else {
1254 /*
1255 * Create a new REFERENCE_REF node
1256 */
1257 node = xmlNewReference(doc, val);
1258 if (node == NULL) {
1259 if (val != NULL) xmlFree(val);
1260 return(ret);
1261 }
1262 else if ((ent != NULL) && (ent->children == NULL)) {
1263 xmlNodePtr temp;
1264
1265 ent->children = xmlStringGetNodeList(doc,
1266 (const xmlChar*)node->content);
1267 ent->owner = 1;
1268 temp = ent->children;
1269 while (temp) {
1270 temp->parent = (xmlNodePtr)ent;
1271 temp = temp->next;
1272 }
1273 }
1274 if (last == NULL) {
1275 last = ret = node;
1276 } else {
1277 last = xmlAddNextSibling(last, node);
1278 }
1279 }
1280 xmlFree(val);
1281 }
1282 cur++;
1283 q = cur;
1284 }
1285 if (charval != 0) {
1286 xmlChar buf[10];
1287 int l;
1288
1289 l = xmlCopyCharMultiByte(buf, charval);
1290 buf[l] = 0;
1291 node = xmlNewDocText(doc, buf);
1292 if (node != NULL) {
1293 if (last == NULL) {
1294 last = ret = node;
1295 } else {
1296 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001297 }
1298 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001299 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001300 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001301 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001302 cur++;
1303 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001304 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001305 /*
1306 * Handle the last piece of text.
1307 */
1308 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1309 xmlNodeAddContentLen(last, q, cur - q);
1310 } else {
1311 node = xmlNewDocTextLen(doc, q, cur - q);
1312 if (node == NULL) return(ret);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001313 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001314 last = ret = node;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001315 } else {
1316 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001317 }
1318 }
1319 }
1320 return(ret);
1321}
1322
1323/**
1324 * xmlStringGetNodeList:
1325 * @doc: the document
1326 * @value: the value of the attribute
1327 *
1328 * Parse the value string and build the node list associated. Should
1329 * produce a flat tree with only TEXTs and ENTITY_REFs.
1330 * Returns a pointer to the first child
1331 */
1332xmlNodePtr
1333xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1334 xmlNodePtr ret = NULL, last = NULL;
1335 xmlNodePtr node;
1336 xmlChar *val;
1337 const xmlChar *cur = value;
1338 const xmlChar *q;
1339 xmlEntityPtr ent;
1340
1341 if (value == NULL) return(NULL);
1342
1343 q = cur;
1344 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001345 if (cur[0] == '&') {
1346 int charval = 0;
1347 xmlChar tmp;
1348
Owen Taylor3473f882001-02-23 17:55:21 +00001349 /*
1350 * Save the current text.
1351 */
1352 if (cur != q) {
1353 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1354 xmlNodeAddContentLen(last, q, cur - q);
1355 } else {
1356 node = xmlNewDocTextLen(doc, q, cur - q);
1357 if (node == NULL) return(ret);
1358 if (last == NULL)
1359 last = ret = node;
1360 else {
1361 last->next = node;
1362 node->prev = last;
1363 last = node;
1364 }
1365 }
1366 }
Owen Taylor3473f882001-02-23 17:55:21 +00001367 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001368 if ((cur[1] == '#') && (cur[2] == 'x')) {
1369 cur += 3;
1370 tmp = *cur;
1371 while (tmp != ';') { /* Non input consuming loop */
1372 if ((tmp >= '0') && (tmp <= '9'))
1373 charval = charval * 16 + (tmp - '0');
1374 else if ((tmp >= 'a') && (tmp <= 'f'))
1375 charval = charval * 16 + (tmp - 'a') + 10;
1376 else if ((tmp >= 'A') && (tmp <= 'F'))
1377 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001378 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001379 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1380 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001381 charval = 0;
1382 break;
1383 }
1384 cur++;
1385 tmp = *cur;
1386 }
1387 if (tmp == ';')
1388 cur++;
1389 q = cur;
1390 } else if (cur[1] == '#') {
1391 cur += 2;
1392 tmp = *cur;
1393 while (tmp != ';') { /* Non input consuming loops */
1394 if ((tmp >= '0') && (tmp <= '9'))
1395 charval = charval * 10 + (tmp - '0');
1396 else {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001397 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1398 NULL);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001399 charval = 0;
1400 break;
1401 }
1402 cur++;
1403 tmp = *cur;
1404 }
1405 if (tmp == ';')
1406 cur++;
1407 q = cur;
1408 } else {
1409 /*
1410 * Read the entity string
1411 */
1412 cur++;
1413 q = cur;
1414 while ((*cur != 0) && (*cur != ';')) cur++;
1415 if (*cur == 0) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001416 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY,
1417 (xmlNodePtr) doc, (const char *) q);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001418 return(ret);
1419 }
1420 if (cur != q) {
1421 /*
1422 * Predefined entities don't generate nodes
1423 */
1424 val = xmlStrndup(q, cur - q);
1425 ent = xmlGetDocEntity(doc, val);
1426 if ((ent != NULL) &&
1427 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1428 if (last == NULL) {
1429 node = xmlNewDocText(doc, ent->content);
1430 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001431 } else if (last->type != XML_TEXT_NODE) {
1432 node = xmlNewDocText(doc, ent->content);
1433 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001434 } else
1435 xmlNodeAddContent(last, ent->content);
1436
1437 } else {
1438 /*
1439 * Create a new REFERENCE_REF node
1440 */
1441 node = xmlNewReference(doc, val);
1442 if (node == NULL) {
1443 if (val != NULL) xmlFree(val);
1444 return(ret);
1445 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001446 else if ((ent != NULL) && (ent->children == NULL)) {
1447 xmlNodePtr temp;
1448
1449 ent->children = xmlStringGetNodeList(doc,
1450 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001451 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001452 temp = ent->children;
1453 while (temp) {
1454 temp->parent = (xmlNodePtr)ent;
1455 temp = temp->next;
1456 }
1457 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001458 if (last == NULL) {
1459 last = ret = node;
1460 } else {
1461 last = xmlAddNextSibling(last, node);
1462 }
1463 }
1464 xmlFree(val);
1465 }
1466 cur++;
1467 q = cur;
1468 }
1469 if (charval != 0) {
1470 xmlChar buf[10];
1471 int len;
1472
1473 len = xmlCopyCharMultiByte(buf, charval);
1474 buf[len] = 0;
1475 node = xmlNewDocText(doc, buf);
1476 if (node != NULL) {
1477 if (last == NULL) {
1478 last = ret = node;
1479 } else {
1480 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001481 }
1482 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001483
1484 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001485 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001486 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001487 cur++;
1488 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001489 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001490 /*
1491 * Handle the last piece of text.
1492 */
1493 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1494 xmlNodeAddContentLen(last, q, cur - q);
1495 } else {
1496 node = xmlNewDocTextLen(doc, q, cur - q);
1497 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001498 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001499 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001500 } else {
1501 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001502 }
1503 }
1504 }
1505 return(ret);
1506}
1507
1508/**
1509 * xmlNodeListGetString:
1510 * @doc: the document
1511 * @list: a Node list
1512 * @inLine: should we replace entity contents or show their external form
1513 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001514 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001515 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001516 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001517 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001518 */
1519xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001520xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1521{
Owen Taylor3473f882001-02-23 17:55:21 +00001522 xmlNodePtr node = list;
1523 xmlChar *ret = NULL;
1524 xmlEntityPtr ent;
1525
Daniel Veillard7646b182002-04-20 06:41:40 +00001526 if (list == NULL)
1527 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001528
1529 while (node != NULL) {
1530 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001531 (node->type == XML_CDATA_SECTION_NODE)) {
1532 if (inLine) {
1533 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001534 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001535 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001536
Daniel Veillard7646b182002-04-20 06:41:40 +00001537 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1538 if (buffer != NULL) {
1539 ret = xmlStrcat(ret, buffer);
1540 xmlFree(buffer);
1541 }
1542 }
1543 } else if (node->type == XML_ENTITY_REF_NODE) {
1544 if (inLine) {
1545 ent = xmlGetDocEntity(doc, node->name);
1546 if (ent != NULL) {
1547 xmlChar *buffer;
1548
1549 /* an entity content can be any "well balanced chunk",
1550 * i.e. the result of the content [43] production:
1551 * http://www.w3.org/TR/REC-xml#NT-content.
1552 * So it can contain text, CDATA section or nested
1553 * entity reference nodes (among others).
1554 * -> we recursive call xmlNodeListGetString()
1555 * which handles these types */
1556 buffer = xmlNodeListGetString(doc, ent->children, 1);
1557 if (buffer != NULL) {
1558 ret = xmlStrcat(ret, buffer);
1559 xmlFree(buffer);
1560 }
1561 } else {
1562 ret = xmlStrcat(ret, node->content);
1563 }
1564 } else {
1565 xmlChar buf[2];
1566
1567 buf[0] = '&';
1568 buf[1] = 0;
1569 ret = xmlStrncat(ret, buf, 1);
1570 ret = xmlStrcat(ret, node->name);
1571 buf[0] = ';';
1572 buf[1] = 0;
1573 ret = xmlStrncat(ret, buf, 1);
1574 }
1575 }
1576#if 0
1577 else {
1578 xmlGenericError(xmlGenericErrorContext,
1579 "xmlGetNodeListString : invalid node type %d\n",
1580 node->type);
1581 }
1582#endif
1583 node = node->next;
1584 }
1585 return (ret);
1586}
Daniel Veillard652327a2003-09-29 18:02:38 +00001587
1588#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001589/**
1590 * xmlNodeListGetRawString:
1591 * @doc: the document
1592 * @list: a Node list
1593 * @inLine: should we replace entity contents or show their external form
1594 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001595 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001596 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1597 * this function doesn't do any character encoding handling.
1598 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001599 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001600 */
1601xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001602xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1603{
Owen Taylor3473f882001-02-23 17:55:21 +00001604 xmlNodePtr node = list;
1605 xmlChar *ret = NULL;
1606 xmlEntityPtr ent;
1607
Daniel Veillard7646b182002-04-20 06:41:40 +00001608 if (list == NULL)
1609 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001610
1611 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001612 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001613 (node->type == XML_CDATA_SECTION_NODE)) {
1614 if (inLine) {
1615 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001616 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001617 xmlChar *buffer;
1618
1619 buffer = xmlEncodeSpecialChars(doc, node->content);
1620 if (buffer != NULL) {
1621 ret = xmlStrcat(ret, buffer);
1622 xmlFree(buffer);
1623 }
1624 }
1625 } else if (node->type == XML_ENTITY_REF_NODE) {
1626 if (inLine) {
1627 ent = xmlGetDocEntity(doc, node->name);
1628 if (ent != NULL) {
1629 xmlChar *buffer;
1630
1631 /* an entity content can be any "well balanced chunk",
1632 * i.e. the result of the content [43] production:
1633 * http://www.w3.org/TR/REC-xml#NT-content.
1634 * So it can contain text, CDATA section or nested
1635 * entity reference nodes (among others).
1636 * -> we recursive call xmlNodeListGetRawString()
1637 * which handles these types */
1638 buffer =
1639 xmlNodeListGetRawString(doc, ent->children, 1);
1640 if (buffer != NULL) {
1641 ret = xmlStrcat(ret, buffer);
1642 xmlFree(buffer);
1643 }
1644 } else {
1645 ret = xmlStrcat(ret, node->content);
1646 }
1647 } else {
1648 xmlChar buf[2];
1649
1650 buf[0] = '&';
1651 buf[1] = 0;
1652 ret = xmlStrncat(ret, buf, 1);
1653 ret = xmlStrcat(ret, node->name);
1654 buf[0] = ';';
1655 buf[1] = 0;
1656 ret = xmlStrncat(ret, buf, 1);
1657 }
1658 }
Owen Taylor3473f882001-02-23 17:55:21 +00001659#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001660 else {
1661 xmlGenericError(xmlGenericErrorContext,
1662 "xmlGetNodeListString : invalid node type %d\n",
1663 node->type);
1664 }
Owen Taylor3473f882001-02-23 17:55:21 +00001665#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001666 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001667 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001668 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001669}
Daniel Veillard652327a2003-09-29 18:02:38 +00001670#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001671
Daniel Veillard652327a2003-09-29 18:02:38 +00001672#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001673/**
1674 * xmlNewProp:
1675 * @node: the holding node
1676 * @name: the name of the attribute
1677 * @value: the value of the attribute
1678 *
1679 * Create a new property carried by a node.
1680 * Returns a pointer to the attribute
1681 */
1682xmlAttrPtr
1683xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1684 xmlAttrPtr cur;
1685 xmlDocPtr doc = NULL;
1686
1687 if (name == NULL) {
1688#ifdef DEBUG_TREE
1689 xmlGenericError(xmlGenericErrorContext,
1690 "xmlNewProp : name == NULL\n");
1691#endif
1692 return(NULL);
1693 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00001694 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
1695 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001696
1697 /*
1698 * Allocate a new property and fill the fields.
1699 */
1700 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1701 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001702 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001703 return(NULL);
1704 }
1705 memset(cur, 0, sizeof(xmlAttr));
1706 cur->type = XML_ATTRIBUTE_NODE;
1707
1708 cur->parent = node;
1709 if (node != NULL) {
1710 doc = node->doc;
1711 cur->doc = doc;
1712 }
1713 cur->name = xmlStrdup(name);
1714 if (value != NULL) {
1715 xmlChar *buffer;
1716 xmlNodePtr tmp;
1717
1718 buffer = xmlEncodeEntitiesReentrant(doc, value);
1719 cur->children = xmlStringGetNodeList(doc, buffer);
1720 cur->last = NULL;
1721 tmp = cur->children;
1722 while (tmp != NULL) {
1723 tmp->parent = (xmlNodePtr) cur;
1724 tmp->doc = doc;
1725 if (tmp->next == NULL)
1726 cur->last = tmp;
1727 tmp = tmp->next;
1728 }
1729 xmlFree(buffer);
1730 }
1731
1732 /*
1733 * Add it at the end to preserve parsing order ...
1734 */
1735 if (node != NULL) {
1736 if (node->properties == NULL) {
1737 node->properties = cur;
1738 } else {
1739 xmlAttrPtr prev = node->properties;
1740
1741 while (prev->next != NULL) prev = prev->next;
1742 prev->next = cur;
1743 cur->prev = prev;
1744 }
1745 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001746
Daniel Veillarda880b122003-04-21 21:36:41 +00001747 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001748 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001749 return(cur);
1750}
Daniel Veillard652327a2003-09-29 18:02:38 +00001751#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001752
1753/**
1754 * xmlNewNsProp:
1755 * @node: the holding node
1756 * @ns: the namespace
1757 * @name: the name of the attribute
1758 * @value: the value of the attribute
1759 *
1760 * Create a new property tagged with a namespace and carried by a node.
1761 * Returns a pointer to the attribute
1762 */
1763xmlAttrPtr
1764xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1765 const xmlChar *value) {
1766 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001767 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001768
1769 if (name == NULL) {
1770#ifdef DEBUG_TREE
1771 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001772 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001773#endif
1774 return(NULL);
1775 }
1776
1777 /*
1778 * Allocate a new property and fill the fields.
1779 */
1780 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1781 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001782 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001783 return(NULL);
1784 }
1785 memset(cur, 0, sizeof(xmlAttr));
1786 cur->type = XML_ATTRIBUTE_NODE;
1787
1788 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001789 if (node != NULL) {
1790 doc = node->doc;
1791 cur->doc = doc;
1792 }
Owen Taylor3473f882001-02-23 17:55:21 +00001793 cur->ns = ns;
1794 cur->name = xmlStrdup(name);
1795 if (value != NULL) {
1796 xmlChar *buffer;
1797 xmlNodePtr tmp;
1798
Daniel Veillarda682b212001-06-07 19:59:42 +00001799 buffer = xmlEncodeEntitiesReentrant(doc, value);
1800 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001801 cur->last = NULL;
1802 tmp = cur->children;
1803 while (tmp != NULL) {
1804 tmp->parent = (xmlNodePtr) cur;
1805 if (tmp->next == NULL)
1806 cur->last = tmp;
1807 tmp = tmp->next;
1808 }
1809 xmlFree(buffer);
1810 }
1811
1812 /*
1813 * Add it at the end to preserve parsing order ...
1814 */
1815 if (node != NULL) {
1816 if (node->properties == NULL) {
1817 node->properties = cur;
1818 } else {
1819 xmlAttrPtr prev = node->properties;
1820
1821 while (prev->next != NULL) prev = prev->next;
1822 prev->next = cur;
1823 cur->prev = prev;
1824 }
1825 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001826
Daniel Veillarda880b122003-04-21 21:36:41 +00001827 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001828 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001829 return(cur);
1830}
1831
1832/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001833 * xmlNewNsPropEatName:
1834 * @node: the holding node
1835 * @ns: the namespace
1836 * @name: the name of the attribute
1837 * @value: the value of the attribute
1838 *
1839 * Create a new property tagged with a namespace and carried by a node.
1840 * Returns a pointer to the attribute
1841 */
1842xmlAttrPtr
1843xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1844 const xmlChar *value) {
1845 xmlAttrPtr cur;
1846 xmlDocPtr doc = NULL;
1847
1848 if (name == NULL) {
1849#ifdef DEBUG_TREE
1850 xmlGenericError(xmlGenericErrorContext,
1851 "xmlNewNsPropEatName : name == NULL\n");
1852#endif
1853 return(NULL);
1854 }
1855
1856 /*
1857 * Allocate a new property and fill the fields.
1858 */
1859 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1860 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001861 xmlTreeErrMemory("building attribute");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001862 xmlFree(name);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001863 return(NULL);
1864 }
1865 memset(cur, 0, sizeof(xmlAttr));
1866 cur->type = XML_ATTRIBUTE_NODE;
1867
1868 cur->parent = node;
1869 if (node != NULL) {
1870 doc = node->doc;
1871 cur->doc = doc;
1872 }
1873 cur->ns = ns;
1874 cur->name = name;
1875 if (value != NULL) {
1876 xmlChar *buffer;
1877 xmlNodePtr tmp;
1878
1879 buffer = xmlEncodeEntitiesReentrant(doc, value);
1880 cur->children = xmlStringGetNodeList(doc, buffer);
1881 cur->last = NULL;
1882 tmp = cur->children;
1883 while (tmp != NULL) {
1884 tmp->parent = (xmlNodePtr) cur;
1885 if (tmp->next == NULL)
1886 cur->last = tmp;
1887 tmp = tmp->next;
1888 }
1889 xmlFree(buffer);
1890 }
1891
1892 /*
1893 * Add it at the end to preserve parsing order ...
1894 */
1895 if (node != NULL) {
1896 if (node->properties == NULL) {
1897 node->properties = cur;
1898 } else {
1899 xmlAttrPtr prev = node->properties;
1900
1901 while (prev->next != NULL) prev = prev->next;
1902 prev->next = cur;
1903 cur->prev = prev;
1904 }
1905 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001906
Daniel Veillarda880b122003-04-21 21:36:41 +00001907 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001908 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001909 return(cur);
1910}
1911
1912/**
Owen Taylor3473f882001-02-23 17:55:21 +00001913 * xmlNewDocProp:
1914 * @doc: the document
1915 * @name: the name of the attribute
1916 * @value: the value of the attribute
1917 *
1918 * Create a new property carried by a document.
1919 * Returns a pointer to the attribute
1920 */
1921xmlAttrPtr
1922xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1923 xmlAttrPtr cur;
1924
1925 if (name == NULL) {
1926#ifdef DEBUG_TREE
1927 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001928 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001929#endif
1930 return(NULL);
1931 }
1932
1933 /*
1934 * Allocate a new property and fill the fields.
1935 */
1936 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1937 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00001938 xmlTreeErrMemory("building attribute");
Owen Taylor3473f882001-02-23 17:55:21 +00001939 return(NULL);
1940 }
1941 memset(cur, 0, sizeof(xmlAttr));
1942 cur->type = XML_ATTRIBUTE_NODE;
1943
1944 cur->name = xmlStrdup(name);
1945 cur->doc = doc;
1946 if (value != NULL) {
1947 xmlNodePtr tmp;
1948
1949 cur->children = xmlStringGetNodeList(doc, value);
1950 cur->last = NULL;
1951
1952 tmp = cur->children;
1953 while (tmp != NULL) {
1954 tmp->parent = (xmlNodePtr) cur;
1955 if (tmp->next == NULL)
1956 cur->last = tmp;
1957 tmp = tmp->next;
1958 }
1959 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001960
Daniel Veillarda880b122003-04-21 21:36:41 +00001961 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001962 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001963 return(cur);
1964}
1965
1966/**
1967 * xmlFreePropList:
1968 * @cur: the first property in the list
1969 *
1970 * Free a property and all its siblings, all the children are freed too.
1971 */
1972void
1973xmlFreePropList(xmlAttrPtr cur) {
1974 xmlAttrPtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001975 if (cur == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001976 while (cur != NULL) {
1977 next = cur->next;
1978 xmlFreeProp(cur);
1979 cur = next;
1980 }
1981}
1982
1983/**
1984 * xmlFreeProp:
1985 * @cur: an attribute
1986 *
1987 * Free one attribute, all the content is freed too
1988 */
1989void
1990xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001991 xmlDictPtr dict = NULL;
1992 if (cur == NULL) return;
1993
1994 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001995
Daniel Veillarda880b122003-04-21 21:36:41 +00001996 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001997 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1998
Owen Taylor3473f882001-02-23 17:55:21 +00001999 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00002000 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
2001 ((cur->parent->doc->intSubset != NULL) ||
2002 (cur->parent->doc->extSubset != NULL))) {
2003 if (xmlIsID(cur->parent->doc, cur->parent, cur))
2004 xmlRemoveID(cur->parent->doc, cur);
2005 }
Owen Taylor3473f882001-02-23 17:55:21 +00002006 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00002007 DICT_FREE(cur->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002008 xmlFree(cur);
2009}
2010
Daniel Veillard652327a2003-09-29 18:02:38 +00002011#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002012/**
2013 * xmlRemoveProp:
2014 * @cur: an attribute
2015 *
2016 * Unlink and free one attribute, all the content is freed too
2017 * Note this doesn't work for namespace definition attributes
2018 *
2019 * Returns 0 if success and -1 in case of error.
2020 */
2021int
2022xmlRemoveProp(xmlAttrPtr cur) {
2023 xmlAttrPtr tmp;
2024 if (cur == NULL) {
2025#ifdef DEBUG_TREE
2026 xmlGenericError(xmlGenericErrorContext,
2027 "xmlRemoveProp : cur == NULL\n");
2028#endif
2029 return(-1);
2030 }
2031 if (cur->parent == NULL) {
2032#ifdef DEBUG_TREE
2033 xmlGenericError(xmlGenericErrorContext,
2034 "xmlRemoveProp : cur->parent == NULL\n");
2035#endif
2036 return(-1);
2037 }
2038 tmp = cur->parent->properties;
2039 if (tmp == cur) {
2040 cur->parent->properties = cur->next;
2041 xmlFreeProp(cur);
2042 return(0);
2043 }
2044 while (tmp != NULL) {
2045 if (tmp->next == cur) {
2046 tmp->next = cur->next;
2047 if (tmp->next != NULL)
2048 tmp->next->prev = tmp;
2049 xmlFreeProp(cur);
2050 return(0);
2051 }
2052 tmp = tmp->next;
2053 }
2054#ifdef DEBUG_TREE
2055 xmlGenericError(xmlGenericErrorContext,
2056 "xmlRemoveProp : attribute not owned by its node\n");
2057#endif
2058 return(-1);
2059}
Daniel Veillard652327a2003-09-29 18:02:38 +00002060#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002061
2062/**
2063 * xmlNewPI:
2064 * @name: the processing instruction name
2065 * @content: the PI content
2066 *
2067 * Creation of a processing instruction element.
2068 * Returns a pointer to the new node object.
2069 */
2070xmlNodePtr
2071xmlNewPI(const xmlChar *name, const xmlChar *content) {
2072 xmlNodePtr cur;
2073
2074 if (name == NULL) {
2075#ifdef DEBUG_TREE
2076 xmlGenericError(xmlGenericErrorContext,
2077 "xmlNewPI : name == NULL\n");
2078#endif
2079 return(NULL);
2080 }
2081
2082 /*
2083 * Allocate a new node and fill the fields.
2084 */
2085 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2086 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002087 xmlTreeErrMemory("building PI");
Owen Taylor3473f882001-02-23 17:55:21 +00002088 return(NULL);
2089 }
2090 memset(cur, 0, sizeof(xmlNode));
2091 cur->type = XML_PI_NODE;
2092
2093 cur->name = xmlStrdup(name);
2094 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002095 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002096 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002097
Daniel Veillarda880b122003-04-21 21:36:41 +00002098 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002099 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002100 return(cur);
2101}
2102
2103/**
2104 * xmlNewNode:
2105 * @ns: namespace if any
2106 * @name: the node name
2107 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002108 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002109 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002110 * Returns a pointer to the new node object. Uses xmlStrdup() to make
2111 * copy of @name.
Owen Taylor3473f882001-02-23 17:55:21 +00002112 */
2113xmlNodePtr
2114xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2115 xmlNodePtr cur;
2116
2117 if (name == NULL) {
2118#ifdef DEBUG_TREE
2119 xmlGenericError(xmlGenericErrorContext,
2120 "xmlNewNode : name == NULL\n");
2121#endif
2122 return(NULL);
2123 }
2124
2125 /*
2126 * Allocate a new node and fill the fields.
2127 */
2128 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2129 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002130 xmlTreeErrMemory("building node");
Owen Taylor3473f882001-02-23 17:55:21 +00002131 return(NULL);
2132 }
2133 memset(cur, 0, sizeof(xmlNode));
2134 cur->type = XML_ELEMENT_NODE;
2135
2136 cur->name = xmlStrdup(name);
2137 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002138
Daniel Veillarda880b122003-04-21 21:36:41 +00002139 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002140 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002141 return(cur);
2142}
2143
2144/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00002145 * xmlNewNodeEatName:
2146 * @ns: namespace if any
2147 * @name: the node name
2148 *
2149 * Creation of a new node element. @ns is optional (NULL).
2150 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00002151 * Returns a pointer to the new node object, with pointer @name as
2152 * new node's name. Use xmlNewNode() if a copy of @name string is
2153 * is needed as new node's name.
Daniel Veillard46de64e2002-05-29 08:21:33 +00002154 */
2155xmlNodePtr
2156xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2157 xmlNodePtr cur;
2158
2159 if (name == NULL) {
2160#ifdef DEBUG_TREE
2161 xmlGenericError(xmlGenericErrorContext,
2162 "xmlNewNode : name == NULL\n");
2163#endif
2164 return(NULL);
2165 }
2166
2167 /*
2168 * Allocate a new node and fill the fields.
2169 */
2170 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2171 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002172 xmlTreeErrMemory("building node");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00002173 xmlFree(name);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002174 return(NULL);
2175 }
2176 memset(cur, 0, sizeof(xmlNode));
2177 cur->type = XML_ELEMENT_NODE;
2178
2179 cur->name = name;
2180 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002181
Daniel Veillarda880b122003-04-21 21:36:41 +00002182 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002183 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002184 return(cur);
2185}
2186
2187/**
Owen Taylor3473f882001-02-23 17:55:21 +00002188 * xmlNewDocNode:
2189 * @doc: the document
2190 * @ns: namespace if any
2191 * @name: the node name
2192 * @content: the XML text content if any
2193 *
2194 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002195 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002196 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2197 * references, but XML special chars need to be escaped first by using
2198 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2199 * need entities support.
2200 *
2201 * Returns a pointer to the new node object.
2202 */
2203xmlNodePtr
2204xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2205 const xmlChar *name, const xmlChar *content) {
2206 xmlNodePtr cur;
2207
2208 cur = xmlNewNode(ns, name);
2209 if (cur != NULL) {
2210 cur->doc = doc;
2211 if (content != NULL) {
2212 cur->children = xmlStringGetNodeList(doc, content);
2213 UPDATE_LAST_CHILD_AND_PARENT(cur)
2214 }
2215 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002216
Owen Taylor3473f882001-02-23 17:55:21 +00002217 return(cur);
2218}
2219
Daniel Veillard46de64e2002-05-29 08:21:33 +00002220/**
2221 * xmlNewDocNodeEatName:
2222 * @doc: the document
2223 * @ns: namespace if any
2224 * @name: the node name
2225 * @content: the XML text content if any
2226 *
2227 * Creation of a new node element within a document. @ns and @content
2228 * are optional (NULL).
2229 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2230 * references, but XML special chars need to be escaped first by using
2231 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2232 * need entities support.
2233 *
2234 * Returns a pointer to the new node object.
2235 */
2236xmlNodePtr
2237xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2238 xmlChar *name, const xmlChar *content) {
2239 xmlNodePtr cur;
2240
2241 cur = xmlNewNodeEatName(ns, name);
2242 if (cur != NULL) {
2243 cur->doc = doc;
2244 if (content != NULL) {
2245 cur->children = xmlStringGetNodeList(doc, content);
2246 UPDATE_LAST_CHILD_AND_PARENT(cur)
2247 }
2248 }
2249 return(cur);
2250}
2251
Daniel Veillard652327a2003-09-29 18:02:38 +00002252#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002253/**
2254 * xmlNewDocRawNode:
2255 * @doc: the document
2256 * @ns: namespace if any
2257 * @name: the node name
2258 * @content: the text content if any
2259 *
2260 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002261 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002262 *
2263 * Returns a pointer to the new node object.
2264 */
2265xmlNodePtr
2266xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2267 const xmlChar *name, const xmlChar *content) {
2268 xmlNodePtr cur;
2269
2270 cur = xmlNewNode(ns, name);
2271 if (cur != NULL) {
2272 cur->doc = doc;
2273 if (content != NULL) {
2274 cur->children = xmlNewDocText(doc, content);
2275 UPDATE_LAST_CHILD_AND_PARENT(cur)
2276 }
2277 }
2278 return(cur);
2279}
2280
2281/**
2282 * xmlNewDocFragment:
2283 * @doc: the document owning the fragment
2284 *
2285 * Creation of a new Fragment node.
2286 * Returns a pointer to the new node object.
2287 */
2288xmlNodePtr
2289xmlNewDocFragment(xmlDocPtr doc) {
2290 xmlNodePtr cur;
2291
2292 /*
2293 * Allocate a new DocumentFragment node and fill the fields.
2294 */
2295 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2296 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002297 xmlTreeErrMemory("building fragment");
Owen Taylor3473f882001-02-23 17:55:21 +00002298 return(NULL);
2299 }
2300 memset(cur, 0, sizeof(xmlNode));
2301 cur->type = XML_DOCUMENT_FRAG_NODE;
2302
2303 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002304
Daniel Veillarda880b122003-04-21 21:36:41 +00002305 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002306 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002307 return(cur);
2308}
Daniel Veillard652327a2003-09-29 18:02:38 +00002309#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002310
2311/**
2312 * xmlNewText:
2313 * @content: the text content
2314 *
2315 * Creation of a new text node.
2316 * Returns a pointer to the new node object.
2317 */
2318xmlNodePtr
2319xmlNewText(const xmlChar *content) {
2320 xmlNodePtr cur;
2321
2322 /*
2323 * Allocate a new node and fill the fields.
2324 */
2325 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2326 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002327 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002328 return(NULL);
2329 }
2330 memset(cur, 0, sizeof(xmlNode));
2331 cur->type = XML_TEXT_NODE;
2332
2333 cur->name = xmlStringText;
2334 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002335 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002336 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002337
Daniel Veillarda880b122003-04-21 21:36:41 +00002338 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002339 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002340 return(cur);
2341}
2342
Daniel Veillard652327a2003-09-29 18:02:38 +00002343#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002344/**
2345 * xmlNewTextChild:
2346 * @parent: the parent node
2347 * @ns: a namespace if any
2348 * @name: the name of the child
2349 * @content: the text content of the child if any.
2350 *
2351 * Creation of a new child element, added at the end of @parent children list.
William M. Brackd7cf7f82003-11-14 07:13:16 +00002352 * @ns and @content parameters are optional (NULL). If @content is non NULL,
2353 * a child TEXT node will be created containing the string @content.
2354 * NOTE: Use xmlNewChild() if entity support for @content is needed.
Owen Taylor3473f882001-02-23 17:55:21 +00002355 *
2356 * Returns a pointer to the new node object.
2357 */
2358xmlNodePtr
2359xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2360 const xmlChar *name, const xmlChar *content) {
2361 xmlNodePtr cur, prev;
2362
2363 if (parent == NULL) {
2364#ifdef DEBUG_TREE
2365 xmlGenericError(xmlGenericErrorContext,
2366 "xmlNewTextChild : parent == NULL\n");
2367#endif
2368 return(NULL);
2369 }
2370
2371 if (name == NULL) {
2372#ifdef DEBUG_TREE
2373 xmlGenericError(xmlGenericErrorContext,
2374 "xmlNewTextChild : name == NULL\n");
2375#endif
2376 return(NULL);
2377 }
2378
2379 /*
2380 * Allocate a new node
2381 */
Daniel Veillard254b1262003-11-01 17:04:58 +00002382 if (parent->type == XML_ELEMENT_NODE) {
2383 if (ns == NULL)
2384 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2385 else
2386 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2387 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2388 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2389 if (ns == NULL)
2390 cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2391 else
2392 cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2393 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2394 cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2395 } else {
2396 return(NULL);
2397 }
Owen Taylor3473f882001-02-23 17:55:21 +00002398 if (cur == NULL) return(NULL);
2399
2400 /*
2401 * add the new element at the end of the children list.
2402 */
2403 cur->type = XML_ELEMENT_NODE;
2404 cur->parent = parent;
2405 cur->doc = parent->doc;
2406 if (parent->children == NULL) {
2407 parent->children = cur;
2408 parent->last = cur;
2409 } else {
2410 prev = parent->last;
2411 prev->next = cur;
2412 cur->prev = prev;
2413 parent->last = cur;
2414 }
2415
2416 return(cur);
2417}
Daniel Veillard652327a2003-09-29 18:02:38 +00002418#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002419
2420/**
2421 * xmlNewCharRef:
2422 * @doc: the document
2423 * @name: the char ref string, starting with # or "&# ... ;"
2424 *
2425 * Creation of a new character reference node.
2426 * Returns a pointer to the new node object.
2427 */
2428xmlNodePtr
2429xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2430 xmlNodePtr cur;
2431
2432 /*
2433 * Allocate a new node and fill the fields.
2434 */
2435 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2436 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002437 xmlTreeErrMemory("building character reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002438 return(NULL);
2439 }
2440 memset(cur, 0, sizeof(xmlNode));
2441 cur->type = XML_ENTITY_REF_NODE;
2442
2443 cur->doc = doc;
2444 if (name[0] == '&') {
2445 int len;
2446 name++;
2447 len = xmlStrlen(name);
2448 if (name[len - 1] == ';')
2449 cur->name = xmlStrndup(name, len - 1);
2450 else
2451 cur->name = xmlStrndup(name, len);
2452 } else
2453 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002454
Daniel Veillarda880b122003-04-21 21:36:41 +00002455 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002456 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002457 return(cur);
2458}
2459
2460/**
2461 * xmlNewReference:
2462 * @doc: the document
2463 * @name: the reference name, or the reference string with & and ;
2464 *
2465 * Creation of a new reference node.
2466 * Returns a pointer to the new node object.
2467 */
2468xmlNodePtr
2469xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2470 xmlNodePtr cur;
2471 xmlEntityPtr ent;
2472
2473 /*
2474 * Allocate a new node and fill the fields.
2475 */
2476 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2477 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002478 xmlTreeErrMemory("building reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002479 return(NULL);
2480 }
2481 memset(cur, 0, sizeof(xmlNode));
2482 cur->type = XML_ENTITY_REF_NODE;
2483
2484 cur->doc = doc;
2485 if (name[0] == '&') {
2486 int len;
2487 name++;
2488 len = xmlStrlen(name);
2489 if (name[len - 1] == ';')
2490 cur->name = xmlStrndup(name, len - 1);
2491 else
2492 cur->name = xmlStrndup(name, len);
2493 } else
2494 cur->name = xmlStrdup(name);
2495
2496 ent = xmlGetDocEntity(doc, cur->name);
2497 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002498 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002499 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002500 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002501 * updated. Not sure if this is 100% correct.
2502 * -George
2503 */
2504 cur->children = (xmlNodePtr) ent;
2505 cur->last = (xmlNodePtr) ent;
2506 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002507
Daniel Veillarda880b122003-04-21 21:36:41 +00002508 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002509 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002510 return(cur);
2511}
2512
2513/**
2514 * xmlNewDocText:
2515 * @doc: the document
2516 * @content: the text content
2517 *
2518 * Creation of a new text node within a document.
2519 * Returns a pointer to the new node object.
2520 */
2521xmlNodePtr
2522xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2523 xmlNodePtr cur;
2524
2525 cur = xmlNewText(content);
2526 if (cur != NULL) cur->doc = doc;
2527 return(cur);
2528}
2529
2530/**
2531 * xmlNewTextLen:
2532 * @content: the text content
2533 * @len: the text len.
2534 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002535 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002536 * Returns a pointer to the new node object.
2537 */
2538xmlNodePtr
2539xmlNewTextLen(const xmlChar *content, int len) {
2540 xmlNodePtr cur;
2541
2542 /*
2543 * Allocate a new node and fill the fields.
2544 */
2545 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2546 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002547 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002548 return(NULL);
2549 }
2550 memset(cur, 0, sizeof(xmlNode));
2551 cur->type = XML_TEXT_NODE;
2552
2553 cur->name = xmlStringText;
2554 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002555 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002556 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002557
Daniel Veillarda880b122003-04-21 21:36:41 +00002558 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002559 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002560 return(cur);
2561}
2562
2563/**
2564 * xmlNewDocTextLen:
2565 * @doc: the document
2566 * @content: the text content
2567 * @len: the text len.
2568 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002569 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002570 * text node pertain to a given document.
2571 * Returns a pointer to the new node object.
2572 */
2573xmlNodePtr
2574xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2575 xmlNodePtr cur;
2576
2577 cur = xmlNewTextLen(content, len);
2578 if (cur != NULL) cur->doc = doc;
2579 return(cur);
2580}
2581
2582/**
2583 * xmlNewComment:
2584 * @content: the comment content
2585 *
2586 * Creation of a new node containing a comment.
2587 * Returns a pointer to the new node object.
2588 */
2589xmlNodePtr
2590xmlNewComment(const xmlChar *content) {
2591 xmlNodePtr cur;
2592
2593 /*
2594 * Allocate a new node and fill the fields.
2595 */
2596 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2597 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002598 xmlTreeErrMemory("building comment");
Owen Taylor3473f882001-02-23 17:55:21 +00002599 return(NULL);
2600 }
2601 memset(cur, 0, sizeof(xmlNode));
2602 cur->type = XML_COMMENT_NODE;
2603
2604 cur->name = xmlStringComment;
2605 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002606 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002607 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002608
Daniel Veillarda880b122003-04-21 21:36:41 +00002609 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002610 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002611 return(cur);
2612}
2613
2614/**
2615 * xmlNewCDataBlock:
2616 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002617 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002618 * @len: the length of the block
2619 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002620 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002621 * Returns a pointer to the new node object.
2622 */
2623xmlNodePtr
2624xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2625 xmlNodePtr cur;
2626
2627 /*
2628 * Allocate a new node and fill the fields.
2629 */
2630 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2631 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002632 xmlTreeErrMemory("building CDATA");
Owen Taylor3473f882001-02-23 17:55:21 +00002633 return(NULL);
2634 }
2635 memset(cur, 0, sizeof(xmlNode));
2636 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002637 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002638
2639 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002640 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002641 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002642
Daniel Veillarda880b122003-04-21 21:36:41 +00002643 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002644 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002645 return(cur);
2646}
2647
2648/**
2649 * xmlNewDocComment:
2650 * @doc: the document
2651 * @content: the comment content
2652 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002653 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002654 * Returns a pointer to the new node object.
2655 */
2656xmlNodePtr
2657xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2658 xmlNodePtr cur;
2659
2660 cur = xmlNewComment(content);
2661 if (cur != NULL) cur->doc = doc;
2662 return(cur);
2663}
2664
2665/**
2666 * xmlSetTreeDoc:
2667 * @tree: the top element
2668 * @doc: the document
2669 *
2670 * update all nodes under the tree to point to the right document
2671 */
2672void
2673xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002674 xmlAttrPtr prop;
2675
Owen Taylor3473f882001-02-23 17:55:21 +00002676 if (tree == NULL)
2677 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002678 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002679 if(tree->type == XML_ELEMENT_NODE) {
2680 prop = tree->properties;
2681 while (prop != NULL) {
2682 prop->doc = doc;
2683 xmlSetListDoc(prop->children, doc);
2684 prop = prop->next;
2685 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002686 }
Owen Taylor3473f882001-02-23 17:55:21 +00002687 if (tree->children != NULL)
2688 xmlSetListDoc(tree->children, doc);
2689 tree->doc = doc;
2690 }
2691}
2692
2693/**
2694 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002695 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002696 * @doc: the document
2697 *
2698 * update all nodes in the list to point to the right document
2699 */
2700void
2701xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2702 xmlNodePtr cur;
2703
2704 if (list == NULL)
2705 return;
2706 cur = list;
2707 while (cur != NULL) {
2708 if (cur->doc != doc)
2709 xmlSetTreeDoc(cur, doc);
2710 cur = cur->next;
2711 }
2712}
2713
Daniel Veillard652327a2003-09-29 18:02:38 +00002714#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002715/**
2716 * xmlNewChild:
2717 * @parent: the parent node
2718 * @ns: a namespace if any
2719 * @name: the name of the child
2720 * @content: the XML content of the child if any.
2721 *
2722 * Creation of a new child element, added at the end of @parent children list.
William M. Brackd7cf7f82003-11-14 07:13:16 +00002723 * @ns and @content parameters are optional (NULL). If @content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002724 * a child list containing the TEXTs and ENTITY_REFs node will be created.
2725 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2726 * references, but XML special chars need to be escaped first by using
2727 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
2728 * support is not needed.
2729 *
2730 * Returns a pointer to the new node object.
2731 */
2732xmlNodePtr
2733xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2734 const xmlChar *name, const xmlChar *content) {
2735 xmlNodePtr cur, prev;
2736
2737 if (parent == NULL) {
2738#ifdef DEBUG_TREE
2739 xmlGenericError(xmlGenericErrorContext,
2740 "xmlNewChild : parent == NULL\n");
2741#endif
2742 return(NULL);
2743 }
2744
2745 if (name == NULL) {
2746#ifdef DEBUG_TREE
2747 xmlGenericError(xmlGenericErrorContext,
2748 "xmlNewChild : name == NULL\n");
2749#endif
2750 return(NULL);
2751 }
2752
2753 /*
2754 * Allocate a new node
2755 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002756 if (parent->type == XML_ELEMENT_NODE) {
2757 if (ns == NULL)
2758 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2759 else
2760 cur = xmlNewDocNode(parent->doc, ns, name, content);
2761 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2762 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2763 if (ns == NULL)
2764 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2765 else
2766 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002767 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2768 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002769 } else {
2770 return(NULL);
2771 }
Owen Taylor3473f882001-02-23 17:55:21 +00002772 if (cur == NULL) return(NULL);
2773
2774 /*
2775 * add the new element at the end of the children list.
2776 */
2777 cur->type = XML_ELEMENT_NODE;
2778 cur->parent = parent;
2779 cur->doc = parent->doc;
2780 if (parent->children == NULL) {
2781 parent->children = cur;
2782 parent->last = cur;
2783 } else {
2784 prev = parent->last;
2785 prev->next = cur;
2786 cur->prev = prev;
2787 parent->last = cur;
2788 }
2789
2790 return(cur);
2791}
Daniel Veillard652327a2003-09-29 18:02:38 +00002792#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002793
2794/**
2795 * xmlAddNextSibling:
2796 * @cur: the child node
2797 * @elem: the new node
2798 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002799 * Add a new node @elem as the next sibling of @cur
2800 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002801 * first unlinked from its existing context.
2802 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002803 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2804 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002805 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002806 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002807 */
2808xmlNodePtr
2809xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2810 if (cur == NULL) {
2811#ifdef DEBUG_TREE
2812 xmlGenericError(xmlGenericErrorContext,
2813 "xmlAddNextSibling : cur == NULL\n");
2814#endif
2815 return(NULL);
2816 }
2817 if (elem == NULL) {
2818#ifdef DEBUG_TREE
2819 xmlGenericError(xmlGenericErrorContext,
2820 "xmlAddNextSibling : elem == NULL\n");
2821#endif
2822 return(NULL);
2823 }
2824
2825 xmlUnlinkNode(elem);
2826
2827 if (elem->type == XML_TEXT_NODE) {
2828 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002829 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002830 xmlFreeNode(elem);
2831 return(cur);
2832 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002833 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2834 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002835 xmlChar *tmp;
2836
2837 tmp = xmlStrdup(elem->content);
2838 tmp = xmlStrcat(tmp, cur->next->content);
2839 xmlNodeSetContent(cur->next, tmp);
2840 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002841 xmlFreeNode(elem);
2842 return(cur->next);
2843 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002844 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2845 /* check if an attribute with the same name exists */
2846 xmlAttrPtr attr;
2847
2848 if (elem->ns == NULL)
2849 attr = xmlHasProp(cur->parent, elem->name);
2850 else
2851 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2852 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2853 /* different instance, destroy it (attributes must be unique) */
2854 xmlFreeProp(attr);
2855 }
Owen Taylor3473f882001-02-23 17:55:21 +00002856 }
2857
2858 if (elem->doc != cur->doc) {
2859 xmlSetTreeDoc(elem, cur->doc);
2860 }
2861 elem->parent = cur->parent;
2862 elem->prev = cur;
2863 elem->next = cur->next;
2864 cur->next = elem;
2865 if (elem->next != NULL)
2866 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002867 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002868 elem->parent->last = elem;
2869 return(elem);
2870}
2871
Daniel Veillard652327a2003-09-29 18:02:38 +00002872#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002873/**
2874 * xmlAddPrevSibling:
2875 * @cur: the child node
2876 * @elem: the new node
2877 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002878 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002879 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002880 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002881 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002882 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2883 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002884 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002885 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002886 */
2887xmlNodePtr
2888xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2889 if (cur == NULL) {
2890#ifdef DEBUG_TREE
2891 xmlGenericError(xmlGenericErrorContext,
2892 "xmlAddPrevSibling : cur == NULL\n");
2893#endif
2894 return(NULL);
2895 }
2896 if (elem == NULL) {
2897#ifdef DEBUG_TREE
2898 xmlGenericError(xmlGenericErrorContext,
2899 "xmlAddPrevSibling : elem == NULL\n");
2900#endif
2901 return(NULL);
2902 }
2903
2904 xmlUnlinkNode(elem);
2905
2906 if (elem->type == XML_TEXT_NODE) {
2907 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002908 xmlChar *tmp;
2909
2910 tmp = xmlStrdup(elem->content);
2911 tmp = xmlStrcat(tmp, cur->content);
2912 xmlNodeSetContent(cur, tmp);
2913 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002914 xmlFreeNode(elem);
2915 return(cur);
2916 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002917 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2918 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002919 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002920 xmlFreeNode(elem);
2921 return(cur->prev);
2922 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002923 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2924 /* check if an attribute with the same name exists */
2925 xmlAttrPtr attr;
2926
2927 if (elem->ns == NULL)
2928 attr = xmlHasProp(cur->parent, elem->name);
2929 else
2930 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2931 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2932 /* different instance, destroy it (attributes must be unique) */
2933 xmlFreeProp(attr);
2934 }
Owen Taylor3473f882001-02-23 17:55:21 +00002935 }
2936
2937 if (elem->doc != cur->doc) {
2938 xmlSetTreeDoc(elem, cur->doc);
2939 }
2940 elem->parent = cur->parent;
2941 elem->next = cur;
2942 elem->prev = cur->prev;
2943 cur->prev = elem;
2944 if (elem->prev != NULL)
2945 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002946 if (elem->parent != NULL) {
2947 if (elem->type == XML_ATTRIBUTE_NODE) {
2948 if (elem->parent->properties == (xmlAttrPtr) cur) {
2949 elem->parent->properties = (xmlAttrPtr) elem;
2950 }
2951 } else {
2952 if (elem->parent->children == cur) {
2953 elem->parent->children = elem;
2954 }
2955 }
2956 }
Owen Taylor3473f882001-02-23 17:55:21 +00002957 return(elem);
2958}
Daniel Veillard652327a2003-09-29 18:02:38 +00002959#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002960
2961/**
2962 * xmlAddSibling:
2963 * @cur: the child node
2964 * @elem: the new node
2965 *
2966 * Add a new element @elem to the list of siblings of @cur
2967 * merging adjacent TEXT nodes (@elem may be freed)
2968 * If the new element was already inserted in a document it is
2969 * first unlinked from its existing context.
2970 *
2971 * Returns the new element or NULL in case of error.
2972 */
2973xmlNodePtr
2974xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2975 xmlNodePtr parent;
2976
2977 if (cur == NULL) {
2978#ifdef DEBUG_TREE
2979 xmlGenericError(xmlGenericErrorContext,
2980 "xmlAddSibling : cur == NULL\n");
2981#endif
2982 return(NULL);
2983 }
2984
2985 if (elem == NULL) {
2986#ifdef DEBUG_TREE
2987 xmlGenericError(xmlGenericErrorContext,
2988 "xmlAddSibling : elem == NULL\n");
2989#endif
2990 return(NULL);
2991 }
2992
2993 /*
2994 * Constant time is we can rely on the ->parent->last to find
2995 * the last sibling.
2996 */
2997 if ((cur->parent != NULL) &&
2998 (cur->parent->children != NULL) &&
2999 (cur->parent->last != NULL) &&
3000 (cur->parent->last->next == NULL)) {
3001 cur = cur->parent->last;
3002 } else {
3003 while (cur->next != NULL) cur = cur->next;
3004 }
3005
3006 xmlUnlinkNode(elem);
3007
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003008 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3009 (cur->name == elem->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003010 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003011 xmlFreeNode(elem);
3012 return(cur);
3013 }
3014
3015 if (elem->doc != cur->doc) {
3016 xmlSetTreeDoc(elem, cur->doc);
3017 }
3018 parent = cur->parent;
3019 elem->prev = cur;
3020 elem->next = NULL;
3021 elem->parent = parent;
3022 cur->next = elem;
3023 if (parent != NULL)
3024 parent->last = elem;
3025
3026 return(elem);
3027}
3028
3029/**
3030 * xmlAddChildList:
3031 * @parent: the parent node
3032 * @cur: the first node in the list
3033 *
3034 * Add a list of node at the end of the child list of the parent
3035 * merging adjacent TEXT nodes (@cur may be freed)
3036 *
3037 * Returns the last child or NULL in case of error.
3038 */
3039xmlNodePtr
3040xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3041 xmlNodePtr prev;
3042
3043 if (parent == NULL) {
3044#ifdef DEBUG_TREE
3045 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003046 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003047#endif
3048 return(NULL);
3049 }
3050
3051 if (cur == NULL) {
3052#ifdef DEBUG_TREE
3053 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003054 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003055#endif
3056 return(NULL);
3057 }
3058
3059 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3060 (cur->doc != parent->doc)) {
3061#ifdef DEBUG_TREE
3062 xmlGenericError(xmlGenericErrorContext,
3063 "Elements moved to a different document\n");
3064#endif
3065 }
3066
3067 /*
3068 * add the first element at the end of the children list.
3069 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003070
Owen Taylor3473f882001-02-23 17:55:21 +00003071 if (parent->children == NULL) {
3072 parent->children = cur;
3073 } else {
3074 /*
3075 * If cur and parent->last both are TEXT nodes, then merge them.
3076 */
3077 if ((cur->type == XML_TEXT_NODE) &&
3078 (parent->last->type == XML_TEXT_NODE) &&
3079 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003080 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003081 /*
3082 * if it's the only child, nothing more to be done.
3083 */
3084 if (cur->next == NULL) {
3085 xmlFreeNode(cur);
3086 return(parent->last);
3087 }
3088 prev = cur;
3089 cur = cur->next;
3090 xmlFreeNode(prev);
3091 }
3092 prev = parent->last;
3093 prev->next = cur;
3094 cur->prev = prev;
3095 }
3096 while (cur->next != NULL) {
3097 cur->parent = parent;
3098 if (cur->doc != parent->doc) {
3099 xmlSetTreeDoc(cur, parent->doc);
3100 }
3101 cur = cur->next;
3102 }
3103 cur->parent = parent;
3104 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
3105 parent->last = cur;
3106
3107 return(cur);
3108}
3109
3110/**
3111 * xmlAddChild:
3112 * @parent: the parent node
3113 * @cur: the child node
3114 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003115 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003116 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003117 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3118 * If there is an attribute with equal name, it is first destroyed.
3119 *
Owen Taylor3473f882001-02-23 17:55:21 +00003120 * Returns the child or NULL in case of error.
3121 */
3122xmlNodePtr
3123xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3124 xmlNodePtr prev;
3125
3126 if (parent == NULL) {
3127#ifdef DEBUG_TREE
3128 xmlGenericError(xmlGenericErrorContext,
3129 "xmlAddChild : parent == NULL\n");
3130#endif
3131 return(NULL);
3132 }
3133
3134 if (cur == NULL) {
3135#ifdef DEBUG_TREE
3136 xmlGenericError(xmlGenericErrorContext,
3137 "xmlAddChild : child == NULL\n");
3138#endif
3139 return(NULL);
3140 }
3141
Owen Taylor3473f882001-02-23 17:55:21 +00003142 /*
3143 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003144 * cur is then freed.
3145 */
3146 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003147 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003148 (parent->content != NULL) &&
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003149 (parent->name == cur->name) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003150 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003151 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003152 xmlFreeNode(cur);
3153 return(parent);
3154 }
3155 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003156 (parent->last->name == cur->name) &&
3157 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003158 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003159 xmlFreeNode(cur);
3160 return(parent->last);
3161 }
3162 }
3163
3164 /*
3165 * add the new element at the end of the children list.
3166 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003167 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003168 cur->parent = parent;
3169 if (cur->doc != parent->doc) {
3170 xmlSetTreeDoc(cur, parent->doc);
3171 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003172 /* this check prevents a loop on tree-traversions if a developer
3173 * tries to add a node to its parent multiple times
3174 */
3175 if (prev == parent)
3176 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003177
3178 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003179 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003180 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003181 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003182 (parent->content != NULL) &&
3183 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003184 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003185 xmlFreeNode(cur);
3186 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003187 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003188 if (cur->type == XML_ATTRIBUTE_NODE) {
3189 if (parent->properties == NULL) {
3190 parent->properties = (xmlAttrPtr) cur;
3191 } else {
3192 /* check if an attribute with the same name exists */
3193 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003194
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003195 if (cur->ns == NULL)
3196 lastattr = xmlHasProp(parent, cur->name);
3197 else
3198 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3199 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
3200 /* different instance, destroy it (attributes must be unique) */
3201 xmlFreeProp(lastattr);
3202 }
3203 /* find the end */
3204 lastattr = parent->properties;
3205 while (lastattr->next != NULL) {
3206 lastattr = lastattr->next;
3207 }
3208 lastattr->next = (xmlAttrPtr) cur;
3209 ((xmlAttrPtr) cur)->prev = lastattr;
3210 }
3211 } else {
3212 if (parent->children == NULL) {
3213 parent->children = cur;
3214 parent->last = cur;
3215 } else {
3216 prev = parent->last;
3217 prev->next = cur;
3218 cur->prev = prev;
3219 parent->last = cur;
3220 }
3221 }
Owen Taylor3473f882001-02-23 17:55:21 +00003222 return(cur);
3223}
3224
3225/**
3226 * xmlGetLastChild:
3227 * @parent: the parent node
3228 *
3229 * Search the last child of a node.
3230 * Returns the last child or NULL if none.
3231 */
3232xmlNodePtr
3233xmlGetLastChild(xmlNodePtr parent) {
3234 if (parent == NULL) {
3235#ifdef DEBUG_TREE
3236 xmlGenericError(xmlGenericErrorContext,
3237 "xmlGetLastChild : parent == NULL\n");
3238#endif
3239 return(NULL);
3240 }
3241 return(parent->last);
3242}
3243
3244/**
3245 * xmlFreeNodeList:
3246 * @cur: the first node in the list
3247 *
3248 * Free a node and all its siblings, this is a recursive behaviour, all
3249 * the children are freed too.
3250 */
3251void
3252xmlFreeNodeList(xmlNodePtr cur) {
3253 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003254 xmlDictPtr dict = NULL;
3255
3256 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003257 if (cur->type == XML_NAMESPACE_DECL) {
3258 xmlFreeNsList((xmlNsPtr) cur);
3259 return;
3260 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003261 if ((cur->type == XML_DOCUMENT_NODE) ||
3262#ifdef LIBXML_DOCB_ENABLED
3263 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003264#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003265 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003266 xmlFreeDoc((xmlDocPtr) cur);
3267 return;
3268 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003269 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003270 while (cur != NULL) {
3271 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003272 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003273
Daniel Veillarda880b122003-04-21 21:36:41 +00003274 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003275 xmlDeregisterNodeDefaultValue(cur);
3276
Daniel Veillard02141ea2001-04-30 11:46:40 +00003277 if ((cur->children != NULL) &&
3278 (cur->type != XML_ENTITY_REF_NODE))
3279 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003280 if (((cur->type == XML_ELEMENT_NODE) ||
3281 (cur->type == XML_XINCLUDE_START) ||
3282 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003283 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003284 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003285 if ((cur->type != XML_ELEMENT_NODE) &&
3286 (cur->type != XML_XINCLUDE_START) &&
3287 (cur->type != XML_XINCLUDE_END) &&
3288 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003289 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003290 }
3291 if (((cur->type == XML_ELEMENT_NODE) ||
3292 (cur->type == XML_XINCLUDE_START) ||
3293 (cur->type == XML_XINCLUDE_END)) &&
3294 (cur->nsDef != NULL))
3295 xmlFreeNsList(cur->nsDef);
3296
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003297 /*
3298 * When a node is a text node or a comment, it uses a global static
3299 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003300 * Otherwise the node name might come from the document's
3301 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003302 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003303 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003304 (cur->type != XML_TEXT_NODE) &&
3305 (cur->type != XML_COMMENT_NODE))
3306 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003307 xmlFree(cur);
3308 }
Owen Taylor3473f882001-02-23 17:55:21 +00003309 cur = next;
3310 }
3311}
3312
3313/**
3314 * xmlFreeNode:
3315 * @cur: the node
3316 *
3317 * Free a node, this is a recursive behaviour, all the children are freed too.
3318 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3319 */
3320void
3321xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003322 xmlDictPtr dict = NULL;
3323
3324 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003325
Daniel Veillard02141ea2001-04-30 11:46:40 +00003326 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003327 if (cur->type == XML_DTD_NODE) {
3328 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003329 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003330 }
3331 if (cur->type == XML_NAMESPACE_DECL) {
3332 xmlFreeNs((xmlNsPtr) cur);
3333 return;
3334 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003335 if (cur->type == XML_ATTRIBUTE_NODE) {
3336 xmlFreeProp((xmlAttrPtr) cur);
3337 return;
3338 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003339
Daniel Veillarda880b122003-04-21 21:36:41 +00003340 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003341 xmlDeregisterNodeDefaultValue(cur);
3342
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003343 if (cur->doc != NULL) dict = cur->doc->dict;
3344
Owen Taylor3473f882001-02-23 17:55:21 +00003345 if ((cur->children != NULL) &&
3346 (cur->type != XML_ENTITY_REF_NODE))
3347 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003348 if (((cur->type == XML_ELEMENT_NODE) ||
3349 (cur->type == XML_XINCLUDE_START) ||
3350 (cur->type == XML_XINCLUDE_END)) &&
3351 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003352 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003353 if ((cur->type != XML_ELEMENT_NODE) &&
3354 (cur->content != NULL) &&
3355 (cur->type != XML_ENTITY_REF_NODE) &&
3356 (cur->type != XML_XINCLUDE_END) &&
3357 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003358 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003359 }
3360
Daniel Veillardacd370f2001-06-09 17:17:51 +00003361 /*
3362 * When a node is a text node or a comment, it uses a global static
3363 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003364 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003365 */
Owen Taylor3473f882001-02-23 17:55:21 +00003366 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003367 (cur->type != XML_TEXT_NODE) &&
3368 (cur->type != XML_COMMENT_NODE))
3369 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003370
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003371 if (((cur->type == XML_ELEMENT_NODE) ||
3372 (cur->type == XML_XINCLUDE_START) ||
3373 (cur->type == XML_XINCLUDE_END)) &&
3374 (cur->nsDef != NULL))
3375 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003376 xmlFree(cur);
3377}
3378
3379/**
3380 * xmlUnlinkNode:
3381 * @cur: the node
3382 *
3383 * Unlink a node from it's current context, the node is not freed
3384 */
3385void
3386xmlUnlinkNode(xmlNodePtr cur) {
3387 if (cur == NULL) {
3388#ifdef DEBUG_TREE
3389 xmlGenericError(xmlGenericErrorContext,
3390 "xmlUnlinkNode : node == NULL\n");
3391#endif
3392 return;
3393 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003394 if (cur->type == XML_DTD_NODE) {
3395 xmlDocPtr doc;
3396 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003397 if (doc != NULL) {
3398 if (doc->intSubset == (xmlDtdPtr) cur)
3399 doc->intSubset = NULL;
3400 if (doc->extSubset == (xmlDtdPtr) cur)
3401 doc->extSubset = NULL;
3402 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003403 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003404 if (cur->parent != NULL) {
3405 xmlNodePtr parent;
3406 parent = cur->parent;
3407 if (cur->type == XML_ATTRIBUTE_NODE) {
3408 if (parent->properties == (xmlAttrPtr) cur)
3409 parent->properties = ((xmlAttrPtr) cur)->next;
3410 } else {
3411 if (parent->children == cur)
3412 parent->children = cur->next;
3413 if (parent->last == cur)
3414 parent->last = cur->prev;
3415 }
3416 cur->parent = NULL;
3417 }
Owen Taylor3473f882001-02-23 17:55:21 +00003418 if (cur->next != NULL)
3419 cur->next->prev = cur->prev;
3420 if (cur->prev != NULL)
3421 cur->prev->next = cur->next;
3422 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003423}
3424
Daniel Veillard652327a2003-09-29 18:02:38 +00003425#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003426/**
3427 * xmlReplaceNode:
3428 * @old: the old node
3429 * @cur: the node
3430 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00003431 * Unlink the old node from its current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003432 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003433 * first unlinked from its existing context.
3434 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003435 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003436 */
3437xmlNodePtr
3438xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3439 if (old == NULL) {
3440#ifdef DEBUG_TREE
3441 xmlGenericError(xmlGenericErrorContext,
3442 "xmlReplaceNode : old == NULL\n");
3443#endif
3444 return(NULL);
3445 }
3446 if (cur == NULL) {
3447 xmlUnlinkNode(old);
3448 return(old);
3449 }
3450 if (cur == old) {
3451 return(old);
3452 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003453 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3454#ifdef DEBUG_TREE
3455 xmlGenericError(xmlGenericErrorContext,
3456 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3457#endif
3458 return(old);
3459 }
3460 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3461#ifdef DEBUG_TREE
3462 xmlGenericError(xmlGenericErrorContext,
3463 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3464#endif
3465 return(old);
3466 }
Owen Taylor3473f882001-02-23 17:55:21 +00003467 xmlUnlinkNode(cur);
3468 cur->doc = old->doc;
3469 cur->parent = old->parent;
3470 cur->next = old->next;
3471 if (cur->next != NULL)
3472 cur->next->prev = cur;
3473 cur->prev = old->prev;
3474 if (cur->prev != NULL)
3475 cur->prev->next = cur;
3476 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003477 if (cur->type == XML_ATTRIBUTE_NODE) {
3478 if (cur->parent->properties == (xmlAttrPtr)old)
3479 cur->parent->properties = ((xmlAttrPtr) cur);
3480 } else {
3481 if (cur->parent->children == old)
3482 cur->parent->children = cur;
3483 if (cur->parent->last == old)
3484 cur->parent->last = cur;
3485 }
Owen Taylor3473f882001-02-23 17:55:21 +00003486 }
3487 old->next = old->prev = NULL;
3488 old->parent = NULL;
3489 return(old);
3490}
Daniel Veillard652327a2003-09-29 18:02:38 +00003491#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003492
3493/************************************************************************
3494 * *
3495 * Copy operations *
3496 * *
3497 ************************************************************************/
3498
3499/**
3500 * xmlCopyNamespace:
3501 * @cur: the namespace
3502 *
3503 * Do a copy of the namespace.
3504 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003505 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003506 */
3507xmlNsPtr
3508xmlCopyNamespace(xmlNsPtr cur) {
3509 xmlNsPtr ret;
3510
3511 if (cur == NULL) return(NULL);
3512 switch (cur->type) {
3513 case XML_LOCAL_NAMESPACE:
3514 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3515 break;
3516 default:
3517#ifdef DEBUG_TREE
3518 xmlGenericError(xmlGenericErrorContext,
3519 "xmlCopyNamespace: invalid type %d\n", cur->type);
3520#endif
3521 return(NULL);
3522 }
3523 return(ret);
3524}
3525
3526/**
3527 * xmlCopyNamespaceList:
3528 * @cur: the first namespace
3529 *
3530 * Do a copy of an namespace list.
3531 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003532 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003533 */
3534xmlNsPtr
3535xmlCopyNamespaceList(xmlNsPtr cur) {
3536 xmlNsPtr ret = NULL;
3537 xmlNsPtr p = NULL,q;
3538
3539 while (cur != NULL) {
3540 q = xmlCopyNamespace(cur);
3541 if (p == NULL) {
3542 ret = p = q;
3543 } else {
3544 p->next = q;
3545 p = q;
3546 }
3547 cur = cur->next;
3548 }
3549 return(ret);
3550}
3551
3552static xmlNodePtr
3553xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3554/**
3555 * xmlCopyProp:
3556 * @target: the element where the attribute will be grafted
3557 * @cur: the attribute
3558 *
3559 * Do a copy of the attribute.
3560 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003561 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003562 */
3563xmlAttrPtr
3564xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3565 xmlAttrPtr ret;
3566
3567 if (cur == NULL) return(NULL);
3568 if (target != NULL)
3569 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3570 else if (cur->parent != NULL)
3571 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3572 else if (cur->children != NULL)
3573 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3574 else
3575 ret = xmlNewDocProp(NULL, cur->name, NULL);
3576 if (ret == NULL) return(NULL);
3577 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003578
Owen Taylor3473f882001-02-23 17:55:21 +00003579 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003580 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003581
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003582 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3583 if (ns == NULL) {
3584 /*
3585 * Humm, we are copying an element whose namespace is defined
3586 * out of the new tree scope. Search it in the original tree
3587 * and add it at the top of the new tree
3588 */
3589 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3590 if (ns != NULL) {
3591 xmlNodePtr root = target;
3592 xmlNodePtr pred = NULL;
3593
3594 while (root->parent != NULL) {
3595 pred = root;
3596 root = root->parent;
3597 }
3598 if (root == (xmlNodePtr) target->doc) {
3599 /* correct possibly cycling above the document elt */
3600 root = pred;
3601 }
3602 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3603 }
3604 } else {
3605 /*
3606 * we have to find something appropriate here since
3607 * we cant be sure, that the namespce we found is identified
3608 * by the prefix
3609 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003610 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003611 /* this is the nice case */
3612 ret->ns = ns;
3613 } else {
3614 /*
3615 * we are in trouble: we need a new reconcilied namespace.
3616 * This is expensive
3617 */
3618 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3619 }
3620 }
3621
Owen Taylor3473f882001-02-23 17:55:21 +00003622 } else
3623 ret->ns = NULL;
3624
3625 if (cur->children != NULL) {
3626 xmlNodePtr tmp;
3627
3628 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3629 ret->last = NULL;
3630 tmp = ret->children;
3631 while (tmp != NULL) {
3632 /* tmp->parent = (xmlNodePtr)ret; */
3633 if (tmp->next == NULL)
3634 ret->last = tmp;
3635 tmp = tmp->next;
3636 }
3637 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003638 /*
3639 * Try to handle IDs
3640 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003641 if ((target!= NULL) && (cur!= NULL) &&
3642 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003643 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3644 if (xmlIsID(cur->doc, cur->parent, cur)) {
3645 xmlChar *id;
3646
3647 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3648 if (id != NULL) {
3649 xmlAddID(NULL, target->doc, id, ret);
3650 xmlFree(id);
3651 }
3652 }
3653 }
Owen Taylor3473f882001-02-23 17:55:21 +00003654 return(ret);
3655}
3656
3657/**
3658 * xmlCopyPropList:
3659 * @target: the element where the attributes will be grafted
3660 * @cur: the first attribute
3661 *
3662 * Do a copy of an attribute list.
3663 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003664 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003665 */
3666xmlAttrPtr
3667xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3668 xmlAttrPtr ret = NULL;
3669 xmlAttrPtr p = NULL,q;
3670
3671 while (cur != NULL) {
3672 q = xmlCopyProp(target, cur);
3673 if (p == NULL) {
3674 ret = p = q;
3675 } else {
3676 p->next = q;
3677 q->prev = p;
3678 p = q;
3679 }
3680 cur = cur->next;
3681 }
3682 return(ret);
3683}
3684
3685/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003686 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003687 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003688 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003689 * tricky reason: namespaces. Doing a direct copy of a node
3690 * say RPM:Copyright without changing the namespace pointer to
3691 * something else can produce stale links. One way to do it is
3692 * to keep a reference counter but this doesn't work as soon
3693 * as one move the element or the subtree out of the scope of
3694 * the existing namespace. The actual solution seems to add
3695 * a copy of the namespace at the top of the copied tree if
3696 * not available in the subtree.
3697 * Hence two functions, the public front-end call the inner ones
3698 */
3699
3700static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003701xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003702 int recursive) {
3703 xmlNodePtr ret;
3704
3705 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003706 switch (node->type) {
3707 case XML_TEXT_NODE:
3708 case XML_CDATA_SECTION_NODE:
3709 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003710 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003711 case XML_ENTITY_REF_NODE:
3712 case XML_ENTITY_NODE:
3713 case XML_PI_NODE:
3714 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003715 case XML_XINCLUDE_START:
3716 case XML_XINCLUDE_END:
3717 break;
3718 case XML_ATTRIBUTE_NODE:
3719 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3720 case XML_NAMESPACE_DECL:
3721 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3722
Daniel Veillard39196eb2001-06-19 18:09:42 +00003723 case XML_DOCUMENT_NODE:
3724 case XML_HTML_DOCUMENT_NODE:
3725#ifdef LIBXML_DOCB_ENABLED
3726 case XML_DOCB_DOCUMENT_NODE:
3727#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00003728#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003729 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard652327a2003-09-29 18:02:38 +00003730#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00003731 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003732 case XML_NOTATION_NODE:
3733 case XML_DTD_NODE:
3734 case XML_ELEMENT_DECL:
3735 case XML_ATTRIBUTE_DECL:
3736 case XML_ENTITY_DECL:
3737 return(NULL);
3738 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003739
Owen Taylor3473f882001-02-23 17:55:21 +00003740 /*
3741 * Allocate a new node and fill the fields.
3742 */
3743 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3744 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00003745 xmlTreeErrMemory("copying node");
Owen Taylor3473f882001-02-23 17:55:21 +00003746 return(NULL);
3747 }
3748 memset(ret, 0, sizeof(xmlNode));
3749 ret->type = node->type;
3750
3751 ret->doc = doc;
3752 ret->parent = parent;
3753 if (node->name == xmlStringText)
3754 ret->name = xmlStringText;
3755 else if (node->name == xmlStringTextNoenc)
3756 ret->name = xmlStringTextNoenc;
3757 else if (node->name == xmlStringComment)
3758 ret->name = xmlStringComment;
3759 else if (node->name != NULL)
3760 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003761 if ((node->type != XML_ELEMENT_NODE) &&
3762 (node->content != NULL) &&
3763 (node->type != XML_ENTITY_REF_NODE) &&
3764 (node->type != XML_XINCLUDE_END) &&
3765 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003766 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003767 }else{
3768 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00003769 ret->line = node->line;
Owen Taylor3473f882001-02-23 17:55:21 +00003770 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003771 if (parent != NULL) {
3772 xmlNodePtr tmp;
3773
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003774 /*
3775 * this is a tricky part for the node register thing:
3776 * in case ret does get coalesced in xmlAddChild
3777 * the deregister-node callback is called; so we register ret now already
3778 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003779 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003780 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3781
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003782 tmp = xmlAddChild(parent, ret);
3783 /* node could have coalesced */
3784 if (tmp != ret)
3785 return(tmp);
3786 }
Owen Taylor3473f882001-02-23 17:55:21 +00003787
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003788 if (!recursive)
3789 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003790 if (node->nsDef != NULL)
3791 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3792
3793 if (node->ns != NULL) {
3794 xmlNsPtr ns;
3795
3796 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3797 if (ns == NULL) {
3798 /*
3799 * Humm, we are copying an element whose namespace is defined
3800 * out of the new tree scope. Search it in the original tree
3801 * and add it at the top of the new tree
3802 */
3803 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3804 if (ns != NULL) {
3805 xmlNodePtr root = ret;
3806
3807 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003808 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003809 }
3810 } else {
3811 /*
3812 * reference the existing namespace definition in our own tree.
3813 */
3814 ret->ns = ns;
3815 }
3816 }
3817 if (node->properties != NULL)
3818 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003819 if (node->type == XML_ENTITY_REF_NODE) {
3820 if ((doc == NULL) || (node->doc != doc)) {
3821 /*
3822 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003823 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003824 * we cannot keep the reference. Try to find it in the
3825 * target document.
3826 */
3827 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3828 } else {
3829 ret->children = node->children;
3830 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003831 ret->last = ret->children;
3832 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003833 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003834 UPDATE_LAST_CHILD_AND_PARENT(ret)
3835 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003836
3837out:
3838 /* if parent != NULL we already registered the node above */
3839 if (parent == NULL && xmlRegisterNodeDefaultValue)
3840 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003841 return(ret);
3842}
3843
3844static xmlNodePtr
3845xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3846 xmlNodePtr ret = NULL;
3847 xmlNodePtr p = NULL,q;
3848
3849 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00003850#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003851 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003852 if (doc == NULL) {
3853 node = node->next;
3854 continue;
3855 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003856 if (doc->intSubset == NULL) {
3857 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3858 q->doc = doc;
3859 q->parent = parent;
3860 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003861 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003862 } else {
3863 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003864 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003865 }
3866 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00003867#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00003868 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003869 if (ret == NULL) {
3870 q->prev = NULL;
3871 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003872 } else if (p != q) {
3873 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003874 p->next = q;
3875 q->prev = p;
3876 p = q;
3877 }
3878 node = node->next;
3879 }
3880 return(ret);
3881}
3882
3883/**
3884 * xmlCopyNode:
3885 * @node: the node
3886 * @recursive: if 1 do a recursive copy.
3887 *
3888 * Do a copy of the node.
3889 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003890 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003891 */
3892xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003893xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003894 xmlNodePtr ret;
3895
3896 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3897 return(ret);
3898}
3899
3900/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003901 * xmlDocCopyNode:
3902 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003903 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003904 * @recursive: if 1 do a recursive copy.
3905 *
3906 * Do a copy of the node to a given document.
3907 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003908 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003909 */
3910xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003911xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003912 xmlNodePtr ret;
3913
3914 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3915 return(ret);
3916}
3917
3918/**
Owen Taylor3473f882001-02-23 17:55:21 +00003919 * xmlCopyNodeList:
3920 * @node: the first node in the list.
3921 *
3922 * Do a recursive copy of the node list.
3923 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003924 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003925 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003926xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003927 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3928 return(ret);
3929}
3930
Daniel Veillard652327a2003-09-29 18:02:38 +00003931#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003932/**
Owen Taylor3473f882001-02-23 17:55:21 +00003933 * xmlCopyDtd:
3934 * @dtd: the dtd
3935 *
3936 * Do a copy of the dtd.
3937 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003938 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003939 */
3940xmlDtdPtr
3941xmlCopyDtd(xmlDtdPtr dtd) {
3942 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003943 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003944
3945 if (dtd == NULL) return(NULL);
3946 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3947 if (ret == NULL) return(NULL);
3948 if (dtd->entities != NULL)
3949 ret->entities = (void *) xmlCopyEntitiesTable(
3950 (xmlEntitiesTablePtr) dtd->entities);
3951 if (dtd->notations != NULL)
3952 ret->notations = (void *) xmlCopyNotationTable(
3953 (xmlNotationTablePtr) dtd->notations);
3954 if (dtd->elements != NULL)
3955 ret->elements = (void *) xmlCopyElementTable(
3956 (xmlElementTablePtr) dtd->elements);
3957 if (dtd->attributes != NULL)
3958 ret->attributes = (void *) xmlCopyAttributeTable(
3959 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003960 if (dtd->pentities != NULL)
3961 ret->pentities = (void *) xmlCopyEntitiesTable(
3962 (xmlEntitiesTablePtr) dtd->pentities);
3963
3964 cur = dtd->children;
3965 while (cur != NULL) {
3966 q = NULL;
3967
3968 if (cur->type == XML_ENTITY_DECL) {
3969 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3970 switch (tmp->etype) {
3971 case XML_INTERNAL_GENERAL_ENTITY:
3972 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3973 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3974 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3975 break;
3976 case XML_INTERNAL_PARAMETER_ENTITY:
3977 case XML_EXTERNAL_PARAMETER_ENTITY:
3978 q = (xmlNodePtr)
3979 xmlGetParameterEntityFromDtd(ret, tmp->name);
3980 break;
3981 case XML_INTERNAL_PREDEFINED_ENTITY:
3982 break;
3983 }
3984 } else if (cur->type == XML_ELEMENT_DECL) {
3985 xmlElementPtr tmp = (xmlElementPtr) cur;
3986 q = (xmlNodePtr)
3987 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3988 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3989 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3990 q = (xmlNodePtr)
3991 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3992 } else if (cur->type == XML_COMMENT_NODE) {
3993 q = xmlCopyNode(cur, 0);
3994 }
3995
3996 if (q == NULL) {
3997 cur = cur->next;
3998 continue;
3999 }
4000
4001 if (p == NULL)
4002 ret->children = q;
4003 else
4004 p->next = q;
4005
4006 q->prev = p;
4007 q->parent = (xmlNodePtr) ret;
4008 q->next = NULL;
4009 ret->last = q;
4010 p = q;
4011 cur = cur->next;
4012 }
4013
Owen Taylor3473f882001-02-23 17:55:21 +00004014 return(ret);
4015}
4016
4017/**
4018 * xmlCopyDoc:
4019 * @doc: the document
4020 * @recursive: if 1 do a recursive copy.
4021 *
4022 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004023 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004024 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004025 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004026 */
4027xmlDocPtr
4028xmlCopyDoc(xmlDocPtr doc, int recursive) {
4029 xmlDocPtr ret;
4030
4031 if (doc == NULL) return(NULL);
4032 ret = xmlNewDoc(doc->version);
4033 if (ret == NULL) return(NULL);
4034 if (doc->name != NULL)
4035 ret->name = xmlMemStrdup(doc->name);
4036 if (doc->encoding != NULL)
4037 ret->encoding = xmlStrdup(doc->encoding);
4038 ret->charset = doc->charset;
4039 ret->compression = doc->compression;
4040 ret->standalone = doc->standalone;
4041 if (!recursive) return(ret);
4042
Daniel Veillardb33c2012001-04-25 12:59:04 +00004043 ret->last = NULL;
4044 ret->children = NULL;
4045 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004046 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004047 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004048 ret->intSubset->parent = ret;
4049 }
Owen Taylor3473f882001-02-23 17:55:21 +00004050 if (doc->oldNs != NULL)
4051 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4052 if (doc->children != NULL) {
4053 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00004054
4055 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4056 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004057 ret->last = NULL;
4058 tmp = ret->children;
4059 while (tmp != NULL) {
4060 if (tmp->next == NULL)
4061 ret->last = tmp;
4062 tmp = tmp->next;
4063 }
4064 }
4065 return(ret);
4066}
Daniel Veillard652327a2003-09-29 18:02:38 +00004067#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004068
4069/************************************************************************
4070 * *
4071 * Content access functions *
4072 * *
4073 ************************************************************************/
4074
4075/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004076 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004077 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004078 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00004079 * Get line number of @node. This requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004080 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004081 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004082 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004083 */
4084long
4085xmlGetLineNo(xmlNodePtr node)
4086{
4087 long result = -1;
4088
4089 if (!node)
4090 return result;
4091 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004092 result = (long) node->line;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004093 else if ((node->prev != NULL) &&
4094 ((node->prev->type == XML_ELEMENT_NODE) ||
4095 (node->prev->type == XML_TEXT_NODE)))
4096 result = xmlGetLineNo(node->prev);
4097 else if ((node->parent != NULL) &&
4098 ((node->parent->type == XML_ELEMENT_NODE) ||
4099 (node->parent->type == XML_TEXT_NODE)))
4100 result = xmlGetLineNo(node->parent);
4101
4102 return result;
4103}
4104
Daniel Veillard652327a2003-09-29 18:02:38 +00004105#ifdef LIBXML_TREE_ENABLED
Daniel Veillard8faa7832001-11-26 15:58:08 +00004106/**
4107 * xmlGetNodePath:
4108 * @node: a node
4109 *
4110 * Build a structure based Path for the given node
4111 *
4112 * Returns the new path or NULL in case of error. The caller must free
4113 * the returned string
4114 */
4115xmlChar *
4116xmlGetNodePath(xmlNodePtr node)
4117{
4118 xmlNodePtr cur, tmp, next;
4119 xmlChar *buffer = NULL, *temp;
4120 size_t buf_len;
4121 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004122 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004123 const char *name;
4124 char nametemp[100];
4125 int occur = 0;
4126
4127 if (node == NULL)
4128 return (NULL);
4129
4130 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004131 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004132 if (buffer == NULL) {
4133 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004134 return (NULL);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004135 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004136 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004137 if (buf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004138 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004139 xmlFree(buffer);
4140 return (NULL);
4141 }
4142
4143 buffer[0] = 0;
4144 cur = node;
4145 do {
4146 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004147 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004148 occur = 0;
4149 if ((cur->type == XML_DOCUMENT_NODE) ||
4150 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4151 if (buffer[0] == '/')
4152 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004153 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004154 next = NULL;
4155 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004156 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004157 name = (const char *) cur->name;
4158 if (cur->ns) {
4159 snprintf(nametemp, sizeof(nametemp) - 1,
4160 "%s:%s", cur->ns->prefix, cur->name);
4161 nametemp[sizeof(nametemp) - 1] = 0;
4162 name = nametemp;
4163 }
4164 next = cur->parent;
4165
4166 /*
4167 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004168 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004169 */
4170 tmp = cur->prev;
4171 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004172 if ((tmp->type == XML_ELEMENT_NODE) &&
4173 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004174 occur++;
4175 tmp = tmp->prev;
4176 }
4177 if (occur == 0) {
4178 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004179 while (tmp != NULL && occur == 0) {
4180 if ((tmp->type == XML_ELEMENT_NODE) &&
4181 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004182 occur++;
4183 tmp = tmp->next;
4184 }
4185 if (occur != 0)
4186 occur = 1;
4187 } else
4188 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004189 } else if (cur->type == XML_COMMENT_NODE) {
4190 sep = "/";
4191 name = "comment()";
4192 next = cur->parent;
4193
4194 /*
4195 * Thumbler index computation
4196 */
4197 tmp = cur->prev;
4198 while (tmp != NULL) {
4199 if (tmp->type == XML_COMMENT_NODE)
4200 occur++;
4201 tmp = tmp->prev;
4202 }
4203 if (occur == 0) {
4204 tmp = cur->next;
4205 while (tmp != NULL && occur == 0) {
4206 if (tmp->type == XML_COMMENT_NODE)
4207 occur++;
4208 tmp = tmp->next;
4209 }
4210 if (occur != 0)
4211 occur = 1;
4212 } else
4213 occur++;
4214 } else if ((cur->type == XML_TEXT_NODE) ||
4215 (cur->type == XML_CDATA_SECTION_NODE)) {
4216 sep = "/";
4217 name = "text()";
4218 next = cur->parent;
4219
4220 /*
4221 * Thumbler index computation
4222 */
4223 tmp = cur->prev;
4224 while (tmp != NULL) {
4225 if ((cur->type == XML_TEXT_NODE) ||
4226 (cur->type == XML_CDATA_SECTION_NODE))
4227 occur++;
4228 tmp = tmp->prev;
4229 }
4230 if (occur == 0) {
4231 tmp = cur->next;
4232 while (tmp != NULL && occur == 0) {
4233 if ((cur->type == XML_TEXT_NODE) ||
4234 (cur->type == XML_CDATA_SECTION_NODE))
4235 occur++;
4236 tmp = tmp->next;
4237 }
4238 if (occur != 0)
4239 occur = 1;
4240 } else
4241 occur++;
4242 } else if (cur->type == XML_PI_NODE) {
4243 sep = "/";
4244 snprintf(nametemp, sizeof(nametemp) - 1,
4245 "processing-instruction('%s')", cur->name);
4246 nametemp[sizeof(nametemp) - 1] = 0;
4247 name = nametemp;
4248
4249 next = cur->parent;
4250
4251 /*
4252 * Thumbler index computation
4253 */
4254 tmp = cur->prev;
4255 while (tmp != NULL) {
4256 if ((tmp->type == XML_PI_NODE) &&
4257 (xmlStrEqual(cur->name, tmp->name)))
4258 occur++;
4259 tmp = tmp->prev;
4260 }
4261 if (occur == 0) {
4262 tmp = cur->next;
4263 while (tmp != NULL && occur == 0) {
4264 if ((tmp->type == XML_PI_NODE) &&
4265 (xmlStrEqual(cur->name, tmp->name)))
4266 occur++;
4267 tmp = tmp->next;
4268 }
4269 if (occur != 0)
4270 occur = 1;
4271 } else
4272 occur++;
4273
Daniel Veillard8faa7832001-11-26 15:58:08 +00004274 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004275 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004276 name = (const char *) (((xmlAttrPtr) cur)->name);
4277 next = ((xmlAttrPtr) cur)->parent;
4278 } else {
4279 next = cur->parent;
4280 }
4281
4282 /*
4283 * Make sure there is enough room
4284 */
4285 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4286 buf_len =
4287 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4288 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4289 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004290 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004291 xmlFree(buf);
4292 xmlFree(buffer);
4293 return (NULL);
4294 }
4295 buffer = temp;
4296 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4297 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004298 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004299 xmlFree(buf);
4300 xmlFree(buffer);
4301 return (NULL);
4302 }
4303 buf = temp;
4304 }
4305 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004306 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004307 sep, name, (char *) buffer);
4308 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004309 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004310 sep, name, occur, (char *) buffer);
4311 snprintf((char *) buffer, buf_len, "%s", buf);
4312 cur = next;
4313 } while (cur != NULL);
4314 xmlFree(buf);
4315 return (buffer);
4316}
Daniel Veillard652327a2003-09-29 18:02:38 +00004317#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004318
4319/**
Owen Taylor3473f882001-02-23 17:55:21 +00004320 * xmlDocGetRootElement:
4321 * @doc: the document
4322 *
4323 * Get the root element of the document (doc->children is a list
4324 * containing possibly comments, PIs, etc ...).
4325 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004326 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004327 */
4328xmlNodePtr
4329xmlDocGetRootElement(xmlDocPtr doc) {
4330 xmlNodePtr ret;
4331
4332 if (doc == NULL) return(NULL);
4333 ret = doc->children;
4334 while (ret != NULL) {
4335 if (ret->type == XML_ELEMENT_NODE)
4336 return(ret);
4337 ret = ret->next;
4338 }
4339 return(ret);
4340}
4341
Daniel Veillard652327a2003-09-29 18:02:38 +00004342#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004343/**
4344 * xmlDocSetRootElement:
4345 * @doc: the document
4346 * @root: the new document root element
4347 *
4348 * Set the root element of the document (doc->children is a list
4349 * containing possibly comments, PIs, etc ...).
4350 *
4351 * Returns the old root element if any was found
4352 */
4353xmlNodePtr
4354xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4355 xmlNodePtr old = NULL;
4356
4357 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004358 if (root == NULL)
4359 return(NULL);
4360 xmlUnlinkNode(root);
4361 root->doc = doc;
4362 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004363 old = doc->children;
4364 while (old != NULL) {
4365 if (old->type == XML_ELEMENT_NODE)
4366 break;
4367 old = old->next;
4368 }
4369 if (old == NULL) {
4370 if (doc->children == NULL) {
4371 doc->children = root;
4372 doc->last = root;
4373 } else {
4374 xmlAddSibling(doc->children, root);
4375 }
4376 } else {
4377 xmlReplaceNode(old, root);
4378 }
4379 return(old);
4380}
4381
4382/**
4383 * xmlNodeSetLang:
4384 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004385 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004386 *
4387 * Set the language of a node, i.e. the values of the xml:lang
4388 * attribute.
4389 */
4390void
4391xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004392 xmlNsPtr ns;
4393
Owen Taylor3473f882001-02-23 17:55:21 +00004394 if (cur == NULL) return;
4395 switch(cur->type) {
4396 case XML_TEXT_NODE:
4397 case XML_CDATA_SECTION_NODE:
4398 case XML_COMMENT_NODE:
4399 case XML_DOCUMENT_NODE:
4400 case XML_DOCUMENT_TYPE_NODE:
4401 case XML_DOCUMENT_FRAG_NODE:
4402 case XML_NOTATION_NODE:
4403 case XML_HTML_DOCUMENT_NODE:
4404 case XML_DTD_NODE:
4405 case XML_ELEMENT_DECL:
4406 case XML_ATTRIBUTE_DECL:
4407 case XML_ENTITY_DECL:
4408 case XML_PI_NODE:
4409 case XML_ENTITY_REF_NODE:
4410 case XML_ENTITY_NODE:
4411 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004412#ifdef LIBXML_DOCB_ENABLED
4413 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004414#endif
4415 case XML_XINCLUDE_START:
4416 case XML_XINCLUDE_END:
4417 return;
4418 case XML_ELEMENT_NODE:
4419 case XML_ATTRIBUTE_NODE:
4420 break;
4421 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004422 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4423 if (ns == NULL)
4424 return;
4425 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004426}
Daniel Veillard652327a2003-09-29 18:02:38 +00004427#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004428
4429/**
4430 * xmlNodeGetLang:
4431 * @cur: the node being checked
4432 *
4433 * Searches the language of a node, i.e. the values of the xml:lang
4434 * attribute or the one carried by the nearest ancestor.
4435 *
4436 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004437 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004438 */
4439xmlChar *
4440xmlNodeGetLang(xmlNodePtr cur) {
4441 xmlChar *lang;
4442
4443 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004444 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004445 if (lang != NULL)
4446 return(lang);
4447 cur = cur->parent;
4448 }
4449 return(NULL);
4450}
4451
4452
Daniel Veillard652327a2003-09-29 18:02:38 +00004453#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004454/**
4455 * xmlNodeSetSpacePreserve:
4456 * @cur: the node being changed
4457 * @val: the xml:space value ("0": default, 1: "preserve")
4458 *
4459 * Set (or reset) the space preserving behaviour of a node, i.e. the
4460 * value of the xml:space attribute.
4461 */
4462void
4463xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004464 xmlNsPtr ns;
4465
Owen Taylor3473f882001-02-23 17:55:21 +00004466 if (cur == NULL) return;
4467 switch(cur->type) {
4468 case XML_TEXT_NODE:
4469 case XML_CDATA_SECTION_NODE:
4470 case XML_COMMENT_NODE:
4471 case XML_DOCUMENT_NODE:
4472 case XML_DOCUMENT_TYPE_NODE:
4473 case XML_DOCUMENT_FRAG_NODE:
4474 case XML_NOTATION_NODE:
4475 case XML_HTML_DOCUMENT_NODE:
4476 case XML_DTD_NODE:
4477 case XML_ELEMENT_DECL:
4478 case XML_ATTRIBUTE_DECL:
4479 case XML_ENTITY_DECL:
4480 case XML_PI_NODE:
4481 case XML_ENTITY_REF_NODE:
4482 case XML_ENTITY_NODE:
4483 case XML_NAMESPACE_DECL:
4484 case XML_XINCLUDE_START:
4485 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004486#ifdef LIBXML_DOCB_ENABLED
4487 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004488#endif
4489 return;
4490 case XML_ELEMENT_NODE:
4491 case XML_ATTRIBUTE_NODE:
4492 break;
4493 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004494 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4495 if (ns == NULL)
4496 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004497 switch (val) {
4498 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004499 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004500 break;
4501 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004502 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004503 break;
4504 }
4505}
Daniel Veillard652327a2003-09-29 18:02:38 +00004506#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004507
4508/**
4509 * xmlNodeGetSpacePreserve:
4510 * @cur: the node being checked
4511 *
4512 * Searches the space preserving behaviour of a node, i.e. the values
4513 * of the xml:space attribute or the one carried by the nearest
4514 * ancestor.
4515 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004516 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004517 */
4518int
4519xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4520 xmlChar *space;
4521
4522 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004523 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004524 if (space != NULL) {
4525 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4526 xmlFree(space);
4527 return(1);
4528 }
4529 if (xmlStrEqual(space, BAD_CAST "default")) {
4530 xmlFree(space);
4531 return(0);
4532 }
4533 xmlFree(space);
4534 }
4535 cur = cur->parent;
4536 }
4537 return(-1);
4538}
4539
Daniel Veillard652327a2003-09-29 18:02:38 +00004540#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004541/**
4542 * xmlNodeSetName:
4543 * @cur: the node being changed
4544 * @name: the new tag name
4545 *
4546 * Set (or reset) the name of a node.
4547 */
4548void
4549xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
4550 if (cur == NULL) return;
4551 if (name == NULL) return;
4552 switch(cur->type) {
4553 case XML_TEXT_NODE:
4554 case XML_CDATA_SECTION_NODE:
4555 case XML_COMMENT_NODE:
4556 case XML_DOCUMENT_TYPE_NODE:
4557 case XML_DOCUMENT_FRAG_NODE:
4558 case XML_NOTATION_NODE:
4559 case XML_HTML_DOCUMENT_NODE:
4560 case XML_NAMESPACE_DECL:
4561 case XML_XINCLUDE_START:
4562 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004563#ifdef LIBXML_DOCB_ENABLED
4564 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004565#endif
4566 return;
4567 case XML_ELEMENT_NODE:
4568 case XML_ATTRIBUTE_NODE:
4569 case XML_PI_NODE:
4570 case XML_ENTITY_REF_NODE:
4571 case XML_ENTITY_NODE:
4572 case XML_DTD_NODE:
4573 case XML_DOCUMENT_NODE:
4574 case XML_ELEMENT_DECL:
4575 case XML_ATTRIBUTE_DECL:
4576 case XML_ENTITY_DECL:
4577 break;
4578 }
4579 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4580 cur->name = xmlStrdup(name);
4581}
4582
4583/**
4584 * xmlNodeSetBase:
4585 * @cur: the node being changed
4586 * @uri: the new base URI
4587 *
4588 * Set (or reset) the base URI of a node, i.e. the value of the
4589 * xml:base attribute.
4590 */
4591void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00004592xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004593 xmlNsPtr ns;
4594
Owen Taylor3473f882001-02-23 17:55:21 +00004595 if (cur == NULL) return;
4596 switch(cur->type) {
4597 case XML_TEXT_NODE:
4598 case XML_CDATA_SECTION_NODE:
4599 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004600 case XML_DOCUMENT_TYPE_NODE:
4601 case XML_DOCUMENT_FRAG_NODE:
4602 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004603 case XML_DTD_NODE:
4604 case XML_ELEMENT_DECL:
4605 case XML_ATTRIBUTE_DECL:
4606 case XML_ENTITY_DECL:
4607 case XML_PI_NODE:
4608 case XML_ENTITY_REF_NODE:
4609 case XML_ENTITY_NODE:
4610 case XML_NAMESPACE_DECL:
4611 case XML_XINCLUDE_START:
4612 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004613 return;
4614 case XML_ELEMENT_NODE:
4615 case XML_ATTRIBUTE_NODE:
4616 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004617 case XML_DOCUMENT_NODE:
4618#ifdef LIBXML_DOCB_ENABLED
4619 case XML_DOCB_DOCUMENT_NODE:
4620#endif
4621 case XML_HTML_DOCUMENT_NODE: {
4622 xmlDocPtr doc = (xmlDocPtr) cur;
4623
4624 if (doc->URL != NULL)
4625 xmlFree((xmlChar *) doc->URL);
4626 if (uri == NULL)
4627 doc->URL = NULL;
4628 else
4629 doc->URL = xmlStrdup(uri);
4630 return;
4631 }
Owen Taylor3473f882001-02-23 17:55:21 +00004632 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004633
4634 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4635 if (ns == NULL)
4636 return;
4637 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004638}
Daniel Veillard652327a2003-09-29 18:02:38 +00004639#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004640
4641/**
Owen Taylor3473f882001-02-23 17:55:21 +00004642 * xmlNodeGetBase:
4643 * @doc: the document the node pertains to
4644 * @cur: the node being checked
4645 *
4646 * Searches for the BASE URL. The code should work on both XML
4647 * and HTML document even if base mechanisms are completely different.
4648 * It returns the base as defined in RFC 2396 sections
4649 * 5.1.1. Base URI within Document Content
4650 * and
4651 * 5.1.2. Base URI from the Encapsulating Entity
4652 * However it does not return the document base (5.1.3), use
4653 * xmlDocumentGetBase() for this
4654 *
4655 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004656 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004657 */
4658xmlChar *
4659xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004660 xmlChar *oldbase = NULL;
4661 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004662
4663 if ((cur == NULL) && (doc == NULL))
4664 return(NULL);
4665 if (doc == NULL) doc = cur->doc;
4666 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4667 cur = doc->children;
4668 while ((cur != NULL) && (cur->name != NULL)) {
4669 if (cur->type != XML_ELEMENT_NODE) {
4670 cur = cur->next;
4671 continue;
4672 }
4673 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4674 cur = cur->children;
4675 continue;
4676 }
4677 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4678 cur = cur->children;
4679 continue;
4680 }
4681 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4682 return(xmlGetProp(cur, BAD_CAST "href"));
4683 }
4684 cur = cur->next;
4685 }
4686 return(NULL);
4687 }
4688 while (cur != NULL) {
4689 if (cur->type == XML_ENTITY_DECL) {
4690 xmlEntityPtr ent = (xmlEntityPtr) cur;
4691 return(xmlStrdup(ent->URI));
4692 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004693 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004694 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004695 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004696 if (oldbase != NULL) {
4697 newbase = xmlBuildURI(oldbase, base);
4698 if (newbase != NULL) {
4699 xmlFree(oldbase);
4700 xmlFree(base);
4701 oldbase = newbase;
4702 } else {
4703 xmlFree(oldbase);
4704 xmlFree(base);
4705 return(NULL);
4706 }
4707 } else {
4708 oldbase = base;
4709 }
4710 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4711 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4712 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4713 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004714 }
4715 }
Owen Taylor3473f882001-02-23 17:55:21 +00004716 cur = cur->parent;
4717 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004718 if ((doc != NULL) && (doc->URL != NULL)) {
4719 if (oldbase == NULL)
4720 return(xmlStrdup(doc->URL));
4721 newbase = xmlBuildURI(oldbase, doc->URL);
4722 xmlFree(oldbase);
4723 return(newbase);
4724 }
4725 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004726}
4727
4728/**
Daniel Veillard78697292003-10-19 20:44:43 +00004729 * xmlNodeBufGetContent:
4730 * @buffer: a buffer
4731 * @cur: the node being read
4732 *
4733 * Read the value of a node @cur, this can be either the text carried
4734 * directly by this node if it's a TEXT node or the aggregate string
4735 * of the values carried by this node child's (TEXT and ENTITY_REF).
4736 * Entity references are substituted.
4737 * Fills up the buffer @buffer with this value
4738 *
4739 * Returns 0 in case of success and -1 in case of error.
4740 */
4741int
4742xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
4743{
4744 if ((cur == NULL) || (buffer == NULL)) return(-1);
4745 switch (cur->type) {
4746 case XML_CDATA_SECTION_NODE:
4747 case XML_TEXT_NODE:
4748 xmlBufferCat(buffer, cur->content);
4749 break;
4750 case XML_DOCUMENT_FRAG_NODE:
4751 case XML_ELEMENT_NODE:{
4752 xmlNodePtr tmp = cur;
4753
4754 while (tmp != NULL) {
4755 switch (tmp->type) {
4756 case XML_CDATA_SECTION_NODE:
4757 case XML_TEXT_NODE:
4758 if (tmp->content != NULL)
4759 xmlBufferCat(buffer, tmp->content);
4760 break;
4761 case XML_ENTITY_REF_NODE:
4762 xmlNodeBufGetContent(buffer, tmp->children);
4763 break;
4764 default:
4765 break;
4766 }
4767 /*
4768 * Skip to next node
4769 */
4770 if (tmp->children != NULL) {
4771 if (tmp->children->type != XML_ENTITY_DECL) {
4772 tmp = tmp->children;
4773 continue;
4774 }
4775 }
4776 if (tmp == cur)
4777 break;
4778
4779 if (tmp->next != NULL) {
4780 tmp = tmp->next;
4781 continue;
4782 }
4783
4784 do {
4785 tmp = tmp->parent;
4786 if (tmp == NULL)
4787 break;
4788 if (tmp == cur) {
4789 tmp = NULL;
4790 break;
4791 }
4792 if (tmp->next != NULL) {
4793 tmp = tmp->next;
4794 break;
4795 }
4796 } while (tmp != NULL);
4797 }
4798 break;
4799 }
4800 case XML_ATTRIBUTE_NODE:{
4801 xmlAttrPtr attr = (xmlAttrPtr) cur;
4802 xmlNodePtr tmp = attr->children;
4803
4804 while (tmp != NULL) {
4805 if (tmp->type == XML_TEXT_NODE)
4806 xmlBufferCat(buffer, tmp->content);
4807 else
4808 xmlNodeBufGetContent(buffer, tmp);
4809 tmp = tmp->next;
4810 }
4811 break;
4812 }
4813 case XML_COMMENT_NODE:
4814 case XML_PI_NODE:
4815 xmlBufferCat(buffer, cur->content);
4816 break;
4817 case XML_ENTITY_REF_NODE:{
4818 xmlEntityPtr ent;
4819 xmlNodePtr tmp;
4820
4821 /* lookup entity declaration */
4822 ent = xmlGetDocEntity(cur->doc, cur->name);
4823 if (ent == NULL)
4824 return(-1);
4825
4826 /* an entity content can be any "well balanced chunk",
4827 * i.e. the result of the content [43] production:
4828 * http://www.w3.org/TR/REC-xml#NT-content
4829 * -> we iterate through child nodes and recursive call
4830 * xmlNodeGetContent() which handles all possible node types */
4831 tmp = ent->children;
4832 while (tmp) {
4833 xmlNodeBufGetContent(buffer, tmp);
4834 tmp = tmp->next;
4835 }
4836 break;
4837 }
4838 case XML_ENTITY_NODE:
4839 case XML_DOCUMENT_TYPE_NODE:
4840 case XML_NOTATION_NODE:
4841 case XML_DTD_NODE:
4842 case XML_XINCLUDE_START:
4843 case XML_XINCLUDE_END:
4844 break;
4845 case XML_DOCUMENT_NODE:
4846#ifdef LIBXML_DOCB_ENABLED
4847 case XML_DOCB_DOCUMENT_NODE:
4848#endif
4849 case XML_HTML_DOCUMENT_NODE:
4850 cur = cur->children;
4851 while (cur!= NULL) {
4852 if ((cur->type == XML_ELEMENT_NODE) ||
4853 (cur->type == XML_TEXT_NODE) ||
4854 (cur->type == XML_CDATA_SECTION_NODE)) {
4855 xmlNodeBufGetContent(buffer, cur);
4856 }
4857 cur = cur->next;
4858 }
4859 break;
4860 case XML_NAMESPACE_DECL:
4861 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
4862 break;
4863 case XML_ELEMENT_DECL:
4864 case XML_ATTRIBUTE_DECL:
4865 case XML_ENTITY_DECL:
4866 break;
4867 }
4868 return(0);
4869}
4870/**
Owen Taylor3473f882001-02-23 17:55:21 +00004871 * xmlNodeGetContent:
4872 * @cur: the node being read
4873 *
4874 * Read the value of a node, this can be either the text carried
4875 * directly by this node if it's a TEXT node or the aggregate string
4876 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004877 * Entity references are substituted.
4878 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004879 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004880 */
4881xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004882xmlNodeGetContent(xmlNodePtr cur)
4883{
4884 if (cur == NULL)
4885 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004886 switch (cur->type) {
4887 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004888 case XML_ELEMENT_NODE:{
Daniel Veillard7646b182002-04-20 06:41:40 +00004889 xmlBufferPtr buffer;
4890 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004891
Daniel Veillard814a76d2003-01-23 18:24:20 +00004892 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004893 if (buffer == NULL)
4894 return (NULL);
Daniel Veillardc4696922003-10-19 21:47:14 +00004895 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00004896 ret = buffer->content;
4897 buffer->content = NULL;
4898 xmlBufferFree(buffer);
4899 return (ret);
4900 }
4901 case XML_ATTRIBUTE_NODE:{
4902 xmlAttrPtr attr = (xmlAttrPtr) cur;
4903
4904 if (attr->parent != NULL)
4905 return (xmlNodeListGetString
4906 (attr->parent->doc, attr->children, 1));
4907 else
4908 return (xmlNodeListGetString(NULL, attr->children, 1));
4909 break;
4910 }
Owen Taylor3473f882001-02-23 17:55:21 +00004911 case XML_COMMENT_NODE:
4912 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004913 if (cur->content != NULL)
4914 return (xmlStrdup(cur->content));
4915 return (NULL);
4916 case XML_ENTITY_REF_NODE:{
4917 xmlEntityPtr ent;
Daniel Veillard7646b182002-04-20 06:41:40 +00004918 xmlBufferPtr buffer;
4919 xmlChar *ret;
4920
4921 /* lookup entity declaration */
4922 ent = xmlGetDocEntity(cur->doc, cur->name);
4923 if (ent == NULL)
4924 return (NULL);
4925
4926 buffer = xmlBufferCreate();
4927 if (buffer == NULL)
4928 return (NULL);
4929
Daniel Veillardc4696922003-10-19 21:47:14 +00004930 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00004931
4932 ret = buffer->content;
4933 buffer->content = NULL;
4934 xmlBufferFree(buffer);
4935 return (ret);
4936 }
Owen Taylor3473f882001-02-23 17:55:21 +00004937 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004938 case XML_DOCUMENT_TYPE_NODE:
4939 case XML_NOTATION_NODE:
4940 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004941 case XML_XINCLUDE_START:
4942 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00004943 return (NULL);
4944 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004945#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004946 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004947#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00004948 case XML_HTML_DOCUMENT_NODE: {
Daniel Veillardc4696922003-10-19 21:47:14 +00004949 xmlBufferPtr buffer;
4950 xmlChar *ret;
Daniel Veillard9adc0462003-03-24 18:39:54 +00004951
Daniel Veillardc4696922003-10-19 21:47:14 +00004952 buffer = xmlBufferCreate();
4953 if (buffer == NULL)
4954 return (NULL);
4955
4956 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
4957
4958 ret = buffer->content;
4959 buffer->content = NULL;
4960 xmlBufferFree(buffer);
4961 return (ret);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004962 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004963 case XML_NAMESPACE_DECL: {
4964 xmlChar *tmp;
4965
4966 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4967 return (tmp);
4968 }
Owen Taylor3473f882001-02-23 17:55:21 +00004969 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004970 /* TODO !!! */
4971 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004972 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004973 /* TODO !!! */
4974 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004975 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004976 /* TODO !!! */
4977 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004978 case XML_CDATA_SECTION_NODE:
4979 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004980 if (cur->content != NULL)
4981 return (xmlStrdup(cur->content));
4982 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004983 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004984 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004985}
Daniel Veillard652327a2003-09-29 18:02:38 +00004986
Owen Taylor3473f882001-02-23 17:55:21 +00004987/**
4988 * xmlNodeSetContent:
4989 * @cur: the node being modified
4990 * @content: the new value of the content
4991 *
4992 * Replace the content of a node.
4993 */
4994void
4995xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4996 if (cur == NULL) {
4997#ifdef DEBUG_TREE
4998 xmlGenericError(xmlGenericErrorContext,
4999 "xmlNodeSetContent : node == NULL\n");
5000#endif
5001 return;
5002 }
5003 switch (cur->type) {
5004 case XML_DOCUMENT_FRAG_NODE:
5005 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005006 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005007 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5008 cur->children = xmlStringGetNodeList(cur->doc, content);
5009 UPDATE_LAST_CHILD_AND_PARENT(cur)
5010 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005011 case XML_TEXT_NODE:
5012 case XML_CDATA_SECTION_NODE:
5013 case XML_ENTITY_REF_NODE:
5014 case XML_ENTITY_NODE:
5015 case XML_PI_NODE:
5016 case XML_COMMENT_NODE:
5017 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005018 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005019 }
5020 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5021 cur->last = cur->children = NULL;
5022 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005023 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00005024 } else
5025 cur->content = NULL;
5026 break;
5027 case XML_DOCUMENT_NODE:
5028 case XML_HTML_DOCUMENT_NODE:
5029 case XML_DOCUMENT_TYPE_NODE:
5030 case XML_XINCLUDE_START:
5031 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005032#ifdef LIBXML_DOCB_ENABLED
5033 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005034#endif
5035 break;
5036 case XML_NOTATION_NODE:
5037 break;
5038 case XML_DTD_NODE:
5039 break;
5040 case XML_NAMESPACE_DECL:
5041 break;
5042 case XML_ELEMENT_DECL:
5043 /* TODO !!! */
5044 break;
5045 case XML_ATTRIBUTE_DECL:
5046 /* TODO !!! */
5047 break;
5048 case XML_ENTITY_DECL:
5049 /* TODO !!! */
5050 break;
5051 }
5052}
5053
Daniel Veillard652327a2003-09-29 18:02:38 +00005054#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005055/**
5056 * xmlNodeSetContentLen:
5057 * @cur: the node being modified
5058 * @content: the new value of the content
5059 * @len: the size of @content
5060 *
5061 * Replace the content of a node.
5062 */
5063void
5064xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5065 if (cur == NULL) {
5066#ifdef DEBUG_TREE
5067 xmlGenericError(xmlGenericErrorContext,
5068 "xmlNodeSetContentLen : node == NULL\n");
5069#endif
5070 return;
5071 }
5072 switch (cur->type) {
5073 case XML_DOCUMENT_FRAG_NODE:
5074 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005075 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005076 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5077 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5078 UPDATE_LAST_CHILD_AND_PARENT(cur)
5079 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005080 case XML_TEXT_NODE:
5081 case XML_CDATA_SECTION_NODE:
5082 case XML_ENTITY_REF_NODE:
5083 case XML_ENTITY_NODE:
5084 case XML_PI_NODE:
5085 case XML_COMMENT_NODE:
5086 case XML_NOTATION_NODE:
5087 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005088 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005089 }
5090 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5091 cur->children = cur->last = NULL;
5092 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005093 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005094 } else
5095 cur->content = NULL;
5096 break;
5097 case XML_DOCUMENT_NODE:
5098 case XML_DTD_NODE:
5099 case XML_HTML_DOCUMENT_NODE:
5100 case XML_DOCUMENT_TYPE_NODE:
5101 case XML_NAMESPACE_DECL:
5102 case XML_XINCLUDE_START:
5103 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005104#ifdef LIBXML_DOCB_ENABLED
5105 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005106#endif
5107 break;
5108 case XML_ELEMENT_DECL:
5109 /* TODO !!! */
5110 break;
5111 case XML_ATTRIBUTE_DECL:
5112 /* TODO !!! */
5113 break;
5114 case XML_ENTITY_DECL:
5115 /* TODO !!! */
5116 break;
5117 }
5118}
Daniel Veillard652327a2003-09-29 18:02:38 +00005119#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005120
5121/**
5122 * xmlNodeAddContentLen:
5123 * @cur: the node being modified
5124 * @content: extra content
5125 * @len: the size of @content
5126 *
5127 * Append the extra substring to the node content.
5128 */
5129void
5130xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5131 if (cur == NULL) {
5132#ifdef DEBUG_TREE
5133 xmlGenericError(xmlGenericErrorContext,
5134 "xmlNodeAddContentLen : node == NULL\n");
5135#endif
5136 return;
5137 }
5138 if (len <= 0) return;
5139 switch (cur->type) {
5140 case XML_DOCUMENT_FRAG_NODE:
5141 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005142 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005143
Daniel Veillard7db37732001-07-12 01:20:08 +00005144 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005145 newNode = xmlNewTextLen(content, len);
5146 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005147 tmp = xmlAddChild(cur, newNode);
5148 if (tmp != newNode)
5149 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005150 if ((last != NULL) && (last->next == newNode)) {
5151 xmlTextMerge(last, newNode);
5152 }
5153 }
5154 break;
5155 }
5156 case XML_ATTRIBUTE_NODE:
5157 break;
5158 case XML_TEXT_NODE:
5159 case XML_CDATA_SECTION_NODE:
5160 case XML_ENTITY_REF_NODE:
5161 case XML_ENTITY_NODE:
5162 case XML_PI_NODE:
5163 case XML_COMMENT_NODE:
5164 case XML_NOTATION_NODE:
5165 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005166 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005167 }
5168 case XML_DOCUMENT_NODE:
5169 case XML_DTD_NODE:
5170 case XML_HTML_DOCUMENT_NODE:
5171 case XML_DOCUMENT_TYPE_NODE:
5172 case XML_NAMESPACE_DECL:
5173 case XML_XINCLUDE_START:
5174 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005175#ifdef LIBXML_DOCB_ENABLED
5176 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005177#endif
5178 break;
5179 case XML_ELEMENT_DECL:
5180 case XML_ATTRIBUTE_DECL:
5181 case XML_ENTITY_DECL:
5182 break;
5183 }
5184}
5185
5186/**
5187 * xmlNodeAddContent:
5188 * @cur: the node being modified
5189 * @content: extra content
5190 *
5191 * Append the extra substring to the node content.
5192 */
5193void
5194xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5195 int len;
5196
5197 if (cur == NULL) {
5198#ifdef DEBUG_TREE
5199 xmlGenericError(xmlGenericErrorContext,
5200 "xmlNodeAddContent : node == NULL\n");
5201#endif
5202 return;
5203 }
5204 if (content == NULL) return;
5205 len = xmlStrlen(content);
5206 xmlNodeAddContentLen(cur, content, len);
5207}
5208
5209/**
5210 * xmlTextMerge:
5211 * @first: the first text node
5212 * @second: the second text node being merged
5213 *
5214 * Merge two text nodes into one
5215 * Returns the first text node augmented
5216 */
5217xmlNodePtr
5218xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5219 if (first == NULL) return(second);
5220 if (second == NULL) return(first);
5221 if (first->type != XML_TEXT_NODE) return(first);
5222 if (second->type != XML_TEXT_NODE) return(first);
5223 if (second->name != first->name)
5224 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005225 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005226 xmlUnlinkNode(second);
5227 xmlFreeNode(second);
5228 return(first);
5229}
5230
Daniel Veillard652327a2003-09-29 18:02:38 +00005231#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005232/**
5233 * xmlGetNsList:
5234 * @doc: the document
5235 * @node: the current node
5236 *
5237 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005238 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005239 * that need to be freed by the caller or NULL if no
5240 * namespace if defined
5241 */
5242xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005243xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5244{
Owen Taylor3473f882001-02-23 17:55:21 +00005245 xmlNsPtr cur;
5246 xmlNsPtr *ret = NULL;
5247 int nbns = 0;
5248 int maxns = 10;
5249 int i;
5250
5251 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005252 if (node->type == XML_ELEMENT_NODE) {
5253 cur = node->nsDef;
5254 while (cur != NULL) {
5255 if (ret == NULL) {
5256 ret =
5257 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5258 sizeof(xmlNsPtr));
5259 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005260 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005261 return (NULL);
5262 }
5263 ret[nbns] = NULL;
5264 }
5265 for (i = 0; i < nbns; i++) {
5266 if ((cur->prefix == ret[i]->prefix) ||
5267 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5268 break;
5269 }
5270 if (i >= nbns) {
5271 if (nbns >= maxns) {
5272 maxns *= 2;
5273 ret = (xmlNsPtr *) xmlRealloc(ret,
5274 (maxns +
5275 1) *
5276 sizeof(xmlNsPtr));
5277 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005278 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005279 return (NULL);
5280 }
5281 }
5282 ret[nbns++] = cur;
5283 ret[nbns] = NULL;
5284 }
Owen Taylor3473f882001-02-23 17:55:21 +00005285
Daniel Veillard77044732001-06-29 21:31:07 +00005286 cur = cur->next;
5287 }
5288 }
5289 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005290 }
Daniel Veillard77044732001-06-29 21:31:07 +00005291 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005292}
Daniel Veillard652327a2003-09-29 18:02:38 +00005293#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005294
5295/**
5296 * xmlSearchNs:
5297 * @doc: the document
5298 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005299 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005300 *
5301 * Search a Ns registered under a given name space for a document.
5302 * recurse on the parents until it finds the defined namespace
5303 * or return NULL otherwise.
5304 * @nameSpace can be NULL, this is a search for the default namespace.
5305 * We don't allow to cross entities boundaries. If you don't declare
5306 * the namespace within those you will be in troubles !!! A warning
5307 * is generated to cover this case.
5308 *
5309 * Returns the namespace pointer or NULL.
5310 */
5311xmlNsPtr
5312xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillardf4e56292003-10-28 14:27:41 +00005313
Owen Taylor3473f882001-02-23 17:55:21 +00005314 xmlNsPtr cur;
Daniel Veillardf4e56292003-10-28 14:27:41 +00005315 xmlNodePtr orig = node;
Owen Taylor3473f882001-02-23 17:55:21 +00005316
5317 if (node == NULL) return(NULL);
5318 if ((nameSpace != NULL) &&
5319 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005320 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5321 /*
5322 * The XML-1.0 namespace is normally held on the root
5323 * element. In this case exceptionally create it on the
5324 * node element.
5325 */
5326 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5327 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005328 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005329 return(NULL);
5330 }
5331 memset(cur, 0, sizeof(xmlNs));
5332 cur->type = XML_LOCAL_NAMESPACE;
5333 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5334 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5335 cur->next = node->nsDef;
5336 node->nsDef = cur;
5337 return(cur);
5338 }
Owen Taylor3473f882001-02-23 17:55:21 +00005339 if (doc->oldNs == NULL) {
5340 /*
5341 * Allocate a new Namespace and fill the fields.
5342 */
5343 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5344 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005345 xmlTreeErrMemory("searching namespace");
Owen Taylor3473f882001-02-23 17:55:21 +00005346 return(NULL);
5347 }
5348 memset(doc->oldNs, 0, sizeof(xmlNs));
5349 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5350
5351 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5352 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5353 }
5354 return(doc->oldNs);
5355 }
5356 while (node != NULL) {
5357 if ((node->type == XML_ENTITY_REF_NODE) ||
5358 (node->type == XML_ENTITY_NODE) ||
5359 (node->type == XML_ENTITY_DECL))
5360 return(NULL);
5361 if (node->type == XML_ELEMENT_NODE) {
5362 cur = node->nsDef;
5363 while (cur != NULL) {
5364 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5365 (cur->href != NULL))
5366 return(cur);
5367 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5368 (cur->href != NULL) &&
5369 (xmlStrEqual(cur->prefix, nameSpace)))
5370 return(cur);
5371 cur = cur->next;
5372 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005373 if (orig != node) {
5374 cur = node->ns;
5375 if (cur != NULL) {
5376 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5377 (cur->href != NULL))
5378 return(cur);
5379 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5380 (cur->href != NULL) &&
5381 (xmlStrEqual(cur->prefix, nameSpace)))
5382 return(cur);
5383 }
5384 }
Owen Taylor3473f882001-02-23 17:55:21 +00005385 }
5386 node = node->parent;
5387 }
5388 return(NULL);
5389}
5390
5391/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005392 * xmlNsInScope:
5393 * @doc: the document
5394 * @node: the current node
5395 * @ancestor: the ancestor carrying the namespace
5396 * @prefix: the namespace prefix
5397 *
5398 * Verify that the given namespace held on @ancestor is still in scope
5399 * on node.
5400 *
5401 * Returns 1 if true, 0 if false and -1 in case of error.
5402 */
5403static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005404xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5405 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005406{
5407 xmlNsPtr tst;
5408
5409 while ((node != NULL) && (node != ancestor)) {
5410 if ((node->type == XML_ENTITY_REF_NODE) ||
5411 (node->type == XML_ENTITY_NODE) ||
5412 (node->type == XML_ENTITY_DECL))
5413 return (-1);
5414 if (node->type == XML_ELEMENT_NODE) {
5415 tst = node->nsDef;
5416 while (tst != NULL) {
5417 if ((tst->prefix == NULL)
5418 && (prefix == NULL))
5419 return (0);
5420 if ((tst->prefix != NULL)
5421 && (prefix != NULL)
5422 && (xmlStrEqual(tst->prefix, prefix)))
5423 return (0);
5424 tst = tst->next;
5425 }
5426 }
5427 node = node->parent;
5428 }
5429 if (node != ancestor)
5430 return (-1);
5431 return (1);
5432}
5433
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005434/**
Owen Taylor3473f882001-02-23 17:55:21 +00005435 * xmlSearchNsByHref:
5436 * @doc: the document
5437 * @node: the current node
5438 * @href: the namespace value
5439 *
5440 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5441 * the defined namespace or return NULL otherwise.
5442 * Returns the namespace pointer or NULL.
5443 */
5444xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005445xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5446{
Owen Taylor3473f882001-02-23 17:55:21 +00005447 xmlNsPtr cur;
5448 xmlNodePtr orig = node;
5449
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005450 if ((node == NULL) || (href == NULL))
5451 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005452 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005453 /*
5454 * Only the document can hold the XML spec namespace.
5455 */
5456 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5457 /*
5458 * The XML-1.0 namespace is normally held on the root
5459 * element. In this case exceptionally create it on the
5460 * node element.
5461 */
5462 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5463 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005464 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005465 return (NULL);
5466 }
5467 memset(cur, 0, sizeof(xmlNs));
5468 cur->type = XML_LOCAL_NAMESPACE;
5469 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5470 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5471 cur->next = node->nsDef;
5472 node->nsDef = cur;
5473 return (cur);
5474 }
5475 if (doc->oldNs == NULL) {
5476 /*
5477 * Allocate a new Namespace and fill the fields.
5478 */
5479 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5480 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005481 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005482 return (NULL);
5483 }
5484 memset(doc->oldNs, 0, sizeof(xmlNs));
5485 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005486
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005487 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5488 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5489 }
5490 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005491 }
5492 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005493 if ((node->type == XML_ENTITY_REF_NODE) ||
5494 (node->type == XML_ENTITY_NODE) ||
5495 (node->type == XML_ENTITY_DECL))
5496 return (NULL);
5497 if (node->type == XML_ELEMENT_NODE) {
5498 cur = node->nsDef;
5499 while (cur != NULL) {
5500 if ((cur->href != NULL) && (href != NULL) &&
5501 (xmlStrEqual(cur->href, href))) {
5502 if (xmlNsInScope(doc, orig, node, cur->href) == 1)
5503 return (cur);
5504 }
5505 cur = cur->next;
5506 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005507 if (orig != node) {
5508 cur = node->ns;
5509 if (cur != NULL) {
5510 if ((cur->href != NULL) && (href != NULL) &&
5511 (xmlStrEqual(cur->href, href))) {
5512 if (xmlNsInScope(doc, orig, node, cur->href) == 1)
5513 return (cur);
5514 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005515 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005516 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005517 }
5518 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005519 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005520 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005521}
5522
5523/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005524 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005525 * @doc: the document
5526 * @tree: a node expected to hold the new namespace
5527 * @ns: the original namespace
5528 *
5529 * This function tries to locate a namespace definition in a tree
5530 * ancestors, or create a new namespace definition node similar to
5531 * @ns trying to reuse the same prefix. However if the given prefix is
5532 * null (default namespace) or reused within the subtree defined by
5533 * @tree or on one of its ancestors then a new prefix is generated.
5534 * Returns the (new) namespace definition or NULL in case of error
5535 */
5536xmlNsPtr
5537xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5538 xmlNsPtr def;
5539 xmlChar prefix[50];
5540 int counter = 1;
5541
5542 if (tree == NULL) {
5543#ifdef DEBUG_TREE
5544 xmlGenericError(xmlGenericErrorContext,
5545 "xmlNewReconciliedNs : tree == NULL\n");
5546#endif
5547 return(NULL);
5548 }
5549 if (ns == NULL) {
5550#ifdef DEBUG_TREE
5551 xmlGenericError(xmlGenericErrorContext,
5552 "xmlNewReconciliedNs : ns == NULL\n");
5553#endif
5554 return(NULL);
5555 }
5556 /*
5557 * Search an existing namespace definition inherited.
5558 */
5559 def = xmlSearchNsByHref(doc, tree, ns->href);
5560 if (def != NULL)
5561 return(def);
5562
5563 /*
5564 * Find a close prefix which is not already in use.
5565 * Let's strip namespace prefixes longer than 20 chars !
5566 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005567 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005568 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005569 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005570 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005571
Owen Taylor3473f882001-02-23 17:55:21 +00005572 def = xmlSearchNs(doc, tree, prefix);
5573 while (def != NULL) {
5574 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005575 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005576 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005577 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005578 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005579 def = xmlSearchNs(doc, tree, prefix);
5580 }
5581
5582 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005583 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005584 */
5585 def = xmlNewNs(tree, ns->href, prefix);
5586 return(def);
5587}
5588
Daniel Veillard652327a2003-09-29 18:02:38 +00005589#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005590/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005591 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005592 * @doc: the document
5593 * @tree: a node defining the subtree to reconciliate
5594 *
5595 * This function checks that all the namespaces declared within the given
5596 * tree are properly declared. This is needed for example after Copy or Cut
5597 * and then paste operations. The subtree may still hold pointers to
5598 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005599 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005600 * the new environment. If not possible the new namespaces are redeclared
5601 * on @tree at the top of the given subtree.
5602 * Returns the number of namespace declarations created or -1 in case of error.
5603 */
5604int
5605xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5606 xmlNsPtr *oldNs = NULL;
5607 xmlNsPtr *newNs = NULL;
5608 int sizeCache = 0;
5609 int nbCache = 0;
5610
5611 xmlNsPtr n;
5612 xmlNodePtr node = tree;
5613 xmlAttrPtr attr;
5614 int ret = 0, i;
5615
5616 while (node != NULL) {
5617 /*
5618 * Reconciliate the node namespace
5619 */
5620 if (node->ns != NULL) {
5621 /*
5622 * initialize the cache if needed
5623 */
5624 if (sizeCache == 0) {
5625 sizeCache = 10;
5626 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5627 sizeof(xmlNsPtr));
5628 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005629 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005630 return(-1);
5631 }
5632 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5633 sizeof(xmlNsPtr));
5634 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005635 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005636 xmlFree(oldNs);
5637 return(-1);
5638 }
5639 }
5640 for (i = 0;i < nbCache;i++) {
5641 if (oldNs[i] == node->ns) {
5642 node->ns = newNs[i];
5643 break;
5644 }
5645 }
5646 if (i == nbCache) {
5647 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005648 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005649 */
5650 n = xmlNewReconciliedNs(doc, tree, node->ns);
5651 if (n != NULL) { /* :-( what if else ??? */
5652 /*
5653 * check if we need to grow the cache buffers.
5654 */
5655 if (sizeCache <= nbCache) {
5656 sizeCache *= 2;
5657 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5658 sizeof(xmlNsPtr));
5659 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005660 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005661 xmlFree(newNs);
5662 return(-1);
5663 }
5664 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5665 sizeof(xmlNsPtr));
5666 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005667 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005668 xmlFree(oldNs);
5669 return(-1);
5670 }
5671 }
5672 newNs[nbCache] = n;
5673 oldNs[nbCache++] = node->ns;
5674 node->ns = n;
5675 }
5676 }
5677 }
5678 /*
5679 * now check for namespace hold by attributes on the node.
5680 */
5681 attr = node->properties;
5682 while (attr != NULL) {
5683 if (attr->ns != NULL) {
5684 /*
5685 * initialize the cache if needed
5686 */
5687 if (sizeCache == 0) {
5688 sizeCache = 10;
5689 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5690 sizeof(xmlNsPtr));
5691 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005692 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005693 return(-1);
5694 }
5695 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5696 sizeof(xmlNsPtr));
5697 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005698 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005699 xmlFree(oldNs);
5700 return(-1);
5701 }
5702 }
5703 for (i = 0;i < nbCache;i++) {
5704 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005705 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005706 break;
5707 }
5708 }
5709 if (i == nbCache) {
5710 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005711 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005712 */
5713 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5714 if (n != NULL) { /* :-( what if else ??? */
5715 /*
5716 * check if we need to grow the cache buffers.
5717 */
5718 if (sizeCache <= nbCache) {
5719 sizeCache *= 2;
5720 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5721 sizeof(xmlNsPtr));
5722 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005723 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005724 xmlFree(newNs);
5725 return(-1);
5726 }
5727 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5728 sizeof(xmlNsPtr));
5729 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005730 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005731 xmlFree(oldNs);
5732 return(-1);
5733 }
5734 }
5735 newNs[nbCache] = n;
5736 oldNs[nbCache++] = attr->ns;
5737 attr->ns = n;
5738 }
5739 }
5740 }
5741 attr = attr->next;
5742 }
5743
5744 /*
5745 * Browse the full subtree, deep first
5746 */
5747 if (node->children != NULL) {
5748 /* deep first */
5749 node = node->children;
5750 } else if ((node != tree) && (node->next != NULL)) {
5751 /* then siblings */
5752 node = node->next;
5753 } else if (node != tree) {
5754 /* go up to parents->next if needed */
5755 while (node != tree) {
5756 if (node->parent != NULL)
5757 node = node->parent;
5758 if ((node != tree) && (node->next != NULL)) {
5759 node = node->next;
5760 break;
5761 }
5762 if (node->parent == NULL) {
5763 node = NULL;
5764 break;
5765 }
5766 }
5767 /* exit condition */
5768 if (node == tree)
5769 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005770 } else
5771 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005772 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005773 if (oldNs != NULL)
5774 xmlFree(oldNs);
5775 if (newNs != NULL)
5776 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005777 return(ret);
5778}
Daniel Veillard652327a2003-09-29 18:02:38 +00005779#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005780
5781/**
5782 * xmlHasProp:
5783 * @node: the node
5784 * @name: the attribute name
5785 *
5786 * Search an attribute associated to a node
5787 * This function also looks in DTD attribute declaration for #FIXED or
5788 * default declaration values unless DTD use has been turned off.
5789 *
5790 * Returns the attribute or the attribute declaration or NULL if
5791 * neither was found.
5792 */
5793xmlAttrPtr
5794xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5795 xmlAttrPtr prop;
5796 xmlDocPtr doc;
5797
5798 if ((node == NULL) || (name == NULL)) return(NULL);
5799 /*
5800 * Check on the properties attached to the node
5801 */
5802 prop = node->properties;
5803 while (prop != NULL) {
5804 if (xmlStrEqual(prop->name, name)) {
5805 return(prop);
5806 }
5807 prop = prop->next;
5808 }
5809 if (!xmlCheckDTD) return(NULL);
5810
5811 /*
5812 * Check if there is a default declaration in the internal
5813 * or external subsets
5814 */
5815 doc = node->doc;
5816 if (doc != NULL) {
5817 xmlAttributePtr attrDecl;
5818 if (doc->intSubset != NULL) {
5819 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5820 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5821 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005822 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5823 /* return attribute declaration only if a default value is given
5824 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005825 return((xmlAttrPtr) attrDecl);
5826 }
5827 }
5828 return(NULL);
5829}
5830
5831/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005832 * xmlHasNsProp:
5833 * @node: the node
5834 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005835 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005836 *
5837 * Search for an attribute associated to a node
5838 * This attribute has to be anchored in the namespace specified.
5839 * This does the entity substitution.
5840 * This function looks in DTD attribute declaration for #FIXED or
5841 * default declaration values unless DTD use has been turned off.
5842 *
5843 * Returns the attribute or the attribute declaration or NULL
5844 * if neither was found.
5845 */
5846xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005847xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005848 xmlAttrPtr prop;
Daniel Veillard652327a2003-09-29 18:02:38 +00005849#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005850 xmlDocPtr doc;
Daniel Veillard652327a2003-09-29 18:02:38 +00005851#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005852
5853 if (node == NULL)
5854 return(NULL);
5855
5856 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005857 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005858 return(xmlHasProp(node, name));
5859 while (prop != NULL) {
5860 /*
5861 * One need to have
5862 * - same attribute names
5863 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005864 */
5865 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005866 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5867 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005868 }
5869 prop = prop->next;
5870 }
5871 if (!xmlCheckDTD) return(NULL);
5872
Daniel Veillard652327a2003-09-29 18:02:38 +00005873#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005874 /*
5875 * Check if there is a default declaration in the internal
5876 * or external subsets
5877 */
5878 doc = node->doc;
5879 if (doc != NULL) {
5880 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005881 xmlAttributePtr attrDecl = NULL;
5882 xmlNsPtr *nsList, *cur;
5883 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005884
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005885 nsList = xmlGetNsList(node->doc, node);
5886 if (nsList == NULL)
5887 return(NULL);
5888 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5889 ename = xmlStrdup(node->ns->prefix);
5890 ename = xmlStrcat(ename, BAD_CAST ":");
5891 ename = xmlStrcat(ename, node->name);
5892 } else {
5893 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005894 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005895 if (ename == NULL) {
5896 xmlFree(nsList);
5897 return(NULL);
5898 }
5899
5900 cur = nsList;
5901 while (*cur != NULL) {
5902 if (xmlStrEqual((*cur)->href, nameSpace)) {
5903 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5904 name, (*cur)->prefix);
5905 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5906 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5907 name, (*cur)->prefix);
5908 }
5909 cur++;
5910 }
5911 xmlFree(nsList);
5912 xmlFree(ename);
5913 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005914 }
5915 }
Daniel Veillard652327a2003-09-29 18:02:38 +00005916#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005917 return(NULL);
5918}
5919
5920/**
Owen Taylor3473f882001-02-23 17:55:21 +00005921 * xmlGetProp:
5922 * @node: the node
5923 * @name: the attribute name
5924 *
5925 * Search and get the value of an attribute associated to a node
5926 * This does the entity substitution.
5927 * This function looks in DTD attribute declaration for #FIXED or
5928 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00005929 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00005930 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
5931 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00005932 *
5933 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005934 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005935 */
5936xmlChar *
5937xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5938 xmlAttrPtr prop;
5939 xmlDocPtr doc;
5940
5941 if ((node == NULL) || (name == NULL)) return(NULL);
5942 /*
5943 * Check on the properties attached to the node
5944 */
5945 prop = node->properties;
5946 while (prop != NULL) {
5947 if (xmlStrEqual(prop->name, name)) {
5948 xmlChar *ret;
5949
5950 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5951 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5952 return(ret);
5953 }
5954 prop = prop->next;
5955 }
5956 if (!xmlCheckDTD) return(NULL);
5957
5958 /*
5959 * Check if there is a default declaration in the internal
5960 * or external subsets
5961 */
5962 doc = node->doc;
5963 if (doc != NULL) {
5964 xmlAttributePtr attrDecl;
5965 if (doc->intSubset != NULL) {
5966 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5967 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5968 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005969 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5970 /* return attribute declaration only if a default value is given
5971 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005972 return(xmlStrdup(attrDecl->defaultValue));
5973 }
5974 }
5975 return(NULL);
5976}
5977
5978/**
Daniel Veillard71531f32003-02-05 13:19:53 +00005979 * xmlGetNoNsProp:
5980 * @node: the node
5981 * @name: the attribute name
5982 *
5983 * Search and get the value of an attribute associated to a node
5984 * This does the entity substitution.
5985 * This function looks in DTD attribute declaration for #FIXED or
5986 * default declaration values unless DTD use has been turned off.
5987 * This function is similar to xmlGetProp except it will accept only
5988 * an attribute in no namespace.
5989 *
5990 * Returns the attribute value or NULL if not found.
5991 * It's up to the caller to free the memory with xmlFree().
5992 */
5993xmlChar *
5994xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
5995 xmlAttrPtr prop;
5996 xmlDocPtr doc;
5997
5998 if ((node == NULL) || (name == NULL)) return(NULL);
5999 /*
6000 * Check on the properties attached to the node
6001 */
6002 prop = node->properties;
6003 while (prop != NULL) {
6004 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
6005 xmlChar *ret;
6006
6007 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6008 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6009 return(ret);
6010 }
6011 prop = prop->next;
6012 }
6013 if (!xmlCheckDTD) return(NULL);
6014
6015 /*
6016 * Check if there is a default declaration in the internal
6017 * or external subsets
6018 */
6019 doc = node->doc;
6020 if (doc != NULL) {
6021 xmlAttributePtr attrDecl;
6022 if (doc->intSubset != NULL) {
6023 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6024 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6025 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006026 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6027 /* return attribute declaration only if a default value is given
6028 (that includes #FIXED declarations) */
Daniel Veillard71531f32003-02-05 13:19:53 +00006029 return(xmlStrdup(attrDecl->defaultValue));
6030 }
6031 }
6032 return(NULL);
6033}
6034
6035/**
Owen Taylor3473f882001-02-23 17:55:21 +00006036 * xmlGetNsProp:
6037 * @node: the node
6038 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006039 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006040 *
6041 * Search and get the value of an attribute associated to a node
6042 * This attribute has to be anchored in the namespace specified.
6043 * This does the entity substitution.
6044 * This function looks in DTD attribute declaration for #FIXED or
6045 * default declaration values unless DTD use has been turned off.
6046 *
6047 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006048 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006049 */
6050xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006051xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006052 xmlAttrPtr prop;
6053 xmlDocPtr doc;
6054 xmlNsPtr ns;
6055
6056 if (node == NULL)
6057 return(NULL);
6058
6059 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00006060 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00006061 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00006062 while (prop != NULL) {
6063 /*
6064 * One need to have
6065 * - same attribute names
6066 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006067 */
6068 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00006069 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00006070 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006071 xmlChar *ret;
6072
6073 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6074 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6075 return(ret);
6076 }
6077 prop = prop->next;
6078 }
6079 if (!xmlCheckDTD) return(NULL);
6080
6081 /*
6082 * Check if there is a default declaration in the internal
6083 * or external subsets
6084 */
6085 doc = node->doc;
6086 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006087 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00006088 xmlAttributePtr attrDecl;
6089
Owen Taylor3473f882001-02-23 17:55:21 +00006090 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6091 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6092 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
6093
6094 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
6095 /*
6096 * The DTD declaration only allows a prefix search
6097 */
6098 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00006099 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00006100 return(xmlStrdup(attrDecl->defaultValue));
6101 }
6102 }
6103 }
6104 return(NULL);
6105}
6106
Daniel Veillard652327a2003-09-29 18:02:38 +00006107#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00006108/**
6109 * xmlSetProp:
6110 * @node: the node
6111 * @name: the attribute name
6112 * @value: the attribute value
6113 *
6114 * Set (or reset) an attribute carried by a node.
6115 * Returns the attribute pointer.
6116 */
6117xmlAttrPtr
6118xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006119 xmlAttrPtr prop;
6120 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00006121
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006122 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006123 return(NULL);
6124 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006125 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00006126 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006127 if ((xmlStrEqual(prop->name, name)) &&
6128 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006129 xmlNodePtr oldprop = prop->children;
6130
Owen Taylor3473f882001-02-23 17:55:21 +00006131 prop->children = NULL;
6132 prop->last = NULL;
6133 if (value != NULL) {
6134 xmlChar *buffer;
6135 xmlNodePtr tmp;
6136
6137 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6138 prop->children = xmlStringGetNodeList(node->doc, buffer);
6139 prop->last = NULL;
6140 prop->doc = doc;
6141 tmp = prop->children;
6142 while (tmp != NULL) {
6143 tmp->parent = (xmlNodePtr) prop;
6144 tmp->doc = doc;
6145 if (tmp->next == NULL)
6146 prop->last = tmp;
6147 tmp = tmp->next;
6148 }
6149 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00006150 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006151 if (oldprop != NULL)
6152 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00006153 return(prop);
6154 }
6155 prop = prop->next;
6156 }
6157 prop = xmlNewProp(node, name, value);
6158 return(prop);
6159}
6160
6161/**
Daniel Veillard75bea542001-05-11 17:41:21 +00006162 * xmlUnsetProp:
6163 * @node: the node
6164 * @name: the attribute name
6165 *
6166 * Remove an attribute carried by a node.
6167 * Returns 0 if successful, -1 if not found
6168 */
6169int
6170xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Daniel Veillard814a76d2003-01-23 18:24:20 +00006171 xmlAttrPtr prop, prev = NULL;;
Daniel Veillard75bea542001-05-11 17:41:21 +00006172
6173 if ((node == NULL) || (name == NULL))
6174 return(-1);
Daniel Veillard814a76d2003-01-23 18:24:20 +00006175 prop = node->properties;
Daniel Veillard75bea542001-05-11 17:41:21 +00006176 while (prop != NULL) {
6177 if ((xmlStrEqual(prop->name, name)) &&
6178 (prop->ns == NULL)) {
6179 if (prev == NULL)
6180 node->properties = prop->next;
6181 else
6182 prev->next = prop->next;
6183 xmlFreeProp(prop);
6184 return(0);
6185 }
6186 prev = prop;
6187 prop = prop->next;
6188 }
6189 return(-1);
6190}
6191
6192/**
Owen Taylor3473f882001-02-23 17:55:21 +00006193 * xmlSetNsProp:
6194 * @node: the node
6195 * @ns: the namespace definition
6196 * @name: the attribute name
6197 * @value: the attribute value
6198 *
6199 * Set (or reset) an attribute carried by a node.
6200 * The ns structure must be in scope, this is not checked.
6201 *
6202 * Returns the attribute pointer.
6203 */
6204xmlAttrPtr
6205xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
6206 const xmlChar *value) {
6207 xmlAttrPtr prop;
6208
6209 if ((node == NULL) || (name == NULL))
6210 return(NULL);
6211
6212 if (ns == NULL)
6213 return(xmlSetProp(node, name, value));
6214 if (ns->href == NULL)
6215 return(NULL);
6216 prop = node->properties;
6217
6218 while (prop != NULL) {
6219 /*
6220 * One need to have
6221 * - same attribute names
6222 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006223 */
6224 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00006225 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006226 if (prop->children != NULL)
6227 xmlFreeNodeList(prop->children);
6228 prop->children = NULL;
6229 prop->last = NULL;
6230 prop->ns = ns;
6231 if (value != NULL) {
6232 xmlChar *buffer;
6233 xmlNodePtr tmp;
6234
6235 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6236 prop->children = xmlStringGetNodeList(node->doc, buffer);
6237 prop->last = NULL;
6238 tmp = prop->children;
6239 while (tmp != NULL) {
6240 tmp->parent = (xmlNodePtr) prop;
6241 if (tmp->next == NULL)
6242 prop->last = tmp;
6243 tmp = tmp->next;
6244 }
6245 xmlFree(buffer);
6246 }
6247 return(prop);
6248 }
6249 prop = prop->next;
6250 }
6251 prop = xmlNewNsProp(node, ns, name, value);
6252 return(prop);
6253}
6254
6255/**
Daniel Veillard75bea542001-05-11 17:41:21 +00006256 * xmlUnsetNsProp:
6257 * @node: the node
6258 * @ns: the namespace definition
6259 * @name: the attribute name
6260 *
6261 * Remove an attribute carried by a node.
6262 * Returns 0 if successful, -1 if not found
6263 */
6264int
6265xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
6266 xmlAttrPtr prop = node->properties, prev = NULL;;
6267
6268 if ((node == NULL) || (name == NULL))
6269 return(-1);
6270 if (ns == NULL)
6271 return(xmlUnsetProp(node, name));
6272 if (ns->href == NULL)
6273 return(-1);
6274 while (prop != NULL) {
6275 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00006276 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006277 if (prev == NULL)
6278 node->properties = prop->next;
6279 else
6280 prev->next = prop->next;
6281 xmlFreeProp(prop);
6282 return(0);
6283 }
6284 prev = prop;
6285 prop = prop->next;
6286 }
6287 return(-1);
6288}
Daniel Veillard652327a2003-09-29 18:02:38 +00006289#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006290
6291/**
Owen Taylor3473f882001-02-23 17:55:21 +00006292 * xmlNodeIsText:
6293 * @node: the node
6294 *
6295 * Is this node a Text node ?
6296 * Returns 1 yes, 0 no
6297 */
6298int
6299xmlNodeIsText(xmlNodePtr node) {
6300 if (node == NULL) return(0);
6301
6302 if (node->type == XML_TEXT_NODE) return(1);
6303 return(0);
6304}
6305
6306/**
6307 * xmlIsBlankNode:
6308 * @node: the node
6309 *
6310 * Checks whether this node is an empty or whitespace only
6311 * (and possibly ignorable) text-node.
6312 *
6313 * Returns 1 yes, 0 no
6314 */
6315int
6316xmlIsBlankNode(xmlNodePtr node) {
6317 const xmlChar *cur;
6318 if (node == NULL) return(0);
6319
Daniel Veillard7db37732001-07-12 01:20:08 +00006320 if ((node->type != XML_TEXT_NODE) &&
6321 (node->type != XML_CDATA_SECTION_NODE))
6322 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006323 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006324 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006325 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006326 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006327 cur++;
6328 }
6329
6330 return(1);
6331}
6332
6333/**
6334 * xmlTextConcat:
6335 * @node: the node
6336 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006337 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006338 *
6339 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006340 *
6341 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006342 */
6343
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006344int
Owen Taylor3473f882001-02-23 17:55:21 +00006345xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006346 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006347
6348 if ((node->type != XML_TEXT_NODE) &&
6349 (node->type != XML_CDATA_SECTION_NODE)) {
6350#ifdef DEBUG_TREE
6351 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006352 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006353#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006354 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006355 }
Owen Taylor3473f882001-02-23 17:55:21 +00006356 node->content = xmlStrncat(node->content, content, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006357 if (node->content == NULL)
6358 return(-1);
6359 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006360}
6361
6362/************************************************************************
6363 * *
6364 * Output : to a FILE or in memory *
6365 * *
6366 ************************************************************************/
6367
Owen Taylor3473f882001-02-23 17:55:21 +00006368/**
6369 * xmlBufferCreate:
6370 *
6371 * routine to create an XML buffer.
6372 * returns the new structure.
6373 */
6374xmlBufferPtr
6375xmlBufferCreate(void) {
6376 xmlBufferPtr ret;
6377
6378 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6379 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006380 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006381 return(NULL);
6382 }
6383 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006384 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006385 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006386 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006387 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006388 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006389 xmlFree(ret);
6390 return(NULL);
6391 }
6392 ret->content[0] = 0;
6393 return(ret);
6394}
6395
6396/**
6397 * xmlBufferCreateSize:
6398 * @size: initial size of buffer
6399 *
6400 * routine to create an XML buffer.
6401 * returns the new structure.
6402 */
6403xmlBufferPtr
6404xmlBufferCreateSize(size_t size) {
6405 xmlBufferPtr ret;
6406
6407 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6408 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006409 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006410 return(NULL);
6411 }
6412 ret->use = 0;
6413 ret->alloc = xmlBufferAllocScheme;
6414 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6415 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006416 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006417 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006418 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006419 xmlFree(ret);
6420 return(NULL);
6421 }
6422 ret->content[0] = 0;
6423 } else
6424 ret->content = NULL;
6425 return(ret);
6426}
6427
6428/**
Daniel Veillard53350552003-09-18 13:35:51 +00006429 * xmlBufferCreateStatic:
6430 * @mem: the memory area
6431 * @size: the size in byte
6432 *
6433 * routine to create an XML buffer from an immutable memory area,
6434 * The are won't be modified nor copied, and is expected to be
6435 * present until the end of the buffer lifetime.
6436 *
6437 * returns the new structure.
6438 */
6439xmlBufferPtr
6440xmlBufferCreateStatic(void *mem, size_t size) {
6441 xmlBufferPtr ret;
6442
6443 if ((mem == NULL) || (size == 0))
6444 return(NULL);
6445
6446 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6447 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006448 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00006449 return(NULL);
6450 }
6451 ret->use = size;
6452 ret->size = size;
6453 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6454 ret->content = (xmlChar *) mem;
6455 return(ret);
6456}
6457
6458/**
Owen Taylor3473f882001-02-23 17:55:21 +00006459 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006460 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006461 * @scheme: allocation scheme to use
6462 *
6463 * Sets the allocation scheme for this buffer
6464 */
6465void
6466xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6467 xmlBufferAllocationScheme scheme) {
6468 if (buf == NULL) {
6469#ifdef DEBUG_BUFFER
6470 xmlGenericError(xmlGenericErrorContext,
6471 "xmlBufferSetAllocationScheme: buf == NULL\n");
6472#endif
6473 return;
6474 }
Daniel Veillard53350552003-09-18 13:35:51 +00006475 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006476
6477 buf->alloc = scheme;
6478}
6479
6480/**
6481 * xmlBufferFree:
6482 * @buf: the buffer to free
6483 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006484 * Frees an XML buffer. It frees both the content and the structure which
6485 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006486 */
6487void
6488xmlBufferFree(xmlBufferPtr buf) {
6489 if (buf == NULL) {
6490#ifdef DEBUG_BUFFER
6491 xmlGenericError(xmlGenericErrorContext,
6492 "xmlBufferFree: buf == NULL\n");
6493#endif
6494 return;
6495 }
Daniel Veillard53350552003-09-18 13:35:51 +00006496
6497 if ((buf->content != NULL) &&
6498 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006499 xmlFree(buf->content);
6500 }
Owen Taylor3473f882001-02-23 17:55:21 +00006501 xmlFree(buf);
6502}
6503
6504/**
6505 * xmlBufferEmpty:
6506 * @buf: the buffer
6507 *
6508 * empty a buffer.
6509 */
6510void
6511xmlBufferEmpty(xmlBufferPtr buf) {
6512 if (buf->content == NULL) return;
6513 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006514 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00006515 buf->content = BAD_CAST "";
Daniel Veillard53350552003-09-18 13:35:51 +00006516 } else {
6517 memset(buf->content, 0, buf->size);
6518 }
Owen Taylor3473f882001-02-23 17:55:21 +00006519}
6520
6521/**
6522 * xmlBufferShrink:
6523 * @buf: the buffer to dump
6524 * @len: the number of xmlChar to remove
6525 *
6526 * Remove the beginning of an XML buffer.
6527 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006528 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006529 */
6530int
6531xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
6532 if (len == 0) return(0);
6533 if (len > buf->use) return(-1);
6534
6535 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006536 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6537 buf->content += len;
6538 } else {
6539 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6540 buf->content[buf->use] = 0;
6541 }
Owen Taylor3473f882001-02-23 17:55:21 +00006542 return(len);
6543}
6544
6545/**
6546 * xmlBufferGrow:
6547 * @buf: the buffer
6548 * @len: the minimum free size to allocate
6549 *
6550 * Grow the available space of an XML buffer.
6551 *
6552 * Returns the new available space or -1 in case of error
6553 */
6554int
6555xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6556 int size;
6557 xmlChar *newbuf;
6558
Daniel Veillard53350552003-09-18 13:35:51 +00006559 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006560 if (len + buf->use < buf->size) return(0);
6561
6562 size = buf->use + len + 100;
6563
6564 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006565 if (newbuf == NULL) {
6566 xmlTreeErrMemory("growing buffer");
6567 return(-1);
6568 }
Owen Taylor3473f882001-02-23 17:55:21 +00006569 buf->content = newbuf;
6570 buf->size = size;
6571 return(buf->size - buf->use);
6572}
6573
6574/**
6575 * xmlBufferDump:
6576 * @file: the file output
6577 * @buf: the buffer to dump
6578 *
6579 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006580 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006581 */
6582int
6583xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6584 int ret;
6585
6586 if (buf == NULL) {
6587#ifdef DEBUG_BUFFER
6588 xmlGenericError(xmlGenericErrorContext,
6589 "xmlBufferDump: buf == NULL\n");
6590#endif
6591 return(0);
6592 }
6593 if (buf->content == NULL) {
6594#ifdef DEBUG_BUFFER
6595 xmlGenericError(xmlGenericErrorContext,
6596 "xmlBufferDump: buf->content == NULL\n");
6597#endif
6598 return(0);
6599 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006600 if (file == NULL)
6601 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006602 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6603 return(ret);
6604}
6605
6606/**
6607 * xmlBufferContent:
6608 * @buf: the buffer
6609 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006610 * Function to extract the content of a buffer
6611 *
Owen Taylor3473f882001-02-23 17:55:21 +00006612 * Returns the internal content
6613 */
6614
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006615const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006616xmlBufferContent(const xmlBufferPtr buf)
6617{
6618 if(!buf)
6619 return NULL;
6620
6621 return buf->content;
6622}
6623
6624/**
6625 * xmlBufferLength:
6626 * @buf: the buffer
6627 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006628 * Function to get the length of a buffer
6629 *
Owen Taylor3473f882001-02-23 17:55:21 +00006630 * Returns the length of data in the internal content
6631 */
6632
6633int
6634xmlBufferLength(const xmlBufferPtr buf)
6635{
6636 if(!buf)
6637 return 0;
6638
6639 return buf->use;
6640}
6641
6642/**
6643 * xmlBufferResize:
6644 * @buf: the buffer to resize
6645 * @size: the desired size
6646 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006647 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006648 *
6649 * Returns 0 in case of problems, 1 otherwise
6650 */
6651int
6652xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6653{
6654 unsigned int newSize;
6655 xmlChar* rebuf = NULL;
6656
Daniel Veillard53350552003-09-18 13:35:51 +00006657 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6658
Owen Taylor3473f882001-02-23 17:55:21 +00006659 /*take care of empty case*/
6660 newSize = (buf->size ? buf->size*2 : size);
6661
6662 /* Don't resize if we don't have to */
6663 if (size < buf->size)
6664 return 1;
6665
6666 /* figure out new size */
6667 switch (buf->alloc){
6668 case XML_BUFFER_ALLOC_DOUBLEIT:
6669 while (size > newSize) newSize *= 2;
6670 break;
6671 case XML_BUFFER_ALLOC_EXACT:
6672 newSize = size+10;
6673 break;
6674 default:
6675 newSize = size+10;
6676 break;
6677 }
6678
6679 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006680 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006681 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006682 rebuf = (xmlChar *) xmlRealloc(buf->content,
6683 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006684 } else {
6685 /*
6686 * if we are reallocating a buffer far from being full, it's
6687 * better to make a new allocation and copy only the used range
6688 * and free the old one.
6689 */
6690 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6691 if (rebuf != NULL) {
6692 memcpy(rebuf, buf->content, buf->use);
6693 xmlFree(buf->content);
6694 }
Daniel Veillarde5984082003-08-19 22:21:13 +00006695 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006696 }
Owen Taylor3473f882001-02-23 17:55:21 +00006697 if (rebuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006698 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006699 return 0;
6700 }
6701 buf->content = rebuf;
6702 buf->size = newSize;
6703
6704 return 1;
6705}
6706
6707/**
6708 * xmlBufferAdd:
6709 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006710 * @str: the #xmlChar string
6711 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006712 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006713 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006714 * str is recomputed.
6715 */
6716void
6717xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6718 unsigned int needSize;
6719
6720 if (str == NULL) {
6721#ifdef DEBUG_BUFFER
6722 xmlGenericError(xmlGenericErrorContext,
6723 "xmlBufferAdd: str == NULL\n");
6724#endif
6725 return;
6726 }
Daniel Veillard53350552003-09-18 13:35:51 +00006727 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006728 if (len < -1) {
6729#ifdef DEBUG_BUFFER
6730 xmlGenericError(xmlGenericErrorContext,
6731 "xmlBufferAdd: len < 0\n");
6732#endif
6733 return;
6734 }
6735 if (len == 0) return;
6736
6737 if (len < 0)
6738 len = xmlStrlen(str);
6739
6740 if (len <= 0) return;
6741
6742 needSize = buf->use + len + 2;
6743 if (needSize > buf->size){
6744 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006745 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006746 return;
6747 }
6748 }
6749
6750 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6751 buf->use += len;
6752 buf->content[buf->use] = 0;
6753}
6754
6755/**
6756 * xmlBufferAddHead:
6757 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006758 * @str: the #xmlChar string
6759 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006760 *
6761 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006762 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00006763 */
6764void
6765xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6766 unsigned int needSize;
6767
Daniel Veillard53350552003-09-18 13:35:51 +00006768 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006769 if (str == NULL) {
6770#ifdef DEBUG_BUFFER
6771 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006772 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006773#endif
6774 return;
6775 }
6776 if (len < -1) {
6777#ifdef DEBUG_BUFFER
6778 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006779 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006780#endif
6781 return;
6782 }
6783 if (len == 0) return;
6784
6785 if (len < 0)
6786 len = xmlStrlen(str);
6787
6788 if (len <= 0) return;
6789
6790 needSize = buf->use + len + 2;
6791 if (needSize > buf->size){
6792 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006793 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006794 return;
6795 }
6796 }
6797
6798 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6799 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6800 buf->use += len;
6801 buf->content[buf->use] = 0;
6802}
6803
6804/**
6805 * xmlBufferCat:
6806 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006807 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006808 *
6809 * Append a zero terminated string to an XML buffer.
6810 */
6811void
6812xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillard53350552003-09-18 13:35:51 +00006813 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006814 if (str != NULL)
6815 xmlBufferAdd(buf, str, -1);
6816}
6817
6818/**
6819 * xmlBufferCCat:
6820 * @buf: the buffer to dump
6821 * @str: the C char string
6822 *
6823 * Append a zero terminated C string to an XML buffer.
6824 */
6825void
6826xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6827 const char *cur;
6828
Daniel Veillard53350552003-09-18 13:35:51 +00006829 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006830 if (str == NULL) {
6831#ifdef DEBUG_BUFFER
6832 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006833 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006834#endif
6835 return;
6836 }
6837 for (cur = str;*cur != 0;cur++) {
6838 if (buf->use + 10 >= buf->size) {
6839 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006840 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006841 return;
6842 }
6843 }
6844 buf->content[buf->use++] = *cur;
6845 }
6846 buf->content[buf->use] = 0;
6847}
6848
6849/**
6850 * xmlBufferWriteCHAR:
6851 * @buf: the XML buffer
6852 * @string: the string to add
6853 *
6854 * routine which manages and grows an output buffer. This one adds
6855 * xmlChars at the end of the buffer.
6856 */
6857void
Daniel Veillard53350552003-09-18 13:35:51 +00006858xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
6859 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006860 xmlBufferCat(buf, string);
6861}
6862
6863/**
6864 * xmlBufferWriteChar:
6865 * @buf: the XML buffer output
6866 * @string: the string to add
6867 *
6868 * routine which manage and grows an output buffer. This one add
6869 * C chars at the end of the array.
6870 */
6871void
6872xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillard53350552003-09-18 13:35:51 +00006873 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006874 xmlBufferCCat(buf, string);
6875}
6876
6877
6878/**
6879 * xmlBufferWriteQuotedString:
6880 * @buf: the XML buffer output
6881 * @string: the string to add
6882 *
6883 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00006884 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00006885 * quote or double-quotes internally
6886 */
6887void
6888xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00006889 const xmlChar *cur, *base;
Daniel Veillard53350552003-09-18 13:35:51 +00006890 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00006891 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00006892 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00006893#ifdef DEBUG_BUFFER
6894 xmlGenericError(xmlGenericErrorContext,
6895 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
6896#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00006897 xmlBufferCCat(buf, "\"");
6898 base = cur = string;
6899 while(*cur != 0){
6900 if(*cur == '"'){
6901 if (base != cur)
6902 xmlBufferAdd(buf, base, cur - base);
6903 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6904 cur++;
6905 base = cur;
6906 }
6907 else {
6908 cur++;
6909 }
6910 }
6911 if (base != cur)
6912 xmlBufferAdd(buf, base, cur - base);
6913 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006914 }
Daniel Veillard39057f42003-08-04 01:33:43 +00006915 else{
6916 xmlBufferCCat(buf, "\'");
6917 xmlBufferCat(buf, string);
6918 xmlBufferCCat(buf, "\'");
6919 }
Owen Taylor3473f882001-02-23 17:55:21 +00006920 } else {
6921 xmlBufferCCat(buf, "\"");
6922 xmlBufferCat(buf, string);
6923 xmlBufferCCat(buf, "\"");
6924 }
6925}
6926
6927
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00006928#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00006929/************************************************************************
6930 * *
Daniel Veillarde2238d52003-10-09 13:14:55 +00006931 * Output error handlers *
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006932 * *
6933 ************************************************************************/
6934/**
6935 * xmlSaveErrMemory:
6936 * @extra: extra informations
6937 *
6938 * Handle an out of memory condition
6939 */
6940static void
6941xmlSaveErrMemory(const char *extra)
6942{
6943 __xmlSimpleError(XML_FROM_OUTPUT, XML_ERR_NO_MEMORY, NULL, NULL, extra);
6944}
6945
6946/**
6947 * xmlSaveErr:
6948 * @code: the error number
6949 * @node: the location of the error.
6950 * @extra: extra informations
6951 *
6952 * Handle an out of memory condition
6953 */
6954static void
6955xmlSaveErr(int code, xmlNodePtr node, const char *extra)
6956{
6957 const char *msg = NULL;
6958
6959 switch(code) {
6960 case XML_SAVE_NOT_UTF8:
6961 msg = "string is not in UTF-8";
6962 break;
6963 case XML_SAVE_CHAR_INVALID:
6964 msg = "invalid character value";
6965 break;
6966 case XML_SAVE_UNKNOWN_ENCODING:
6967 msg = "unknown encoding %s";
6968 break;
Daniel Veillarde2238d52003-10-09 13:14:55 +00006969 case XML_SAVE_NO_DOCTYPE:
6970 msg = "document has no DOCTYPE";
6971 break;
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006972 default:
6973 msg = "unexpected error number";
6974 }
Daniel Veillarde2238d52003-10-09 13:14:55 +00006975 __xmlSimpleError(XML_FROM_OUTPUT, code, node, msg, extra);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006976}
6977/************************************************************************
6978 * *
Owen Taylor3473f882001-02-23 17:55:21 +00006979 * Dumping XML tree content to a simple buffer *
6980 * *
6981 ************************************************************************/
6982
Owen Taylor3473f882001-02-23 17:55:21 +00006983/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00006984 * xmlAttrSerializeContent:
6985 * @buf: the XML buffer output
6986 * @doc: the document
6987 * @attr: the attribute pointer
6988 *
6989 * Serialize the attribute in the buffer
6990 */
6991static void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006992xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr)
6993{
Daniel Veillarda6d05382002-02-13 13:07:41 +00006994 const xmlChar *cur, *base;
6995 xmlNodePtr children;
6996
6997 children = attr->children;
6998 while (children != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006999 switch (children->type) {
7000 case XML_TEXT_NODE:
7001 base = cur = children->content;
7002 while (*cur != 0) {
7003 if (*cur == '\n') {
7004 if (base != cur)
7005 xmlBufferAdd(buf, base, cur - base);
7006 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
7007 cur++;
7008 base = cur;
Daniel Veillard0046c0f2003-02-23 13:52:30 +00007009 } else if (*cur == '\r') {
7010 if (base != cur)
7011 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00007012 xmlBufferAdd(buf, BAD_CAST "&#13;", 5);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00007013 cur++;
7014 base = cur;
7015 } else if (*cur == '\t') {
7016 if (base != cur)
7017 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00007018 xmlBufferAdd(buf, BAD_CAST "&#9;", 4);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00007019 cur++;
7020 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00007021#if 0
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007022 } else if (*cur == '\'') {
7023 if (base != cur)
7024 xmlBufferAdd(buf, base, cur - base);
7025 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
7026 cur++;
7027 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00007028#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007029 } else if (*cur == '"') {
7030 if (base != cur)
7031 xmlBufferAdd(buf, base, cur - base);
7032 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7033 cur++;
7034 base = cur;
7035 } else if (*cur == '<') {
7036 if (base != cur)
7037 xmlBufferAdd(buf, base, cur - base);
7038 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
7039 cur++;
7040 base = cur;
7041 } else if (*cur == '>') {
7042 if (base != cur)
7043 xmlBufferAdd(buf, base, cur - base);
7044 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
7045 cur++;
7046 base = cur;
7047 } else if (*cur == '&') {
7048 if (base != cur)
7049 xmlBufferAdd(buf, base, cur - base);
7050 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
7051 cur++;
7052 base = cur;
7053 } else if ((*cur >= 0x80) && ((doc == NULL) ||
7054 (doc->encoding ==
7055 NULL))) {
7056 /*
7057 * We assume we have UTF-8 content.
7058 */
7059 char tmp[10];
7060 int val = 0, l = 1;
Daniel Veillarda6d05382002-02-13 13:07:41 +00007061
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007062 if (base != cur)
7063 xmlBufferAdd(buf, base, cur - base);
7064 if (*cur < 0xC0) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007065 xmlSaveErr(XML_SAVE_NOT_UTF8, (xmlNodePtr) attr,
7066 NULL);
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007067 if (doc != NULL)
7068 doc->encoding =
7069 xmlStrdup(BAD_CAST "ISO-8859-1");
7070 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
7071 tmp[sizeof(tmp) - 1] = 0;
7072 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
7073 cur++;
7074 base = cur;
7075 continue;
7076 } else if (*cur < 0xE0) {
7077 val = (cur[0]) & 0x1F;
7078 val <<= 6;
7079 val |= (cur[1]) & 0x3F;
7080 l = 2;
7081 } else if (*cur < 0xF0) {
7082 val = (cur[0]) & 0x0F;
7083 val <<= 6;
7084 val |= (cur[1]) & 0x3F;
7085 val <<= 6;
7086 val |= (cur[2]) & 0x3F;
7087 l = 3;
7088 } else if (*cur < 0xF8) {
7089 val = (cur[0]) & 0x07;
7090 val <<= 6;
7091 val |= (cur[1]) & 0x3F;
7092 val <<= 6;
7093 val |= (cur[2]) & 0x3F;
7094 val <<= 6;
7095 val |= (cur[3]) & 0x3F;
7096 l = 4;
7097 }
7098 if ((l == 1) || (!IS_CHAR(val))) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007099 xmlSaveErr(XML_SAVE_CHAR_INVALID, (xmlNodePtr) attr,
7100 NULL);
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007101 if (doc != NULL)
7102 doc->encoding =
7103 xmlStrdup(BAD_CAST "ISO-8859-1");
7104 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
7105 tmp[sizeof(tmp) - 1] = 0;
7106 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
7107 cur++;
7108 base = cur;
7109 continue;
7110 }
7111 /*
7112 * We could do multiple things here. Just save
7113 * as a char ref
7114 */
7115 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
7116 tmp[sizeof(tmp) - 1] = 0;
7117 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
7118 cur += l;
7119 base = cur;
7120 } else {
7121 cur++;
7122 }
7123 }
7124 if (base != cur)
7125 xmlBufferAdd(buf, base, cur - base);
7126 break;
7127 case XML_ENTITY_REF_NODE:
7128 xmlBufferAdd(buf, BAD_CAST "&", 1);
7129 xmlBufferAdd(buf, children->name,
7130 xmlStrlen(children->name));
7131 xmlBufferAdd(buf, BAD_CAST ";", 1);
7132 break;
7133 default:
7134 /* should not happen unless we have a badly built tree */
7135 break;
7136 }
7137 children = children->next;
Owen Taylor3473f882001-02-23 17:55:21 +00007138 }
7139}
7140
7141/**
7142 * xmlNodeDump:
7143 * @buf: the XML buffer output
7144 * @doc: the document
7145 * @cur: the current node
7146 * @level: the imbrication level for indenting
7147 * @format: is formatting allowed
7148 *
7149 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007150 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007151 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007152 *
7153 * Returns the number of bytes written to the buffer or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00007154 */
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007155int
Owen Taylor3473f882001-02-23 17:55:21 +00007156xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007157 int format)
7158{
7159 unsigned int use;
7160 int ret;
7161 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00007162
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007163 xmlInitParser();
7164
Owen Taylor3473f882001-02-23 17:55:21 +00007165 if (cur == NULL) {
7166#ifdef DEBUG_TREE
7167 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007168 "xmlNodeDump : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007169#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007170 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007171 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007172 if (buf == NULL) {
7173#ifdef DEBUG_TREE
7174 xmlGenericError(xmlGenericErrorContext,
7175 "xmlNodeDump : buf == NULL\n");
7176#endif
7177 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007178 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007179 outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
7180 if (outbuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007181 xmlSaveErrMemory("creating buffer");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007182 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007183 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007184 memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
7185 outbuf->buffer = buf;
7186 outbuf->encoder = NULL;
7187 outbuf->writecallback = NULL;
7188 outbuf->closecallback = NULL;
7189 outbuf->context = NULL;
7190 outbuf->written = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007191
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007192 use = buf->use;
7193 xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
7194 xmlFree(outbuf);
7195 ret = buf->use - use;
7196 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00007197}
7198
7199/**
7200 * xmlElemDump:
7201 * @f: the FILE * for the output
7202 * @doc: the document
7203 * @cur: the current node
7204 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007205 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00007206 */
7207void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007208xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur)
7209{
7210 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00007211
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007212 xmlInitParser();
7213
Owen Taylor3473f882001-02-23 17:55:21 +00007214 if (cur == NULL) {
7215#ifdef DEBUG_TREE
7216 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007217 "xmlElemDump : cur == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007218#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007219 return;
Owen Taylor3473f882001-02-23 17:55:21 +00007220 }
Owen Taylor3473f882001-02-23 17:55:21 +00007221#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007222 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00007223 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007224 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007225 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007226#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007227
7228 outbuf = xmlOutputBufferCreateFile(f, NULL);
7229 if (outbuf == NULL)
7230 return;
7231 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007232#ifdef LIBXML_HTML_ENABLED
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007233 htmlNodeDumpOutput(outbuf, doc, cur, NULL);
7234#else
Daniel Veillard2189b592003-10-21 00:08:42 +00007235 xmlSaveErr(XML_ERR_INTERNAL_ERROR, cur, "HTML support not compiled in\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007236#endif /* LIBXML_HTML_ENABLED */
7237 } else
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007238 xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL);
7239 xmlOutputBufferClose(outbuf);
Owen Taylor3473f882001-02-23 17:55:21 +00007240}
7241
7242/************************************************************************
7243 * *
7244 * Dumping XML tree content to an I/O output buffer *
7245 * *
7246 ************************************************************************/
7247
Daniel Veillard4432df22003-09-28 18:58:27 +00007248#ifdef LIBXML_HTML_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00007249static void
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007250xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7251 int level, int format, const char *encoding);
Daniel Veillard4432df22003-09-28 18:58:27 +00007252#endif
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007253static void
Owen Taylor3473f882001-02-23 17:55:21 +00007254xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7255 int level, int format, const char *encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007256static void
7257xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
7258 xmlNodePtr cur, int level, int format, const char *encoding);
7259
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00007260void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
7261
Owen Taylor3473f882001-02-23 17:55:21 +00007262/**
7263 * xmlNsDumpOutput:
7264 * @buf: the XML buffer output
7265 * @cur: a namespace
7266 *
7267 * Dump a local Namespace definition.
7268 * Should be called in the context of attributes dumps.
7269 */
7270static void
7271xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
7272 if (cur == NULL) {
7273#ifdef DEBUG_TREE
7274 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007275 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007276#endif
7277 return;
7278 }
7279 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00007280 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
7281 return;
7282
Owen Taylor3473f882001-02-23 17:55:21 +00007283 /* Within the context of an element attributes */
7284 if (cur->prefix != NULL) {
7285 xmlOutputBufferWriteString(buf, " xmlns:");
7286 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
7287 } else
7288 xmlOutputBufferWriteString(buf, " xmlns");
7289 xmlOutputBufferWriteString(buf, "=");
7290 xmlBufferWriteQuotedString(buf->buffer, cur->href);
7291 }
7292}
7293
7294/**
7295 * xmlNsListDumpOutput:
7296 * @buf: the XML buffer output
7297 * @cur: the first namespace
7298 *
7299 * Dump a list of local Namespace definitions.
7300 * Should be called in the context of attributes dumps.
7301 */
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00007302void
Owen Taylor3473f882001-02-23 17:55:21 +00007303xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
7304 while (cur != NULL) {
7305 xmlNsDumpOutput(buf, cur);
7306 cur = cur->next;
7307 }
7308}
7309
7310/**
7311 * xmlDtdDumpOutput:
7312 * @buf: the XML buffer output
7313 * @doc: the document
7314 * @encoding: an optional encoding string
7315 *
7316 * Dump the XML document DTD, if any.
7317 */
7318static void
7319xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
7320 if (dtd == NULL) {
7321#ifdef DEBUG_TREE
7322 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007323 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007324#endif
7325 return;
7326 }
7327 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
7328 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
7329 if (dtd->ExternalID != NULL) {
7330 xmlOutputBufferWriteString(buf, " PUBLIC ");
7331 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
7332 xmlOutputBufferWriteString(buf, " ");
7333 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
7334 } else if (dtd->SystemID != NULL) {
7335 xmlOutputBufferWriteString(buf, " SYSTEM ");
7336 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
7337 }
7338 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
7339 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
7340 xmlOutputBufferWriteString(buf, ">");
7341 return;
7342 }
7343 xmlOutputBufferWriteString(buf, " [\n");
7344 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
7345 xmlOutputBufferWriteString(buf, "]>");
7346}
7347
7348/**
7349 * xmlAttrDumpOutput:
7350 * @buf: the XML buffer output
7351 * @doc: the document
7352 * @cur: the attribute pointer
7353 * @encoding: an optional encoding string
7354 *
7355 * Dump an XML attribute
7356 */
7357static void
7358xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00007359 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00007360 if (cur == NULL) {
7361#ifdef DEBUG_TREE
7362 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007363 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007364#endif
7365 return;
7366 }
7367 xmlOutputBufferWriteString(buf, " ");
7368 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7369 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7370 xmlOutputBufferWriteString(buf, ":");
7371 }
7372 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00007373 xmlOutputBufferWriteString(buf, "=\"");
7374 xmlAttrSerializeContent(buf->buffer, doc, cur);
7375 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007376}
7377
7378/**
7379 * xmlAttrListDumpOutput:
7380 * @buf: the XML buffer output
7381 * @doc: the document
7382 * @cur: the first attribute pointer
7383 * @encoding: an optional encoding string
7384 *
7385 * Dump a list of XML attributes
7386 */
7387static void
7388xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7389 xmlAttrPtr cur, const char *encoding) {
7390 if (cur == NULL) {
7391#ifdef DEBUG_TREE
7392 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007393 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007394#endif
7395 return;
7396 }
7397 while (cur != NULL) {
7398 xmlAttrDumpOutput(buf, doc, cur, encoding);
7399 cur = cur->next;
7400 }
7401}
7402
7403
7404
7405/**
7406 * xmlNodeListDumpOutput:
7407 * @buf: the XML buffer output
7408 * @doc: the document
7409 * @cur: the first node
7410 * @level: the imbrication level for indenting
7411 * @format: is formatting allowed
7412 * @encoding: an optional encoding string
7413 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007414 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007415 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007416 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007417 */
7418static void
7419xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7420 xmlNodePtr cur, int level, int format, const char *encoding) {
7421 int i;
7422
7423 if (cur == NULL) {
7424#ifdef DEBUG_TREE
7425 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007426 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007427#endif
7428 return;
7429 }
7430 while (cur != NULL) {
7431 if ((format) && (xmlIndentTreeOutput) &&
7432 (cur->type == XML_ELEMENT_NODE))
7433 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007434 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007435 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007436 if (format) {
7437 xmlOutputBufferWriteString(buf, "\n");
7438 }
7439 cur = cur->next;
7440 }
7441}
7442
7443/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007444 * xmlNodeDumpOutputInternal:
Owen Taylor3473f882001-02-23 17:55:21 +00007445 * @buf: the XML buffer output
7446 * @doc: the document
7447 * @cur: the current node
7448 * @level: the imbrication level for indenting
7449 * @format: is formatting allowed
7450 * @encoding: an optional encoding string
7451 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007452 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007453 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007454 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007455 */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007456static void
7457xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
7458 xmlNodePtr cur, int level, int format, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007459 int i;
7460 xmlNodePtr tmp;
Daniel Veillard9475a352003-09-26 12:47:50 +00007461 xmlChar *start, *end;
Owen Taylor3473f882001-02-23 17:55:21 +00007462
7463 if (cur == NULL) {
7464#ifdef DEBUG_TREE
7465 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007466 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007467#endif
7468 return;
7469 }
7470 if (cur->type == XML_XINCLUDE_START)
7471 return;
7472 if (cur->type == XML_XINCLUDE_END)
7473 return;
7474 if (cur->type == XML_DTD_NODE) {
7475 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7476 return;
7477 }
Daniel Veillardcec50a62003-10-28 13:26:51 +00007478 if (cur->type == XML_DOCUMENT_FRAG_NODE) {
7479 xmlNodeListDumpOutput(buf, doc, cur->children, level, format, encoding);
7480 return;
7481 }
Owen Taylor3473f882001-02-23 17:55:21 +00007482 if (cur->type == XML_ELEMENT_DECL) {
7483 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7484 return;
7485 }
7486 if (cur->type == XML_ATTRIBUTE_DECL) {
7487 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7488 return;
7489 }
7490 if (cur->type == XML_ENTITY_DECL) {
7491 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7492 return;
7493 }
7494 if (cur->type == XML_TEXT_NODE) {
7495 if (cur->content != NULL) {
7496 if ((cur->name == xmlStringText) ||
7497 (cur->name != xmlStringTextNoenc)) {
7498 xmlChar *buffer;
7499
Owen Taylor3473f882001-02-23 17:55:21 +00007500 if (encoding == NULL)
7501 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7502 else
7503 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007504 if (buffer != NULL) {
7505 xmlOutputBufferWriteString(buf, (const char *)buffer);
7506 xmlFree(buffer);
7507 }
7508 } else {
7509 /*
7510 * Disable escaping, needed for XSLT
7511 */
Owen Taylor3473f882001-02-23 17:55:21 +00007512 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007513 }
7514 }
7515
7516 return;
7517 }
7518 if (cur->type == XML_PI_NODE) {
7519 if (cur->content != NULL) {
7520 xmlOutputBufferWriteString(buf, "<?");
7521 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7522 if (cur->content != NULL) {
7523 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00007524 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007525 }
7526 xmlOutputBufferWriteString(buf, "?>");
7527 } else {
7528 xmlOutputBufferWriteString(buf, "<?");
7529 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7530 xmlOutputBufferWriteString(buf, "?>");
7531 }
7532 return;
7533 }
7534 if (cur->type == XML_COMMENT_NODE) {
7535 if (cur->content != NULL) {
7536 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00007537 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007538 xmlOutputBufferWriteString(buf, "-->");
7539 }
7540 return;
7541 }
7542 if (cur->type == XML_ENTITY_REF_NODE) {
7543 xmlOutputBufferWriteString(buf, "&");
7544 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7545 xmlOutputBufferWriteString(buf, ";");
7546 return;
7547 }
7548 if (cur->type == XML_CDATA_SECTION_NODE) {
Daniel Veillard9475a352003-09-26 12:47:50 +00007549 start = end = cur->content;
7550 while (*end != '\0') {
7551 if ((*end == ']') && (*(end + 1) == ']') && (*(end + 2) == '>')) {
7552 end = end + 2;
7553 xmlOutputBufferWriteString(buf, "<![CDATA[");
7554 xmlOutputBufferWrite(buf, end - start, (const char *)start);
7555 xmlOutputBufferWriteString(buf, "]]>");
7556 start = end;
7557 }
7558 end++;
7559 }
7560 if (start != end) {
7561 xmlOutputBufferWriteString(buf, "<![CDATA[");
7562 xmlOutputBufferWriteString(buf, (const char *)start);
7563 xmlOutputBufferWriteString(buf, "]]>");
7564 }
Owen Taylor3473f882001-02-23 17:55:21 +00007565 return;
7566 }
Daniel Veillard7b72ee52003-02-27 23:24:53 +00007567 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillarda1a9d042003-03-18 16:53:17 +00007568 xmlAttrDumpOutput(buf,doc, (xmlAttrPtr) cur,encoding);
Daniel Veillard7b72ee52003-02-27 23:24:53 +00007569 return;
7570 }
Daniel Veillard6aa2f602003-02-10 00:01:56 +00007571 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007572 xmlNsDumpOutput(buf, (xmlNsPtr) cur);
Daniel Veillard6aa2f602003-02-10 00:01:56 +00007573 return;
7574 }
Owen Taylor3473f882001-02-23 17:55:21 +00007575
7576 if (format == 1) {
7577 tmp = cur->children;
7578 while (tmp != NULL) {
William M. Brack9ca682f2003-10-19 10:01:59 +00007579 if ((tmp->type == XML_TEXT_NODE) ||
7580 (tmp->type == XML_CDATA_SECTION_NODE) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007581 (tmp->type == XML_ENTITY_REF_NODE)) {
7582 format = 0;
7583 break;
7584 }
7585 tmp = tmp->next;
7586 }
7587 }
7588 xmlOutputBufferWriteString(buf, "<");
7589 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7590 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7591 xmlOutputBufferWriteString(buf, ":");
7592 }
7593
7594 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7595 if (cur->nsDef)
7596 xmlNsListDumpOutput(buf, cur->nsDef);
7597 if (cur->properties != NULL)
7598 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7599
Daniel Veillard7db37732001-07-12 01:20:08 +00007600 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
7601 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007602 xmlOutputBufferWriteString(buf, "/>");
7603 return;
7604 }
7605 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00007606 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007607 xmlChar *buffer;
7608
Owen Taylor3473f882001-02-23 17:55:21 +00007609 if (encoding == NULL)
7610 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7611 else
7612 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007613 if (buffer != NULL) {
7614 xmlOutputBufferWriteString(buf, (const char *)buffer);
7615 xmlFree(buffer);
7616 }
7617 }
7618 if (cur->children != NULL) {
7619 if (format) xmlOutputBufferWriteString(buf, "\n");
7620 xmlNodeListDumpOutput(buf, doc, cur->children,
7621 (level >= 0?level+1:-1), format, encoding);
7622 if ((xmlIndentTreeOutput) && (format))
7623 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007624 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00007625 }
7626 xmlOutputBufferWriteString(buf, "</");
7627 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7628 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7629 xmlOutputBufferWriteString(buf, ":");
7630 }
7631
7632 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7633 xmlOutputBufferWriteString(buf, ">");
7634}
7635
7636/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007637 * xmlNodeDumpOutput:
7638 * @buf: the XML buffer output
7639 * @doc: the document
7640 * @cur: the current node
7641 * @level: the imbrication level for indenting
7642 * @format: is formatting allowed
7643 * @encoding: an optional encoding string
7644 *
7645 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007646 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007647 * or xmlKeepBlanksDefault(0) was called
7648 */
7649void
7650xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007651 int level, int format, const char *encoding)
7652{
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007653#ifdef LIBXML_HTML_ENABLED
7654 xmlDtdPtr dtd;
7655 int is_xhtml = 0;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007656#endif
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007657
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007658 xmlInitParser();
7659
7660#ifdef LIBXML_HTML_ENABLED
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007661 dtd = xmlGetIntSubset(doc);
7662 if (dtd != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007663 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7664 if (is_xhtml < 0)
7665 is_xhtml = 0;
7666 if ((is_xhtml) && (cur->parent == (xmlNodePtr) doc) &&
7667 (cur->type == XML_ELEMENT_NODE) &&
7668 (xmlStrEqual(cur->name, BAD_CAST "html"))) {
7669 if (encoding != NULL)
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007670 htmlSetMetaEncoding((htmlDocPtr) doc,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007671 (const xmlChar *) encoding);
7672 else
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007673 htmlSetMetaEncoding((htmlDocPtr) doc, BAD_CAST "UTF-8");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007674 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007675 }
7676
7677 if (is_xhtml)
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007678 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007679 else
7680#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007681 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007682}
7683
7684/**
Owen Taylor3473f882001-02-23 17:55:21 +00007685 * xmlDocContentDumpOutput:
7686 * @buf: the XML buffer output
7687 * @cur: the document
7688 * @encoding: an optional encoding string
7689 * @format: should formatting spaces been added
7690 *
7691 * Dump an XML document.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007692 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007693 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007694 */
7695static void
7696xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
7697 const char *encoding, int format) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007698#ifdef LIBXML_HTML_ENABLED
7699 xmlDtdPtr dtd;
7700 int is_xhtml = 0;
7701#endif
7702
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007703 xmlInitParser();
7704
Owen Taylor3473f882001-02-23 17:55:21 +00007705 xmlOutputBufferWriteString(buf, "<?xml version=");
7706 if (cur->version != NULL)
7707 xmlBufferWriteQuotedString(buf->buffer, cur->version);
7708 else
7709 xmlOutputBufferWriteString(buf, "\"1.0\"");
7710 if (encoding == NULL) {
7711 if (cur->encoding != NULL)
7712 encoding = (const char *) cur->encoding;
7713 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
7714 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
7715 }
7716 if (encoding != NULL) {
7717 xmlOutputBufferWriteString(buf, " encoding=");
7718 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
7719 }
7720 switch (cur->standalone) {
7721 case 0:
7722 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
7723 break;
7724 case 1:
7725 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
7726 break;
7727 }
7728 xmlOutputBufferWriteString(buf, "?>\n");
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007729
7730#ifdef LIBXML_HTML_ENABLED
7731 dtd = xmlGetIntSubset(cur);
7732 if (dtd != NULL) {
7733 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7734 if (is_xhtml < 0) is_xhtml = 0;
7735 }
7736 if (is_xhtml) {
7737 if (encoding != NULL)
7738 htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
7739 else
7740 htmlSetMetaEncoding(cur, BAD_CAST "UTF-8");
7741 }
7742#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007743 if (cur->children != NULL) {
7744 xmlNodePtr child = cur->children;
7745
7746 while (child != NULL) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007747#ifdef LIBXML_HTML_ENABLED
7748 if (is_xhtml)
7749 xhtmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
7750 else
7751#endif
7752 xmlNodeDumpOutputInternal(buf, cur, child, 0, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007753 xmlOutputBufferWriteString(buf, "\n");
7754 child = child->next;
7755 }
7756 }
7757}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007758#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00007759
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007760#ifdef LIBXML_HTML_ENABLED
7761/************************************************************************
7762 * *
7763 * Functions specific to XHTML serialization *
7764 * *
7765 ************************************************************************/
7766
7767#define XHTML_STRICT_PUBLIC_ID BAD_CAST \
7768 "-//W3C//DTD XHTML 1.0 Strict//EN"
7769#define XHTML_STRICT_SYSTEM_ID BAD_CAST \
7770 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
7771#define XHTML_FRAME_PUBLIC_ID BAD_CAST \
7772 "-//W3C//DTD XHTML 1.0 Frameset//EN"
7773#define XHTML_FRAME_SYSTEM_ID BAD_CAST \
7774 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
7775#define XHTML_TRANS_PUBLIC_ID BAD_CAST \
7776 "-//W3C//DTD XHTML 1.0 Transitional//EN"
7777#define XHTML_TRANS_SYSTEM_ID BAD_CAST \
7778 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
7779
7780#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
7781/**
7782 * xmlIsXHTML:
7783 * @systemID: the system identifier
7784 * @publicID: the public identifier
7785 *
7786 * Try to find if the document correspond to an XHTML DTD
7787 *
7788 * Returns 1 if true, 0 if not and -1 in case of error
7789 */
7790int
7791xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) {
7792 if ((systemID == NULL) && (publicID == NULL))
7793 return(-1);
7794 if (publicID != NULL) {
7795 if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1);
7796 if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1);
7797 if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1);
7798 }
7799 if (systemID != NULL) {
7800 if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1);
7801 if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1);
7802 if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1);
7803 }
7804 return(0);
7805}
7806
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007807#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007808/**
7809 * xhtmlIsEmpty:
7810 * @node: the node
7811 *
7812 * Check if a node is an empty xhtml node
7813 *
7814 * Returns 1 if the node is an empty node, 0 if not and -1 in case of error
7815 */
7816static int
7817xhtmlIsEmpty(xmlNodePtr node) {
7818 if (node == NULL)
7819 return(-1);
7820 if (node->type != XML_ELEMENT_NODE)
7821 return(0);
7822 if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME)))
7823 return(0);
7824 if (node->children != NULL)
7825 return(0);
7826 switch (node->name[0]) {
7827 case 'a':
7828 if (xmlStrEqual(node->name, BAD_CAST "area"))
7829 return(1);
7830 return(0);
7831 case 'b':
7832 if (xmlStrEqual(node->name, BAD_CAST "br"))
7833 return(1);
7834 if (xmlStrEqual(node->name, BAD_CAST "base"))
7835 return(1);
7836 if (xmlStrEqual(node->name, BAD_CAST "basefont"))
7837 return(1);
7838 return(0);
7839 case 'c':
7840 if (xmlStrEqual(node->name, BAD_CAST "col"))
7841 return(1);
7842 return(0);
7843 case 'f':
7844 if (xmlStrEqual(node->name, BAD_CAST "frame"))
7845 return(1);
7846 return(0);
7847 case 'h':
7848 if (xmlStrEqual(node->name, BAD_CAST "hr"))
7849 return(1);
7850 return(0);
7851 case 'i':
7852 if (xmlStrEqual(node->name, BAD_CAST "img"))
7853 return(1);
7854 if (xmlStrEqual(node->name, BAD_CAST "input"))
7855 return(1);
7856 if (xmlStrEqual(node->name, BAD_CAST "isindex"))
7857 return(1);
7858 return(0);
7859 case 'l':
7860 if (xmlStrEqual(node->name, BAD_CAST "link"))
7861 return(1);
7862 return(0);
7863 case 'm':
7864 if (xmlStrEqual(node->name, BAD_CAST "meta"))
7865 return(1);
7866 return(0);
7867 case 'p':
7868 if (xmlStrEqual(node->name, BAD_CAST "param"))
7869 return(1);
7870 return(0);
7871 }
7872 return(0);
7873}
7874
7875/**
7876 * xhtmlAttrListDumpOutput:
7877 * @buf: the XML buffer output
7878 * @doc: the document
7879 * @cur: the first attribute pointer
7880 * @encoding: an optional encoding string
7881 *
7882 * Dump a list of XML attributes
7883 */
7884static void
7885xhtmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7886 xmlAttrPtr cur, const char *encoding) {
7887 xmlAttrPtr xml_lang = NULL;
7888 xmlAttrPtr lang = NULL;
7889 xmlAttrPtr name = NULL;
7890 xmlAttrPtr id = NULL;
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007891 xmlNodePtr parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007892
7893 if (cur == NULL) {
7894#ifdef DEBUG_TREE
7895 xmlGenericError(xmlGenericErrorContext,
7896 "xmlAttrListDumpOutput : property == NULL\n");
7897#endif
7898 return;
7899 }
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007900 parent = cur->parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007901 while (cur != NULL) {
7902 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id")))
7903 id = cur;
7904 else
7905 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name")))
7906 name = cur;
7907 else
7908 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")))
7909 lang = cur;
7910 else
7911 if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) &&
7912 (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml")))
7913 xml_lang = cur;
7914 else if ((cur->ns == NULL) &&
7915 ((cur->children == NULL) ||
7916 (cur->children->content == NULL) ||
7917 (cur->children->content[0] == 0)) &&
7918 (htmlIsBooleanAttr(cur->name))) {
7919 if (cur->children != NULL)
7920 xmlFreeNode(cur->children);
7921 cur->children = xmlNewText(cur->name);
7922 if (cur->children != NULL)
7923 cur->children->parent = (xmlNodePtr) cur;
7924 }
7925 xmlAttrDumpOutput(buf, doc, cur, encoding);
7926 cur = cur->next;
7927 }
7928 /*
7929 * C.8
7930 */
7931 if ((name != NULL) && (id == NULL)) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007932 if ((parent != NULL) && (parent->name != NULL) &&
7933 ((xmlStrEqual(parent->name, BAD_CAST "a")) ||
7934 (xmlStrEqual(parent->name, BAD_CAST "p")) ||
7935 (xmlStrEqual(parent->name, BAD_CAST "div")) ||
7936 (xmlStrEqual(parent->name, BAD_CAST "img")) ||
7937 (xmlStrEqual(parent->name, BAD_CAST "map")) ||
7938 (xmlStrEqual(parent->name, BAD_CAST "applet")) ||
7939 (xmlStrEqual(parent->name, BAD_CAST "form")) ||
7940 (xmlStrEqual(parent->name, BAD_CAST "frame")) ||
7941 (xmlStrEqual(parent->name, BAD_CAST "iframe")))) {
7942 xmlOutputBufferWriteString(buf, " id=\"");
7943 xmlAttrSerializeContent(buf->buffer, doc, name);
7944 xmlOutputBufferWriteString(buf, "\"");
7945 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007946 }
7947 /*
7948 * C.7.
7949 */
7950 if ((lang != NULL) && (xml_lang == NULL)) {
7951 xmlOutputBufferWriteString(buf, " xml:lang=\"");
7952 xmlAttrSerializeContent(buf->buffer, doc, lang);
7953 xmlOutputBufferWriteString(buf, "\"");
7954 } else
7955 if ((xml_lang != NULL) && (lang == NULL)) {
7956 xmlOutputBufferWriteString(buf, " lang=\"");
7957 xmlAttrSerializeContent(buf->buffer, doc, xml_lang);
7958 xmlOutputBufferWriteString(buf, "\"");
7959 }
7960}
7961
7962/**
7963 * xhtmlNodeListDumpOutput:
7964 * @buf: the XML buffer output
7965 * @doc: the XHTML document
7966 * @cur: the first node
7967 * @level: the imbrication level for indenting
7968 * @format: is formatting allowed
7969 * @encoding: an optional encoding string
7970 *
7971 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007972 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007973 * or xmlKeepBlanksDefault(0) was called
7974 */
7975static void
7976xhtmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7977 xmlNodePtr cur, int level, int format, const char *encoding) {
7978 int i;
7979
7980 if (cur == NULL) {
7981#ifdef DEBUG_TREE
7982 xmlGenericError(xmlGenericErrorContext,
7983 "xhtmlNodeListDumpOutput : node == NULL\n");
7984#endif
7985 return;
7986 }
7987 while (cur != NULL) {
7988 if ((format) && (xmlIndentTreeOutput) &&
7989 (cur->type == XML_ELEMENT_NODE))
7990 for (i = 0;i < level;i++)
7991 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7992 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
7993 if (format) {
7994 xmlOutputBufferWriteString(buf, "\n");
7995 }
7996 cur = cur->next;
7997 }
7998}
7999
8000/**
8001 * xhtmlNodeDumpOutput:
8002 * @buf: the XML buffer output
8003 * @doc: the XHTML document
8004 * @cur: the current node
8005 * @level: the imbrication level for indenting
8006 * @format: is formatting allowed
8007 * @encoding: an optional encoding string
8008 *
8009 * Dump an XHTML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008010 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00008011 * or xmlKeepBlanksDefault(0) was called
8012 */
8013static void
8014xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
8015 int level, int format, const char *encoding) {
8016 int i;
8017 xmlNodePtr tmp;
Daniel Veillard9475a352003-09-26 12:47:50 +00008018 xmlChar *start, *end;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00008019
8020 if (cur == NULL) {
8021#ifdef DEBUG_TREE
8022 xmlGenericError(xmlGenericErrorContext,
8023 "xmlNodeDumpOutput : node == NULL\n");
8024#endif
8025 return;
8026 }
8027 if (cur->type == XML_XINCLUDE_START)
8028 return;
8029 if (cur->type == XML_XINCLUDE_END)
8030 return;
8031 if (cur->type == XML_DTD_NODE) {
8032 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
8033 return;
8034 }
8035 if (cur->type == XML_ELEMENT_DECL) {
8036 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
8037 return;
8038 }
8039 if (cur->type == XML_ATTRIBUTE_DECL) {
8040 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
8041 return;
8042 }
8043 if (cur->type == XML_ENTITY_DECL) {
8044 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
8045 return;
8046 }
8047 if (cur->type == XML_TEXT_NODE) {
8048 if (cur->content != NULL) {
8049 if ((cur->name == xmlStringText) ||
8050 (cur->name != xmlStringTextNoenc)) {
8051 xmlChar *buffer;
8052
8053 if (encoding == NULL)
8054 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
8055 else
8056 buffer = xmlEncodeSpecialChars(doc, cur->content);
8057 if (buffer != NULL) {
8058 xmlOutputBufferWriteString(buf, (const char *)buffer);
8059 xmlFree(buffer);
8060 }
8061 } else {
8062 /*
8063 * Disable escaping, needed for XSLT
8064 */
8065 xmlOutputBufferWriteString(buf, (const char *) cur->content);
8066 }
8067 }
8068
8069 return;
8070 }
8071 if (cur->type == XML_PI_NODE) {
8072 if (cur->content != NULL) {
8073 xmlOutputBufferWriteString(buf, "<?");
8074 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8075 if (cur->content != NULL) {
8076 xmlOutputBufferWriteString(buf, " ");
8077 xmlOutputBufferWriteString(buf, (const char *)cur->content);
8078 }
8079 xmlOutputBufferWriteString(buf, "?>");
8080 } else {
8081 xmlOutputBufferWriteString(buf, "<?");
8082 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8083 xmlOutputBufferWriteString(buf, "?>");
8084 }
8085 return;
8086 }
8087 if (cur->type == XML_COMMENT_NODE) {
8088 if (cur->content != NULL) {
8089 xmlOutputBufferWriteString(buf, "<!--");
8090 xmlOutputBufferWriteString(buf, (const char *)cur->content);
8091 xmlOutputBufferWriteString(buf, "-->");
8092 }
8093 return;
8094 }
8095 if (cur->type == XML_ENTITY_REF_NODE) {
8096 xmlOutputBufferWriteString(buf, "&");
8097 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8098 xmlOutputBufferWriteString(buf, ";");
8099 return;
8100 }
8101 if (cur->type == XML_CDATA_SECTION_NODE) {
Daniel Veillard9475a352003-09-26 12:47:50 +00008102 start = end = cur->content;
8103 while (*end != '\0') {
8104 if (*end == ']' && *(end + 1) == ']' && *(end + 2) == '>') {
8105 end = end + 2;
8106 xmlOutputBufferWriteString(buf, "<![CDATA[");
8107 xmlOutputBufferWrite(buf, end - start, (const char *)start);
8108 xmlOutputBufferWriteString(buf, "]]>");
8109 start = end;
8110 }
8111 end++;
8112 }
8113 if (start != end) {
8114 xmlOutputBufferWriteString(buf, "<![CDATA[");
8115 xmlOutputBufferWriteString(buf, (const char *)start);
8116 xmlOutputBufferWriteString(buf, "]]>");
8117 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00008118 return;
8119 }
8120
8121 if (format == 1) {
8122 tmp = cur->children;
8123 while (tmp != NULL) {
8124 if ((tmp->type == XML_TEXT_NODE) ||
8125 (tmp->type == XML_ENTITY_REF_NODE)) {
8126 format = 0;
8127 break;
8128 }
8129 tmp = tmp->next;
8130 }
8131 }
8132 xmlOutputBufferWriteString(buf, "<");
8133 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
8134 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
8135 xmlOutputBufferWriteString(buf, ":");
8136 }
8137
8138 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8139 if (cur->nsDef)
8140 xmlNsListDumpOutput(buf, cur->nsDef);
8141 if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
8142 (cur->ns == NULL) && (cur->nsDef == NULL))) {
8143 /*
8144 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
8145 */
8146 xmlOutputBufferWriteString(buf,
8147 " xmlns=\"http://www.w3.org/1999/xhtml\"");
8148 }
8149 if (cur->properties != NULL)
8150 xhtmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
8151
8152 if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) {
8153 if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
8154 (xhtmlIsEmpty(cur) == 1)) {
8155 /*
8156 * C.2. Empty Elements
8157 */
8158 xmlOutputBufferWriteString(buf, " />");
8159 } else {
8160 /*
8161 * C.3. Element Minimization and Empty Element Content
8162 */
8163 xmlOutputBufferWriteString(buf, "></");
8164 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
8165 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
8166 xmlOutputBufferWriteString(buf, ":");
8167 }
8168 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8169 xmlOutputBufferWriteString(buf, ">");
8170 }
8171 return;
8172 }
8173 xmlOutputBufferWriteString(buf, ">");
8174 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
8175 xmlChar *buffer;
8176
8177 if (encoding == NULL)
8178 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
8179 else
8180 buffer = xmlEncodeSpecialChars(doc, cur->content);
8181 if (buffer != NULL) {
8182 xmlOutputBufferWriteString(buf, (const char *)buffer);
8183 xmlFree(buffer);
8184 }
8185 }
8186
8187 /*
8188 * 4.8. Script and Style elements
8189 */
8190 if ((cur->type == XML_ELEMENT_NODE) &&
8191 ((xmlStrEqual(cur->name, BAD_CAST "script")) ||
8192 (xmlStrEqual(cur->name, BAD_CAST "style"))) &&
8193 ((cur->ns == NULL) ||
8194 (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) {
8195 xmlNodePtr child = cur->children;
8196
8197 while (child != NULL) {
8198 if ((child->type == XML_TEXT_NODE) ||
8199 (child->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard64b35282002-12-04 15:10:40 +00008200 /*
8201 * Apparently CDATA escaping for style just break on IE,
8202 * mozilla and galeon, so ...
8203 */
8204 if (xmlStrEqual(cur->name, BAD_CAST "style") &&
8205 (xmlStrchr(child->content, '<') == NULL) &&
8206 (xmlStrchr(child->content, '>') == NULL) &&
8207 (xmlStrchr(child->content, '&') == NULL)) {
8208 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
8209 } else {
Daniel Veillard9475a352003-09-26 12:47:50 +00008210 start = end = child->content;
8211 while (*end != '\0') {
8212 if (*end == ']' &&
8213 *(end + 1) == ']' &&
8214 *(end + 2) == '>') {
8215 end = end + 2;
8216 xmlOutputBufferWriteString(buf, "<![CDATA[");
8217 xmlOutputBufferWrite(buf, end - start,
8218 (const char *)start);
8219 xmlOutputBufferWriteString(buf, "]]>");
8220 start = end;
8221 }
8222 end++;
8223 }
8224 if (start != end) {
8225 xmlOutputBufferWriteString(buf, "<![CDATA[");
8226 xmlOutputBufferWriteString(buf, (const char *)start);
8227 xmlOutputBufferWriteString(buf, "]]>");
8228 }
Daniel Veillard64b35282002-12-04 15:10:40 +00008229 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00008230 } else {
8231 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
8232 }
8233 child = child->next;
8234 }
8235 } else if (cur->children != NULL) {
8236 if (format) xmlOutputBufferWriteString(buf, "\n");
8237 xhtmlNodeListDumpOutput(buf, doc, cur->children,
8238 (level >= 0?level+1:-1), format, encoding);
8239 if ((xmlIndentTreeOutput) && (format))
8240 for (i = 0;i < level;i++)
8241 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
8242 }
8243 xmlOutputBufferWriteString(buf, "</");
8244 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
8245 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
8246 xmlOutputBufferWriteString(buf, ":");
8247 }
8248
8249 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8250 xmlOutputBufferWriteString(buf, ">");
8251}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00008252#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00008253#endif
8254
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00008255#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00008256/************************************************************************
8257 * *
8258 * Saving functions front-ends *
8259 * *
8260 ************************************************************************/
8261
8262/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00008263 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00008264 * @out_doc: Document to generate XML text from
8265 * @doc_txt_ptr: Memory pointer for allocated XML text
8266 * @doc_txt_len: Length of the generated XML text
8267 * @txt_encoding: Character encoding to use when generating XML text
8268 * @format: should formatting spaces been added
8269 *
8270 * Dump the current DOM tree into memory using the character encoding specified
8271 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008272 * allocated memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00008273 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00008274 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008275 */
8276
8277void
8278xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008279 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008280 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00008281 int dummy = 0;
8282
Owen Taylor3473f882001-02-23 17:55:21 +00008283 xmlOutputBufferPtr out_buff = NULL;
8284 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
8285
8286 if (doc_txt_len == NULL) {
8287 doc_txt_len = &dummy; /* Continue, caller just won't get length */
8288 }
8289
8290 if (doc_txt_ptr == NULL) {
8291 *doc_txt_len = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008292 return;
8293 }
8294
8295 *doc_txt_ptr = NULL;
8296 *doc_txt_len = 0;
8297
8298 if (out_doc == NULL) {
8299 /* No document, no output */
Owen Taylor3473f882001-02-23 17:55:21 +00008300 return;
8301 }
8302
8303 /*
8304 * Validate the encoding value, if provided.
8305 * This logic is copied from xmlSaveFileEnc.
8306 */
8307
8308 if (txt_encoding == NULL)
8309 txt_encoding = (const char *) out_doc->encoding;
8310 if (txt_encoding != NULL) {
Daniel Veillarde1326112003-06-05 09:32:20 +00008311 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00008312 if ( conv_hdlr == NULL ) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00008313 xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, (xmlNodePtr) out_doc,
8314 txt_encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00008315 return;
8316 }
8317 }
Owen Taylor3473f882001-02-23 17:55:21 +00008318
8319 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00008320 xmlSaveErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00008321 return;
8322 }
8323
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008324 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008325 xmlOutputBufferFlush(out_buff);
8326 if (out_buff->conv != NULL) {
8327 *doc_txt_len = out_buff->conv->use;
8328 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
8329 } else {
8330 *doc_txt_len = out_buff->buffer->use;
8331 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
8332 }
8333 (void)xmlOutputBufferClose(out_buff);
8334
8335 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
8336 *doc_txt_len = 0;
Daniel Veillard18ec16e2003-10-07 23:16:40 +00008337 xmlSaveErrMemory("creating output");
Owen Taylor3473f882001-02-23 17:55:21 +00008338 }
8339
8340 return;
8341}
8342
8343/**
8344 * xmlDocDumpMemory:
8345 * @cur: the document
8346 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00008347 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00008348 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008349 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008350 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00008351 */
8352void
8353xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
8354 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
8355}
8356
8357/**
8358 * xmlDocDumpFormatMemory:
8359 * @cur: the document
8360 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00008361 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00008362 * @format: should formatting spaces been added
8363 *
8364 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008365 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008366 * It's up to the caller to free the memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00008367 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00008368 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008369 */
8370void
8371xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
8372 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
8373}
8374
8375/**
8376 * xmlDocDumpMemoryEnc:
8377 * @out_doc: Document to generate XML text from
8378 * @doc_txt_ptr: Memory pointer for allocated XML text
8379 * @doc_txt_len: Length of the generated XML text
8380 * @txt_encoding: Character encoding to use when generating XML text
8381 *
8382 * Dump the current DOM tree into memory using the character encoding specified
8383 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008384 * allocated memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00008385 */
8386
8387void
8388xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
8389 int * doc_txt_len, const char * txt_encoding) {
8390 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008391 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008392}
8393
8394/**
Daniel Veillard9e412302002-06-10 15:59:44 +00008395 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00008396 * @f: the FILE*
8397 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00008398 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00008399 *
8400 * Dump an XML document to an open FILE.
8401 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008402 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008403 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8404 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008405 */
8406int
Daniel Veillard9e412302002-06-10 15:59:44 +00008407xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00008408 xmlOutputBufferPtr buf;
8409 const char * encoding;
8410 xmlCharEncodingHandlerPtr handler = NULL;
8411 int ret;
8412
8413 if (cur == NULL) {
8414#ifdef DEBUG_TREE
8415 xmlGenericError(xmlGenericErrorContext,
8416 "xmlDocDump : document == NULL\n");
8417#endif
8418 return(-1);
8419 }
8420 encoding = (const char *) cur->encoding;
8421
8422 if (encoding != NULL) {
Daniel Veillarde1326112003-06-05 09:32:20 +00008423 handler = xmlFindCharEncodingHandler(encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00008424 if (handler == NULL) {
8425 xmlFree((char *) cur->encoding);
8426 cur->encoding = NULL;
8427 }
8428 }
Owen Taylor3473f882001-02-23 17:55:21 +00008429 buf = xmlOutputBufferCreateFile(f, handler);
8430 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00008431 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008432
8433 ret = xmlOutputBufferClose(buf);
8434 return(ret);
8435}
8436
8437/**
Daniel Veillard9e412302002-06-10 15:59:44 +00008438 * xmlDocDump:
8439 * @f: the FILE*
8440 * @cur: the document
8441 *
8442 * Dump an XML document to an open FILE.
8443 *
8444 * returns: the number of bytes written or -1 in case of failure.
8445 */
8446int
8447xmlDocDump(FILE *f, xmlDocPtr cur) {
Daniel Veillard828ce832003-10-08 19:19:10 +00008448 return(xmlDocFormatDump (f, cur, 0));
Daniel Veillard9e412302002-06-10 15:59:44 +00008449}
8450
8451/**
Owen Taylor3473f882001-02-23 17:55:21 +00008452 * xmlSaveFileTo:
8453 * @buf: an output I/O buffer
8454 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00008455 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00008456 *
8457 * Dump an XML document to an I/O buffer.
8458 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008459 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008460 */
8461int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00008462xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00008463 int ret;
8464
8465 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008466 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008467 ret = xmlOutputBufferClose(buf);
8468 return(ret);
8469}
8470
8471/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00008472 * xmlSaveFormatFileTo:
8473 * @buf: an output I/O buffer
8474 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00008475 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00008476 * @format: should formatting spaces been added
8477 *
8478 * Dump an XML document to an I/O buffer.
8479 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008480 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008481 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8482 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardeefd4492001-04-28 16:55:50 +00008483 */
8484int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00008485xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00008486 int ret;
8487
8488 if (buf == NULL) return(0);
8489 xmlDocContentDumpOutput(buf, cur, encoding, format);
8490 ret = xmlOutputBufferClose(buf);
8491 return(ret);
8492}
8493
8494/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00008495 * xmlSaveFormatFileEnc:
Daniel Veillardf012a642001-07-23 19:10:52 +00008496 * @filename: the filename or URL to output
8497 * @cur: the document being saved
8498 * @encoding: the name of the encoding to use or NULL.
8499 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00008500 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00008501 * Dump an XML document to a file or an URL.
8502 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008503 * Returns the number of bytes written or -1 in case of error.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008504 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8505 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008506 */
8507int
Daniel Veillardf012a642001-07-23 19:10:52 +00008508xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
8509 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00008510 xmlOutputBufferPtr buf;
8511 xmlCharEncodingHandlerPtr handler = NULL;
8512 int ret;
8513
Daniel Veillard4dbe77a2003-01-14 00:17:42 +00008514 if (cur == NULL)
8515 return(-1);
8516
Daniel Veillardfb25a512002-01-13 20:32:08 +00008517 if (encoding == NULL)
8518 encoding = (const char *) cur->encoding;
8519
Owen Taylor3473f882001-02-23 17:55:21 +00008520 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00008521
Owen Taylor3473f882001-02-23 17:55:21 +00008522 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00008523 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00008524 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00008525 }
8526
Daniel Veillardf012a642001-07-23 19:10:52 +00008527#ifdef HAVE_ZLIB_H
8528 if (cur->compression < 0) cur->compression = xmlCompressMode;
8529#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008530 /*
8531 * save the content to a temp buffer.
8532 */
Daniel Veillardf012a642001-07-23 19:10:52 +00008533 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00008534 if (buf == NULL) return(-1);
8535
Daniel Veillardf012a642001-07-23 19:10:52 +00008536 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008537
8538 ret = xmlOutputBufferClose(buf);
8539 return(ret);
8540}
8541
Daniel Veillardf012a642001-07-23 19:10:52 +00008542
8543/**
8544 * xmlSaveFileEnc:
8545 * @filename: the filename (or URL)
8546 * @cur: the document
8547 * @encoding: the name of an encoding (or NULL)
8548 *
8549 * Dump an XML document, converting it to the given encoding
8550 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008551 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00008552 */
8553int
8554xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
8555 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
8556}
8557
Owen Taylor3473f882001-02-23 17:55:21 +00008558/**
Daniel Veillard67fee942001-04-26 18:59:03 +00008559 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00008560 * @filename: the filename (or URL)
8561 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00008562 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00008563 *
8564 * Dump an XML document to a file. Will use compression if
8565 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00008566 * used. If @format is set then the document will be indented on output.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008567 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8568 * or xmlKeepBlanksDefault(0) was called
Daniel Veillard67fee942001-04-26 18:59:03 +00008569 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008570 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008571 */
8572int
Daniel Veillard67fee942001-04-26 18:59:03 +00008573xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008574 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00008575}
8576
Daniel Veillard67fee942001-04-26 18:59:03 +00008577/**
8578 * xmlSaveFile:
8579 * @filename: the filename (or URL)
8580 * @cur: the document
8581 *
8582 * Dump an XML document to a file. Will use compression if
8583 * compiled in and enabled. If @filename is "-" the stdout file is
8584 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00008585 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00008586 */
8587int
8588xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008589 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00008590}
8591
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00008592#endif /* LIBXML_OUTPUT_ENABLED */
8593
8594/**
8595 * xmlGetDocCompressMode:
8596 * @doc: the document
8597 *
8598 * get the compression ratio for a document, ZLIB based
8599 * Returns 0 (uncompressed) to 9 (max compression)
8600 */
8601int
8602xmlGetDocCompressMode (xmlDocPtr doc) {
8603 if (doc == NULL) return(-1);
8604 return(doc->compression);
8605}
8606
8607/**
8608 * xmlSetDocCompressMode:
8609 * @doc: the document
8610 * @mode: the compression ratio
8611 *
8612 * set the compression ratio for a document, ZLIB based
8613 * Correct values: 0 (uncompressed) to 9 (max compression)
8614 */
8615void
8616xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
8617 if (doc == NULL) return;
8618 if (mode < 0) doc->compression = 0;
8619 else if (mode > 9) doc->compression = 9;
8620 else doc->compression = mode;
8621}
8622
8623/**
8624 * xmlGetCompressMode:
8625 *
8626 * get the default compression mode used, ZLIB based.
8627 * Returns 0 (uncompressed) to 9 (max compression)
8628 */
8629int
8630xmlGetCompressMode(void)
8631{
8632 return (xmlCompressMode);
8633}
8634
8635/**
8636 * xmlSetCompressMode:
8637 * @mode: the compression ratio
8638 *
8639 * set the default compression mode used, ZLIB based
8640 * Correct values: 0 (uncompressed) to 9 (max compression)
8641 */
8642void
8643xmlSetCompressMode(int mode) {
8644 if (mode < 0) xmlCompressMode = 0;
8645 else if (mode > 9) xmlCompressMode = 9;
8646 else xmlCompressMode = mode;
8647}
8648