blob: b804a98b32ec2918d993dd9dc284f26242eadfb6 [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.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002352 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2353 * created element inherits the namespace of @parent. If @content is non NULL,
William M. Brackd7cf7f82003-11-14 07:13:16 +00002354 * a child TEXT node will be created containing the string @content.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002355 * NOTE: Use xmlNewChild() if @content will contain entities that need to be
2356 * preserved. Use this function, xmlNewTextChild(), if you need to ensure that
2357 * reserved XML chars that might appear in @content, such as the ampersand,
2358 * greater-than or less-than signs, are automatically replaced by their XML
2359 * escaped entity representations.
Owen Taylor3473f882001-02-23 17:55:21 +00002360 *
2361 * Returns a pointer to the new node object.
2362 */
2363xmlNodePtr
2364xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2365 const xmlChar *name, const xmlChar *content) {
2366 xmlNodePtr cur, prev;
2367
2368 if (parent == NULL) {
2369#ifdef DEBUG_TREE
2370 xmlGenericError(xmlGenericErrorContext,
2371 "xmlNewTextChild : parent == NULL\n");
2372#endif
2373 return(NULL);
2374 }
2375
2376 if (name == NULL) {
2377#ifdef DEBUG_TREE
2378 xmlGenericError(xmlGenericErrorContext,
2379 "xmlNewTextChild : name == NULL\n");
2380#endif
2381 return(NULL);
2382 }
2383
2384 /*
2385 * Allocate a new node
2386 */
Daniel Veillard254b1262003-11-01 17:04:58 +00002387 if (parent->type == XML_ELEMENT_NODE) {
2388 if (ns == NULL)
2389 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2390 else
2391 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2392 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2393 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2394 if (ns == NULL)
2395 cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2396 else
2397 cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2398 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2399 cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2400 } else {
2401 return(NULL);
2402 }
Owen Taylor3473f882001-02-23 17:55:21 +00002403 if (cur == NULL) return(NULL);
2404
2405 /*
2406 * add the new element at the end of the children list.
2407 */
2408 cur->type = XML_ELEMENT_NODE;
2409 cur->parent = parent;
2410 cur->doc = parent->doc;
2411 if (parent->children == NULL) {
2412 parent->children = cur;
2413 parent->last = cur;
2414 } else {
2415 prev = parent->last;
2416 prev->next = cur;
2417 cur->prev = prev;
2418 parent->last = cur;
2419 }
2420
2421 return(cur);
2422}
Daniel Veillard652327a2003-09-29 18:02:38 +00002423#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002424
2425/**
2426 * xmlNewCharRef:
2427 * @doc: the document
2428 * @name: the char ref string, starting with # or "&# ... ;"
2429 *
2430 * Creation of a new character reference node.
2431 * Returns a pointer to the new node object.
2432 */
2433xmlNodePtr
2434xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2435 xmlNodePtr cur;
2436
2437 /*
2438 * Allocate a new node and fill the fields.
2439 */
2440 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2441 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002442 xmlTreeErrMemory("building character reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002443 return(NULL);
2444 }
2445 memset(cur, 0, sizeof(xmlNode));
2446 cur->type = XML_ENTITY_REF_NODE;
2447
2448 cur->doc = doc;
2449 if (name[0] == '&') {
2450 int len;
2451 name++;
2452 len = xmlStrlen(name);
2453 if (name[len - 1] == ';')
2454 cur->name = xmlStrndup(name, len - 1);
2455 else
2456 cur->name = xmlStrndup(name, len);
2457 } else
2458 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002459
Daniel Veillarda880b122003-04-21 21:36:41 +00002460 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002461 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002462 return(cur);
2463}
2464
2465/**
2466 * xmlNewReference:
2467 * @doc: the document
2468 * @name: the reference name, or the reference string with & and ;
2469 *
2470 * Creation of a new reference node.
2471 * Returns a pointer to the new node object.
2472 */
2473xmlNodePtr
2474xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2475 xmlNodePtr cur;
2476 xmlEntityPtr ent;
2477
2478 /*
2479 * Allocate a new node and fill the fields.
2480 */
2481 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2482 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002483 xmlTreeErrMemory("building reference");
Owen Taylor3473f882001-02-23 17:55:21 +00002484 return(NULL);
2485 }
2486 memset(cur, 0, sizeof(xmlNode));
2487 cur->type = XML_ENTITY_REF_NODE;
2488
2489 cur->doc = doc;
2490 if (name[0] == '&') {
2491 int len;
2492 name++;
2493 len = xmlStrlen(name);
2494 if (name[len - 1] == ';')
2495 cur->name = xmlStrndup(name, len - 1);
2496 else
2497 cur->name = xmlStrndup(name, len);
2498 } else
2499 cur->name = xmlStrdup(name);
2500
2501 ent = xmlGetDocEntity(doc, cur->name);
2502 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002503 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002504 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002505 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002506 * updated. Not sure if this is 100% correct.
2507 * -George
2508 */
2509 cur->children = (xmlNodePtr) ent;
2510 cur->last = (xmlNodePtr) ent;
2511 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002512
Daniel Veillarda880b122003-04-21 21:36:41 +00002513 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002514 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002515 return(cur);
2516}
2517
2518/**
2519 * xmlNewDocText:
2520 * @doc: the document
2521 * @content: the text content
2522 *
2523 * Creation of a new text node within a document.
2524 * Returns a pointer to the new node object.
2525 */
2526xmlNodePtr
2527xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2528 xmlNodePtr cur;
2529
2530 cur = xmlNewText(content);
2531 if (cur != NULL) cur->doc = doc;
2532 return(cur);
2533}
2534
2535/**
2536 * xmlNewTextLen:
2537 * @content: the text content
2538 * @len: the text len.
2539 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002540 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002541 * Returns a pointer to the new node object.
2542 */
2543xmlNodePtr
2544xmlNewTextLen(const xmlChar *content, int len) {
2545 xmlNodePtr cur;
2546
2547 /*
2548 * Allocate a new node and fill the fields.
2549 */
2550 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2551 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002552 xmlTreeErrMemory("building text");
Owen Taylor3473f882001-02-23 17:55:21 +00002553 return(NULL);
2554 }
2555 memset(cur, 0, sizeof(xmlNode));
2556 cur->type = XML_TEXT_NODE;
2557
2558 cur->name = xmlStringText;
2559 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002560 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002561 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002562
Daniel Veillarda880b122003-04-21 21:36:41 +00002563 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002564 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002565 return(cur);
2566}
2567
2568/**
2569 * xmlNewDocTextLen:
2570 * @doc: the document
2571 * @content: the text content
2572 * @len: the text len.
2573 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002574 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002575 * text node pertain to a given document.
2576 * Returns a pointer to the new node object.
2577 */
2578xmlNodePtr
2579xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2580 xmlNodePtr cur;
2581
2582 cur = xmlNewTextLen(content, len);
2583 if (cur != NULL) cur->doc = doc;
2584 return(cur);
2585}
2586
2587/**
2588 * xmlNewComment:
2589 * @content: the comment content
2590 *
2591 * Creation of a new node containing a comment.
2592 * Returns a pointer to the new node object.
2593 */
2594xmlNodePtr
2595xmlNewComment(const xmlChar *content) {
2596 xmlNodePtr cur;
2597
2598 /*
2599 * Allocate a new node and fill the fields.
2600 */
2601 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2602 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002603 xmlTreeErrMemory("building comment");
Owen Taylor3473f882001-02-23 17:55:21 +00002604 return(NULL);
2605 }
2606 memset(cur, 0, sizeof(xmlNode));
2607 cur->type = XML_COMMENT_NODE;
2608
2609 cur->name = xmlStringComment;
2610 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002611 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002612 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002613
Daniel Veillarda880b122003-04-21 21:36:41 +00002614 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002615 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002616 return(cur);
2617}
2618
2619/**
2620 * xmlNewCDataBlock:
2621 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002622 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002623 * @len: the length of the block
2624 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002625 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002626 * Returns a pointer to the new node object.
2627 */
2628xmlNodePtr
2629xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2630 xmlNodePtr cur;
2631
2632 /*
2633 * Allocate a new node and fill the fields.
2634 */
2635 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2636 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00002637 xmlTreeErrMemory("building CDATA");
Owen Taylor3473f882001-02-23 17:55:21 +00002638 return(NULL);
2639 }
2640 memset(cur, 0, sizeof(xmlNode));
2641 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002642 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002643
2644 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002645 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002646 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002647
Daniel Veillarda880b122003-04-21 21:36:41 +00002648 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002649 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002650 return(cur);
2651}
2652
2653/**
2654 * xmlNewDocComment:
2655 * @doc: the document
2656 * @content: the comment content
2657 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002658 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002659 * Returns a pointer to the new node object.
2660 */
2661xmlNodePtr
2662xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2663 xmlNodePtr cur;
2664
2665 cur = xmlNewComment(content);
2666 if (cur != NULL) cur->doc = doc;
2667 return(cur);
2668}
2669
2670/**
2671 * xmlSetTreeDoc:
2672 * @tree: the top element
2673 * @doc: the document
2674 *
2675 * update all nodes under the tree to point to the right document
2676 */
2677void
2678xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002679 xmlAttrPtr prop;
2680
Owen Taylor3473f882001-02-23 17:55:21 +00002681 if (tree == NULL)
2682 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002683 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002684 if(tree->type == XML_ELEMENT_NODE) {
2685 prop = tree->properties;
2686 while (prop != NULL) {
2687 prop->doc = doc;
2688 xmlSetListDoc(prop->children, doc);
2689 prop = prop->next;
2690 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002691 }
Owen Taylor3473f882001-02-23 17:55:21 +00002692 if (tree->children != NULL)
2693 xmlSetListDoc(tree->children, doc);
2694 tree->doc = doc;
2695 }
2696}
2697
2698/**
2699 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002700 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002701 * @doc: the document
2702 *
2703 * update all nodes in the list to point to the right document
2704 */
2705void
2706xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2707 xmlNodePtr cur;
2708
2709 if (list == NULL)
2710 return;
2711 cur = list;
2712 while (cur != NULL) {
2713 if (cur->doc != doc)
2714 xmlSetTreeDoc(cur, doc);
2715 cur = cur->next;
2716 }
2717}
2718
Daniel Veillard652327a2003-09-29 18:02:38 +00002719#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002720/**
2721 * xmlNewChild:
2722 * @parent: the parent node
2723 * @ns: a namespace if any
2724 * @name: the name of the child
2725 * @content: the XML content of the child if any.
2726 *
2727 * Creation of a new child element, added at the end of @parent children list.
MST 2003 John Flecke1f70492003-12-20 23:43:28 +00002728 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2729 * created element inherits the namespace of @parent. If @content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002730 * a child list containing the TEXTs and ENTITY_REFs node will be created.
MST 2003 John Fleck8b03bc52003-12-17 03:45:01 +00002731 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
2732 * references. XML special chars must be escaped first by using
2733 * xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used.
Owen Taylor3473f882001-02-23 17:55:21 +00002734 *
2735 * Returns a pointer to the new node object.
2736 */
2737xmlNodePtr
2738xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2739 const xmlChar *name, const xmlChar *content) {
2740 xmlNodePtr cur, prev;
2741
2742 if (parent == NULL) {
2743#ifdef DEBUG_TREE
2744 xmlGenericError(xmlGenericErrorContext,
2745 "xmlNewChild : parent == NULL\n");
2746#endif
2747 return(NULL);
2748 }
2749
2750 if (name == NULL) {
2751#ifdef DEBUG_TREE
2752 xmlGenericError(xmlGenericErrorContext,
2753 "xmlNewChild : name == NULL\n");
2754#endif
2755 return(NULL);
2756 }
2757
2758 /*
2759 * Allocate a new node
2760 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002761 if (parent->type == XML_ELEMENT_NODE) {
2762 if (ns == NULL)
2763 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2764 else
2765 cur = xmlNewDocNode(parent->doc, ns, name, content);
2766 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2767 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2768 if (ns == NULL)
2769 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2770 else
2771 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002772 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2773 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002774 } else {
2775 return(NULL);
2776 }
Owen Taylor3473f882001-02-23 17:55:21 +00002777 if (cur == NULL) return(NULL);
2778
2779 /*
2780 * add the new element at the end of the children list.
2781 */
2782 cur->type = XML_ELEMENT_NODE;
2783 cur->parent = parent;
2784 cur->doc = parent->doc;
2785 if (parent->children == NULL) {
2786 parent->children = cur;
2787 parent->last = cur;
2788 } else {
2789 prev = parent->last;
2790 prev->next = cur;
2791 cur->prev = prev;
2792 parent->last = cur;
2793 }
2794
2795 return(cur);
2796}
Daniel Veillard652327a2003-09-29 18:02:38 +00002797#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002798
2799/**
2800 * xmlAddNextSibling:
2801 * @cur: the child node
2802 * @elem: the new node
2803 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002804 * Add a new node @elem as the next sibling of @cur
2805 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002806 * first unlinked from its existing context.
2807 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002808 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2809 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002810 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002811 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002812 */
2813xmlNodePtr
2814xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2815 if (cur == NULL) {
2816#ifdef DEBUG_TREE
2817 xmlGenericError(xmlGenericErrorContext,
2818 "xmlAddNextSibling : cur == NULL\n");
2819#endif
2820 return(NULL);
2821 }
2822 if (elem == NULL) {
2823#ifdef DEBUG_TREE
2824 xmlGenericError(xmlGenericErrorContext,
2825 "xmlAddNextSibling : elem == NULL\n");
2826#endif
2827 return(NULL);
2828 }
2829
2830 xmlUnlinkNode(elem);
2831
2832 if (elem->type == XML_TEXT_NODE) {
2833 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002834 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002835 xmlFreeNode(elem);
2836 return(cur);
2837 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002838 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2839 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002840 xmlChar *tmp;
2841
2842 tmp = xmlStrdup(elem->content);
2843 tmp = xmlStrcat(tmp, cur->next->content);
2844 xmlNodeSetContent(cur->next, tmp);
2845 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002846 xmlFreeNode(elem);
2847 return(cur->next);
2848 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002849 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2850 /* check if an attribute with the same name exists */
2851 xmlAttrPtr attr;
2852
2853 if (elem->ns == NULL)
2854 attr = xmlHasProp(cur->parent, elem->name);
2855 else
2856 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2857 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2858 /* different instance, destroy it (attributes must be unique) */
2859 xmlFreeProp(attr);
2860 }
Owen Taylor3473f882001-02-23 17:55:21 +00002861 }
2862
2863 if (elem->doc != cur->doc) {
2864 xmlSetTreeDoc(elem, cur->doc);
2865 }
2866 elem->parent = cur->parent;
2867 elem->prev = cur;
2868 elem->next = cur->next;
2869 cur->next = elem;
2870 if (elem->next != NULL)
2871 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002872 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002873 elem->parent->last = elem;
2874 return(elem);
2875}
2876
Daniel Veillard652327a2003-09-29 18:02:38 +00002877#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002878/**
2879 * xmlAddPrevSibling:
2880 * @cur: the child node
2881 * @elem: the new node
2882 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002883 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002884 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002885 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002886 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002887 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2888 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002889 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002890 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002891 */
2892xmlNodePtr
2893xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2894 if (cur == NULL) {
2895#ifdef DEBUG_TREE
2896 xmlGenericError(xmlGenericErrorContext,
2897 "xmlAddPrevSibling : cur == NULL\n");
2898#endif
2899 return(NULL);
2900 }
2901 if (elem == NULL) {
2902#ifdef DEBUG_TREE
2903 xmlGenericError(xmlGenericErrorContext,
2904 "xmlAddPrevSibling : elem == NULL\n");
2905#endif
2906 return(NULL);
2907 }
2908
2909 xmlUnlinkNode(elem);
2910
2911 if (elem->type == XML_TEXT_NODE) {
2912 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002913 xmlChar *tmp;
2914
2915 tmp = xmlStrdup(elem->content);
2916 tmp = xmlStrcat(tmp, cur->content);
2917 xmlNodeSetContent(cur, tmp);
2918 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002919 xmlFreeNode(elem);
2920 return(cur);
2921 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002922 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2923 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002924 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002925 xmlFreeNode(elem);
2926 return(cur->prev);
2927 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002928 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2929 /* check if an attribute with the same name exists */
2930 xmlAttrPtr attr;
2931
2932 if (elem->ns == NULL)
2933 attr = xmlHasProp(cur->parent, elem->name);
2934 else
2935 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2936 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2937 /* different instance, destroy it (attributes must be unique) */
2938 xmlFreeProp(attr);
2939 }
Owen Taylor3473f882001-02-23 17:55:21 +00002940 }
2941
2942 if (elem->doc != cur->doc) {
2943 xmlSetTreeDoc(elem, cur->doc);
2944 }
2945 elem->parent = cur->parent;
2946 elem->next = cur;
2947 elem->prev = cur->prev;
2948 cur->prev = elem;
2949 if (elem->prev != NULL)
2950 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002951 if (elem->parent != NULL) {
2952 if (elem->type == XML_ATTRIBUTE_NODE) {
2953 if (elem->parent->properties == (xmlAttrPtr) cur) {
2954 elem->parent->properties = (xmlAttrPtr) elem;
2955 }
2956 } else {
2957 if (elem->parent->children == cur) {
2958 elem->parent->children = elem;
2959 }
2960 }
2961 }
Owen Taylor3473f882001-02-23 17:55:21 +00002962 return(elem);
2963}
Daniel Veillard652327a2003-09-29 18:02:38 +00002964#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002965
2966/**
2967 * xmlAddSibling:
2968 * @cur: the child node
2969 * @elem: the new node
2970 *
2971 * Add a new element @elem to the list of siblings of @cur
2972 * merging adjacent TEXT nodes (@elem may be freed)
2973 * If the new element was already inserted in a document it is
2974 * first unlinked from its existing context.
2975 *
2976 * Returns the new element or NULL in case of error.
2977 */
2978xmlNodePtr
2979xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2980 xmlNodePtr parent;
2981
2982 if (cur == NULL) {
2983#ifdef DEBUG_TREE
2984 xmlGenericError(xmlGenericErrorContext,
2985 "xmlAddSibling : cur == NULL\n");
2986#endif
2987 return(NULL);
2988 }
2989
2990 if (elem == NULL) {
2991#ifdef DEBUG_TREE
2992 xmlGenericError(xmlGenericErrorContext,
2993 "xmlAddSibling : elem == NULL\n");
2994#endif
2995 return(NULL);
2996 }
2997
2998 /*
2999 * Constant time is we can rely on the ->parent->last to find
3000 * the last sibling.
3001 */
3002 if ((cur->parent != NULL) &&
3003 (cur->parent->children != NULL) &&
3004 (cur->parent->last != NULL) &&
3005 (cur->parent->last->next == NULL)) {
3006 cur = cur->parent->last;
3007 } else {
3008 while (cur->next != NULL) cur = cur->next;
3009 }
3010
3011 xmlUnlinkNode(elem);
3012
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003013 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3014 (cur->name == elem->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003015 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003016 xmlFreeNode(elem);
3017 return(cur);
3018 }
3019
3020 if (elem->doc != cur->doc) {
3021 xmlSetTreeDoc(elem, cur->doc);
3022 }
3023 parent = cur->parent;
3024 elem->prev = cur;
3025 elem->next = NULL;
3026 elem->parent = parent;
3027 cur->next = elem;
3028 if (parent != NULL)
3029 parent->last = elem;
3030
3031 return(elem);
3032}
3033
3034/**
3035 * xmlAddChildList:
3036 * @parent: the parent node
3037 * @cur: the first node in the list
3038 *
3039 * Add a list of node at the end of the child list of the parent
3040 * merging adjacent TEXT nodes (@cur may be freed)
3041 *
3042 * Returns the last child or NULL in case of error.
3043 */
3044xmlNodePtr
3045xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3046 xmlNodePtr prev;
3047
3048 if (parent == NULL) {
3049#ifdef DEBUG_TREE
3050 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003051 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003052#endif
3053 return(NULL);
3054 }
3055
3056 if (cur == NULL) {
3057#ifdef DEBUG_TREE
3058 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003059 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003060#endif
3061 return(NULL);
3062 }
3063
3064 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3065 (cur->doc != parent->doc)) {
3066#ifdef DEBUG_TREE
3067 xmlGenericError(xmlGenericErrorContext,
3068 "Elements moved to a different document\n");
3069#endif
3070 }
3071
3072 /*
3073 * add the first element at the end of the children list.
3074 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003075
Owen Taylor3473f882001-02-23 17:55:21 +00003076 if (parent->children == NULL) {
3077 parent->children = cur;
3078 } else {
3079 /*
3080 * If cur and parent->last both are TEXT nodes, then merge them.
3081 */
3082 if ((cur->type == XML_TEXT_NODE) &&
3083 (parent->last->type == XML_TEXT_NODE) &&
3084 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003085 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003086 /*
3087 * if it's the only child, nothing more to be done.
3088 */
3089 if (cur->next == NULL) {
3090 xmlFreeNode(cur);
3091 return(parent->last);
3092 }
3093 prev = cur;
3094 cur = cur->next;
3095 xmlFreeNode(prev);
3096 }
3097 prev = parent->last;
3098 prev->next = cur;
3099 cur->prev = prev;
3100 }
3101 while (cur->next != NULL) {
3102 cur->parent = parent;
3103 if (cur->doc != parent->doc) {
3104 xmlSetTreeDoc(cur, parent->doc);
3105 }
3106 cur = cur->next;
3107 }
3108 cur->parent = parent;
3109 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
3110 parent->last = cur;
3111
3112 return(cur);
3113}
3114
3115/**
3116 * xmlAddChild:
3117 * @parent: the parent node
3118 * @cur: the child node
3119 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003120 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003121 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003122 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3123 * If there is an attribute with equal name, it is first destroyed.
3124 *
Owen Taylor3473f882001-02-23 17:55:21 +00003125 * Returns the child or NULL in case of error.
3126 */
3127xmlNodePtr
3128xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3129 xmlNodePtr prev;
3130
3131 if (parent == NULL) {
3132#ifdef DEBUG_TREE
3133 xmlGenericError(xmlGenericErrorContext,
3134 "xmlAddChild : parent == NULL\n");
3135#endif
3136 return(NULL);
3137 }
3138
3139 if (cur == NULL) {
3140#ifdef DEBUG_TREE
3141 xmlGenericError(xmlGenericErrorContext,
3142 "xmlAddChild : child == NULL\n");
3143#endif
3144 return(NULL);
3145 }
3146
Owen Taylor3473f882001-02-23 17:55:21 +00003147 /*
3148 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003149 * cur is then freed.
3150 */
3151 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003152 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003153 (parent->content != NULL) &&
Daniel Veillarde22dd5c2003-10-29 12:53:27 +00003154 (parent->name == cur->name) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003155 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003156 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003157 xmlFreeNode(cur);
3158 return(parent);
3159 }
3160 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003161 (parent->last->name == cur->name) &&
3162 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003163 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003164 xmlFreeNode(cur);
3165 return(parent->last);
3166 }
3167 }
3168
3169 /*
3170 * add the new element at the end of the children list.
3171 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003172 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003173 cur->parent = parent;
3174 if (cur->doc != parent->doc) {
3175 xmlSetTreeDoc(cur, parent->doc);
3176 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003177 /* this check prevents a loop on tree-traversions if a developer
3178 * tries to add a node to its parent multiple times
3179 */
3180 if (prev == parent)
3181 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003182
3183 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003184 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003185 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003186 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003187 (parent->content != NULL) &&
3188 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003189 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003190 xmlFreeNode(cur);
3191 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003192 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003193 if (cur->type == XML_ATTRIBUTE_NODE) {
3194 if (parent->properties == NULL) {
3195 parent->properties = (xmlAttrPtr) cur;
3196 } else {
3197 /* check if an attribute with the same name exists */
3198 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003199
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003200 if (cur->ns == NULL)
3201 lastattr = xmlHasProp(parent, cur->name);
3202 else
3203 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3204 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
3205 /* different instance, destroy it (attributes must be unique) */
3206 xmlFreeProp(lastattr);
3207 }
3208 /* find the end */
3209 lastattr = parent->properties;
3210 while (lastattr->next != NULL) {
3211 lastattr = lastattr->next;
3212 }
3213 lastattr->next = (xmlAttrPtr) cur;
3214 ((xmlAttrPtr) cur)->prev = lastattr;
3215 }
3216 } else {
3217 if (parent->children == NULL) {
3218 parent->children = cur;
3219 parent->last = cur;
3220 } else {
3221 prev = parent->last;
3222 prev->next = cur;
3223 cur->prev = prev;
3224 parent->last = cur;
3225 }
3226 }
Owen Taylor3473f882001-02-23 17:55:21 +00003227 return(cur);
3228}
3229
3230/**
3231 * xmlGetLastChild:
3232 * @parent: the parent node
3233 *
3234 * Search the last child of a node.
3235 * Returns the last child or NULL if none.
3236 */
3237xmlNodePtr
3238xmlGetLastChild(xmlNodePtr parent) {
3239 if (parent == NULL) {
3240#ifdef DEBUG_TREE
3241 xmlGenericError(xmlGenericErrorContext,
3242 "xmlGetLastChild : parent == NULL\n");
3243#endif
3244 return(NULL);
3245 }
3246 return(parent->last);
3247}
3248
3249/**
3250 * xmlFreeNodeList:
3251 * @cur: the first node in the list
3252 *
3253 * Free a node and all its siblings, this is a recursive behaviour, all
3254 * the children are freed too.
3255 */
3256void
3257xmlFreeNodeList(xmlNodePtr cur) {
3258 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003259 xmlDictPtr dict = NULL;
3260
3261 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003262 if (cur->type == XML_NAMESPACE_DECL) {
3263 xmlFreeNsList((xmlNsPtr) cur);
3264 return;
3265 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003266 if ((cur->type == XML_DOCUMENT_NODE) ||
3267#ifdef LIBXML_DOCB_ENABLED
3268 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003269#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003270 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003271 xmlFreeDoc((xmlDocPtr) cur);
3272 return;
3273 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003274 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003275 while (cur != NULL) {
3276 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003277 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003278
Daniel Veillarda880b122003-04-21 21:36:41 +00003279 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003280 xmlDeregisterNodeDefaultValue(cur);
3281
Daniel Veillard02141ea2001-04-30 11:46:40 +00003282 if ((cur->children != NULL) &&
3283 (cur->type != XML_ENTITY_REF_NODE))
3284 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003285 if (((cur->type == XML_ELEMENT_NODE) ||
3286 (cur->type == XML_XINCLUDE_START) ||
3287 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003288 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003289 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003290 if ((cur->type != XML_ELEMENT_NODE) &&
3291 (cur->type != XML_XINCLUDE_START) &&
3292 (cur->type != XML_XINCLUDE_END) &&
3293 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003294 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003295 }
3296 if (((cur->type == XML_ELEMENT_NODE) ||
3297 (cur->type == XML_XINCLUDE_START) ||
3298 (cur->type == XML_XINCLUDE_END)) &&
3299 (cur->nsDef != NULL))
3300 xmlFreeNsList(cur->nsDef);
3301
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003302 /*
3303 * When a node is a text node or a comment, it uses a global static
3304 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003305 * Otherwise the node name might come from the document's
3306 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003307 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003308 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003309 (cur->type != XML_TEXT_NODE) &&
3310 (cur->type != XML_COMMENT_NODE))
3311 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003312 xmlFree(cur);
3313 }
Owen Taylor3473f882001-02-23 17:55:21 +00003314 cur = next;
3315 }
3316}
3317
3318/**
3319 * xmlFreeNode:
3320 * @cur: the node
3321 *
3322 * Free a node, this is a recursive behaviour, all the children are freed too.
3323 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3324 */
3325void
3326xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003327 xmlDictPtr dict = NULL;
3328
3329 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003330
Daniel Veillard02141ea2001-04-30 11:46:40 +00003331 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003332 if (cur->type == XML_DTD_NODE) {
3333 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003334 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003335 }
3336 if (cur->type == XML_NAMESPACE_DECL) {
3337 xmlFreeNs((xmlNsPtr) cur);
3338 return;
3339 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003340 if (cur->type == XML_ATTRIBUTE_NODE) {
3341 xmlFreeProp((xmlAttrPtr) cur);
3342 return;
3343 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003344
Daniel Veillarda880b122003-04-21 21:36:41 +00003345 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003346 xmlDeregisterNodeDefaultValue(cur);
3347
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003348 if (cur->doc != NULL) dict = cur->doc->dict;
3349
Owen Taylor3473f882001-02-23 17:55:21 +00003350 if ((cur->children != NULL) &&
3351 (cur->type != XML_ENTITY_REF_NODE))
3352 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003353 if (((cur->type == XML_ELEMENT_NODE) ||
3354 (cur->type == XML_XINCLUDE_START) ||
3355 (cur->type == XML_XINCLUDE_END)) &&
3356 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003357 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003358 if ((cur->type != XML_ELEMENT_NODE) &&
3359 (cur->content != NULL) &&
3360 (cur->type != XML_ENTITY_REF_NODE) &&
3361 (cur->type != XML_XINCLUDE_END) &&
3362 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003363 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003364 }
3365
Daniel Veillardacd370f2001-06-09 17:17:51 +00003366 /*
3367 * When a node is a text node or a comment, it uses a global static
3368 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003369 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003370 */
Owen Taylor3473f882001-02-23 17:55:21 +00003371 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003372 (cur->type != XML_TEXT_NODE) &&
3373 (cur->type != XML_COMMENT_NODE))
3374 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003375
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003376 if (((cur->type == XML_ELEMENT_NODE) ||
3377 (cur->type == XML_XINCLUDE_START) ||
3378 (cur->type == XML_XINCLUDE_END)) &&
3379 (cur->nsDef != NULL))
3380 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003381 xmlFree(cur);
3382}
3383
3384/**
3385 * xmlUnlinkNode:
3386 * @cur: the node
3387 *
3388 * Unlink a node from it's current context, the node is not freed
3389 */
3390void
3391xmlUnlinkNode(xmlNodePtr cur) {
3392 if (cur == NULL) {
3393#ifdef DEBUG_TREE
3394 xmlGenericError(xmlGenericErrorContext,
3395 "xmlUnlinkNode : node == NULL\n");
3396#endif
3397 return;
3398 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003399 if (cur->type == XML_DTD_NODE) {
3400 xmlDocPtr doc;
3401 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003402 if (doc != NULL) {
3403 if (doc->intSubset == (xmlDtdPtr) cur)
3404 doc->intSubset = NULL;
3405 if (doc->extSubset == (xmlDtdPtr) cur)
3406 doc->extSubset = NULL;
3407 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003408 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003409 if (cur->parent != NULL) {
3410 xmlNodePtr parent;
3411 parent = cur->parent;
3412 if (cur->type == XML_ATTRIBUTE_NODE) {
3413 if (parent->properties == (xmlAttrPtr) cur)
3414 parent->properties = ((xmlAttrPtr) cur)->next;
3415 } else {
3416 if (parent->children == cur)
3417 parent->children = cur->next;
3418 if (parent->last == cur)
3419 parent->last = cur->prev;
3420 }
3421 cur->parent = NULL;
3422 }
Owen Taylor3473f882001-02-23 17:55:21 +00003423 if (cur->next != NULL)
3424 cur->next->prev = cur->prev;
3425 if (cur->prev != NULL)
3426 cur->prev->next = cur->next;
3427 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003428}
3429
Daniel Veillard652327a2003-09-29 18:02:38 +00003430#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003431/**
3432 * xmlReplaceNode:
3433 * @old: the old node
3434 * @cur: the node
3435 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00003436 * Unlink the old node from its current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003437 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003438 * first unlinked from its existing context.
3439 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003440 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003441 */
3442xmlNodePtr
3443xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3444 if (old == NULL) {
3445#ifdef DEBUG_TREE
3446 xmlGenericError(xmlGenericErrorContext,
3447 "xmlReplaceNode : old == NULL\n");
3448#endif
3449 return(NULL);
3450 }
3451 if (cur == NULL) {
3452 xmlUnlinkNode(old);
3453 return(old);
3454 }
3455 if (cur == old) {
3456 return(old);
3457 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003458 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3459#ifdef DEBUG_TREE
3460 xmlGenericError(xmlGenericErrorContext,
3461 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3462#endif
3463 return(old);
3464 }
3465 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3466#ifdef DEBUG_TREE
3467 xmlGenericError(xmlGenericErrorContext,
3468 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3469#endif
3470 return(old);
3471 }
Owen Taylor3473f882001-02-23 17:55:21 +00003472 xmlUnlinkNode(cur);
3473 cur->doc = old->doc;
3474 cur->parent = old->parent;
3475 cur->next = old->next;
3476 if (cur->next != NULL)
3477 cur->next->prev = cur;
3478 cur->prev = old->prev;
3479 if (cur->prev != NULL)
3480 cur->prev->next = cur;
3481 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003482 if (cur->type == XML_ATTRIBUTE_NODE) {
3483 if (cur->parent->properties == (xmlAttrPtr)old)
3484 cur->parent->properties = ((xmlAttrPtr) cur);
3485 } else {
3486 if (cur->parent->children == old)
3487 cur->parent->children = cur;
3488 if (cur->parent->last == old)
3489 cur->parent->last = cur;
3490 }
Owen Taylor3473f882001-02-23 17:55:21 +00003491 }
3492 old->next = old->prev = NULL;
3493 old->parent = NULL;
3494 return(old);
3495}
Daniel Veillard652327a2003-09-29 18:02:38 +00003496#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003497
3498/************************************************************************
3499 * *
3500 * Copy operations *
3501 * *
3502 ************************************************************************/
3503
3504/**
3505 * xmlCopyNamespace:
3506 * @cur: the namespace
3507 *
3508 * Do a copy of the namespace.
3509 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003510 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003511 */
3512xmlNsPtr
3513xmlCopyNamespace(xmlNsPtr cur) {
3514 xmlNsPtr ret;
3515
3516 if (cur == NULL) return(NULL);
3517 switch (cur->type) {
3518 case XML_LOCAL_NAMESPACE:
3519 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3520 break;
3521 default:
3522#ifdef DEBUG_TREE
3523 xmlGenericError(xmlGenericErrorContext,
3524 "xmlCopyNamespace: invalid type %d\n", cur->type);
3525#endif
3526 return(NULL);
3527 }
3528 return(ret);
3529}
3530
3531/**
3532 * xmlCopyNamespaceList:
3533 * @cur: the first namespace
3534 *
3535 * Do a copy of an namespace list.
3536 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003537 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003538 */
3539xmlNsPtr
3540xmlCopyNamespaceList(xmlNsPtr cur) {
3541 xmlNsPtr ret = NULL;
3542 xmlNsPtr p = NULL,q;
3543
3544 while (cur != NULL) {
3545 q = xmlCopyNamespace(cur);
3546 if (p == NULL) {
3547 ret = p = q;
3548 } else {
3549 p->next = q;
3550 p = q;
3551 }
3552 cur = cur->next;
3553 }
3554 return(ret);
3555}
3556
3557static xmlNodePtr
3558xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3559/**
3560 * xmlCopyProp:
3561 * @target: the element where the attribute will be grafted
3562 * @cur: the attribute
3563 *
3564 * Do a copy of the attribute.
3565 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003566 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003567 */
3568xmlAttrPtr
3569xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3570 xmlAttrPtr ret;
3571
3572 if (cur == NULL) return(NULL);
3573 if (target != NULL)
3574 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3575 else if (cur->parent != NULL)
3576 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3577 else if (cur->children != NULL)
3578 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3579 else
3580 ret = xmlNewDocProp(NULL, cur->name, NULL);
3581 if (ret == NULL) return(NULL);
3582 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003583
Owen Taylor3473f882001-02-23 17:55:21 +00003584 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003585 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003586
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003587 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3588 if (ns == NULL) {
3589 /*
3590 * Humm, we are copying an element whose namespace is defined
3591 * out of the new tree scope. Search it in the original tree
3592 * and add it at the top of the new tree
3593 */
3594 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3595 if (ns != NULL) {
3596 xmlNodePtr root = target;
3597 xmlNodePtr pred = NULL;
3598
3599 while (root->parent != NULL) {
3600 pred = root;
3601 root = root->parent;
3602 }
3603 if (root == (xmlNodePtr) target->doc) {
3604 /* correct possibly cycling above the document elt */
3605 root = pred;
3606 }
3607 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3608 }
3609 } else {
3610 /*
3611 * we have to find something appropriate here since
3612 * we cant be sure, that the namespce we found is identified
3613 * by the prefix
3614 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003615 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003616 /* this is the nice case */
3617 ret->ns = ns;
3618 } else {
3619 /*
3620 * we are in trouble: we need a new reconcilied namespace.
3621 * This is expensive
3622 */
3623 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3624 }
3625 }
3626
Owen Taylor3473f882001-02-23 17:55:21 +00003627 } else
3628 ret->ns = NULL;
3629
3630 if (cur->children != NULL) {
3631 xmlNodePtr tmp;
3632
3633 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3634 ret->last = NULL;
3635 tmp = ret->children;
3636 while (tmp != NULL) {
3637 /* tmp->parent = (xmlNodePtr)ret; */
3638 if (tmp->next == NULL)
3639 ret->last = tmp;
3640 tmp = tmp->next;
3641 }
3642 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003643 /*
3644 * Try to handle IDs
3645 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003646 if ((target!= NULL) && (cur!= NULL) &&
3647 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003648 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3649 if (xmlIsID(cur->doc, cur->parent, cur)) {
3650 xmlChar *id;
3651
3652 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3653 if (id != NULL) {
3654 xmlAddID(NULL, target->doc, id, ret);
3655 xmlFree(id);
3656 }
3657 }
3658 }
Owen Taylor3473f882001-02-23 17:55:21 +00003659 return(ret);
3660}
3661
3662/**
3663 * xmlCopyPropList:
3664 * @target: the element where the attributes will be grafted
3665 * @cur: the first attribute
3666 *
3667 * Do a copy of an attribute list.
3668 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003669 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003670 */
3671xmlAttrPtr
3672xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3673 xmlAttrPtr ret = NULL;
3674 xmlAttrPtr p = NULL,q;
3675
3676 while (cur != NULL) {
3677 q = xmlCopyProp(target, cur);
3678 if (p == NULL) {
3679 ret = p = q;
3680 } else {
3681 p->next = q;
3682 q->prev = p;
3683 p = q;
3684 }
3685 cur = cur->next;
3686 }
3687 return(ret);
3688}
3689
3690/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003691 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003692 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003693 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003694 * tricky reason: namespaces. Doing a direct copy of a node
3695 * say RPM:Copyright without changing the namespace pointer to
3696 * something else can produce stale links. One way to do it is
3697 * to keep a reference counter but this doesn't work as soon
3698 * as one move the element or the subtree out of the scope of
3699 * the existing namespace. The actual solution seems to add
3700 * a copy of the namespace at the top of the copied tree if
3701 * not available in the subtree.
3702 * Hence two functions, the public front-end call the inner ones
3703 */
3704
3705static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003706xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003707 int recursive) {
3708 xmlNodePtr ret;
3709
3710 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003711 switch (node->type) {
3712 case XML_TEXT_NODE:
3713 case XML_CDATA_SECTION_NODE:
3714 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003715 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003716 case XML_ENTITY_REF_NODE:
3717 case XML_ENTITY_NODE:
3718 case XML_PI_NODE:
3719 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003720 case XML_XINCLUDE_START:
3721 case XML_XINCLUDE_END:
3722 break;
3723 case XML_ATTRIBUTE_NODE:
3724 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3725 case XML_NAMESPACE_DECL:
3726 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3727
Daniel Veillard39196eb2001-06-19 18:09:42 +00003728 case XML_DOCUMENT_NODE:
3729 case XML_HTML_DOCUMENT_NODE:
3730#ifdef LIBXML_DOCB_ENABLED
3731 case XML_DOCB_DOCUMENT_NODE:
3732#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00003733#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003734 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard652327a2003-09-29 18:02:38 +00003735#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00003736 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003737 case XML_NOTATION_NODE:
3738 case XML_DTD_NODE:
3739 case XML_ELEMENT_DECL:
3740 case XML_ATTRIBUTE_DECL:
3741 case XML_ENTITY_DECL:
3742 return(NULL);
3743 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003744
Owen Taylor3473f882001-02-23 17:55:21 +00003745 /*
3746 * Allocate a new node and fill the fields.
3747 */
3748 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3749 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00003750 xmlTreeErrMemory("copying node");
Owen Taylor3473f882001-02-23 17:55:21 +00003751 return(NULL);
3752 }
3753 memset(ret, 0, sizeof(xmlNode));
3754 ret->type = node->type;
3755
3756 ret->doc = doc;
3757 ret->parent = parent;
3758 if (node->name == xmlStringText)
3759 ret->name = xmlStringText;
3760 else if (node->name == xmlStringTextNoenc)
3761 ret->name = xmlStringTextNoenc;
3762 else if (node->name == xmlStringComment)
3763 ret->name = xmlStringComment;
3764 else if (node->name != NULL)
3765 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003766 if ((node->type != XML_ELEMENT_NODE) &&
3767 (node->content != NULL) &&
3768 (node->type != XML_ENTITY_REF_NODE) &&
3769 (node->type != XML_XINCLUDE_END) &&
3770 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003771 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003772 }else{
3773 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00003774 ret->line = node->line;
Owen Taylor3473f882001-02-23 17:55:21 +00003775 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003776 if (parent != NULL) {
3777 xmlNodePtr tmp;
3778
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003779 /*
3780 * this is a tricky part for the node register thing:
3781 * in case ret does get coalesced in xmlAddChild
3782 * the deregister-node callback is called; so we register ret now already
3783 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003784 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003785 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3786
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003787 tmp = xmlAddChild(parent, ret);
3788 /* node could have coalesced */
3789 if (tmp != ret)
3790 return(tmp);
3791 }
Owen Taylor3473f882001-02-23 17:55:21 +00003792
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003793 if (!recursive)
3794 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003795 if (node->nsDef != NULL)
3796 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3797
3798 if (node->ns != NULL) {
3799 xmlNsPtr ns;
3800
3801 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3802 if (ns == NULL) {
3803 /*
3804 * Humm, we are copying an element whose namespace is defined
3805 * out of the new tree scope. Search it in the original tree
3806 * and add it at the top of the new tree
3807 */
3808 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3809 if (ns != NULL) {
3810 xmlNodePtr root = ret;
3811
3812 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003813 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003814 }
3815 } else {
3816 /*
3817 * reference the existing namespace definition in our own tree.
3818 */
3819 ret->ns = ns;
3820 }
3821 }
3822 if (node->properties != NULL)
3823 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003824 if (node->type == XML_ENTITY_REF_NODE) {
3825 if ((doc == NULL) || (node->doc != doc)) {
3826 /*
3827 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003828 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003829 * we cannot keep the reference. Try to find it in the
3830 * target document.
3831 */
3832 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3833 } else {
3834 ret->children = node->children;
3835 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003836 ret->last = ret->children;
3837 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003838 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003839 UPDATE_LAST_CHILD_AND_PARENT(ret)
3840 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003841
3842out:
3843 /* if parent != NULL we already registered the node above */
3844 if (parent == NULL && xmlRegisterNodeDefaultValue)
3845 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003846 return(ret);
3847}
3848
3849static xmlNodePtr
3850xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3851 xmlNodePtr ret = NULL;
3852 xmlNodePtr p = NULL,q;
3853
3854 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00003855#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003856 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003857 if (doc == NULL) {
3858 node = node->next;
3859 continue;
3860 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003861 if (doc->intSubset == NULL) {
3862 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3863 q->doc = doc;
3864 q->parent = parent;
3865 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003866 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003867 } else {
3868 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003869 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003870 }
3871 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00003872#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00003873 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003874 if (ret == NULL) {
3875 q->prev = NULL;
3876 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003877 } else if (p != q) {
3878 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003879 p->next = q;
3880 q->prev = p;
3881 p = q;
3882 }
3883 node = node->next;
3884 }
3885 return(ret);
3886}
3887
3888/**
3889 * xmlCopyNode:
3890 * @node: the node
3891 * @recursive: if 1 do a recursive copy.
3892 *
3893 * Do a copy of the node.
3894 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003895 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003896 */
3897xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003898xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003899 xmlNodePtr ret;
3900
3901 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3902 return(ret);
3903}
3904
3905/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003906 * xmlDocCopyNode:
3907 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003908 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003909 * @recursive: if 1 do a recursive copy.
3910 *
3911 * Do a copy of the node to a given document.
3912 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003913 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003914 */
3915xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003916xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003917 xmlNodePtr ret;
3918
3919 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3920 return(ret);
3921}
3922
3923/**
Owen Taylor3473f882001-02-23 17:55:21 +00003924 * xmlCopyNodeList:
3925 * @node: the first node in the list.
3926 *
3927 * Do a recursive copy of the node list.
3928 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003929 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003930 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003931xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003932 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3933 return(ret);
3934}
3935
Daniel Veillard652327a2003-09-29 18:02:38 +00003936#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003937/**
Owen Taylor3473f882001-02-23 17:55:21 +00003938 * xmlCopyDtd:
3939 * @dtd: the dtd
3940 *
3941 * Do a copy of the dtd.
3942 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003943 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003944 */
3945xmlDtdPtr
3946xmlCopyDtd(xmlDtdPtr dtd) {
3947 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003948 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003949
3950 if (dtd == NULL) return(NULL);
3951 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3952 if (ret == NULL) return(NULL);
3953 if (dtd->entities != NULL)
3954 ret->entities = (void *) xmlCopyEntitiesTable(
3955 (xmlEntitiesTablePtr) dtd->entities);
3956 if (dtd->notations != NULL)
3957 ret->notations = (void *) xmlCopyNotationTable(
3958 (xmlNotationTablePtr) dtd->notations);
3959 if (dtd->elements != NULL)
3960 ret->elements = (void *) xmlCopyElementTable(
3961 (xmlElementTablePtr) dtd->elements);
3962 if (dtd->attributes != NULL)
3963 ret->attributes = (void *) xmlCopyAttributeTable(
3964 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003965 if (dtd->pentities != NULL)
3966 ret->pentities = (void *) xmlCopyEntitiesTable(
3967 (xmlEntitiesTablePtr) dtd->pentities);
3968
3969 cur = dtd->children;
3970 while (cur != NULL) {
3971 q = NULL;
3972
3973 if (cur->type == XML_ENTITY_DECL) {
3974 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3975 switch (tmp->etype) {
3976 case XML_INTERNAL_GENERAL_ENTITY:
3977 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3978 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3979 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3980 break;
3981 case XML_INTERNAL_PARAMETER_ENTITY:
3982 case XML_EXTERNAL_PARAMETER_ENTITY:
3983 q = (xmlNodePtr)
3984 xmlGetParameterEntityFromDtd(ret, tmp->name);
3985 break;
3986 case XML_INTERNAL_PREDEFINED_ENTITY:
3987 break;
3988 }
3989 } else if (cur->type == XML_ELEMENT_DECL) {
3990 xmlElementPtr tmp = (xmlElementPtr) cur;
3991 q = (xmlNodePtr)
3992 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3993 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3994 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3995 q = (xmlNodePtr)
3996 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3997 } else if (cur->type == XML_COMMENT_NODE) {
3998 q = xmlCopyNode(cur, 0);
3999 }
4000
4001 if (q == NULL) {
4002 cur = cur->next;
4003 continue;
4004 }
4005
4006 if (p == NULL)
4007 ret->children = q;
4008 else
4009 p->next = q;
4010
4011 q->prev = p;
4012 q->parent = (xmlNodePtr) ret;
4013 q->next = NULL;
4014 ret->last = q;
4015 p = q;
4016 cur = cur->next;
4017 }
4018
Owen Taylor3473f882001-02-23 17:55:21 +00004019 return(ret);
4020}
4021
4022/**
4023 * xmlCopyDoc:
4024 * @doc: the document
4025 * @recursive: if 1 do a recursive copy.
4026 *
4027 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004028 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004029 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004030 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004031 */
4032xmlDocPtr
4033xmlCopyDoc(xmlDocPtr doc, int recursive) {
4034 xmlDocPtr ret;
4035
4036 if (doc == NULL) return(NULL);
4037 ret = xmlNewDoc(doc->version);
4038 if (ret == NULL) return(NULL);
4039 if (doc->name != NULL)
4040 ret->name = xmlMemStrdup(doc->name);
4041 if (doc->encoding != NULL)
4042 ret->encoding = xmlStrdup(doc->encoding);
4043 ret->charset = doc->charset;
4044 ret->compression = doc->compression;
4045 ret->standalone = doc->standalone;
4046 if (!recursive) return(ret);
4047
Daniel Veillardb33c2012001-04-25 12:59:04 +00004048 ret->last = NULL;
4049 ret->children = NULL;
4050 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004051 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004052 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004053 ret->intSubset->parent = ret;
4054 }
Owen Taylor3473f882001-02-23 17:55:21 +00004055 if (doc->oldNs != NULL)
4056 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4057 if (doc->children != NULL) {
4058 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00004059
4060 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4061 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004062 ret->last = NULL;
4063 tmp = ret->children;
4064 while (tmp != NULL) {
4065 if (tmp->next == NULL)
4066 ret->last = tmp;
4067 tmp = tmp->next;
4068 }
4069 }
4070 return(ret);
4071}
Daniel Veillard652327a2003-09-29 18:02:38 +00004072#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004073
4074/************************************************************************
4075 * *
4076 * Content access functions *
4077 * *
4078 ************************************************************************/
4079
4080/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004081 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004082 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004083 *
William M. Brackd7cf7f82003-11-14 07:13:16 +00004084 * Get line number of @node. This requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004085 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004086 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004087 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004088 */
4089long
4090xmlGetLineNo(xmlNodePtr node)
4091{
4092 long result = -1;
4093
4094 if (!node)
4095 return result;
4096 if (node->type == XML_ELEMENT_NODE)
Daniel Veillard3e35f8e2003-10-21 00:05:38 +00004097 result = (long) node->line;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004098 else if ((node->prev != NULL) &&
4099 ((node->prev->type == XML_ELEMENT_NODE) ||
4100 (node->prev->type == XML_TEXT_NODE)))
4101 result = xmlGetLineNo(node->prev);
4102 else if ((node->parent != NULL) &&
4103 ((node->parent->type == XML_ELEMENT_NODE) ||
4104 (node->parent->type == XML_TEXT_NODE)))
4105 result = xmlGetLineNo(node->parent);
4106
4107 return result;
4108}
4109
Daniel Veillard652327a2003-09-29 18:02:38 +00004110#ifdef LIBXML_TREE_ENABLED
Daniel Veillard8faa7832001-11-26 15:58:08 +00004111/**
4112 * xmlGetNodePath:
4113 * @node: a node
4114 *
4115 * Build a structure based Path for the given node
4116 *
4117 * Returns the new path or NULL in case of error. The caller must free
4118 * the returned string
4119 */
4120xmlChar *
4121xmlGetNodePath(xmlNodePtr node)
4122{
4123 xmlNodePtr cur, tmp, next;
4124 xmlChar *buffer = NULL, *temp;
4125 size_t buf_len;
4126 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004127 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004128 const char *name;
4129 char nametemp[100];
4130 int occur = 0;
4131
4132 if (node == NULL)
4133 return (NULL);
4134
4135 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004136 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004137 if (buffer == NULL) {
4138 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004139 return (NULL);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004140 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004141 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004142 if (buf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004143 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004144 xmlFree(buffer);
4145 return (NULL);
4146 }
4147
4148 buffer[0] = 0;
4149 cur = node;
4150 do {
4151 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004152 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004153 occur = 0;
4154 if ((cur->type == XML_DOCUMENT_NODE) ||
4155 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4156 if (buffer[0] == '/')
4157 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004158 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004159 next = NULL;
4160 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004161 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004162 name = (const char *) cur->name;
4163 if (cur->ns) {
William M. Brack84d83e32003-12-23 03:45:17 +00004164 if (cur->ns->prefix != NULL)
4165 snprintf(nametemp, sizeof(nametemp) - 1,
Daniel Veillard8faa7832001-11-26 15:58:08 +00004166 "%s:%s", cur->ns->prefix, cur->name);
William M. Brack84d83e32003-12-23 03:45:17 +00004167 else
4168 snprintf(nametemp, sizeof(nametemp) - 1,
4169 "%s", cur->name);
Daniel Veillard8faa7832001-11-26 15:58:08 +00004170 nametemp[sizeof(nametemp) - 1] = 0;
4171 name = nametemp;
4172 }
4173 next = cur->parent;
4174
4175 /*
4176 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004177 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004178 */
4179 tmp = cur->prev;
4180 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004181 if ((tmp->type == XML_ELEMENT_NODE) &&
4182 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004183 occur++;
4184 tmp = tmp->prev;
4185 }
4186 if (occur == 0) {
4187 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004188 while (tmp != NULL && occur == 0) {
4189 if ((tmp->type == XML_ELEMENT_NODE) &&
4190 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004191 occur++;
4192 tmp = tmp->next;
4193 }
4194 if (occur != 0)
4195 occur = 1;
4196 } else
4197 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004198 } else if (cur->type == XML_COMMENT_NODE) {
4199 sep = "/";
4200 name = "comment()";
4201 next = cur->parent;
4202
4203 /*
4204 * Thumbler index computation
4205 */
4206 tmp = cur->prev;
4207 while (tmp != NULL) {
4208 if (tmp->type == XML_COMMENT_NODE)
4209 occur++;
4210 tmp = tmp->prev;
4211 }
4212 if (occur == 0) {
4213 tmp = cur->next;
4214 while (tmp != NULL && occur == 0) {
4215 if (tmp->type == XML_COMMENT_NODE)
4216 occur++;
4217 tmp = tmp->next;
4218 }
4219 if (occur != 0)
4220 occur = 1;
4221 } else
4222 occur++;
4223 } else if ((cur->type == XML_TEXT_NODE) ||
4224 (cur->type == XML_CDATA_SECTION_NODE)) {
4225 sep = "/";
4226 name = "text()";
4227 next = cur->parent;
4228
4229 /*
4230 * Thumbler index computation
4231 */
4232 tmp = cur->prev;
4233 while (tmp != NULL) {
4234 if ((cur->type == XML_TEXT_NODE) ||
4235 (cur->type == XML_CDATA_SECTION_NODE))
4236 occur++;
4237 tmp = tmp->prev;
4238 }
4239 if (occur == 0) {
4240 tmp = cur->next;
4241 while (tmp != NULL && occur == 0) {
4242 if ((cur->type == XML_TEXT_NODE) ||
4243 (cur->type == XML_CDATA_SECTION_NODE))
4244 occur++;
4245 tmp = tmp->next;
4246 }
4247 if (occur != 0)
4248 occur = 1;
4249 } else
4250 occur++;
4251 } else if (cur->type == XML_PI_NODE) {
4252 sep = "/";
4253 snprintf(nametemp, sizeof(nametemp) - 1,
4254 "processing-instruction('%s')", cur->name);
4255 nametemp[sizeof(nametemp) - 1] = 0;
4256 name = nametemp;
4257
4258 next = cur->parent;
4259
4260 /*
4261 * Thumbler index computation
4262 */
4263 tmp = cur->prev;
4264 while (tmp != NULL) {
4265 if ((tmp->type == XML_PI_NODE) &&
4266 (xmlStrEqual(cur->name, tmp->name)))
4267 occur++;
4268 tmp = tmp->prev;
4269 }
4270 if (occur == 0) {
4271 tmp = cur->next;
4272 while (tmp != NULL && occur == 0) {
4273 if ((tmp->type == XML_PI_NODE) &&
4274 (xmlStrEqual(cur->name, tmp->name)))
4275 occur++;
4276 tmp = tmp->next;
4277 }
4278 if (occur != 0)
4279 occur = 1;
4280 } else
4281 occur++;
4282
Daniel Veillard8faa7832001-11-26 15:58:08 +00004283 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004284 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004285 name = (const char *) (((xmlAttrPtr) cur)->name);
4286 next = ((xmlAttrPtr) cur)->parent;
4287 } else {
4288 next = cur->parent;
4289 }
4290
4291 /*
4292 * Make sure there is enough room
4293 */
4294 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4295 buf_len =
4296 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4297 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4298 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004299 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004300 xmlFree(buf);
4301 xmlFree(buffer);
4302 return (NULL);
4303 }
4304 buffer = temp;
4305 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4306 if (temp == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00004307 xmlTreeErrMemory("getting node path");
Daniel Veillard8faa7832001-11-26 15:58:08 +00004308 xmlFree(buf);
4309 xmlFree(buffer);
4310 return (NULL);
4311 }
4312 buf = temp;
4313 }
4314 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004315 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004316 sep, name, (char *) buffer);
4317 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004318 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004319 sep, name, occur, (char *) buffer);
4320 snprintf((char *) buffer, buf_len, "%s", buf);
4321 cur = next;
4322 } while (cur != NULL);
4323 xmlFree(buf);
4324 return (buffer);
4325}
Daniel Veillard652327a2003-09-29 18:02:38 +00004326#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004327
4328/**
Owen Taylor3473f882001-02-23 17:55:21 +00004329 * xmlDocGetRootElement:
4330 * @doc: the document
4331 *
4332 * Get the root element of the document (doc->children is a list
4333 * containing possibly comments, PIs, etc ...).
4334 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004335 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004336 */
4337xmlNodePtr
4338xmlDocGetRootElement(xmlDocPtr doc) {
4339 xmlNodePtr ret;
4340
4341 if (doc == NULL) return(NULL);
4342 ret = doc->children;
4343 while (ret != NULL) {
4344 if (ret->type == XML_ELEMENT_NODE)
4345 return(ret);
4346 ret = ret->next;
4347 }
4348 return(ret);
4349}
4350
Daniel Veillard652327a2003-09-29 18:02:38 +00004351#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004352/**
4353 * xmlDocSetRootElement:
4354 * @doc: the document
4355 * @root: the new document root element
4356 *
4357 * Set the root element of the document (doc->children is a list
4358 * containing possibly comments, PIs, etc ...).
4359 *
4360 * Returns the old root element if any was found
4361 */
4362xmlNodePtr
4363xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4364 xmlNodePtr old = NULL;
4365
4366 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004367 if (root == NULL)
4368 return(NULL);
4369 xmlUnlinkNode(root);
4370 root->doc = doc;
4371 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004372 old = doc->children;
4373 while (old != NULL) {
4374 if (old->type == XML_ELEMENT_NODE)
4375 break;
4376 old = old->next;
4377 }
4378 if (old == NULL) {
4379 if (doc->children == NULL) {
4380 doc->children = root;
4381 doc->last = root;
4382 } else {
4383 xmlAddSibling(doc->children, root);
4384 }
4385 } else {
4386 xmlReplaceNode(old, root);
4387 }
4388 return(old);
4389}
4390
4391/**
4392 * xmlNodeSetLang:
4393 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004394 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004395 *
4396 * Set the language of a node, i.e. the values of the xml:lang
4397 * attribute.
4398 */
4399void
4400xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004401 xmlNsPtr ns;
4402
Owen Taylor3473f882001-02-23 17:55:21 +00004403 if (cur == NULL) return;
4404 switch(cur->type) {
4405 case XML_TEXT_NODE:
4406 case XML_CDATA_SECTION_NODE:
4407 case XML_COMMENT_NODE:
4408 case XML_DOCUMENT_NODE:
4409 case XML_DOCUMENT_TYPE_NODE:
4410 case XML_DOCUMENT_FRAG_NODE:
4411 case XML_NOTATION_NODE:
4412 case XML_HTML_DOCUMENT_NODE:
4413 case XML_DTD_NODE:
4414 case XML_ELEMENT_DECL:
4415 case XML_ATTRIBUTE_DECL:
4416 case XML_ENTITY_DECL:
4417 case XML_PI_NODE:
4418 case XML_ENTITY_REF_NODE:
4419 case XML_ENTITY_NODE:
4420 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004421#ifdef LIBXML_DOCB_ENABLED
4422 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004423#endif
4424 case XML_XINCLUDE_START:
4425 case XML_XINCLUDE_END:
4426 return;
4427 case XML_ELEMENT_NODE:
4428 case XML_ATTRIBUTE_NODE:
4429 break;
4430 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004431 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4432 if (ns == NULL)
4433 return;
4434 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004435}
Daniel Veillard652327a2003-09-29 18:02:38 +00004436#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004437
4438/**
4439 * xmlNodeGetLang:
4440 * @cur: the node being checked
4441 *
4442 * Searches the language of a node, i.e. the values of the xml:lang
4443 * attribute or the one carried by the nearest ancestor.
4444 *
4445 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004446 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004447 */
4448xmlChar *
4449xmlNodeGetLang(xmlNodePtr cur) {
4450 xmlChar *lang;
4451
4452 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004453 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004454 if (lang != NULL)
4455 return(lang);
4456 cur = cur->parent;
4457 }
4458 return(NULL);
4459}
4460
4461
Daniel Veillard652327a2003-09-29 18:02:38 +00004462#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004463/**
4464 * xmlNodeSetSpacePreserve:
4465 * @cur: the node being changed
4466 * @val: the xml:space value ("0": default, 1: "preserve")
4467 *
4468 * Set (or reset) the space preserving behaviour of a node, i.e. the
4469 * value of the xml:space attribute.
4470 */
4471void
4472xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004473 xmlNsPtr ns;
4474
Owen Taylor3473f882001-02-23 17:55:21 +00004475 if (cur == NULL) return;
4476 switch(cur->type) {
4477 case XML_TEXT_NODE:
4478 case XML_CDATA_SECTION_NODE:
4479 case XML_COMMENT_NODE:
4480 case XML_DOCUMENT_NODE:
4481 case XML_DOCUMENT_TYPE_NODE:
4482 case XML_DOCUMENT_FRAG_NODE:
4483 case XML_NOTATION_NODE:
4484 case XML_HTML_DOCUMENT_NODE:
4485 case XML_DTD_NODE:
4486 case XML_ELEMENT_DECL:
4487 case XML_ATTRIBUTE_DECL:
4488 case XML_ENTITY_DECL:
4489 case XML_PI_NODE:
4490 case XML_ENTITY_REF_NODE:
4491 case XML_ENTITY_NODE:
4492 case XML_NAMESPACE_DECL:
4493 case XML_XINCLUDE_START:
4494 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004495#ifdef LIBXML_DOCB_ENABLED
4496 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004497#endif
4498 return;
4499 case XML_ELEMENT_NODE:
4500 case XML_ATTRIBUTE_NODE:
4501 break;
4502 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004503 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4504 if (ns == NULL)
4505 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004506 switch (val) {
4507 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004508 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004509 break;
4510 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004511 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004512 break;
4513 }
4514}
Daniel Veillard652327a2003-09-29 18:02:38 +00004515#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004516
4517/**
4518 * xmlNodeGetSpacePreserve:
4519 * @cur: the node being checked
4520 *
4521 * Searches the space preserving behaviour of a node, i.e. the values
4522 * of the xml:space attribute or the one carried by the nearest
4523 * ancestor.
4524 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004525 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004526 */
4527int
4528xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4529 xmlChar *space;
4530
4531 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004532 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004533 if (space != NULL) {
4534 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4535 xmlFree(space);
4536 return(1);
4537 }
4538 if (xmlStrEqual(space, BAD_CAST "default")) {
4539 xmlFree(space);
4540 return(0);
4541 }
4542 xmlFree(space);
4543 }
4544 cur = cur->parent;
4545 }
4546 return(-1);
4547}
4548
Daniel Veillard652327a2003-09-29 18:02:38 +00004549#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004550/**
4551 * xmlNodeSetName:
4552 * @cur: the node being changed
4553 * @name: the new tag name
4554 *
4555 * Set (or reset) the name of a node.
4556 */
4557void
4558xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
4559 if (cur == NULL) return;
4560 if (name == NULL) return;
4561 switch(cur->type) {
4562 case XML_TEXT_NODE:
4563 case XML_CDATA_SECTION_NODE:
4564 case XML_COMMENT_NODE:
4565 case XML_DOCUMENT_TYPE_NODE:
4566 case XML_DOCUMENT_FRAG_NODE:
4567 case XML_NOTATION_NODE:
4568 case XML_HTML_DOCUMENT_NODE:
4569 case XML_NAMESPACE_DECL:
4570 case XML_XINCLUDE_START:
4571 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004572#ifdef LIBXML_DOCB_ENABLED
4573 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004574#endif
4575 return;
4576 case XML_ELEMENT_NODE:
4577 case XML_ATTRIBUTE_NODE:
4578 case XML_PI_NODE:
4579 case XML_ENTITY_REF_NODE:
4580 case XML_ENTITY_NODE:
4581 case XML_DTD_NODE:
4582 case XML_DOCUMENT_NODE:
4583 case XML_ELEMENT_DECL:
4584 case XML_ATTRIBUTE_DECL:
4585 case XML_ENTITY_DECL:
4586 break;
4587 }
4588 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4589 cur->name = xmlStrdup(name);
4590}
4591
4592/**
4593 * xmlNodeSetBase:
4594 * @cur: the node being changed
4595 * @uri: the new base URI
4596 *
4597 * Set (or reset) the base URI of a node, i.e. the value of the
4598 * xml:base attribute.
4599 */
4600void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00004601xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004602 xmlNsPtr ns;
4603
Owen Taylor3473f882001-02-23 17:55:21 +00004604 if (cur == NULL) return;
4605 switch(cur->type) {
4606 case XML_TEXT_NODE:
4607 case XML_CDATA_SECTION_NODE:
4608 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004609 case XML_DOCUMENT_TYPE_NODE:
4610 case XML_DOCUMENT_FRAG_NODE:
4611 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004612 case XML_DTD_NODE:
4613 case XML_ELEMENT_DECL:
4614 case XML_ATTRIBUTE_DECL:
4615 case XML_ENTITY_DECL:
4616 case XML_PI_NODE:
4617 case XML_ENTITY_REF_NODE:
4618 case XML_ENTITY_NODE:
4619 case XML_NAMESPACE_DECL:
4620 case XML_XINCLUDE_START:
4621 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004622 return;
4623 case XML_ELEMENT_NODE:
4624 case XML_ATTRIBUTE_NODE:
4625 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004626 case XML_DOCUMENT_NODE:
4627#ifdef LIBXML_DOCB_ENABLED
4628 case XML_DOCB_DOCUMENT_NODE:
4629#endif
4630 case XML_HTML_DOCUMENT_NODE: {
4631 xmlDocPtr doc = (xmlDocPtr) cur;
4632
4633 if (doc->URL != NULL)
4634 xmlFree((xmlChar *) doc->URL);
4635 if (uri == NULL)
4636 doc->URL = NULL;
4637 else
4638 doc->URL = xmlStrdup(uri);
4639 return;
4640 }
Owen Taylor3473f882001-02-23 17:55:21 +00004641 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004642
4643 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4644 if (ns == NULL)
4645 return;
4646 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004647}
Daniel Veillard652327a2003-09-29 18:02:38 +00004648#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004649
4650/**
Owen Taylor3473f882001-02-23 17:55:21 +00004651 * xmlNodeGetBase:
4652 * @doc: the document the node pertains to
4653 * @cur: the node being checked
4654 *
4655 * Searches for the BASE URL. The code should work on both XML
4656 * and HTML document even if base mechanisms are completely different.
4657 * It returns the base as defined in RFC 2396 sections
4658 * 5.1.1. Base URI within Document Content
4659 * and
4660 * 5.1.2. Base URI from the Encapsulating Entity
4661 * However it does not return the document base (5.1.3), use
4662 * xmlDocumentGetBase() for this
4663 *
4664 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004665 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004666 */
4667xmlChar *
4668xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004669 xmlChar *oldbase = NULL;
4670 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004671
4672 if ((cur == NULL) && (doc == NULL))
4673 return(NULL);
4674 if (doc == NULL) doc = cur->doc;
4675 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4676 cur = doc->children;
4677 while ((cur != NULL) && (cur->name != NULL)) {
4678 if (cur->type != XML_ELEMENT_NODE) {
4679 cur = cur->next;
4680 continue;
4681 }
4682 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4683 cur = cur->children;
4684 continue;
4685 }
4686 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4687 cur = cur->children;
4688 continue;
4689 }
4690 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4691 return(xmlGetProp(cur, BAD_CAST "href"));
4692 }
4693 cur = cur->next;
4694 }
4695 return(NULL);
4696 }
4697 while (cur != NULL) {
4698 if (cur->type == XML_ENTITY_DECL) {
4699 xmlEntityPtr ent = (xmlEntityPtr) cur;
4700 return(xmlStrdup(ent->URI));
4701 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004702 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004703 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004704 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004705 if (oldbase != NULL) {
4706 newbase = xmlBuildURI(oldbase, base);
4707 if (newbase != NULL) {
4708 xmlFree(oldbase);
4709 xmlFree(base);
4710 oldbase = newbase;
4711 } else {
4712 xmlFree(oldbase);
4713 xmlFree(base);
4714 return(NULL);
4715 }
4716 } else {
4717 oldbase = base;
4718 }
4719 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4720 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4721 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4722 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004723 }
4724 }
Owen Taylor3473f882001-02-23 17:55:21 +00004725 cur = cur->parent;
4726 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004727 if ((doc != NULL) && (doc->URL != NULL)) {
4728 if (oldbase == NULL)
4729 return(xmlStrdup(doc->URL));
4730 newbase = xmlBuildURI(oldbase, doc->URL);
4731 xmlFree(oldbase);
4732 return(newbase);
4733 }
4734 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004735}
4736
4737/**
Daniel Veillard78697292003-10-19 20:44:43 +00004738 * xmlNodeBufGetContent:
4739 * @buffer: a buffer
4740 * @cur: the node being read
4741 *
4742 * Read the value of a node @cur, this can be either the text carried
4743 * directly by this node if it's a TEXT node or the aggregate string
4744 * of the values carried by this node child's (TEXT and ENTITY_REF).
4745 * Entity references are substituted.
4746 * Fills up the buffer @buffer with this value
4747 *
4748 * Returns 0 in case of success and -1 in case of error.
4749 */
4750int
4751xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
4752{
4753 if ((cur == NULL) || (buffer == NULL)) return(-1);
4754 switch (cur->type) {
4755 case XML_CDATA_SECTION_NODE:
4756 case XML_TEXT_NODE:
4757 xmlBufferCat(buffer, cur->content);
4758 break;
4759 case XML_DOCUMENT_FRAG_NODE:
4760 case XML_ELEMENT_NODE:{
4761 xmlNodePtr tmp = cur;
4762
4763 while (tmp != NULL) {
4764 switch (tmp->type) {
4765 case XML_CDATA_SECTION_NODE:
4766 case XML_TEXT_NODE:
4767 if (tmp->content != NULL)
4768 xmlBufferCat(buffer, tmp->content);
4769 break;
4770 case XML_ENTITY_REF_NODE:
4771 xmlNodeBufGetContent(buffer, tmp->children);
4772 break;
4773 default:
4774 break;
4775 }
4776 /*
4777 * Skip to next node
4778 */
4779 if (tmp->children != NULL) {
4780 if (tmp->children->type != XML_ENTITY_DECL) {
4781 tmp = tmp->children;
4782 continue;
4783 }
4784 }
4785 if (tmp == cur)
4786 break;
4787
4788 if (tmp->next != NULL) {
4789 tmp = tmp->next;
4790 continue;
4791 }
4792
4793 do {
4794 tmp = tmp->parent;
4795 if (tmp == NULL)
4796 break;
4797 if (tmp == cur) {
4798 tmp = NULL;
4799 break;
4800 }
4801 if (tmp->next != NULL) {
4802 tmp = tmp->next;
4803 break;
4804 }
4805 } while (tmp != NULL);
4806 }
4807 break;
4808 }
4809 case XML_ATTRIBUTE_NODE:{
4810 xmlAttrPtr attr = (xmlAttrPtr) cur;
4811 xmlNodePtr tmp = attr->children;
4812
4813 while (tmp != NULL) {
4814 if (tmp->type == XML_TEXT_NODE)
4815 xmlBufferCat(buffer, tmp->content);
4816 else
4817 xmlNodeBufGetContent(buffer, tmp);
4818 tmp = tmp->next;
4819 }
4820 break;
4821 }
4822 case XML_COMMENT_NODE:
4823 case XML_PI_NODE:
4824 xmlBufferCat(buffer, cur->content);
4825 break;
4826 case XML_ENTITY_REF_NODE:{
4827 xmlEntityPtr ent;
4828 xmlNodePtr tmp;
4829
4830 /* lookup entity declaration */
4831 ent = xmlGetDocEntity(cur->doc, cur->name);
4832 if (ent == NULL)
4833 return(-1);
4834
4835 /* an entity content can be any "well balanced chunk",
4836 * i.e. the result of the content [43] production:
4837 * http://www.w3.org/TR/REC-xml#NT-content
4838 * -> we iterate through child nodes and recursive call
4839 * xmlNodeGetContent() which handles all possible node types */
4840 tmp = ent->children;
4841 while (tmp) {
4842 xmlNodeBufGetContent(buffer, tmp);
4843 tmp = tmp->next;
4844 }
4845 break;
4846 }
4847 case XML_ENTITY_NODE:
4848 case XML_DOCUMENT_TYPE_NODE:
4849 case XML_NOTATION_NODE:
4850 case XML_DTD_NODE:
4851 case XML_XINCLUDE_START:
4852 case XML_XINCLUDE_END:
4853 break;
4854 case XML_DOCUMENT_NODE:
4855#ifdef LIBXML_DOCB_ENABLED
4856 case XML_DOCB_DOCUMENT_NODE:
4857#endif
4858 case XML_HTML_DOCUMENT_NODE:
4859 cur = cur->children;
4860 while (cur!= NULL) {
4861 if ((cur->type == XML_ELEMENT_NODE) ||
4862 (cur->type == XML_TEXT_NODE) ||
4863 (cur->type == XML_CDATA_SECTION_NODE)) {
4864 xmlNodeBufGetContent(buffer, cur);
4865 }
4866 cur = cur->next;
4867 }
4868 break;
4869 case XML_NAMESPACE_DECL:
4870 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
4871 break;
4872 case XML_ELEMENT_DECL:
4873 case XML_ATTRIBUTE_DECL:
4874 case XML_ENTITY_DECL:
4875 break;
4876 }
4877 return(0);
4878}
4879/**
Owen Taylor3473f882001-02-23 17:55:21 +00004880 * xmlNodeGetContent:
4881 * @cur: the node being read
4882 *
4883 * Read the value of a node, this can be either the text carried
4884 * directly by this node if it's a TEXT node or the aggregate string
4885 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004886 * Entity references are substituted.
4887 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004888 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004889 */
4890xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004891xmlNodeGetContent(xmlNodePtr cur)
4892{
4893 if (cur == NULL)
4894 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004895 switch (cur->type) {
4896 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004897 case XML_ELEMENT_NODE:{
Daniel Veillard7646b182002-04-20 06:41:40 +00004898 xmlBufferPtr buffer;
4899 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004900
Daniel Veillard814a76d2003-01-23 18:24:20 +00004901 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004902 if (buffer == NULL)
4903 return (NULL);
Daniel Veillardc4696922003-10-19 21:47:14 +00004904 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00004905 ret = buffer->content;
4906 buffer->content = NULL;
4907 xmlBufferFree(buffer);
4908 return (ret);
4909 }
4910 case XML_ATTRIBUTE_NODE:{
4911 xmlAttrPtr attr = (xmlAttrPtr) cur;
4912
4913 if (attr->parent != NULL)
4914 return (xmlNodeListGetString
4915 (attr->parent->doc, attr->children, 1));
4916 else
4917 return (xmlNodeListGetString(NULL, attr->children, 1));
4918 break;
4919 }
Owen Taylor3473f882001-02-23 17:55:21 +00004920 case XML_COMMENT_NODE:
4921 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004922 if (cur->content != NULL)
4923 return (xmlStrdup(cur->content));
4924 return (NULL);
4925 case XML_ENTITY_REF_NODE:{
4926 xmlEntityPtr ent;
Daniel Veillard7646b182002-04-20 06:41:40 +00004927 xmlBufferPtr buffer;
4928 xmlChar *ret;
4929
4930 /* lookup entity declaration */
4931 ent = xmlGetDocEntity(cur->doc, cur->name);
4932 if (ent == NULL)
4933 return (NULL);
4934
4935 buffer = xmlBufferCreate();
4936 if (buffer == NULL)
4937 return (NULL);
4938
Daniel Veillardc4696922003-10-19 21:47:14 +00004939 xmlNodeBufGetContent(buffer, cur);
Daniel Veillard7646b182002-04-20 06:41:40 +00004940
4941 ret = buffer->content;
4942 buffer->content = NULL;
4943 xmlBufferFree(buffer);
4944 return (ret);
4945 }
Owen Taylor3473f882001-02-23 17:55:21 +00004946 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004947 case XML_DOCUMENT_TYPE_NODE:
4948 case XML_NOTATION_NODE:
4949 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004950 case XML_XINCLUDE_START:
4951 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00004952 return (NULL);
4953 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004954#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004955 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004956#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00004957 case XML_HTML_DOCUMENT_NODE: {
Daniel Veillardc4696922003-10-19 21:47:14 +00004958 xmlBufferPtr buffer;
4959 xmlChar *ret;
Daniel Veillard9adc0462003-03-24 18:39:54 +00004960
Daniel Veillardc4696922003-10-19 21:47:14 +00004961 buffer = xmlBufferCreate();
4962 if (buffer == NULL)
4963 return (NULL);
4964
4965 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
4966
4967 ret = buffer->content;
4968 buffer->content = NULL;
4969 xmlBufferFree(buffer);
4970 return (ret);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004971 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004972 case XML_NAMESPACE_DECL: {
4973 xmlChar *tmp;
4974
4975 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4976 return (tmp);
4977 }
Owen Taylor3473f882001-02-23 17:55:21 +00004978 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004979 /* TODO !!! */
4980 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004981 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004982 /* TODO !!! */
4983 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004984 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004985 /* TODO !!! */
4986 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004987 case XML_CDATA_SECTION_NODE:
4988 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004989 if (cur->content != NULL)
4990 return (xmlStrdup(cur->content));
4991 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004992 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004993 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004994}
Daniel Veillard652327a2003-09-29 18:02:38 +00004995
Owen Taylor3473f882001-02-23 17:55:21 +00004996/**
4997 * xmlNodeSetContent:
4998 * @cur: the node being modified
4999 * @content: the new value of the content
5000 *
5001 * Replace the content of a node.
5002 */
5003void
5004xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5005 if (cur == NULL) {
5006#ifdef DEBUG_TREE
5007 xmlGenericError(xmlGenericErrorContext,
5008 "xmlNodeSetContent : node == NULL\n");
5009#endif
5010 return;
5011 }
5012 switch (cur->type) {
5013 case XML_DOCUMENT_FRAG_NODE:
5014 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005015 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005016 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5017 cur->children = xmlStringGetNodeList(cur->doc, content);
5018 UPDATE_LAST_CHILD_AND_PARENT(cur)
5019 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005020 case XML_TEXT_NODE:
5021 case XML_CDATA_SECTION_NODE:
5022 case XML_ENTITY_REF_NODE:
5023 case XML_ENTITY_NODE:
5024 case XML_PI_NODE:
5025 case XML_COMMENT_NODE:
5026 if (cur->content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005027 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5028 xmlDictOwns(cur->doc->dict, cur->content)))
5029 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005030 }
5031 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5032 cur->last = cur->children = NULL;
5033 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005034 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00005035 } else
5036 cur->content = NULL;
5037 break;
5038 case XML_DOCUMENT_NODE:
5039 case XML_HTML_DOCUMENT_NODE:
5040 case XML_DOCUMENT_TYPE_NODE:
5041 case XML_XINCLUDE_START:
5042 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005043#ifdef LIBXML_DOCB_ENABLED
5044 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005045#endif
5046 break;
5047 case XML_NOTATION_NODE:
5048 break;
5049 case XML_DTD_NODE:
5050 break;
5051 case XML_NAMESPACE_DECL:
5052 break;
5053 case XML_ELEMENT_DECL:
5054 /* TODO !!! */
5055 break;
5056 case XML_ATTRIBUTE_DECL:
5057 /* TODO !!! */
5058 break;
5059 case XML_ENTITY_DECL:
5060 /* TODO !!! */
5061 break;
5062 }
5063}
5064
Daniel Veillard652327a2003-09-29 18:02:38 +00005065#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005066/**
5067 * xmlNodeSetContentLen:
5068 * @cur: the node being modified
5069 * @content: the new value of the content
5070 * @len: the size of @content
5071 *
5072 * Replace the content of a node.
5073 */
5074void
5075xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5076 if (cur == NULL) {
5077#ifdef DEBUG_TREE
5078 xmlGenericError(xmlGenericErrorContext,
5079 "xmlNodeSetContentLen : node == NULL\n");
5080#endif
5081 return;
5082 }
5083 switch (cur->type) {
5084 case XML_DOCUMENT_FRAG_NODE:
5085 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00005086 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005087 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5088 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5089 UPDATE_LAST_CHILD_AND_PARENT(cur)
5090 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005091 case XML_TEXT_NODE:
5092 case XML_CDATA_SECTION_NODE:
5093 case XML_ENTITY_REF_NODE:
5094 case XML_ENTITY_NODE:
5095 case XML_PI_NODE:
5096 case XML_COMMENT_NODE:
5097 case XML_NOTATION_NODE:
5098 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005099 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005100 }
5101 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5102 cur->children = cur->last = NULL;
5103 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005104 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005105 } else
5106 cur->content = NULL;
5107 break;
5108 case XML_DOCUMENT_NODE:
5109 case XML_DTD_NODE:
5110 case XML_HTML_DOCUMENT_NODE:
5111 case XML_DOCUMENT_TYPE_NODE:
5112 case XML_NAMESPACE_DECL:
5113 case XML_XINCLUDE_START:
5114 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005115#ifdef LIBXML_DOCB_ENABLED
5116 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005117#endif
5118 break;
5119 case XML_ELEMENT_DECL:
5120 /* TODO !!! */
5121 break;
5122 case XML_ATTRIBUTE_DECL:
5123 /* TODO !!! */
5124 break;
5125 case XML_ENTITY_DECL:
5126 /* TODO !!! */
5127 break;
5128 }
5129}
Daniel Veillard652327a2003-09-29 18:02:38 +00005130#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005131
5132/**
5133 * xmlNodeAddContentLen:
5134 * @cur: the node being modified
5135 * @content: extra content
5136 * @len: the size of @content
5137 *
5138 * Append the extra substring to the node content.
5139 */
5140void
5141xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5142 if (cur == NULL) {
5143#ifdef DEBUG_TREE
5144 xmlGenericError(xmlGenericErrorContext,
5145 "xmlNodeAddContentLen : node == NULL\n");
5146#endif
5147 return;
5148 }
5149 if (len <= 0) return;
5150 switch (cur->type) {
5151 case XML_DOCUMENT_FRAG_NODE:
5152 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005153 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005154
Daniel Veillard7db37732001-07-12 01:20:08 +00005155 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005156 newNode = xmlNewTextLen(content, len);
5157 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005158 tmp = xmlAddChild(cur, newNode);
5159 if (tmp != newNode)
5160 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005161 if ((last != NULL) && (last->next == newNode)) {
5162 xmlTextMerge(last, newNode);
5163 }
5164 }
5165 break;
5166 }
5167 case XML_ATTRIBUTE_NODE:
5168 break;
5169 case XML_TEXT_NODE:
5170 case XML_CDATA_SECTION_NODE:
5171 case XML_ENTITY_REF_NODE:
5172 case XML_ENTITY_NODE:
5173 case XML_PI_NODE:
5174 case XML_COMMENT_NODE:
5175 case XML_NOTATION_NODE:
5176 if (content != NULL) {
William M. Brack7762bb12004-01-04 14:49:01 +00005177 if ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5178 xmlDictOwns(cur->doc->dict, cur->content)) {
5179 cur->content =
5180 xmlStrncatNew(cur->content, content, len);
5181 break;
5182 }
Owen Taylor3473f882001-02-23 17:55:21 +00005183 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005184 }
5185 case XML_DOCUMENT_NODE:
5186 case XML_DTD_NODE:
5187 case XML_HTML_DOCUMENT_NODE:
5188 case XML_DOCUMENT_TYPE_NODE:
5189 case XML_NAMESPACE_DECL:
5190 case XML_XINCLUDE_START:
5191 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005192#ifdef LIBXML_DOCB_ENABLED
5193 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005194#endif
5195 break;
5196 case XML_ELEMENT_DECL:
5197 case XML_ATTRIBUTE_DECL:
5198 case XML_ENTITY_DECL:
5199 break;
5200 }
5201}
5202
5203/**
5204 * xmlNodeAddContent:
5205 * @cur: the node being modified
5206 * @content: extra content
5207 *
5208 * Append the extra substring to the node content.
5209 */
5210void
5211xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5212 int len;
5213
5214 if (cur == NULL) {
5215#ifdef DEBUG_TREE
5216 xmlGenericError(xmlGenericErrorContext,
5217 "xmlNodeAddContent : node == NULL\n");
5218#endif
5219 return;
5220 }
5221 if (content == NULL) return;
5222 len = xmlStrlen(content);
5223 xmlNodeAddContentLen(cur, content, len);
5224}
5225
5226/**
5227 * xmlTextMerge:
5228 * @first: the first text node
5229 * @second: the second text node being merged
5230 *
5231 * Merge two text nodes into one
5232 * Returns the first text node augmented
5233 */
5234xmlNodePtr
5235xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5236 if (first == NULL) return(second);
5237 if (second == NULL) return(first);
5238 if (first->type != XML_TEXT_NODE) return(first);
5239 if (second->type != XML_TEXT_NODE) return(first);
5240 if (second->name != first->name)
5241 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005242 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005243 xmlUnlinkNode(second);
5244 xmlFreeNode(second);
5245 return(first);
5246}
5247
Daniel Veillard652327a2003-09-29 18:02:38 +00005248#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005249/**
5250 * xmlGetNsList:
5251 * @doc: the document
5252 * @node: the current node
5253 *
5254 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005255 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005256 * that need to be freed by the caller or NULL if no
5257 * namespace if defined
5258 */
5259xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005260xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5261{
Owen Taylor3473f882001-02-23 17:55:21 +00005262 xmlNsPtr cur;
5263 xmlNsPtr *ret = NULL;
5264 int nbns = 0;
5265 int maxns = 10;
5266 int i;
5267
5268 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005269 if (node->type == XML_ELEMENT_NODE) {
5270 cur = node->nsDef;
5271 while (cur != NULL) {
5272 if (ret == NULL) {
5273 ret =
5274 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5275 sizeof(xmlNsPtr));
5276 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005277 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005278 return (NULL);
5279 }
5280 ret[nbns] = NULL;
5281 }
5282 for (i = 0; i < nbns; i++) {
5283 if ((cur->prefix == ret[i]->prefix) ||
5284 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5285 break;
5286 }
5287 if (i >= nbns) {
5288 if (nbns >= maxns) {
5289 maxns *= 2;
5290 ret = (xmlNsPtr *) xmlRealloc(ret,
5291 (maxns +
5292 1) *
5293 sizeof(xmlNsPtr));
5294 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005295 xmlTreeErrMemory("getting namespace list");
Daniel Veillard77044732001-06-29 21:31:07 +00005296 return (NULL);
5297 }
5298 }
5299 ret[nbns++] = cur;
5300 ret[nbns] = NULL;
5301 }
Owen Taylor3473f882001-02-23 17:55:21 +00005302
Daniel Veillard77044732001-06-29 21:31:07 +00005303 cur = cur->next;
5304 }
5305 }
5306 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005307 }
Daniel Veillard77044732001-06-29 21:31:07 +00005308 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005309}
Daniel Veillard652327a2003-09-29 18:02:38 +00005310#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005311
5312/**
5313 * xmlSearchNs:
5314 * @doc: the document
5315 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005316 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005317 *
5318 * Search a Ns registered under a given name space for a document.
5319 * recurse on the parents until it finds the defined namespace
5320 * or return NULL otherwise.
5321 * @nameSpace can be NULL, this is a search for the default namespace.
5322 * We don't allow to cross entities boundaries. If you don't declare
5323 * the namespace within those you will be in troubles !!! A warning
5324 * is generated to cover this case.
5325 *
5326 * Returns the namespace pointer or NULL.
5327 */
5328xmlNsPtr
5329xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillardf4e56292003-10-28 14:27:41 +00005330
Owen Taylor3473f882001-02-23 17:55:21 +00005331 xmlNsPtr cur;
Daniel Veillardf4e56292003-10-28 14:27:41 +00005332 xmlNodePtr orig = node;
Owen Taylor3473f882001-02-23 17:55:21 +00005333
5334 if (node == NULL) return(NULL);
5335 if ((nameSpace != NULL) &&
5336 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005337 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5338 /*
5339 * The XML-1.0 namespace is normally held on the root
5340 * element. In this case exceptionally create it on the
5341 * node element.
5342 */
5343 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5344 if (cur == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005345 xmlTreeErrMemory("searching namespace");
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005346 return(NULL);
5347 }
5348 memset(cur, 0, sizeof(xmlNs));
5349 cur->type = XML_LOCAL_NAMESPACE;
5350 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5351 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5352 cur->next = node->nsDef;
5353 node->nsDef = cur;
5354 return(cur);
5355 }
Owen Taylor3473f882001-02-23 17:55:21 +00005356 if (doc->oldNs == NULL) {
5357 /*
5358 * Allocate a new Namespace and fill the fields.
5359 */
5360 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5361 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005362 xmlTreeErrMemory("searching namespace");
Owen Taylor3473f882001-02-23 17:55:21 +00005363 return(NULL);
5364 }
5365 memset(doc->oldNs, 0, sizeof(xmlNs));
5366 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5367
5368 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5369 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5370 }
5371 return(doc->oldNs);
5372 }
5373 while (node != NULL) {
5374 if ((node->type == XML_ENTITY_REF_NODE) ||
5375 (node->type == XML_ENTITY_NODE) ||
5376 (node->type == XML_ENTITY_DECL))
5377 return(NULL);
5378 if (node->type == XML_ELEMENT_NODE) {
5379 cur = node->nsDef;
5380 while (cur != NULL) {
5381 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5382 (cur->href != NULL))
5383 return(cur);
5384 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5385 (cur->href != NULL) &&
5386 (xmlStrEqual(cur->prefix, nameSpace)))
5387 return(cur);
5388 cur = cur->next;
5389 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005390 if (orig != node) {
5391 cur = node->ns;
5392 if (cur != NULL) {
5393 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5394 (cur->href != NULL))
5395 return(cur);
5396 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5397 (cur->href != NULL) &&
5398 (xmlStrEqual(cur->prefix, nameSpace)))
5399 return(cur);
5400 }
5401 }
Owen Taylor3473f882001-02-23 17:55:21 +00005402 }
5403 node = node->parent;
5404 }
5405 return(NULL);
5406}
5407
5408/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005409 * xmlNsInScope:
5410 * @doc: the document
5411 * @node: the current node
5412 * @ancestor: the ancestor carrying the namespace
5413 * @prefix: the namespace prefix
5414 *
5415 * Verify that the given namespace held on @ancestor is still in scope
5416 * on node.
5417 *
5418 * Returns 1 if true, 0 if false and -1 in case of error.
5419 */
5420static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005421xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5422 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005423{
5424 xmlNsPtr tst;
5425
5426 while ((node != NULL) && (node != ancestor)) {
5427 if ((node->type == XML_ENTITY_REF_NODE) ||
5428 (node->type == XML_ENTITY_NODE) ||
5429 (node->type == XML_ENTITY_DECL))
5430 return (-1);
5431 if (node->type == XML_ELEMENT_NODE) {
5432 tst = node->nsDef;
5433 while (tst != NULL) {
5434 if ((tst->prefix == NULL)
5435 && (prefix == NULL))
5436 return (0);
5437 if ((tst->prefix != NULL)
5438 && (prefix != NULL)
5439 && (xmlStrEqual(tst->prefix, prefix)))
5440 return (0);
5441 tst = tst->next;
5442 }
5443 }
5444 node = node->parent;
5445 }
5446 if (node != ancestor)
5447 return (-1);
5448 return (1);
5449}
5450
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005451/**
Owen Taylor3473f882001-02-23 17:55:21 +00005452 * xmlSearchNsByHref:
5453 * @doc: the document
5454 * @node: the current node
5455 * @href: the namespace value
5456 *
5457 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5458 * the defined namespace or return NULL otherwise.
5459 * Returns the namespace pointer or NULL.
5460 */
5461xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005462xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5463{
Owen Taylor3473f882001-02-23 17:55:21 +00005464 xmlNsPtr cur;
5465 xmlNodePtr orig = node;
5466
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005467 if ((node == NULL) || (href == NULL))
5468 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005469 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005470 /*
5471 * Only the document can hold the XML spec namespace.
5472 */
5473 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5474 /*
5475 * The XML-1.0 namespace is normally held on the root
5476 * element. In this case exceptionally create it on the
5477 * node element.
5478 */
5479 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5480 if (cur == 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(cur, 0, sizeof(xmlNs));
5485 cur->type = XML_LOCAL_NAMESPACE;
5486 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5487 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5488 cur->next = node->nsDef;
5489 node->nsDef = cur;
5490 return (cur);
5491 }
5492 if (doc->oldNs == NULL) {
5493 /*
5494 * Allocate a new Namespace and fill the fields.
5495 */
5496 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5497 if (doc->oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005498 xmlTreeErrMemory("searching namespace");
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005499 return (NULL);
5500 }
5501 memset(doc->oldNs, 0, sizeof(xmlNs));
5502 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005503
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005504 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5505 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5506 }
5507 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005508 }
5509 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005510 if ((node->type == XML_ENTITY_REF_NODE) ||
5511 (node->type == XML_ENTITY_NODE) ||
5512 (node->type == XML_ENTITY_DECL))
5513 return (NULL);
5514 if (node->type == XML_ELEMENT_NODE) {
5515 cur = node->nsDef;
5516 while (cur != NULL) {
5517 if ((cur->href != NULL) && (href != NULL) &&
5518 (xmlStrEqual(cur->href, href))) {
5519 if (xmlNsInScope(doc, orig, node, cur->href) == 1)
5520 return (cur);
5521 }
5522 cur = cur->next;
5523 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005524 if (orig != node) {
5525 cur = node->ns;
5526 if (cur != NULL) {
5527 if ((cur->href != NULL) && (href != NULL) &&
5528 (xmlStrEqual(cur->href, href))) {
5529 if (xmlNsInScope(doc, orig, node, cur->href) == 1)
5530 return (cur);
5531 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005532 }
Daniel Veillardf4e56292003-10-28 14:27:41 +00005533 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005534 }
5535 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005536 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005537 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005538}
5539
5540/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005541 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005542 * @doc: the document
5543 * @tree: a node expected to hold the new namespace
5544 * @ns: the original namespace
5545 *
5546 * This function tries to locate a namespace definition in a tree
5547 * ancestors, or create a new namespace definition node similar to
5548 * @ns trying to reuse the same prefix. However if the given prefix is
5549 * null (default namespace) or reused within the subtree defined by
5550 * @tree or on one of its ancestors then a new prefix is generated.
5551 * Returns the (new) namespace definition or NULL in case of error
5552 */
5553xmlNsPtr
5554xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5555 xmlNsPtr def;
5556 xmlChar prefix[50];
5557 int counter = 1;
5558
5559 if (tree == NULL) {
5560#ifdef DEBUG_TREE
5561 xmlGenericError(xmlGenericErrorContext,
5562 "xmlNewReconciliedNs : tree == NULL\n");
5563#endif
5564 return(NULL);
5565 }
5566 if (ns == NULL) {
5567#ifdef DEBUG_TREE
5568 xmlGenericError(xmlGenericErrorContext,
5569 "xmlNewReconciliedNs : ns == NULL\n");
5570#endif
5571 return(NULL);
5572 }
5573 /*
5574 * Search an existing namespace definition inherited.
5575 */
5576 def = xmlSearchNsByHref(doc, tree, ns->href);
5577 if (def != NULL)
5578 return(def);
5579
5580 /*
5581 * Find a close prefix which is not already in use.
5582 * Let's strip namespace prefixes longer than 20 chars !
5583 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005584 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005585 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005586 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005587 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005588
Owen Taylor3473f882001-02-23 17:55:21 +00005589 def = xmlSearchNs(doc, tree, prefix);
5590 while (def != NULL) {
5591 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005592 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005593 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005594 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005595 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005596 def = xmlSearchNs(doc, tree, prefix);
5597 }
5598
5599 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005600 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005601 */
5602 def = xmlNewNs(tree, ns->href, prefix);
5603 return(def);
5604}
5605
Daniel Veillard652327a2003-09-29 18:02:38 +00005606#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005607/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005608 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005609 * @doc: the document
5610 * @tree: a node defining the subtree to reconciliate
5611 *
5612 * This function checks that all the namespaces declared within the given
5613 * tree are properly declared. This is needed for example after Copy or Cut
5614 * and then paste operations. The subtree may still hold pointers to
5615 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005616 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005617 * the new environment. If not possible the new namespaces are redeclared
5618 * on @tree at the top of the given subtree.
5619 * Returns the number of namespace declarations created or -1 in case of error.
5620 */
5621int
5622xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5623 xmlNsPtr *oldNs = NULL;
5624 xmlNsPtr *newNs = NULL;
5625 int sizeCache = 0;
5626 int nbCache = 0;
5627
5628 xmlNsPtr n;
5629 xmlNodePtr node = tree;
5630 xmlAttrPtr attr;
5631 int ret = 0, i;
5632
5633 while (node != NULL) {
5634 /*
5635 * Reconciliate the node namespace
5636 */
5637 if (node->ns != NULL) {
5638 /*
5639 * initialize the cache if needed
5640 */
5641 if (sizeCache == 0) {
5642 sizeCache = 10;
5643 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5644 sizeof(xmlNsPtr));
5645 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005646 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005647 return(-1);
5648 }
5649 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5650 sizeof(xmlNsPtr));
5651 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005652 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005653 xmlFree(oldNs);
5654 return(-1);
5655 }
5656 }
5657 for (i = 0;i < nbCache;i++) {
5658 if (oldNs[i] == node->ns) {
5659 node->ns = newNs[i];
5660 break;
5661 }
5662 }
5663 if (i == nbCache) {
5664 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005665 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005666 */
5667 n = xmlNewReconciliedNs(doc, tree, node->ns);
5668 if (n != NULL) { /* :-( what if else ??? */
5669 /*
5670 * check if we need to grow the cache buffers.
5671 */
5672 if (sizeCache <= nbCache) {
5673 sizeCache *= 2;
5674 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5675 sizeof(xmlNsPtr));
5676 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005677 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005678 xmlFree(newNs);
5679 return(-1);
5680 }
5681 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5682 sizeof(xmlNsPtr));
5683 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005684 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005685 xmlFree(oldNs);
5686 return(-1);
5687 }
5688 }
5689 newNs[nbCache] = n;
5690 oldNs[nbCache++] = node->ns;
5691 node->ns = n;
5692 }
5693 }
5694 }
5695 /*
5696 * now check for namespace hold by attributes on the node.
5697 */
5698 attr = node->properties;
5699 while (attr != NULL) {
5700 if (attr->ns != NULL) {
5701 /*
5702 * initialize the cache if needed
5703 */
5704 if (sizeCache == 0) {
5705 sizeCache = 10;
5706 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5707 sizeof(xmlNsPtr));
5708 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005709 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005710 return(-1);
5711 }
5712 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5713 sizeof(xmlNsPtr));
5714 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005715 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005716 xmlFree(oldNs);
5717 return(-1);
5718 }
5719 }
5720 for (i = 0;i < nbCache;i++) {
5721 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005722 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005723 break;
5724 }
5725 }
5726 if (i == nbCache) {
5727 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005728 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005729 */
5730 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5731 if (n != NULL) { /* :-( what if else ??? */
5732 /*
5733 * check if we need to grow the cache buffers.
5734 */
5735 if (sizeCache <= nbCache) {
5736 sizeCache *= 2;
5737 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5738 sizeof(xmlNsPtr));
5739 if (oldNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005740 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005741 xmlFree(newNs);
5742 return(-1);
5743 }
5744 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5745 sizeof(xmlNsPtr));
5746 if (newNs == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00005747 xmlTreeErrMemory("fixing namespaces");
Owen Taylor3473f882001-02-23 17:55:21 +00005748 xmlFree(oldNs);
5749 return(-1);
5750 }
5751 }
5752 newNs[nbCache] = n;
5753 oldNs[nbCache++] = attr->ns;
5754 attr->ns = n;
5755 }
5756 }
5757 }
5758 attr = attr->next;
5759 }
5760
5761 /*
5762 * Browse the full subtree, deep first
5763 */
5764 if (node->children != NULL) {
5765 /* deep first */
5766 node = node->children;
5767 } else if ((node != tree) && (node->next != NULL)) {
5768 /* then siblings */
5769 node = node->next;
5770 } else if (node != tree) {
5771 /* go up to parents->next if needed */
5772 while (node != tree) {
5773 if (node->parent != NULL)
5774 node = node->parent;
5775 if ((node != tree) && (node->next != NULL)) {
5776 node = node->next;
5777 break;
5778 }
5779 if (node->parent == NULL) {
5780 node = NULL;
5781 break;
5782 }
5783 }
5784 /* exit condition */
5785 if (node == tree)
5786 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005787 } else
5788 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005789 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005790 if (oldNs != NULL)
5791 xmlFree(oldNs);
5792 if (newNs != NULL)
5793 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005794 return(ret);
5795}
Daniel Veillard652327a2003-09-29 18:02:38 +00005796#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005797
5798/**
5799 * xmlHasProp:
5800 * @node: the node
5801 * @name: the attribute name
5802 *
5803 * Search an attribute associated to a node
5804 * This function also looks in DTD attribute declaration for #FIXED or
5805 * default declaration values unless DTD use has been turned off.
5806 *
5807 * Returns the attribute or the attribute declaration or NULL if
5808 * neither was found.
5809 */
5810xmlAttrPtr
5811xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5812 xmlAttrPtr prop;
5813 xmlDocPtr doc;
5814
5815 if ((node == NULL) || (name == NULL)) return(NULL);
5816 /*
5817 * Check on the properties attached to the node
5818 */
5819 prop = node->properties;
5820 while (prop != NULL) {
5821 if (xmlStrEqual(prop->name, name)) {
5822 return(prop);
5823 }
5824 prop = prop->next;
5825 }
5826 if (!xmlCheckDTD) return(NULL);
5827
5828 /*
5829 * Check if there is a default declaration in the internal
5830 * or external subsets
5831 */
5832 doc = node->doc;
5833 if (doc != NULL) {
5834 xmlAttributePtr attrDecl;
5835 if (doc->intSubset != NULL) {
5836 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5837 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5838 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005839 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5840 /* return attribute declaration only if a default value is given
5841 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005842 return((xmlAttrPtr) attrDecl);
5843 }
5844 }
5845 return(NULL);
5846}
5847
5848/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005849 * xmlHasNsProp:
5850 * @node: the node
5851 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005852 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005853 *
5854 * Search for an attribute associated to a node
5855 * This attribute has to be anchored in the namespace specified.
5856 * This does the entity substitution.
5857 * This function looks in DTD attribute declaration for #FIXED or
5858 * default declaration values unless DTD use has been turned off.
5859 *
5860 * Returns the attribute or the attribute declaration or NULL
5861 * if neither was found.
5862 */
5863xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005864xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005865 xmlAttrPtr prop;
Daniel Veillard652327a2003-09-29 18:02:38 +00005866#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005867 xmlDocPtr doc;
Daniel Veillard652327a2003-09-29 18:02:38 +00005868#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005869
5870 if (node == NULL)
5871 return(NULL);
5872
5873 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005874 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005875 return(xmlHasProp(node, name));
5876 while (prop != NULL) {
5877 /*
5878 * One need to have
5879 * - same attribute names
5880 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005881 */
5882 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005883 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5884 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005885 }
5886 prop = prop->next;
5887 }
5888 if (!xmlCheckDTD) return(NULL);
5889
Daniel Veillard652327a2003-09-29 18:02:38 +00005890#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005891 /*
5892 * Check if there is a default declaration in the internal
5893 * or external subsets
5894 */
5895 doc = node->doc;
5896 if (doc != NULL) {
5897 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005898 xmlAttributePtr attrDecl = NULL;
5899 xmlNsPtr *nsList, *cur;
5900 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005901
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005902 nsList = xmlGetNsList(node->doc, node);
5903 if (nsList == NULL)
5904 return(NULL);
5905 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5906 ename = xmlStrdup(node->ns->prefix);
5907 ename = xmlStrcat(ename, BAD_CAST ":");
5908 ename = xmlStrcat(ename, node->name);
5909 } else {
5910 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005911 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005912 if (ename == NULL) {
5913 xmlFree(nsList);
5914 return(NULL);
5915 }
5916
5917 cur = nsList;
5918 while (*cur != NULL) {
5919 if (xmlStrEqual((*cur)->href, nameSpace)) {
5920 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5921 name, (*cur)->prefix);
5922 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5923 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5924 name, (*cur)->prefix);
5925 }
5926 cur++;
5927 }
5928 xmlFree(nsList);
5929 xmlFree(ename);
5930 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005931 }
5932 }
Daniel Veillard652327a2003-09-29 18:02:38 +00005933#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005934 return(NULL);
5935}
5936
5937/**
Owen Taylor3473f882001-02-23 17:55:21 +00005938 * xmlGetProp:
5939 * @node: the node
5940 * @name: the attribute name
5941 *
5942 * Search and get the value of an attribute associated to a node
5943 * This does the entity substitution.
5944 * This function looks in DTD attribute declaration for #FIXED or
5945 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00005946 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00005947 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
5948 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00005949 *
5950 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005951 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005952 */
5953xmlChar *
5954xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5955 xmlAttrPtr prop;
5956 xmlDocPtr doc;
5957
5958 if ((node == NULL) || (name == NULL)) return(NULL);
5959 /*
5960 * Check on the properties attached to the node
5961 */
5962 prop = node->properties;
5963 while (prop != NULL) {
5964 if (xmlStrEqual(prop->name, name)) {
5965 xmlChar *ret;
5966
5967 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5968 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5969 return(ret);
5970 }
5971 prop = prop->next;
5972 }
5973 if (!xmlCheckDTD) return(NULL);
5974
5975 /*
5976 * Check if there is a default declaration in the internal
5977 * or external subsets
5978 */
5979 doc = node->doc;
5980 if (doc != NULL) {
5981 xmlAttributePtr attrDecl;
5982 if (doc->intSubset != NULL) {
5983 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5984 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5985 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005986 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5987 /* return attribute declaration only if a default value is given
5988 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005989 return(xmlStrdup(attrDecl->defaultValue));
5990 }
5991 }
5992 return(NULL);
5993}
5994
5995/**
Daniel Veillard71531f32003-02-05 13:19:53 +00005996 * xmlGetNoNsProp:
5997 * @node: the node
5998 * @name: the attribute name
5999 *
6000 * Search and get the value of an attribute associated to a node
6001 * This does the entity substitution.
6002 * This function looks in DTD attribute declaration for #FIXED or
6003 * default declaration values unless DTD use has been turned off.
6004 * This function is similar to xmlGetProp except it will accept only
6005 * an attribute in no namespace.
6006 *
6007 * Returns the attribute value or NULL if not found.
6008 * It's up to the caller to free the memory with xmlFree().
6009 */
6010xmlChar *
6011xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
6012 xmlAttrPtr prop;
6013 xmlDocPtr doc;
6014
6015 if ((node == NULL) || (name == NULL)) return(NULL);
6016 /*
6017 * Check on the properties attached to the node
6018 */
6019 prop = node->properties;
6020 while (prop != NULL) {
6021 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
6022 xmlChar *ret;
6023
6024 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6025 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6026 return(ret);
6027 }
6028 prop = prop->next;
6029 }
6030 if (!xmlCheckDTD) return(NULL);
6031
6032 /*
6033 * Check if there is a default declaration in the internal
6034 * or external subsets
6035 */
6036 doc = node->doc;
6037 if (doc != NULL) {
6038 xmlAttributePtr attrDecl;
6039 if (doc->intSubset != NULL) {
6040 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6041 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6042 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00006043 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6044 /* return attribute declaration only if a default value is given
6045 (that includes #FIXED declarations) */
Daniel Veillard71531f32003-02-05 13:19:53 +00006046 return(xmlStrdup(attrDecl->defaultValue));
6047 }
6048 }
6049 return(NULL);
6050}
6051
6052/**
Owen Taylor3473f882001-02-23 17:55:21 +00006053 * xmlGetNsProp:
6054 * @node: the node
6055 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00006056 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006057 *
6058 * Search and get the value of an attribute associated to a node
6059 * This attribute has to be anchored in the namespace specified.
6060 * This does the entity substitution.
6061 * This function looks in DTD attribute declaration for #FIXED or
6062 * default declaration values unless DTD use has been turned off.
6063 *
6064 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006065 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00006066 */
6067xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00006068xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00006069 xmlAttrPtr prop;
6070 xmlDocPtr doc;
6071 xmlNsPtr ns;
6072
6073 if (node == NULL)
6074 return(NULL);
6075
6076 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00006077 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00006078 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00006079 while (prop != NULL) {
6080 /*
6081 * One need to have
6082 * - same attribute names
6083 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006084 */
6085 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00006086 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00006087 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006088 xmlChar *ret;
6089
6090 ret = xmlNodeListGetString(node->doc, prop->children, 1);
6091 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
6092 return(ret);
6093 }
6094 prop = prop->next;
6095 }
6096 if (!xmlCheckDTD) return(NULL);
6097
6098 /*
6099 * Check if there is a default declaration in the internal
6100 * or external subsets
6101 */
6102 doc = node->doc;
6103 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006104 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00006105 xmlAttributePtr attrDecl;
6106
Owen Taylor3473f882001-02-23 17:55:21 +00006107 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6108 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6109 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
6110
6111 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
6112 /*
6113 * The DTD declaration only allows a prefix search
6114 */
6115 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00006116 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00006117 return(xmlStrdup(attrDecl->defaultValue));
6118 }
6119 }
6120 }
6121 return(NULL);
6122}
6123
Daniel Veillard652327a2003-09-29 18:02:38 +00006124#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00006125/**
6126 * xmlSetProp:
6127 * @node: the node
6128 * @name: the attribute name
6129 * @value: the attribute value
6130 *
6131 * Set (or reset) an attribute carried by a node.
6132 * Returns the attribute pointer.
6133 */
6134xmlAttrPtr
6135xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006136 xmlAttrPtr prop;
6137 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00006138
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006139 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006140 return(NULL);
6141 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006142 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00006143 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006144 if ((xmlStrEqual(prop->name, name)) &&
6145 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006146 xmlNodePtr oldprop = prop->children;
6147
Owen Taylor3473f882001-02-23 17:55:21 +00006148 prop->children = NULL;
6149 prop->last = NULL;
6150 if (value != NULL) {
6151 xmlChar *buffer;
6152 xmlNodePtr tmp;
6153
6154 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6155 prop->children = xmlStringGetNodeList(node->doc, buffer);
6156 prop->last = NULL;
6157 prop->doc = doc;
6158 tmp = prop->children;
6159 while (tmp != NULL) {
6160 tmp->parent = (xmlNodePtr) prop;
6161 tmp->doc = doc;
6162 if (tmp->next == NULL)
6163 prop->last = tmp;
6164 tmp = tmp->next;
6165 }
6166 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00006167 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006168 if (oldprop != NULL)
6169 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00006170 return(prop);
6171 }
6172 prop = prop->next;
6173 }
6174 prop = xmlNewProp(node, name, value);
6175 return(prop);
6176}
6177
6178/**
Daniel Veillard75bea542001-05-11 17:41:21 +00006179 * xmlUnsetProp:
6180 * @node: the node
6181 * @name: the attribute name
6182 *
6183 * Remove an attribute carried by a node.
6184 * Returns 0 if successful, -1 if not found
6185 */
6186int
6187xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Daniel Veillard814a76d2003-01-23 18:24:20 +00006188 xmlAttrPtr prop, prev = NULL;;
Daniel Veillard75bea542001-05-11 17:41:21 +00006189
6190 if ((node == NULL) || (name == NULL))
6191 return(-1);
Daniel Veillard814a76d2003-01-23 18:24:20 +00006192 prop = node->properties;
Daniel Veillard75bea542001-05-11 17:41:21 +00006193 while (prop != NULL) {
6194 if ((xmlStrEqual(prop->name, name)) &&
6195 (prop->ns == NULL)) {
6196 if (prev == NULL)
6197 node->properties = prop->next;
6198 else
6199 prev->next = prop->next;
6200 xmlFreeProp(prop);
6201 return(0);
6202 }
6203 prev = prop;
6204 prop = prop->next;
6205 }
6206 return(-1);
6207}
6208
6209/**
Owen Taylor3473f882001-02-23 17:55:21 +00006210 * xmlSetNsProp:
6211 * @node: the node
6212 * @ns: the namespace definition
6213 * @name: the attribute name
6214 * @value: the attribute value
6215 *
6216 * Set (or reset) an attribute carried by a node.
6217 * The ns structure must be in scope, this is not checked.
6218 *
6219 * Returns the attribute pointer.
6220 */
6221xmlAttrPtr
6222xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
6223 const xmlChar *value) {
6224 xmlAttrPtr prop;
6225
6226 if ((node == NULL) || (name == NULL))
6227 return(NULL);
6228
6229 if (ns == NULL)
6230 return(xmlSetProp(node, name, value));
6231 if (ns->href == NULL)
6232 return(NULL);
6233 prop = node->properties;
6234
6235 while (prop != NULL) {
6236 /*
6237 * One need to have
6238 * - same attribute names
6239 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006240 */
6241 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00006242 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006243 if (prop->children != NULL)
6244 xmlFreeNodeList(prop->children);
6245 prop->children = NULL;
6246 prop->last = NULL;
6247 prop->ns = ns;
6248 if (value != NULL) {
6249 xmlChar *buffer;
6250 xmlNodePtr tmp;
6251
6252 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6253 prop->children = xmlStringGetNodeList(node->doc, buffer);
6254 prop->last = NULL;
6255 tmp = prop->children;
6256 while (tmp != NULL) {
6257 tmp->parent = (xmlNodePtr) prop;
6258 if (tmp->next == NULL)
6259 prop->last = tmp;
6260 tmp = tmp->next;
6261 }
6262 xmlFree(buffer);
6263 }
6264 return(prop);
6265 }
6266 prop = prop->next;
6267 }
6268 prop = xmlNewNsProp(node, ns, name, value);
6269 return(prop);
6270}
6271
6272/**
Daniel Veillard75bea542001-05-11 17:41:21 +00006273 * xmlUnsetNsProp:
6274 * @node: the node
6275 * @ns: the namespace definition
6276 * @name: the attribute name
6277 *
6278 * Remove an attribute carried by a node.
6279 * Returns 0 if successful, -1 if not found
6280 */
6281int
6282xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
6283 xmlAttrPtr prop = node->properties, prev = NULL;;
6284
6285 if ((node == NULL) || (name == NULL))
6286 return(-1);
6287 if (ns == NULL)
6288 return(xmlUnsetProp(node, name));
6289 if (ns->href == NULL)
6290 return(-1);
6291 while (prop != NULL) {
6292 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00006293 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006294 if (prev == NULL)
6295 node->properties = prop->next;
6296 else
6297 prev->next = prop->next;
6298 xmlFreeProp(prop);
6299 return(0);
6300 }
6301 prev = prop;
6302 prop = prop->next;
6303 }
6304 return(-1);
6305}
Daniel Veillard652327a2003-09-29 18:02:38 +00006306#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006307
6308/**
Owen Taylor3473f882001-02-23 17:55:21 +00006309 * xmlNodeIsText:
6310 * @node: the node
6311 *
6312 * Is this node a Text node ?
6313 * Returns 1 yes, 0 no
6314 */
6315int
6316xmlNodeIsText(xmlNodePtr node) {
6317 if (node == NULL) return(0);
6318
6319 if (node->type == XML_TEXT_NODE) return(1);
6320 return(0);
6321}
6322
6323/**
6324 * xmlIsBlankNode:
6325 * @node: the node
6326 *
6327 * Checks whether this node is an empty or whitespace only
6328 * (and possibly ignorable) text-node.
6329 *
6330 * Returns 1 yes, 0 no
6331 */
6332int
6333xmlIsBlankNode(xmlNodePtr node) {
6334 const xmlChar *cur;
6335 if (node == NULL) return(0);
6336
Daniel Veillard7db37732001-07-12 01:20:08 +00006337 if ((node->type != XML_TEXT_NODE) &&
6338 (node->type != XML_CDATA_SECTION_NODE))
6339 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006340 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006341 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006342 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006343 if (!IS_BLANK_CH(*cur)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006344 cur++;
6345 }
6346
6347 return(1);
6348}
6349
6350/**
6351 * xmlTextConcat:
6352 * @node: the node
6353 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006354 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006355 *
6356 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006357 *
6358 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006359 */
6360
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006361int
Owen Taylor3473f882001-02-23 17:55:21 +00006362xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006363 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006364
6365 if ((node->type != XML_TEXT_NODE) &&
6366 (node->type != XML_CDATA_SECTION_NODE)) {
6367#ifdef DEBUG_TREE
6368 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006369 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006370#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006371 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006372 }
William M. Brack7762bb12004-01-04 14:49:01 +00006373 /* need to check if content is currently in the dictionary */
6374 if ((node->doc != NULL) && (node->doc->dict != NULL) &&
6375 xmlDictOwns(node->doc->dict, node->content)) {
6376 node->content = xmlStrncatNew(node->content, content, len);
6377 } else {
6378 node->content = xmlStrncat(node->content, content, len);
6379 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006380 if (node->content == NULL)
6381 return(-1);
6382 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006383}
6384
6385/************************************************************************
6386 * *
6387 * Output : to a FILE or in memory *
6388 * *
6389 ************************************************************************/
6390
Owen Taylor3473f882001-02-23 17:55:21 +00006391/**
6392 * xmlBufferCreate:
6393 *
6394 * routine to create an XML buffer.
6395 * returns the new structure.
6396 */
6397xmlBufferPtr
6398xmlBufferCreate(void) {
6399 xmlBufferPtr ret;
6400
6401 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6402 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006403 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006404 return(NULL);
6405 }
6406 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006407 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006408 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006409 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006410 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006411 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006412 xmlFree(ret);
6413 return(NULL);
6414 }
6415 ret->content[0] = 0;
6416 return(ret);
6417}
6418
6419/**
6420 * xmlBufferCreateSize:
6421 * @size: initial size of buffer
6422 *
6423 * routine to create an XML buffer.
6424 * returns the new structure.
6425 */
6426xmlBufferPtr
6427xmlBufferCreateSize(size_t size) {
6428 xmlBufferPtr ret;
6429
6430 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6431 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006432 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006433 return(NULL);
6434 }
6435 ret->use = 0;
6436 ret->alloc = xmlBufferAllocScheme;
6437 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6438 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006439 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006440 if (ret->content == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006441 xmlTreeErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006442 xmlFree(ret);
6443 return(NULL);
6444 }
6445 ret->content[0] = 0;
6446 } else
6447 ret->content = NULL;
6448 return(ret);
6449}
6450
6451/**
Daniel Veillard53350552003-09-18 13:35:51 +00006452 * xmlBufferCreateStatic:
6453 * @mem: the memory area
6454 * @size: the size in byte
6455 *
MST 2003 John Flecka0e7e932003-12-19 03:13:47 +00006456 * routine to create an XML buffer from an immutable memory area.
6457 * The area won't be modified nor copied, and is expected to be
Daniel Veillard53350552003-09-18 13:35:51 +00006458 * present until the end of the buffer lifetime.
6459 *
6460 * returns the new structure.
6461 */
6462xmlBufferPtr
6463xmlBufferCreateStatic(void *mem, size_t size) {
6464 xmlBufferPtr ret;
6465
6466 if ((mem == NULL) || (size == 0))
6467 return(NULL);
6468
6469 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6470 if (ret == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006471 xmlTreeErrMemory("creating buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00006472 return(NULL);
6473 }
6474 ret->use = size;
6475 ret->size = size;
6476 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6477 ret->content = (xmlChar *) mem;
6478 return(ret);
6479}
6480
6481/**
Owen Taylor3473f882001-02-23 17:55:21 +00006482 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006483 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006484 * @scheme: allocation scheme to use
6485 *
6486 * Sets the allocation scheme for this buffer
6487 */
6488void
6489xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6490 xmlBufferAllocationScheme scheme) {
6491 if (buf == NULL) {
6492#ifdef DEBUG_BUFFER
6493 xmlGenericError(xmlGenericErrorContext,
6494 "xmlBufferSetAllocationScheme: buf == NULL\n");
6495#endif
6496 return;
6497 }
Daniel Veillard53350552003-09-18 13:35:51 +00006498 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006499
6500 buf->alloc = scheme;
6501}
6502
6503/**
6504 * xmlBufferFree:
6505 * @buf: the buffer to free
6506 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006507 * Frees an XML buffer. It frees both the content and the structure which
6508 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006509 */
6510void
6511xmlBufferFree(xmlBufferPtr buf) {
6512 if (buf == NULL) {
6513#ifdef DEBUG_BUFFER
6514 xmlGenericError(xmlGenericErrorContext,
6515 "xmlBufferFree: buf == NULL\n");
6516#endif
6517 return;
6518 }
Daniel Veillard53350552003-09-18 13:35:51 +00006519
6520 if ((buf->content != NULL) &&
6521 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006522 xmlFree(buf->content);
6523 }
Owen Taylor3473f882001-02-23 17:55:21 +00006524 xmlFree(buf);
6525}
6526
6527/**
6528 * xmlBufferEmpty:
6529 * @buf: the buffer
6530 *
6531 * empty a buffer.
6532 */
6533void
6534xmlBufferEmpty(xmlBufferPtr buf) {
6535 if (buf->content == NULL) return;
6536 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006537 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00006538 buf->content = BAD_CAST "";
Daniel Veillard53350552003-09-18 13:35:51 +00006539 } else {
6540 memset(buf->content, 0, buf->size);
6541 }
Owen Taylor3473f882001-02-23 17:55:21 +00006542}
6543
6544/**
6545 * xmlBufferShrink:
6546 * @buf: the buffer to dump
6547 * @len: the number of xmlChar to remove
6548 *
6549 * Remove the beginning of an XML buffer.
6550 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006551 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006552 */
6553int
6554xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
6555 if (len == 0) return(0);
6556 if (len > buf->use) return(-1);
6557
6558 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006559 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6560 buf->content += len;
6561 } else {
6562 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6563 buf->content[buf->use] = 0;
6564 }
Owen Taylor3473f882001-02-23 17:55:21 +00006565 return(len);
6566}
6567
6568/**
6569 * xmlBufferGrow:
6570 * @buf: the buffer
6571 * @len: the minimum free size to allocate
6572 *
6573 * Grow the available space of an XML buffer.
6574 *
6575 * Returns the new available space or -1 in case of error
6576 */
6577int
6578xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6579 int size;
6580 xmlChar *newbuf;
6581
Daniel Veillard53350552003-09-18 13:35:51 +00006582 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006583 if (len + buf->use < buf->size) return(0);
6584
6585 size = buf->use + len + 100;
6586
6587 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006588 if (newbuf == NULL) {
6589 xmlTreeErrMemory("growing buffer");
6590 return(-1);
6591 }
Owen Taylor3473f882001-02-23 17:55:21 +00006592 buf->content = newbuf;
6593 buf->size = size;
6594 return(buf->size - buf->use);
6595}
6596
6597/**
6598 * xmlBufferDump:
6599 * @file: the file output
6600 * @buf: the buffer to dump
6601 *
6602 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006603 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006604 */
6605int
6606xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6607 int ret;
6608
6609 if (buf == NULL) {
6610#ifdef DEBUG_BUFFER
6611 xmlGenericError(xmlGenericErrorContext,
6612 "xmlBufferDump: buf == NULL\n");
6613#endif
6614 return(0);
6615 }
6616 if (buf->content == NULL) {
6617#ifdef DEBUG_BUFFER
6618 xmlGenericError(xmlGenericErrorContext,
6619 "xmlBufferDump: buf->content == NULL\n");
6620#endif
6621 return(0);
6622 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006623 if (file == NULL)
6624 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006625 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6626 return(ret);
6627}
6628
6629/**
6630 * xmlBufferContent:
6631 * @buf: the buffer
6632 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006633 * Function to extract the content of a buffer
6634 *
Owen Taylor3473f882001-02-23 17:55:21 +00006635 * Returns the internal content
6636 */
6637
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006638const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006639xmlBufferContent(const xmlBufferPtr buf)
6640{
6641 if(!buf)
6642 return NULL;
6643
6644 return buf->content;
6645}
6646
6647/**
6648 * xmlBufferLength:
6649 * @buf: the buffer
6650 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006651 * Function to get the length of a buffer
6652 *
Owen Taylor3473f882001-02-23 17:55:21 +00006653 * Returns the length of data in the internal content
6654 */
6655
6656int
6657xmlBufferLength(const xmlBufferPtr buf)
6658{
6659 if(!buf)
6660 return 0;
6661
6662 return buf->use;
6663}
6664
6665/**
6666 * xmlBufferResize:
6667 * @buf: the buffer to resize
6668 * @size: the desired size
6669 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006670 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006671 *
6672 * Returns 0 in case of problems, 1 otherwise
6673 */
6674int
6675xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6676{
6677 unsigned int newSize;
6678 xmlChar* rebuf = NULL;
6679
Daniel Veillard53350552003-09-18 13:35:51 +00006680 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6681
Owen Taylor3473f882001-02-23 17:55:21 +00006682 /*take care of empty case*/
6683 newSize = (buf->size ? buf->size*2 : size);
6684
6685 /* Don't resize if we don't have to */
6686 if (size < buf->size)
6687 return 1;
6688
6689 /* figure out new size */
6690 switch (buf->alloc){
6691 case XML_BUFFER_ALLOC_DOUBLEIT:
6692 while (size > newSize) newSize *= 2;
6693 break;
6694 case XML_BUFFER_ALLOC_EXACT:
6695 newSize = size+10;
6696 break;
6697 default:
6698 newSize = size+10;
6699 break;
6700 }
6701
6702 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006703 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006704 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006705 rebuf = (xmlChar *) xmlRealloc(buf->content,
6706 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006707 } else {
6708 /*
6709 * if we are reallocating a buffer far from being full, it's
6710 * better to make a new allocation and copy only the used range
6711 * and free the old one.
6712 */
6713 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6714 if (rebuf != NULL) {
6715 memcpy(rebuf, buf->content, buf->use);
6716 xmlFree(buf->content);
6717 }
Daniel Veillarde5984082003-08-19 22:21:13 +00006718 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006719 }
Owen Taylor3473f882001-02-23 17:55:21 +00006720 if (rebuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006721 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006722 return 0;
6723 }
6724 buf->content = rebuf;
6725 buf->size = newSize;
6726
6727 return 1;
6728}
6729
6730/**
6731 * xmlBufferAdd:
6732 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006733 * @str: the #xmlChar string
6734 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006735 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006736 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006737 * str is recomputed.
6738 */
6739void
6740xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6741 unsigned int needSize;
6742
6743 if (str == NULL) {
6744#ifdef DEBUG_BUFFER
6745 xmlGenericError(xmlGenericErrorContext,
6746 "xmlBufferAdd: str == NULL\n");
6747#endif
6748 return;
6749 }
Daniel Veillard53350552003-09-18 13:35:51 +00006750 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006751 if (len < -1) {
6752#ifdef DEBUG_BUFFER
6753 xmlGenericError(xmlGenericErrorContext,
6754 "xmlBufferAdd: len < 0\n");
6755#endif
6756 return;
6757 }
6758 if (len == 0) return;
6759
6760 if (len < 0)
6761 len = xmlStrlen(str);
6762
6763 if (len <= 0) return;
6764
6765 needSize = buf->use + len + 2;
6766 if (needSize > buf->size){
6767 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006768 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006769 return;
6770 }
6771 }
6772
6773 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6774 buf->use += len;
6775 buf->content[buf->use] = 0;
6776}
6777
6778/**
6779 * xmlBufferAddHead:
6780 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006781 * @str: the #xmlChar string
6782 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006783 *
6784 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006785 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00006786 */
6787void
6788xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6789 unsigned int needSize;
6790
Daniel Veillard53350552003-09-18 13:35:51 +00006791 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006792 if (str == NULL) {
6793#ifdef DEBUG_BUFFER
6794 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006795 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006796#endif
6797 return;
6798 }
6799 if (len < -1) {
6800#ifdef DEBUG_BUFFER
6801 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006802 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006803#endif
6804 return;
6805 }
6806 if (len == 0) return;
6807
6808 if (len < 0)
6809 len = xmlStrlen(str);
6810
6811 if (len <= 0) return;
6812
6813 needSize = buf->use + len + 2;
6814 if (needSize > buf->size){
6815 if (!xmlBufferResize(buf, needSize)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006816 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006817 return;
6818 }
6819 }
6820
6821 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6822 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6823 buf->use += len;
6824 buf->content[buf->use] = 0;
6825}
6826
6827/**
6828 * xmlBufferCat:
6829 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006830 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006831 *
6832 * Append a zero terminated string to an XML buffer.
6833 */
6834void
6835xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillard53350552003-09-18 13:35:51 +00006836 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006837 if (str != NULL)
6838 xmlBufferAdd(buf, str, -1);
6839}
6840
6841/**
6842 * xmlBufferCCat:
6843 * @buf: the buffer to dump
6844 * @str: the C char string
6845 *
6846 * Append a zero terminated C string to an XML buffer.
6847 */
6848void
6849xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6850 const char *cur;
6851
Daniel Veillard53350552003-09-18 13:35:51 +00006852 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006853 if (str == NULL) {
6854#ifdef DEBUG_BUFFER
6855 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006856 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006857#endif
6858 return;
6859 }
6860 for (cur = str;*cur != 0;cur++) {
6861 if (buf->use + 10 >= buf->size) {
6862 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006863 xmlTreeErrMemory("growing buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00006864 return;
6865 }
6866 }
6867 buf->content[buf->use++] = *cur;
6868 }
6869 buf->content[buf->use] = 0;
6870}
6871
6872/**
6873 * xmlBufferWriteCHAR:
6874 * @buf: the XML buffer
6875 * @string: the string to add
6876 *
6877 * routine which manages and grows an output buffer. This one adds
6878 * xmlChars at the end of the buffer.
6879 */
6880void
Daniel Veillard53350552003-09-18 13:35:51 +00006881xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
6882 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006883 xmlBufferCat(buf, string);
6884}
6885
6886/**
6887 * xmlBufferWriteChar:
6888 * @buf: the XML buffer output
6889 * @string: the string to add
6890 *
6891 * routine which manage and grows an output buffer. This one add
6892 * C chars at the end of the array.
6893 */
6894void
6895xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillard53350552003-09-18 13:35:51 +00006896 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006897 xmlBufferCCat(buf, string);
6898}
6899
6900
6901/**
6902 * xmlBufferWriteQuotedString:
6903 * @buf: the XML buffer output
6904 * @string: the string to add
6905 *
6906 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00006907 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00006908 * quote or double-quotes internally
6909 */
6910void
6911xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00006912 const xmlChar *cur, *base;
Daniel Veillard53350552003-09-18 13:35:51 +00006913 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00006914 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00006915 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00006916#ifdef DEBUG_BUFFER
6917 xmlGenericError(xmlGenericErrorContext,
6918 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
6919#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00006920 xmlBufferCCat(buf, "\"");
6921 base = cur = string;
6922 while(*cur != 0){
6923 if(*cur == '"'){
6924 if (base != cur)
6925 xmlBufferAdd(buf, base, cur - base);
6926 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6927 cur++;
6928 base = cur;
6929 }
6930 else {
6931 cur++;
6932 }
6933 }
6934 if (base != cur)
6935 xmlBufferAdd(buf, base, cur - base);
6936 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006937 }
Daniel Veillard39057f42003-08-04 01:33:43 +00006938 else{
6939 xmlBufferCCat(buf, "\'");
6940 xmlBufferCat(buf, string);
6941 xmlBufferCCat(buf, "\'");
6942 }
Owen Taylor3473f882001-02-23 17:55:21 +00006943 } else {
6944 xmlBufferCCat(buf, "\"");
6945 xmlBufferCat(buf, string);
6946 xmlBufferCCat(buf, "\"");
6947 }
6948}
6949
6950
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00006951#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00006952/************************************************************************
6953 * *
Daniel Veillarde2238d52003-10-09 13:14:55 +00006954 * Output error handlers *
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006955 * *
6956 ************************************************************************/
6957/**
6958 * xmlSaveErrMemory:
6959 * @extra: extra informations
6960 *
6961 * Handle an out of memory condition
6962 */
6963static void
6964xmlSaveErrMemory(const char *extra)
6965{
6966 __xmlSimpleError(XML_FROM_OUTPUT, XML_ERR_NO_MEMORY, NULL, NULL, extra);
6967}
6968
6969/**
6970 * xmlSaveErr:
6971 * @code: the error number
6972 * @node: the location of the error.
6973 * @extra: extra informations
6974 *
6975 * Handle an out of memory condition
6976 */
6977static void
6978xmlSaveErr(int code, xmlNodePtr node, const char *extra)
6979{
6980 const char *msg = NULL;
6981
6982 switch(code) {
6983 case XML_SAVE_NOT_UTF8:
6984 msg = "string is not in UTF-8";
6985 break;
6986 case XML_SAVE_CHAR_INVALID:
6987 msg = "invalid character value";
6988 break;
6989 case XML_SAVE_UNKNOWN_ENCODING:
6990 msg = "unknown encoding %s";
6991 break;
Daniel Veillarde2238d52003-10-09 13:14:55 +00006992 case XML_SAVE_NO_DOCTYPE:
6993 msg = "document has no DOCTYPE";
6994 break;
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006995 default:
6996 msg = "unexpected error number";
6997 }
Daniel Veillarde2238d52003-10-09 13:14:55 +00006998 __xmlSimpleError(XML_FROM_OUTPUT, code, node, msg, extra);
Daniel Veillard18ec16e2003-10-07 23:16:40 +00006999}
7000/************************************************************************
7001 * *
Owen Taylor3473f882001-02-23 17:55:21 +00007002 * Dumping XML tree content to a simple buffer *
7003 * *
7004 ************************************************************************/
7005
Owen Taylor3473f882001-02-23 17:55:21 +00007006/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00007007 * xmlAttrSerializeContent:
7008 * @buf: the XML buffer output
7009 * @doc: the document
7010 * @attr: the attribute pointer
7011 *
7012 * Serialize the attribute in the buffer
7013 */
7014static void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007015xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr)
7016{
Daniel Veillarda6d05382002-02-13 13:07:41 +00007017 const xmlChar *cur, *base;
7018 xmlNodePtr children;
7019
7020 children = attr->children;
7021 while (children != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007022 switch (children->type) {
7023 case XML_TEXT_NODE:
7024 base = cur = children->content;
7025 while (*cur != 0) {
7026 if (*cur == '\n') {
7027 if (base != cur)
7028 xmlBufferAdd(buf, base, cur - base);
7029 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
7030 cur++;
7031 base = cur;
Daniel Veillard0046c0f2003-02-23 13:52:30 +00007032 } else if (*cur == '\r') {
7033 if (base != cur)
7034 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00007035 xmlBufferAdd(buf, BAD_CAST "&#13;", 5);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00007036 cur++;
7037 base = cur;
7038 } else if (*cur == '\t') {
7039 if (base != cur)
7040 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00007041 xmlBufferAdd(buf, BAD_CAST "&#9;", 4);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00007042 cur++;
7043 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00007044#if 0
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007045 } else if (*cur == '\'') {
7046 if (base != cur)
7047 xmlBufferAdd(buf, base, cur - base);
7048 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
7049 cur++;
7050 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00007051#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007052 } else if (*cur == '"') {
7053 if (base != cur)
7054 xmlBufferAdd(buf, base, cur - base);
7055 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7056 cur++;
7057 base = cur;
7058 } else if (*cur == '<') {
7059 if (base != cur)
7060 xmlBufferAdd(buf, base, cur - base);
7061 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
7062 cur++;
7063 base = cur;
7064 } else if (*cur == '>') {
7065 if (base != cur)
7066 xmlBufferAdd(buf, base, cur - base);
7067 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
7068 cur++;
7069 base = cur;
7070 } else if (*cur == '&') {
7071 if (base != cur)
7072 xmlBufferAdd(buf, base, cur - base);
7073 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
7074 cur++;
7075 base = cur;
7076 } else if ((*cur >= 0x80) && ((doc == NULL) ||
7077 (doc->encoding ==
7078 NULL))) {
7079 /*
7080 * We assume we have UTF-8 content.
7081 */
7082 char tmp[10];
7083 int val = 0, l = 1;
Daniel Veillarda6d05382002-02-13 13:07:41 +00007084
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007085 if (base != cur)
7086 xmlBufferAdd(buf, base, cur - base);
7087 if (*cur < 0xC0) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007088 xmlSaveErr(XML_SAVE_NOT_UTF8, (xmlNodePtr) attr,
7089 NULL);
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007090 if (doc != NULL)
7091 doc->encoding =
7092 xmlStrdup(BAD_CAST "ISO-8859-1");
7093 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
7094 tmp[sizeof(tmp) - 1] = 0;
7095 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
7096 cur++;
7097 base = cur;
7098 continue;
7099 } else if (*cur < 0xE0) {
7100 val = (cur[0]) & 0x1F;
7101 val <<= 6;
7102 val |= (cur[1]) & 0x3F;
7103 l = 2;
7104 } else if (*cur < 0xF0) {
7105 val = (cur[0]) & 0x0F;
7106 val <<= 6;
7107 val |= (cur[1]) & 0x3F;
7108 val <<= 6;
7109 val |= (cur[2]) & 0x3F;
7110 l = 3;
7111 } else if (*cur < 0xF8) {
7112 val = (cur[0]) & 0x07;
7113 val <<= 6;
7114 val |= (cur[1]) & 0x3F;
7115 val <<= 6;
7116 val |= (cur[2]) & 0x3F;
7117 val <<= 6;
7118 val |= (cur[3]) & 0x3F;
7119 l = 4;
7120 }
7121 if ((l == 1) || (!IS_CHAR(val))) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007122 xmlSaveErr(XML_SAVE_CHAR_INVALID, (xmlNodePtr) attr,
7123 NULL);
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007124 if (doc != NULL)
7125 doc->encoding =
7126 xmlStrdup(BAD_CAST "ISO-8859-1");
7127 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
7128 tmp[sizeof(tmp) - 1] = 0;
7129 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
7130 cur++;
7131 base = cur;
7132 continue;
7133 }
7134 /*
7135 * We could do multiple things here. Just save
7136 * as a char ref
7137 */
7138 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
7139 tmp[sizeof(tmp) - 1] = 0;
7140 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
7141 cur += l;
7142 base = cur;
7143 } else {
7144 cur++;
7145 }
7146 }
7147 if (base != cur)
7148 xmlBufferAdd(buf, base, cur - base);
7149 break;
7150 case XML_ENTITY_REF_NODE:
7151 xmlBufferAdd(buf, BAD_CAST "&", 1);
7152 xmlBufferAdd(buf, children->name,
7153 xmlStrlen(children->name));
7154 xmlBufferAdd(buf, BAD_CAST ";", 1);
7155 break;
7156 default:
7157 /* should not happen unless we have a badly built tree */
7158 break;
7159 }
7160 children = children->next;
Owen Taylor3473f882001-02-23 17:55:21 +00007161 }
7162}
7163
7164/**
7165 * xmlNodeDump:
7166 * @buf: the XML buffer output
7167 * @doc: the document
7168 * @cur: the current node
7169 * @level: the imbrication level for indenting
7170 * @format: is formatting allowed
7171 *
7172 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007173 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007174 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007175 *
7176 * Returns the number of bytes written to the buffer or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00007177 */
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007178int
Owen Taylor3473f882001-02-23 17:55:21 +00007179xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007180 int format)
7181{
7182 unsigned int use;
7183 int ret;
7184 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00007185
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007186 xmlInitParser();
7187
Owen Taylor3473f882001-02-23 17:55:21 +00007188 if (cur == NULL) {
7189#ifdef DEBUG_TREE
7190 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007191 "xmlNodeDump : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007192#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007193 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007194 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007195 if (buf == NULL) {
7196#ifdef DEBUG_TREE
7197 xmlGenericError(xmlGenericErrorContext,
7198 "xmlNodeDump : buf == NULL\n");
7199#endif
7200 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007201 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007202 outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
7203 if (outbuf == NULL) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00007204 xmlSaveErrMemory("creating buffer");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007205 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007206 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007207 memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
7208 outbuf->buffer = buf;
7209 outbuf->encoder = NULL;
7210 outbuf->writecallback = NULL;
7211 outbuf->closecallback = NULL;
7212 outbuf->context = NULL;
7213 outbuf->written = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007214
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007215 use = buf->use;
7216 xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
7217 xmlFree(outbuf);
7218 ret = buf->use - use;
7219 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00007220}
7221
7222/**
7223 * xmlElemDump:
7224 * @f: the FILE * for the output
7225 * @doc: the document
7226 * @cur: the current node
7227 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007228 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00007229 */
7230void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007231xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur)
7232{
7233 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00007234
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007235 xmlInitParser();
7236
Owen Taylor3473f882001-02-23 17:55:21 +00007237 if (cur == NULL) {
7238#ifdef DEBUG_TREE
7239 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007240 "xmlElemDump : cur == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007241#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007242 return;
Owen Taylor3473f882001-02-23 17:55:21 +00007243 }
Owen Taylor3473f882001-02-23 17:55:21 +00007244#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007245 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00007246 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007247 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007248 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007249#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007250
7251 outbuf = xmlOutputBufferCreateFile(f, NULL);
7252 if (outbuf == NULL)
7253 return;
7254 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007255#ifdef LIBXML_HTML_ENABLED
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007256 htmlNodeDumpOutput(outbuf, doc, cur, NULL);
7257#else
Daniel Veillard2189b592003-10-21 00:08:42 +00007258 xmlSaveErr(XML_ERR_INTERNAL_ERROR, cur, "HTML support not compiled in\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007259#endif /* LIBXML_HTML_ENABLED */
7260 } else
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007261 xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL);
7262 xmlOutputBufferClose(outbuf);
Owen Taylor3473f882001-02-23 17:55:21 +00007263}
7264
7265/************************************************************************
7266 * *
7267 * Dumping XML tree content to an I/O output buffer *
7268 * *
7269 ************************************************************************/
7270
Daniel Veillard4432df22003-09-28 18:58:27 +00007271#ifdef LIBXML_HTML_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00007272static void
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007273xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7274 int level, int format, const char *encoding);
Daniel Veillard4432df22003-09-28 18:58:27 +00007275#endif
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007276static void
Owen Taylor3473f882001-02-23 17:55:21 +00007277xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7278 int level, int format, const char *encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007279static void
7280xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
7281 xmlNodePtr cur, int level, int format, const char *encoding);
7282
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00007283void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
7284
Owen Taylor3473f882001-02-23 17:55:21 +00007285/**
7286 * xmlNsDumpOutput:
7287 * @buf: the XML buffer output
7288 * @cur: a namespace
7289 *
7290 * Dump a local Namespace definition.
7291 * Should be called in the context of attributes dumps.
7292 */
7293static void
7294xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
7295 if (cur == NULL) {
7296#ifdef DEBUG_TREE
7297 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007298 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007299#endif
7300 return;
7301 }
7302 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00007303 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
7304 return;
7305
Owen Taylor3473f882001-02-23 17:55:21 +00007306 /* Within the context of an element attributes */
7307 if (cur->prefix != NULL) {
7308 xmlOutputBufferWriteString(buf, " xmlns:");
7309 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
7310 } else
7311 xmlOutputBufferWriteString(buf, " xmlns");
7312 xmlOutputBufferWriteString(buf, "=");
7313 xmlBufferWriteQuotedString(buf->buffer, cur->href);
7314 }
7315}
7316
7317/**
7318 * xmlNsListDumpOutput:
7319 * @buf: the XML buffer output
7320 * @cur: the first namespace
7321 *
7322 * Dump a list of local Namespace definitions.
7323 * Should be called in the context of attributes dumps.
7324 */
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00007325void
Owen Taylor3473f882001-02-23 17:55:21 +00007326xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
7327 while (cur != NULL) {
7328 xmlNsDumpOutput(buf, cur);
7329 cur = cur->next;
7330 }
7331}
7332
7333/**
7334 * xmlDtdDumpOutput:
7335 * @buf: the XML buffer output
7336 * @doc: the document
7337 * @encoding: an optional encoding string
7338 *
7339 * Dump the XML document DTD, if any.
7340 */
7341static void
7342xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
7343 if (dtd == NULL) {
7344#ifdef DEBUG_TREE
7345 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007346 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007347#endif
7348 return;
7349 }
7350 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
7351 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
7352 if (dtd->ExternalID != NULL) {
7353 xmlOutputBufferWriteString(buf, " PUBLIC ");
7354 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
7355 xmlOutputBufferWriteString(buf, " ");
7356 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
7357 } else if (dtd->SystemID != NULL) {
7358 xmlOutputBufferWriteString(buf, " SYSTEM ");
7359 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
7360 }
7361 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
7362 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
7363 xmlOutputBufferWriteString(buf, ">");
7364 return;
7365 }
7366 xmlOutputBufferWriteString(buf, " [\n");
7367 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
7368 xmlOutputBufferWriteString(buf, "]>");
7369}
7370
7371/**
7372 * xmlAttrDumpOutput:
7373 * @buf: the XML buffer output
7374 * @doc: the document
7375 * @cur: the attribute pointer
7376 * @encoding: an optional encoding string
7377 *
7378 * Dump an XML attribute
7379 */
7380static void
7381xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00007382 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00007383 if (cur == NULL) {
7384#ifdef DEBUG_TREE
7385 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007386 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007387#endif
7388 return;
7389 }
7390 xmlOutputBufferWriteString(buf, " ");
7391 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7392 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7393 xmlOutputBufferWriteString(buf, ":");
7394 }
7395 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00007396 xmlOutputBufferWriteString(buf, "=\"");
7397 xmlAttrSerializeContent(buf->buffer, doc, cur);
7398 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007399}
7400
7401/**
7402 * xmlAttrListDumpOutput:
7403 * @buf: the XML buffer output
7404 * @doc: the document
7405 * @cur: the first attribute pointer
7406 * @encoding: an optional encoding string
7407 *
7408 * Dump a list of XML attributes
7409 */
7410static void
7411xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7412 xmlAttrPtr cur, const char *encoding) {
7413 if (cur == NULL) {
7414#ifdef DEBUG_TREE
7415 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007416 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007417#endif
7418 return;
7419 }
7420 while (cur != NULL) {
7421 xmlAttrDumpOutput(buf, doc, cur, encoding);
7422 cur = cur->next;
7423 }
7424}
7425
7426
7427
7428/**
7429 * xmlNodeListDumpOutput:
7430 * @buf: the XML buffer output
7431 * @doc: the document
7432 * @cur: the first node
7433 * @level: the imbrication level for indenting
7434 * @format: is formatting allowed
7435 * @encoding: an optional encoding string
7436 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007437 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007438 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007439 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007440 */
7441static void
7442xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7443 xmlNodePtr cur, int level, int format, const char *encoding) {
7444 int i;
7445
7446 if (cur == NULL) {
7447#ifdef DEBUG_TREE
7448 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007449 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007450#endif
7451 return;
7452 }
7453 while (cur != NULL) {
7454 if ((format) && (xmlIndentTreeOutput) &&
7455 (cur->type == XML_ELEMENT_NODE))
7456 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007457 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007458 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007459 if (format) {
7460 xmlOutputBufferWriteString(buf, "\n");
7461 }
7462 cur = cur->next;
7463 }
7464}
7465
7466/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007467 * xmlNodeDumpOutputInternal:
Owen Taylor3473f882001-02-23 17:55:21 +00007468 * @buf: the XML buffer output
7469 * @doc: the document
7470 * @cur: the current node
7471 * @level: the imbrication level for indenting
7472 * @format: is formatting allowed
7473 * @encoding: an optional encoding string
7474 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007475 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007476 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007477 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007478 */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007479static void
7480xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
7481 xmlNodePtr cur, int level, int format, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007482 int i;
7483 xmlNodePtr tmp;
Daniel Veillard9475a352003-09-26 12:47:50 +00007484 xmlChar *start, *end;
Owen Taylor3473f882001-02-23 17:55:21 +00007485
7486 if (cur == NULL) {
7487#ifdef DEBUG_TREE
7488 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007489 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007490#endif
7491 return;
7492 }
7493 if (cur->type == XML_XINCLUDE_START)
7494 return;
7495 if (cur->type == XML_XINCLUDE_END)
7496 return;
7497 if (cur->type == XML_DTD_NODE) {
7498 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7499 return;
7500 }
Daniel Veillardcec50a62003-10-28 13:26:51 +00007501 if (cur->type == XML_DOCUMENT_FRAG_NODE) {
7502 xmlNodeListDumpOutput(buf, doc, cur->children, level, format, encoding);
7503 return;
7504 }
Owen Taylor3473f882001-02-23 17:55:21 +00007505 if (cur->type == XML_ELEMENT_DECL) {
7506 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7507 return;
7508 }
7509 if (cur->type == XML_ATTRIBUTE_DECL) {
7510 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7511 return;
7512 }
7513 if (cur->type == XML_ENTITY_DECL) {
7514 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7515 return;
7516 }
7517 if (cur->type == XML_TEXT_NODE) {
7518 if (cur->content != NULL) {
7519 if ((cur->name == xmlStringText) ||
7520 (cur->name != xmlStringTextNoenc)) {
7521 xmlChar *buffer;
7522
Owen Taylor3473f882001-02-23 17:55:21 +00007523 if (encoding == NULL)
7524 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7525 else
7526 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007527 if (buffer != NULL) {
7528 xmlOutputBufferWriteString(buf, (const char *)buffer);
7529 xmlFree(buffer);
7530 }
7531 } else {
7532 /*
7533 * Disable escaping, needed for XSLT
7534 */
Owen Taylor3473f882001-02-23 17:55:21 +00007535 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007536 }
7537 }
7538
7539 return;
7540 }
7541 if (cur->type == XML_PI_NODE) {
7542 if (cur->content != NULL) {
7543 xmlOutputBufferWriteString(buf, "<?");
7544 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7545 if (cur->content != NULL) {
7546 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00007547 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007548 }
7549 xmlOutputBufferWriteString(buf, "?>");
7550 } else {
7551 xmlOutputBufferWriteString(buf, "<?");
7552 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7553 xmlOutputBufferWriteString(buf, "?>");
7554 }
7555 return;
7556 }
7557 if (cur->type == XML_COMMENT_NODE) {
7558 if (cur->content != NULL) {
7559 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00007560 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007561 xmlOutputBufferWriteString(buf, "-->");
7562 }
7563 return;
7564 }
7565 if (cur->type == XML_ENTITY_REF_NODE) {
7566 xmlOutputBufferWriteString(buf, "&");
7567 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7568 xmlOutputBufferWriteString(buf, ";");
7569 return;
7570 }
7571 if (cur->type == XML_CDATA_SECTION_NODE) {
Daniel Veillard9475a352003-09-26 12:47:50 +00007572 start = end = cur->content;
7573 while (*end != '\0') {
7574 if ((*end == ']') && (*(end + 1) == ']') && (*(end + 2) == '>')) {
7575 end = end + 2;
7576 xmlOutputBufferWriteString(buf, "<![CDATA[");
7577 xmlOutputBufferWrite(buf, end - start, (const char *)start);
7578 xmlOutputBufferWriteString(buf, "]]>");
7579 start = end;
7580 }
7581 end++;
7582 }
7583 if (start != end) {
7584 xmlOutputBufferWriteString(buf, "<![CDATA[");
7585 xmlOutputBufferWriteString(buf, (const char *)start);
7586 xmlOutputBufferWriteString(buf, "]]>");
7587 }
Owen Taylor3473f882001-02-23 17:55:21 +00007588 return;
7589 }
Daniel Veillard7b72ee52003-02-27 23:24:53 +00007590 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillarda1a9d042003-03-18 16:53:17 +00007591 xmlAttrDumpOutput(buf,doc, (xmlAttrPtr) cur,encoding);
Daniel Veillard7b72ee52003-02-27 23:24:53 +00007592 return;
7593 }
Daniel Veillard6aa2f602003-02-10 00:01:56 +00007594 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007595 xmlNsDumpOutput(buf, (xmlNsPtr) cur);
Daniel Veillard6aa2f602003-02-10 00:01:56 +00007596 return;
7597 }
Owen Taylor3473f882001-02-23 17:55:21 +00007598
7599 if (format == 1) {
7600 tmp = cur->children;
7601 while (tmp != NULL) {
William M. Brack9ca682f2003-10-19 10:01:59 +00007602 if ((tmp->type == XML_TEXT_NODE) ||
7603 (tmp->type == XML_CDATA_SECTION_NODE) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007604 (tmp->type == XML_ENTITY_REF_NODE)) {
7605 format = 0;
7606 break;
7607 }
7608 tmp = tmp->next;
7609 }
7610 }
7611 xmlOutputBufferWriteString(buf, "<");
7612 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7613 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7614 xmlOutputBufferWriteString(buf, ":");
7615 }
7616
7617 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7618 if (cur->nsDef)
7619 xmlNsListDumpOutput(buf, cur->nsDef);
7620 if (cur->properties != NULL)
7621 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7622
Daniel Veillard7db37732001-07-12 01:20:08 +00007623 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
7624 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007625 xmlOutputBufferWriteString(buf, "/>");
7626 return;
7627 }
7628 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00007629 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007630 xmlChar *buffer;
7631
Owen Taylor3473f882001-02-23 17:55:21 +00007632 if (encoding == NULL)
7633 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7634 else
7635 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007636 if (buffer != NULL) {
7637 xmlOutputBufferWriteString(buf, (const char *)buffer);
7638 xmlFree(buffer);
7639 }
7640 }
7641 if (cur->children != NULL) {
7642 if (format) xmlOutputBufferWriteString(buf, "\n");
7643 xmlNodeListDumpOutput(buf, doc, cur->children,
7644 (level >= 0?level+1:-1), format, encoding);
7645 if ((xmlIndentTreeOutput) && (format))
7646 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007647 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00007648 }
7649 xmlOutputBufferWriteString(buf, "</");
7650 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7651 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7652 xmlOutputBufferWriteString(buf, ":");
7653 }
7654
7655 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7656 xmlOutputBufferWriteString(buf, ">");
7657}
7658
7659/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007660 * xmlNodeDumpOutput:
7661 * @buf: the XML buffer output
7662 * @doc: the document
7663 * @cur: the current node
7664 * @level: the imbrication level for indenting
7665 * @format: is formatting allowed
7666 * @encoding: an optional encoding string
7667 *
7668 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007669 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007670 * or xmlKeepBlanksDefault(0) was called
7671 */
7672void
7673xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007674 int level, int format, const char *encoding)
7675{
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007676#ifdef LIBXML_HTML_ENABLED
7677 xmlDtdPtr dtd;
7678 int is_xhtml = 0;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007679#endif
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007680
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007681 xmlInitParser();
7682
7683#ifdef LIBXML_HTML_ENABLED
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007684 dtd = xmlGetIntSubset(doc);
7685 if (dtd != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007686 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7687 if (is_xhtml < 0)
7688 is_xhtml = 0;
7689 if ((is_xhtml) && (cur->parent == (xmlNodePtr) doc) &&
7690 (cur->type == XML_ELEMENT_NODE) &&
7691 (xmlStrEqual(cur->name, BAD_CAST "html"))) {
7692 if (encoding != NULL)
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007693 htmlSetMetaEncoding((htmlDocPtr) doc,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007694 (const xmlChar *) encoding);
7695 else
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007696 htmlSetMetaEncoding((htmlDocPtr) doc, BAD_CAST "UTF-8");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007697 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007698 }
7699
7700 if (is_xhtml)
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007701 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007702 else
7703#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007704 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007705}
7706
7707/**
Owen Taylor3473f882001-02-23 17:55:21 +00007708 * xmlDocContentDumpOutput:
7709 * @buf: the XML buffer output
7710 * @cur: the document
7711 * @encoding: an optional encoding string
7712 * @format: should formatting spaces been added
7713 *
7714 * Dump an XML document.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007715 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007716 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007717 */
7718static void
7719xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
7720 const char *encoding, int format) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007721#ifdef LIBXML_HTML_ENABLED
7722 xmlDtdPtr dtd;
7723 int is_xhtml = 0;
7724#endif
Daniel Veillard2f6ff812003-12-08 12:11:14 +00007725 const xmlChar *oldenc = cur->encoding;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007726
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007727 xmlInitParser();
7728
Daniel Veillard2f6ff812003-12-08 12:11:14 +00007729 if (encoding != NULL)
7730 cur->encoding = BAD_CAST encoding;
7731
Owen Taylor3473f882001-02-23 17:55:21 +00007732 xmlOutputBufferWriteString(buf, "<?xml version=");
7733 if (cur->version != NULL)
7734 xmlBufferWriteQuotedString(buf->buffer, cur->version);
7735 else
7736 xmlOutputBufferWriteString(buf, "\"1.0\"");
7737 if (encoding == NULL) {
7738 if (cur->encoding != NULL)
7739 encoding = (const char *) cur->encoding;
7740 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
7741 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
7742 }
7743 if (encoding != NULL) {
7744 xmlOutputBufferWriteString(buf, " encoding=");
7745 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
7746 }
7747 switch (cur->standalone) {
7748 case 0:
7749 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
7750 break;
7751 case 1:
7752 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
7753 break;
7754 }
7755 xmlOutputBufferWriteString(buf, "?>\n");
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007756
7757#ifdef LIBXML_HTML_ENABLED
7758 dtd = xmlGetIntSubset(cur);
7759 if (dtd != NULL) {
7760 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7761 if (is_xhtml < 0) is_xhtml = 0;
7762 }
7763 if (is_xhtml) {
7764 if (encoding != NULL)
7765 htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
7766 else
7767 htmlSetMetaEncoding(cur, BAD_CAST "UTF-8");
7768 }
7769#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007770 if (cur->children != NULL) {
7771 xmlNodePtr child = cur->children;
7772
7773 while (child != NULL) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007774#ifdef LIBXML_HTML_ENABLED
7775 if (is_xhtml)
7776 xhtmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
7777 else
7778#endif
7779 xmlNodeDumpOutputInternal(buf, cur, child, 0, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007780 xmlOutputBufferWriteString(buf, "\n");
7781 child = child->next;
7782 }
7783 }
Daniel Veillard2f6ff812003-12-08 12:11:14 +00007784 if (encoding != NULL)
7785 cur->encoding = oldenc;
Owen Taylor3473f882001-02-23 17:55:21 +00007786}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007787#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00007788
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007789#ifdef LIBXML_HTML_ENABLED
7790/************************************************************************
7791 * *
7792 * Functions specific to XHTML serialization *
7793 * *
7794 ************************************************************************/
7795
7796#define XHTML_STRICT_PUBLIC_ID BAD_CAST \
7797 "-//W3C//DTD XHTML 1.0 Strict//EN"
7798#define XHTML_STRICT_SYSTEM_ID BAD_CAST \
7799 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
7800#define XHTML_FRAME_PUBLIC_ID BAD_CAST \
7801 "-//W3C//DTD XHTML 1.0 Frameset//EN"
7802#define XHTML_FRAME_SYSTEM_ID BAD_CAST \
7803 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
7804#define XHTML_TRANS_PUBLIC_ID BAD_CAST \
7805 "-//W3C//DTD XHTML 1.0 Transitional//EN"
7806#define XHTML_TRANS_SYSTEM_ID BAD_CAST \
7807 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
7808
7809#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
7810/**
7811 * xmlIsXHTML:
7812 * @systemID: the system identifier
7813 * @publicID: the public identifier
7814 *
7815 * Try to find if the document correspond to an XHTML DTD
7816 *
7817 * Returns 1 if true, 0 if not and -1 in case of error
7818 */
7819int
7820xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) {
7821 if ((systemID == NULL) && (publicID == NULL))
7822 return(-1);
7823 if (publicID != NULL) {
7824 if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1);
7825 if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1);
7826 if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1);
7827 }
7828 if (systemID != NULL) {
7829 if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1);
7830 if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1);
7831 if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1);
7832 }
7833 return(0);
7834}
7835
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007836#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007837/**
7838 * xhtmlIsEmpty:
7839 * @node: the node
7840 *
7841 * Check if a node is an empty xhtml node
7842 *
7843 * Returns 1 if the node is an empty node, 0 if not and -1 in case of error
7844 */
7845static int
7846xhtmlIsEmpty(xmlNodePtr node) {
7847 if (node == NULL)
7848 return(-1);
7849 if (node->type != XML_ELEMENT_NODE)
7850 return(0);
7851 if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME)))
7852 return(0);
7853 if (node->children != NULL)
7854 return(0);
7855 switch (node->name[0]) {
7856 case 'a':
7857 if (xmlStrEqual(node->name, BAD_CAST "area"))
7858 return(1);
7859 return(0);
7860 case 'b':
7861 if (xmlStrEqual(node->name, BAD_CAST "br"))
7862 return(1);
7863 if (xmlStrEqual(node->name, BAD_CAST "base"))
7864 return(1);
7865 if (xmlStrEqual(node->name, BAD_CAST "basefont"))
7866 return(1);
7867 return(0);
7868 case 'c':
7869 if (xmlStrEqual(node->name, BAD_CAST "col"))
7870 return(1);
7871 return(0);
7872 case 'f':
7873 if (xmlStrEqual(node->name, BAD_CAST "frame"))
7874 return(1);
7875 return(0);
7876 case 'h':
7877 if (xmlStrEqual(node->name, BAD_CAST "hr"))
7878 return(1);
7879 return(0);
7880 case 'i':
7881 if (xmlStrEqual(node->name, BAD_CAST "img"))
7882 return(1);
7883 if (xmlStrEqual(node->name, BAD_CAST "input"))
7884 return(1);
7885 if (xmlStrEqual(node->name, BAD_CAST "isindex"))
7886 return(1);
7887 return(0);
7888 case 'l':
7889 if (xmlStrEqual(node->name, BAD_CAST "link"))
7890 return(1);
7891 return(0);
7892 case 'm':
7893 if (xmlStrEqual(node->name, BAD_CAST "meta"))
7894 return(1);
7895 return(0);
7896 case 'p':
7897 if (xmlStrEqual(node->name, BAD_CAST "param"))
7898 return(1);
7899 return(0);
7900 }
7901 return(0);
7902}
7903
7904/**
7905 * xhtmlAttrListDumpOutput:
7906 * @buf: the XML buffer output
7907 * @doc: the document
7908 * @cur: the first attribute pointer
7909 * @encoding: an optional encoding string
7910 *
7911 * Dump a list of XML attributes
7912 */
7913static void
7914xhtmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7915 xmlAttrPtr cur, const char *encoding) {
7916 xmlAttrPtr xml_lang = NULL;
7917 xmlAttrPtr lang = NULL;
7918 xmlAttrPtr name = NULL;
7919 xmlAttrPtr id = NULL;
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007920 xmlNodePtr parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007921
7922 if (cur == NULL) {
7923#ifdef DEBUG_TREE
7924 xmlGenericError(xmlGenericErrorContext,
7925 "xmlAttrListDumpOutput : property == NULL\n");
7926#endif
7927 return;
7928 }
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007929 parent = cur->parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007930 while (cur != NULL) {
7931 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id")))
7932 id = cur;
7933 else
7934 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name")))
7935 name = cur;
7936 else
7937 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")))
7938 lang = cur;
7939 else
7940 if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) &&
7941 (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml")))
7942 xml_lang = cur;
7943 else if ((cur->ns == NULL) &&
7944 ((cur->children == NULL) ||
7945 (cur->children->content == NULL) ||
7946 (cur->children->content[0] == 0)) &&
7947 (htmlIsBooleanAttr(cur->name))) {
7948 if (cur->children != NULL)
7949 xmlFreeNode(cur->children);
7950 cur->children = xmlNewText(cur->name);
7951 if (cur->children != NULL)
7952 cur->children->parent = (xmlNodePtr) cur;
7953 }
7954 xmlAttrDumpOutput(buf, doc, cur, encoding);
7955 cur = cur->next;
7956 }
7957 /*
7958 * C.8
7959 */
7960 if ((name != NULL) && (id == NULL)) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007961 if ((parent != NULL) && (parent->name != NULL) &&
7962 ((xmlStrEqual(parent->name, BAD_CAST "a")) ||
7963 (xmlStrEqual(parent->name, BAD_CAST "p")) ||
7964 (xmlStrEqual(parent->name, BAD_CAST "div")) ||
7965 (xmlStrEqual(parent->name, BAD_CAST "img")) ||
7966 (xmlStrEqual(parent->name, BAD_CAST "map")) ||
7967 (xmlStrEqual(parent->name, BAD_CAST "applet")) ||
7968 (xmlStrEqual(parent->name, BAD_CAST "form")) ||
7969 (xmlStrEqual(parent->name, BAD_CAST "frame")) ||
7970 (xmlStrEqual(parent->name, BAD_CAST "iframe")))) {
7971 xmlOutputBufferWriteString(buf, " id=\"");
7972 xmlAttrSerializeContent(buf->buffer, doc, name);
7973 xmlOutputBufferWriteString(buf, "\"");
7974 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007975 }
7976 /*
7977 * C.7.
7978 */
7979 if ((lang != NULL) && (xml_lang == NULL)) {
7980 xmlOutputBufferWriteString(buf, " xml:lang=\"");
7981 xmlAttrSerializeContent(buf->buffer, doc, lang);
7982 xmlOutputBufferWriteString(buf, "\"");
7983 } else
7984 if ((xml_lang != NULL) && (lang == NULL)) {
7985 xmlOutputBufferWriteString(buf, " lang=\"");
7986 xmlAttrSerializeContent(buf->buffer, doc, xml_lang);
7987 xmlOutputBufferWriteString(buf, "\"");
7988 }
7989}
7990
7991/**
7992 * xhtmlNodeListDumpOutput:
7993 * @buf: the XML buffer output
7994 * @doc: the XHTML document
7995 * @cur: the first node
7996 * @level: the imbrication level for indenting
7997 * @format: is formatting allowed
7998 * @encoding: an optional encoding string
7999 *
8000 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008001 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00008002 * or xmlKeepBlanksDefault(0) was called
8003 */
8004static void
8005xhtmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
8006 xmlNodePtr cur, int level, int format, const char *encoding) {
8007 int i;
8008
8009 if (cur == NULL) {
8010#ifdef DEBUG_TREE
8011 xmlGenericError(xmlGenericErrorContext,
8012 "xhtmlNodeListDumpOutput : node == NULL\n");
8013#endif
8014 return;
8015 }
8016 while (cur != NULL) {
8017 if ((format) && (xmlIndentTreeOutput) &&
8018 (cur->type == XML_ELEMENT_NODE))
8019 for (i = 0;i < level;i++)
8020 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
8021 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
8022 if (format) {
8023 xmlOutputBufferWriteString(buf, "\n");
8024 }
8025 cur = cur->next;
8026 }
8027}
8028
8029/**
8030 * xhtmlNodeDumpOutput:
8031 * @buf: the XML buffer output
8032 * @doc: the XHTML document
8033 * @cur: the current node
8034 * @level: the imbrication level for indenting
8035 * @format: is formatting allowed
8036 * @encoding: an optional encoding string
8037 *
8038 * Dump an XHTML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008039 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00008040 * or xmlKeepBlanksDefault(0) was called
8041 */
8042static void
8043xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
8044 int level, int format, const char *encoding) {
8045 int i;
8046 xmlNodePtr tmp;
Daniel Veillard9475a352003-09-26 12:47:50 +00008047 xmlChar *start, *end;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00008048
8049 if (cur == NULL) {
8050#ifdef DEBUG_TREE
8051 xmlGenericError(xmlGenericErrorContext,
8052 "xmlNodeDumpOutput : node == NULL\n");
8053#endif
8054 return;
8055 }
8056 if (cur->type == XML_XINCLUDE_START)
8057 return;
8058 if (cur->type == XML_XINCLUDE_END)
8059 return;
8060 if (cur->type == XML_DTD_NODE) {
8061 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
8062 return;
8063 }
8064 if (cur->type == XML_ELEMENT_DECL) {
8065 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
8066 return;
8067 }
8068 if (cur->type == XML_ATTRIBUTE_DECL) {
8069 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
8070 return;
8071 }
8072 if (cur->type == XML_ENTITY_DECL) {
8073 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
8074 return;
8075 }
8076 if (cur->type == XML_TEXT_NODE) {
8077 if (cur->content != NULL) {
8078 if ((cur->name == xmlStringText) ||
8079 (cur->name != xmlStringTextNoenc)) {
8080 xmlChar *buffer;
8081
8082 if (encoding == NULL)
8083 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
8084 else
8085 buffer = xmlEncodeSpecialChars(doc, cur->content);
8086 if (buffer != NULL) {
8087 xmlOutputBufferWriteString(buf, (const char *)buffer);
8088 xmlFree(buffer);
8089 }
8090 } else {
8091 /*
8092 * Disable escaping, needed for XSLT
8093 */
8094 xmlOutputBufferWriteString(buf, (const char *) cur->content);
8095 }
8096 }
8097
8098 return;
8099 }
8100 if (cur->type == XML_PI_NODE) {
8101 if (cur->content != NULL) {
8102 xmlOutputBufferWriteString(buf, "<?");
8103 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8104 if (cur->content != NULL) {
8105 xmlOutputBufferWriteString(buf, " ");
8106 xmlOutputBufferWriteString(buf, (const char *)cur->content);
8107 }
8108 xmlOutputBufferWriteString(buf, "?>");
8109 } else {
8110 xmlOutputBufferWriteString(buf, "<?");
8111 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8112 xmlOutputBufferWriteString(buf, "?>");
8113 }
8114 return;
8115 }
8116 if (cur->type == XML_COMMENT_NODE) {
8117 if (cur->content != NULL) {
8118 xmlOutputBufferWriteString(buf, "<!--");
8119 xmlOutputBufferWriteString(buf, (const char *)cur->content);
8120 xmlOutputBufferWriteString(buf, "-->");
8121 }
8122 return;
8123 }
8124 if (cur->type == XML_ENTITY_REF_NODE) {
8125 xmlOutputBufferWriteString(buf, "&");
8126 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8127 xmlOutputBufferWriteString(buf, ";");
8128 return;
8129 }
8130 if (cur->type == XML_CDATA_SECTION_NODE) {
Daniel Veillard9475a352003-09-26 12:47:50 +00008131 start = end = cur->content;
8132 while (*end != '\0') {
8133 if (*end == ']' && *(end + 1) == ']' && *(end + 2) == '>') {
8134 end = end + 2;
8135 xmlOutputBufferWriteString(buf, "<![CDATA[");
8136 xmlOutputBufferWrite(buf, end - start, (const char *)start);
8137 xmlOutputBufferWriteString(buf, "]]>");
8138 start = end;
8139 }
8140 end++;
8141 }
8142 if (start != end) {
8143 xmlOutputBufferWriteString(buf, "<![CDATA[");
8144 xmlOutputBufferWriteString(buf, (const char *)start);
8145 xmlOutputBufferWriteString(buf, "]]>");
8146 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00008147 return;
8148 }
8149
8150 if (format == 1) {
8151 tmp = cur->children;
8152 while (tmp != NULL) {
8153 if ((tmp->type == XML_TEXT_NODE) ||
8154 (tmp->type == XML_ENTITY_REF_NODE)) {
8155 format = 0;
8156 break;
8157 }
8158 tmp = tmp->next;
8159 }
8160 }
8161 xmlOutputBufferWriteString(buf, "<");
8162 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
8163 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
8164 xmlOutputBufferWriteString(buf, ":");
8165 }
8166
8167 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8168 if (cur->nsDef)
8169 xmlNsListDumpOutput(buf, cur->nsDef);
8170 if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
8171 (cur->ns == NULL) && (cur->nsDef == NULL))) {
8172 /*
8173 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
8174 */
8175 xmlOutputBufferWriteString(buf,
8176 " xmlns=\"http://www.w3.org/1999/xhtml\"");
8177 }
8178 if (cur->properties != NULL)
8179 xhtmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
8180
8181 if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) {
8182 if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
8183 (xhtmlIsEmpty(cur) == 1)) {
8184 /*
8185 * C.2. Empty Elements
8186 */
8187 xmlOutputBufferWriteString(buf, " />");
8188 } else {
8189 /*
8190 * C.3. Element Minimization and Empty Element Content
8191 */
8192 xmlOutputBufferWriteString(buf, "></");
8193 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
8194 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
8195 xmlOutputBufferWriteString(buf, ":");
8196 }
8197 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8198 xmlOutputBufferWriteString(buf, ">");
8199 }
8200 return;
8201 }
8202 xmlOutputBufferWriteString(buf, ">");
8203 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
8204 xmlChar *buffer;
8205
8206 if (encoding == NULL)
8207 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
8208 else
8209 buffer = xmlEncodeSpecialChars(doc, cur->content);
8210 if (buffer != NULL) {
8211 xmlOutputBufferWriteString(buf, (const char *)buffer);
8212 xmlFree(buffer);
8213 }
8214 }
8215
8216 /*
8217 * 4.8. Script and Style elements
8218 */
8219 if ((cur->type == XML_ELEMENT_NODE) &&
8220 ((xmlStrEqual(cur->name, BAD_CAST "script")) ||
8221 (xmlStrEqual(cur->name, BAD_CAST "style"))) &&
8222 ((cur->ns == NULL) ||
8223 (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) {
8224 xmlNodePtr child = cur->children;
8225
8226 while (child != NULL) {
8227 if ((child->type == XML_TEXT_NODE) ||
8228 (child->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard64b35282002-12-04 15:10:40 +00008229 /*
8230 * Apparently CDATA escaping for style just break on IE,
8231 * mozilla and galeon, so ...
8232 */
8233 if (xmlStrEqual(cur->name, BAD_CAST "style") &&
8234 (xmlStrchr(child->content, '<') == NULL) &&
8235 (xmlStrchr(child->content, '>') == NULL) &&
8236 (xmlStrchr(child->content, '&') == NULL)) {
8237 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
8238 } else {
Daniel Veillard9475a352003-09-26 12:47:50 +00008239 start = end = child->content;
8240 while (*end != '\0') {
8241 if (*end == ']' &&
8242 *(end + 1) == ']' &&
8243 *(end + 2) == '>') {
8244 end = end + 2;
8245 xmlOutputBufferWriteString(buf, "<![CDATA[");
8246 xmlOutputBufferWrite(buf, end - start,
8247 (const char *)start);
8248 xmlOutputBufferWriteString(buf, "]]>");
8249 start = end;
8250 }
8251 end++;
8252 }
8253 if (start != end) {
8254 xmlOutputBufferWriteString(buf, "<![CDATA[");
8255 xmlOutputBufferWriteString(buf, (const char *)start);
8256 xmlOutputBufferWriteString(buf, "]]>");
8257 }
Daniel Veillard64b35282002-12-04 15:10:40 +00008258 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00008259 } else {
8260 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
8261 }
8262 child = child->next;
8263 }
8264 } else if (cur->children != NULL) {
8265 if (format) xmlOutputBufferWriteString(buf, "\n");
8266 xhtmlNodeListDumpOutput(buf, doc, cur->children,
8267 (level >= 0?level+1:-1), format, encoding);
8268 if ((xmlIndentTreeOutput) && (format))
8269 for (i = 0;i < level;i++)
8270 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
8271 }
8272 xmlOutputBufferWriteString(buf, "</");
8273 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
8274 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
8275 xmlOutputBufferWriteString(buf, ":");
8276 }
8277
8278 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8279 xmlOutputBufferWriteString(buf, ">");
8280}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00008281#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00008282#endif
8283
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00008284#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00008285/************************************************************************
8286 * *
8287 * Saving functions front-ends *
8288 * *
8289 ************************************************************************/
8290
8291/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00008292 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00008293 * @out_doc: Document to generate XML text from
8294 * @doc_txt_ptr: Memory pointer for allocated XML text
8295 * @doc_txt_len: Length of the generated XML text
8296 * @txt_encoding: Character encoding to use when generating XML text
8297 * @format: should formatting spaces been added
8298 *
8299 * Dump the current DOM tree into memory using the character encoding specified
8300 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008301 * allocated memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00008302 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00008303 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008304 */
8305
8306void
8307xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008308 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008309 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00008310 int dummy = 0;
8311
Owen Taylor3473f882001-02-23 17:55:21 +00008312 xmlOutputBufferPtr out_buff = NULL;
8313 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
8314
8315 if (doc_txt_len == NULL) {
8316 doc_txt_len = &dummy; /* Continue, caller just won't get length */
8317 }
8318
8319 if (doc_txt_ptr == NULL) {
8320 *doc_txt_len = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008321 return;
8322 }
8323
8324 *doc_txt_ptr = NULL;
8325 *doc_txt_len = 0;
8326
8327 if (out_doc == NULL) {
8328 /* No document, no output */
Owen Taylor3473f882001-02-23 17:55:21 +00008329 return;
8330 }
8331
8332 /*
8333 * Validate the encoding value, if provided.
8334 * This logic is copied from xmlSaveFileEnc.
8335 */
8336
8337 if (txt_encoding == NULL)
8338 txt_encoding = (const char *) out_doc->encoding;
8339 if (txt_encoding != NULL) {
Daniel Veillarde1326112003-06-05 09:32:20 +00008340 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00008341 if ( conv_hdlr == NULL ) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00008342 xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, (xmlNodePtr) out_doc,
8343 txt_encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00008344 return;
8345 }
8346 }
Owen Taylor3473f882001-02-23 17:55:21 +00008347
8348 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
Daniel Veillard18ec16e2003-10-07 23:16:40 +00008349 xmlSaveErrMemory("creating buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00008350 return;
8351 }
8352
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008353 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008354 xmlOutputBufferFlush(out_buff);
8355 if (out_buff->conv != NULL) {
8356 *doc_txt_len = out_buff->conv->use;
8357 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
8358 } else {
8359 *doc_txt_len = out_buff->buffer->use;
8360 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
8361 }
8362 (void)xmlOutputBufferClose(out_buff);
8363
8364 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
8365 *doc_txt_len = 0;
Daniel Veillard18ec16e2003-10-07 23:16:40 +00008366 xmlSaveErrMemory("creating output");
Owen Taylor3473f882001-02-23 17:55:21 +00008367 }
8368
8369 return;
8370}
8371
8372/**
8373 * xmlDocDumpMemory:
8374 * @cur: the document
8375 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00008376 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00008377 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008378 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008379 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00008380 */
8381void
8382xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
8383 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
8384}
8385
8386/**
8387 * xmlDocDumpFormatMemory:
8388 * @cur: the document
8389 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00008390 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00008391 * @format: should formatting spaces been added
8392 *
8393 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008394 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008395 * It's up to the caller to free the memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00008396 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00008397 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008398 */
8399void
8400xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
8401 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
8402}
8403
8404/**
8405 * xmlDocDumpMemoryEnc:
8406 * @out_doc: Document to generate XML text from
8407 * @doc_txt_ptr: Memory pointer for allocated XML text
8408 * @doc_txt_len: Length of the generated XML text
8409 * @txt_encoding: Character encoding to use when generating XML text
8410 *
8411 * Dump the current DOM tree into memory using the character encoding specified
8412 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008413 * allocated memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00008414 */
8415
8416void
8417xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
8418 int * doc_txt_len, const char * txt_encoding) {
8419 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008420 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008421}
8422
8423/**
Daniel Veillard9e412302002-06-10 15:59:44 +00008424 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00008425 * @f: the FILE*
8426 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00008427 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00008428 *
8429 * Dump an XML document to an open FILE.
8430 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008431 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008432 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8433 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008434 */
8435int
Daniel Veillard9e412302002-06-10 15:59:44 +00008436xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00008437 xmlOutputBufferPtr buf;
8438 const char * encoding;
8439 xmlCharEncodingHandlerPtr handler = NULL;
8440 int ret;
8441
8442 if (cur == NULL) {
8443#ifdef DEBUG_TREE
8444 xmlGenericError(xmlGenericErrorContext,
8445 "xmlDocDump : document == NULL\n");
8446#endif
8447 return(-1);
8448 }
8449 encoding = (const char *) cur->encoding;
8450
8451 if (encoding != NULL) {
Daniel Veillarde1326112003-06-05 09:32:20 +00008452 handler = xmlFindCharEncodingHandler(encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00008453 if (handler == NULL) {
8454 xmlFree((char *) cur->encoding);
8455 cur->encoding = NULL;
8456 }
8457 }
Owen Taylor3473f882001-02-23 17:55:21 +00008458 buf = xmlOutputBufferCreateFile(f, handler);
8459 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00008460 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008461
8462 ret = xmlOutputBufferClose(buf);
8463 return(ret);
8464}
8465
8466/**
Daniel Veillard9e412302002-06-10 15:59:44 +00008467 * xmlDocDump:
8468 * @f: the FILE*
8469 * @cur: the document
8470 *
8471 * Dump an XML document to an open FILE.
8472 *
8473 * returns: the number of bytes written or -1 in case of failure.
8474 */
8475int
8476xmlDocDump(FILE *f, xmlDocPtr cur) {
Daniel Veillard828ce832003-10-08 19:19:10 +00008477 return(xmlDocFormatDump (f, cur, 0));
Daniel Veillard9e412302002-06-10 15:59:44 +00008478}
8479
8480/**
Owen Taylor3473f882001-02-23 17:55:21 +00008481 * xmlSaveFileTo:
8482 * @buf: an output I/O buffer
8483 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00008484 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00008485 *
8486 * Dump an XML document to an I/O buffer.
8487 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008488 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008489 */
8490int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00008491xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00008492 int ret;
8493
8494 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008495 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008496 ret = xmlOutputBufferClose(buf);
8497 return(ret);
8498}
8499
8500/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00008501 * xmlSaveFormatFileTo:
8502 * @buf: an output I/O buffer
8503 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00008504 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00008505 * @format: should formatting spaces been added
8506 *
8507 * Dump an XML document to an I/O buffer.
8508 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008509 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008510 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8511 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardeefd4492001-04-28 16:55:50 +00008512 */
8513int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00008514xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00008515 int ret;
8516
8517 if (buf == NULL) return(0);
8518 xmlDocContentDumpOutput(buf, cur, encoding, format);
8519 ret = xmlOutputBufferClose(buf);
8520 return(ret);
8521}
8522
8523/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00008524 * xmlSaveFormatFileEnc:
Daniel Veillardf012a642001-07-23 19:10:52 +00008525 * @filename: the filename or URL to output
8526 * @cur: the document being saved
8527 * @encoding: the name of the encoding to use or NULL.
8528 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00008529 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00008530 * Dump an XML document to a file or an URL.
8531 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008532 * Returns the number of bytes written or -1 in case of error.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008533 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8534 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008535 */
8536int
Daniel Veillardf012a642001-07-23 19:10:52 +00008537xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
8538 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00008539 xmlOutputBufferPtr buf;
8540 xmlCharEncodingHandlerPtr handler = NULL;
8541 int ret;
8542
Daniel Veillard4dbe77a2003-01-14 00:17:42 +00008543 if (cur == NULL)
8544 return(-1);
8545
Daniel Veillardfb25a512002-01-13 20:32:08 +00008546 if (encoding == NULL)
8547 encoding = (const char *) cur->encoding;
8548
Owen Taylor3473f882001-02-23 17:55:21 +00008549 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00008550
Owen Taylor3473f882001-02-23 17:55:21 +00008551 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00008552 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00008553 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00008554 }
8555
Daniel Veillardf012a642001-07-23 19:10:52 +00008556#ifdef HAVE_ZLIB_H
8557 if (cur->compression < 0) cur->compression = xmlCompressMode;
8558#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008559 /*
8560 * save the content to a temp buffer.
8561 */
Daniel Veillardf012a642001-07-23 19:10:52 +00008562 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00008563 if (buf == NULL) return(-1);
8564
Daniel Veillardf012a642001-07-23 19:10:52 +00008565 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008566
8567 ret = xmlOutputBufferClose(buf);
8568 return(ret);
8569}
8570
Daniel Veillardf012a642001-07-23 19:10:52 +00008571
8572/**
8573 * xmlSaveFileEnc:
8574 * @filename: the filename (or URL)
8575 * @cur: the document
8576 * @encoding: the name of an encoding (or NULL)
8577 *
8578 * Dump an XML document, converting it to the given encoding
8579 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008580 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00008581 */
8582int
8583xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
8584 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
8585}
8586
Owen Taylor3473f882001-02-23 17:55:21 +00008587/**
Daniel Veillard67fee942001-04-26 18:59:03 +00008588 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00008589 * @filename: the filename (or URL)
8590 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00008591 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00008592 *
8593 * Dump an XML document to a file. Will use compression if
8594 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00008595 * used. If @format is set then the document will be indented on output.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008596 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8597 * or xmlKeepBlanksDefault(0) was called
Daniel Veillard67fee942001-04-26 18:59:03 +00008598 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008599 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008600 */
8601int
Daniel Veillard67fee942001-04-26 18:59:03 +00008602xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008603 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00008604}
8605
Daniel Veillard67fee942001-04-26 18:59:03 +00008606/**
8607 * xmlSaveFile:
8608 * @filename: the filename (or URL)
8609 * @cur: the document
8610 *
8611 * Dump an XML document to a file. Will use compression if
8612 * compiled in and enabled. If @filename is "-" the stdout file is
8613 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00008614 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00008615 */
8616int
8617xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008618 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00008619}
8620
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00008621#endif /* LIBXML_OUTPUT_ENABLED */
8622
8623/**
8624 * xmlGetDocCompressMode:
8625 * @doc: the document
8626 *
8627 * get the compression ratio for a document, ZLIB based
8628 * Returns 0 (uncompressed) to 9 (max compression)
8629 */
8630int
8631xmlGetDocCompressMode (xmlDocPtr doc) {
8632 if (doc == NULL) return(-1);
8633 return(doc->compression);
8634}
8635
8636/**
8637 * xmlSetDocCompressMode:
8638 * @doc: the document
8639 * @mode: the compression ratio
8640 *
8641 * set the compression ratio for a document, ZLIB based
8642 * Correct values: 0 (uncompressed) to 9 (max compression)
8643 */
8644void
8645xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
8646 if (doc == NULL) return;
8647 if (mode < 0) doc->compression = 0;
8648 else if (mode > 9) doc->compression = 9;
8649 else doc->compression = mode;
8650}
8651
8652/**
8653 * xmlGetCompressMode:
8654 *
8655 * get the default compression mode used, ZLIB based.
8656 * Returns 0 (uncompressed) to 9 (max compression)
8657 */
8658int
8659xmlGetCompressMode(void)
8660{
8661 return (xmlCompressMode);
8662}
8663
8664/**
8665 * xmlSetCompressMode:
8666 * @mode: the compression ratio
8667 *
8668 * set the default compression mode used, ZLIB based
8669 * Correct values: 0 (uncompressed) to 9 (max compression)
8670 */
8671void
8672xmlSetCompressMode(int mode) {
8673 if (mode < 0) xmlCompressMode = 0;
8674 else if (mode > 9) xmlCompressMode = 9;
8675 else xmlCompressMode = mode;
8676}
8677