blob: ab798496991370c3529bebce470eb39f88da8bdf [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 * *
47 * A few static variables and macros *
48 * *
49 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +000050/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +000051const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000052/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +000053const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +000054 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000055/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +000056const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
57
Owen Taylor3473f882001-02-23 17:55:21 +000058static int xmlCompressMode = 0;
59static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000060
Owen Taylor3473f882001-02-23 17:55:21 +000061#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
62 xmlNodePtr ulccur = (n)->children; \
63 if (ulccur == NULL) { \
64 (n)->last = NULL; \
65 } else { \
66 while (ulccur->next != NULL) { \
67 ulccur->parent = (n); \
68 ulccur = ulccur->next; \
69 } \
70 ulccur->parent = (n); \
71 (n)->last = ulccur; \
72}}
73
74/* #define DEBUG_BUFFER */
75/* #define DEBUG_TREE */
76
77/************************************************************************
78 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +000079 * Functions to move to entities.c once the *
80 * API freeze is smoothen and they can be made public. *
81 * *
82 ************************************************************************/
83#include <libxml/hash.h>
84
Daniel Veillard652327a2003-09-29 18:02:38 +000085#ifdef LIBXML_TREE_ENABLED
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +000086/**
87 * xmlGetEntityFromDtd:
88 * @dtd: A pointer to the DTD to search
89 * @name: The entity name
90 *
91 * Do an entity lookup in the DTD entity hash table and
92 * return the corresponding entity, if found.
93 *
94 * Returns A pointer to the entity structure or NULL if not found.
95 */
96static xmlEntityPtr
97xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
98 xmlEntitiesTablePtr table;
99
100 if((dtd != NULL) && (dtd->entities != NULL)) {
101 table = (xmlEntitiesTablePtr) dtd->entities;
102 return((xmlEntityPtr) xmlHashLookup(table, name));
103 /* return(xmlGetEntityFromTable(table, name)); */
104 }
105 return(NULL);
106}
107/**
108 * xmlGetParameterEntityFromDtd:
109 * @dtd: A pointer to the DTD to search
110 * @name: The entity name
111 *
112 * Do an entity lookup in the DTD pararmeter entity hash table and
113 * return the corresponding entity, if found.
114 *
115 * Returns A pointer to the entity structure or NULL if not found.
116 */
117static xmlEntityPtr
118xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
119 xmlEntitiesTablePtr table;
120
121 if ((dtd != NULL) && (dtd->pentities != NULL)) {
122 table = (xmlEntitiesTablePtr) dtd->pentities;
123 return((xmlEntityPtr) xmlHashLookup(table, name));
124 /* return(xmlGetEntityFromTable(table, name)); */
125 }
126 return(NULL);
127}
Daniel Veillard652327a2003-09-29 18:02:38 +0000128#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +0000129
130/************************************************************************
131 * *
Daniel Veillardc00cda82003-04-07 10:22:39 +0000132 * QName handling helper *
133 * *
134 ************************************************************************/
135
136/**
137 * xmlBuildQName:
138 * @ncname: the Name
139 * @prefix: the prefix
140 * @memory: preallocated memory
141 * @len: preallocated memory length
142 *
143 * Builds the QName @prefix:@ncname in @memory if there is enough space
144 * and prefix is not NULL nor empty, otherwise allocate a new string.
145 * If prefix is NULL or empty it returns ncname.
146 *
147 * Returns the new string which must be freed by the caller if different from
148 * @memory and @ncname or NULL in case of error
149 */
150xmlChar *
151xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix,
152 xmlChar *memory, int len) {
153 int lenn, lenp;
154 xmlChar *ret;
155
Daniel Veillard3b7840c2003-09-11 23:42:01 +0000156 if (ncname == NULL) return(NULL);
157 if (prefix == NULL) return((xmlChar *) ncname);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000158
159 lenn = strlen((char *) ncname);
160 lenp = strlen((char *) prefix);
161
162 if ((memory == NULL) || (len < lenn + lenp + 2)) {
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000163 ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000164 if (ret == NULL) return(NULL);
165 } else {
166 ret = memory;
167 }
168 memcpy(&ret[0], prefix, lenp);
169 ret[lenp] = ':';
170 memcpy(&ret[lenp + 1], ncname, lenn);
171 ret[lenn + lenp + 1] = 0;
172 return(ret);
173}
174
175/**
176 * xmlSplitQName2:
177 * @name: the full QName
178 * @prefix: a xmlChar **
179 *
180 * parse an XML qualified name string
181 *
182 * [NS 5] QName ::= (Prefix ':')? LocalPart
183 *
184 * [NS 6] Prefix ::= NCName
185 *
186 * [NS 7] LocalPart ::= NCName
187 *
188 * Returns NULL if not a QName, otherwise the local part, and prefix
189 * is updated to get the Prefix if any.
190 */
191
192xmlChar *
193xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
194 int len = 0;
195 xmlChar *ret = NULL;
196
197 *prefix = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000198 if (name == NULL) return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000199
200#ifndef XML_XML_NAMESPACE
201 /* xml: prefix is not really a namespace */
202 if ((name[0] == 'x') && (name[1] == 'm') &&
203 (name[2] == 'l') && (name[3] == ':'))
204 return(NULL);
205#endif
206
207 /* nasty but valid */
208 if (name[0] == ':')
209 return(NULL);
210
211 /*
212 * we are not trying to validate but just to cut, and yes it will
213 * work even if this is as set of UTF-8 encoded chars
214 */
215 while ((name[len] != 0) && (name[len] != ':'))
216 len++;
217
218 if (name[len] == 0)
219 return(NULL);
220
221 *prefix = xmlStrndup(name, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000222 if (*prefix == NULL) {
223 xmlGenericError(xmlGenericErrorContext,
224 "xmlSplitQName2 : out of memory!\n");
225 return(NULL);
226 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000227 ret = xmlStrdup(&name[len + 1]);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000228 if (ret == NULL) {
229 xmlGenericError(xmlGenericErrorContext,
230 "xmlSplitQName2 : out of memory!\n");
231 if (*prefix != NULL) {
232 xmlFree(*prefix);
233 *prefix = NULL;
234 }
235 return(NULL);
236 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000237
238 return(ret);
239}
240
Daniel Veillard8d73bcb2003-08-04 01:06:15 +0000241/**
242 * xmlSplitQName3:
243 * @name: the full QName
244 * @len: an int *
245 *
246 * parse an XML qualified name string,i
247 *
248 * returns NULL if it is not a Qualified Name, otherwise, update len
249 * with the lenght in byte of the prefix and return a pointer
250 */
251
252const xmlChar *
253xmlSplitQName3(const xmlChar *name, int *len) {
254 int l = 0;
255
256 if (name == NULL) return(NULL);
257 if (len == NULL) return(NULL);
258
259 /* nasty but valid */
260 if (name[0] == ':')
261 return(NULL);
262
263 /*
264 * we are not trying to validate but just to cut, and yes it will
265 * work even if this is as set of UTF-8 encoded chars
266 */
267 while ((name[l] != 0) && (name[l] != ':'))
268 l++;
269
270 if (name[l] == 0)
271 return(NULL);
272
273 *len = l;
274
275 return(&name[l+1]);
276}
277
Daniel Veillard652327a2003-09-29 18:02:38 +0000278#ifdef LIBXML_TREE_ENABLED
Daniel Veillardc00cda82003-04-07 10:22:39 +0000279/************************************************************************
280 * *
Daniel Veillardd2298792003-02-14 16:54:11 +0000281 * Check Name, NCName and QName strings *
282 * *
283 ************************************************************************/
284
285#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
286
287/**
288 * xmlValidateNCName:
289 * @value: the value to check
290 * @space: allow spaces in front and end of the string
291 *
292 * Check that a value conforms to the lexical space of NCName
293 *
294 * Returns 0 if this validates, a positive error code number otherwise
295 * and -1 in case of internal or API error.
296 */
297int
298xmlValidateNCName(const xmlChar *value, int space) {
299 const xmlChar *cur = value;
300 int c,l;
301
302 /*
303 * First quick algorithm for ASCII range
304 */
305 if (space)
306 while (IS_BLANK(*cur)) cur++;
307 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
308 (*cur == '_'))
309 cur++;
310 else
311 goto try_complex;
312 while (((*cur >= 'a') && (*cur <= 'z')) ||
313 ((*cur >= 'A') && (*cur <= 'Z')) ||
314 ((*cur >= '0') && (*cur <= '9')) ||
315 (*cur == '_') || (*cur == '-') || (*cur == '.'))
316 cur++;
317 if (space)
318 while (IS_BLANK(*cur)) cur++;
319 if (*cur == 0)
320 return(0);
321
322try_complex:
323 /*
324 * Second check for chars outside the ASCII range
325 */
326 cur = value;
327 c = CUR_SCHAR(cur, l);
328 if (space) {
329 while (IS_BLANK(c)) {
330 cur += l;
331 c = CUR_SCHAR(cur, l);
332 }
333 }
334 if ((!xmlIsLetter(c)) && (c != '_'))
335 return(1);
336 cur += l;
337 c = CUR_SCHAR(cur, l);
338 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') ||
339 (c == '-') || (c == '_') || xmlIsCombining(c) ||
340 xmlIsExtender(c)) {
341 cur += l;
342 c = CUR_SCHAR(cur, l);
343 }
344 if (space) {
345 while (IS_BLANK(c)) {
346 cur += l;
347 c = CUR_SCHAR(cur, l);
348 }
349 }
350 if (c != 0)
351 return(1);
352
353 return(0);
354}
355
356/**
357 * xmlValidateQName:
358 * @value: the value to check
359 * @space: allow spaces in front and end of the string
360 *
361 * Check that a value conforms to the lexical space of QName
362 *
363 * Returns 0 if this validates, a positive error code number otherwise
364 * and -1 in case of internal or API error.
365 */
366int
367xmlValidateQName(const xmlChar *value, int space) {
368 const xmlChar *cur = value;
369 int c,l;
370
371 /*
372 * First quick algorithm for ASCII range
373 */
374 if (space)
375 while (IS_BLANK(*cur)) cur++;
376 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
377 (*cur == '_'))
378 cur++;
379 else
380 goto try_complex;
381 while (((*cur >= 'a') && (*cur <= 'z')) ||
382 ((*cur >= 'A') && (*cur <= 'Z')) ||
383 ((*cur >= '0') && (*cur <= '9')) ||
384 (*cur == '_') || (*cur == '-') || (*cur == '.'))
385 cur++;
386 if (*cur == ':') {
387 cur++;
388 if (((*cur >= 'a') && (*cur <= 'z')) ||
389 ((*cur >= 'A') && (*cur <= 'Z')) ||
390 (*cur == '_'))
391 cur++;
392 else
393 goto try_complex;
394 while (((*cur >= 'a') && (*cur <= 'z')) ||
395 ((*cur >= 'A') && (*cur <= 'Z')) ||
396 ((*cur >= '0') && (*cur <= '9')) ||
397 (*cur == '_') || (*cur == '-') || (*cur == '.'))
398 cur++;
399 }
400 if (space)
401 while (IS_BLANK(*cur)) cur++;
402 if (*cur == 0)
403 return(0);
404
405try_complex:
406 /*
407 * Second check for chars outside the ASCII range
408 */
409 cur = value;
410 c = CUR_SCHAR(cur, l);
411 if (space) {
412 while (IS_BLANK(c)) {
413 cur += l;
414 c = CUR_SCHAR(cur, l);
415 }
416 }
417 if ((!xmlIsLetter(c)) && (c != '_'))
418 return(1);
419 cur += l;
420 c = CUR_SCHAR(cur, l);
421 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') ||
422 (c == '-') || (c == '_') || xmlIsCombining(c) ||
423 xmlIsExtender(c)) {
424 cur += l;
425 c = CUR_SCHAR(cur, l);
426 }
427 if (c == ':') {
428 cur += l;
429 c = CUR_SCHAR(cur, l);
430 if ((!xmlIsLetter(c)) && (c != '_'))
431 return(1);
432 cur += l;
433 c = CUR_SCHAR(cur, l);
434 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') ||
435 (c == '-') || (c == '_') || xmlIsCombining(c) ||
436 xmlIsExtender(c)) {
437 cur += l;
438 c = CUR_SCHAR(cur, l);
439 }
440 }
441 if (space) {
442 while (IS_BLANK(c)) {
443 cur += l;
444 c = CUR_SCHAR(cur, l);
445 }
446 }
447 if (c != 0)
448 return(1);
449 return(0);
450}
451
452/**
453 * xmlValidateName:
454 * @value: the value to check
455 * @space: allow spaces in front and end of the string
456 *
457 * Check that a value conforms to the lexical space of Name
458 *
459 * Returns 0 if this validates, a positive error code number otherwise
460 * and -1 in case of internal or API error.
461 */
462int
463xmlValidateName(const xmlChar *value, int space) {
464 const xmlChar *cur = value;
465 int c,l;
466
467 /*
468 * First quick algorithm for ASCII range
469 */
470 if (space)
471 while (IS_BLANK(*cur)) cur++;
472 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
473 (*cur == '_') || (*cur == ':'))
474 cur++;
475 else
476 goto try_complex;
477 while (((*cur >= 'a') && (*cur <= 'z')) ||
478 ((*cur >= 'A') && (*cur <= 'Z')) ||
479 ((*cur >= '0') && (*cur <= '9')) ||
480 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
481 cur++;
482 if (space)
483 while (IS_BLANK(*cur)) cur++;
484 if (*cur == 0)
485 return(0);
486
487try_complex:
488 /*
489 * Second check for chars outside the ASCII range
490 */
491 cur = value;
492 c = CUR_SCHAR(cur, l);
493 if (space) {
494 while (IS_BLANK(c)) {
495 cur += l;
496 c = CUR_SCHAR(cur, l);
497 }
498 }
499 if ((!xmlIsLetter(c)) && (c != '_') && (c != ':'))
500 return(1);
501 cur += l;
502 c = CUR_SCHAR(cur, l);
503 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') || (c == ':') ||
504 (c == '-') || (c == '_') || xmlIsCombining(c) || xmlIsExtender(c)) {
505 cur += l;
506 c = CUR_SCHAR(cur, l);
507 }
508 if (space) {
509 while (IS_BLANK(c)) {
510 cur += l;
511 c = CUR_SCHAR(cur, l);
512 }
513 }
514 if (c != 0)
515 return(1);
516 return(0);
517}
518
Daniel Veillardd4310742003-02-18 21:12:46 +0000519/**
520 * xmlValidateNMToken:
521 * @value: the value to check
522 * @space: allow spaces in front and end of the string
523 *
524 * Check that a value conforms to the lexical space of NMToken
525 *
526 * Returns 0 if this validates, a positive error code number otherwise
527 * and -1 in case of internal or API error.
528 */
529int
530xmlValidateNMToken(const xmlChar *value, int space) {
531 const xmlChar *cur = value;
532 int c,l;
533
534 /*
535 * First quick algorithm for ASCII range
536 */
537 if (space)
538 while (IS_BLANK(*cur)) cur++;
539 if (((*cur >= 'a') && (*cur <= 'z')) ||
540 ((*cur >= 'A') && (*cur <= 'Z')) ||
541 ((*cur >= '0') && (*cur <= '9')) ||
542 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
543 cur++;
544 else
545 goto try_complex;
546 while (((*cur >= 'a') && (*cur <= 'z')) ||
547 ((*cur >= 'A') && (*cur <= 'Z')) ||
548 ((*cur >= '0') && (*cur <= '9')) ||
549 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
550 cur++;
551 if (space)
552 while (IS_BLANK(*cur)) cur++;
553 if (*cur == 0)
554 return(0);
555
556try_complex:
557 /*
558 * Second check for chars outside the ASCII range
559 */
560 cur = value;
561 c = CUR_SCHAR(cur, l);
562 if (space) {
563 while (IS_BLANK(c)) {
564 cur += l;
565 c = CUR_SCHAR(cur, l);
566 }
567 }
568 if (!(xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') || (c == ':') ||
569 (c == '-') || (c == '_') || xmlIsCombining(c) || xmlIsExtender(c)))
570 return(1);
571 cur += l;
572 c = CUR_SCHAR(cur, l);
573 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') || (c == ':') ||
574 (c == '-') || (c == '_') || xmlIsCombining(c) || xmlIsExtender(c)) {
575 cur += l;
576 c = CUR_SCHAR(cur, l);
577 }
578 if (space) {
579 while (IS_BLANK(c)) {
580 cur += l;
581 c = CUR_SCHAR(cur, l);
582 }
583 }
584 if (c != 0)
585 return(1);
586 return(0);
587}
Daniel Veillard652327a2003-09-29 18:02:38 +0000588#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardd4310742003-02-18 21:12:46 +0000589
Daniel Veillardd2298792003-02-14 16:54:11 +0000590/************************************************************************
591 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000592 * Allocation and deallocation of basic structures *
593 * *
594 ************************************************************************/
595
596/**
597 * xmlSetBufferAllocationScheme:
598 * @scheme: allocation method to use
599 *
600 * Set the buffer allocation method. Types are
601 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
602 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
603 * improves performance
604 */
605void
606xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
607 xmlBufferAllocScheme = scheme;
608}
609
610/**
611 * xmlGetBufferAllocationScheme:
612 *
613 * Types are
614 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
615 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
616 * improves performance
617 *
618 * Returns the current allocation scheme
619 */
620xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000621xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000622 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000623}
624
625/**
626 * xmlNewNs:
627 * @node: the element carrying the namespace
628 * @href: the URI associated
629 * @prefix: the prefix for the namespace
630 *
631 * Creation of a new Namespace. This function will refuse to create
632 * a namespace with a similar prefix than an existing one present on this
633 * node.
634 * We use href==NULL in the case of an element creation where the namespace
635 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000636 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000637 */
638xmlNsPtr
639xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
640 xmlNsPtr cur;
641
642 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
643 return(NULL);
644
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000645 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
646 return(NULL);
647
Owen Taylor3473f882001-02-23 17:55:21 +0000648 /*
649 * Allocate a new Namespace and fill the fields.
650 */
651 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
652 if (cur == NULL) {
653 xmlGenericError(xmlGenericErrorContext,
654 "xmlNewNs : malloc failed\n");
655 return(NULL);
656 }
657 memset(cur, 0, sizeof(xmlNs));
658 cur->type = XML_LOCAL_NAMESPACE;
659
660 if (href != NULL)
661 cur->href = xmlStrdup(href);
662 if (prefix != NULL)
663 cur->prefix = xmlStrdup(prefix);
664
665 /*
666 * Add it at the end to preserve parsing order ...
667 * and checks for existing use of the prefix
668 */
669 if (node != NULL) {
670 if (node->nsDef == NULL) {
671 node->nsDef = cur;
672 } else {
673 xmlNsPtr prev = node->nsDef;
674
675 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
676 (xmlStrEqual(prev->prefix, cur->prefix))) {
677 xmlFreeNs(cur);
678 return(NULL);
679 }
680 while (prev->next != NULL) {
681 prev = prev->next;
682 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
683 (xmlStrEqual(prev->prefix, cur->prefix))) {
684 xmlFreeNs(cur);
685 return(NULL);
686 }
687 }
688 prev->next = cur;
689 }
690 }
691 return(cur);
692}
693
694/**
695 * xmlSetNs:
696 * @node: a node in the document
697 * @ns: a namespace pointer
698 *
699 * Associate a namespace to a node, a posteriori.
700 */
701void
702xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
703 if (node == NULL) {
704#ifdef DEBUG_TREE
705 xmlGenericError(xmlGenericErrorContext,
706 "xmlSetNs: node == NULL\n");
707#endif
708 return;
709 }
710 node->ns = ns;
711}
712
713/**
714 * xmlFreeNs:
715 * @cur: the namespace pointer
716 *
717 * Free up the structures associated to a namespace
718 */
719void
720xmlFreeNs(xmlNsPtr cur) {
721 if (cur == NULL) {
722#ifdef DEBUG_TREE
723 xmlGenericError(xmlGenericErrorContext,
724 "xmlFreeNs : ns == NULL\n");
725#endif
726 return;
727 }
728 if (cur->href != NULL) xmlFree((char *) cur->href);
729 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000730 xmlFree(cur);
731}
732
733/**
734 * xmlFreeNsList:
735 * @cur: the first namespace pointer
736 *
737 * Free up all the structures associated to the chained namespaces.
738 */
739void
740xmlFreeNsList(xmlNsPtr cur) {
741 xmlNsPtr next;
742 if (cur == NULL) {
743#ifdef DEBUG_TREE
744 xmlGenericError(xmlGenericErrorContext,
745 "xmlFreeNsList : ns == NULL\n");
746#endif
747 return;
748 }
749 while (cur != NULL) {
750 next = cur->next;
751 xmlFreeNs(cur);
752 cur = next;
753 }
754}
755
756/**
757 * xmlNewDtd:
758 * @doc: the document pointer
759 * @name: the DTD name
760 * @ExternalID: the external ID
761 * @SystemID: the system ID
762 *
763 * Creation of a new DTD for the external subset. To create an
764 * internal subset, use xmlCreateIntSubset().
765 *
766 * Returns a pointer to the new DTD structure
767 */
768xmlDtdPtr
769xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
770 const xmlChar *ExternalID, const xmlChar *SystemID) {
771 xmlDtdPtr cur;
772
773 if ((doc != NULL) && (doc->extSubset != NULL)) {
774#ifdef DEBUG_TREE
775 xmlGenericError(xmlGenericErrorContext,
776 "xmlNewDtd(%s): document %s already have a DTD %s\n",
777 /* !!! */ (char *) name, doc->name,
778 /* !!! */ (char *)doc->extSubset->name);
779#endif
780 return(NULL);
781 }
782
783 /*
784 * Allocate a new DTD and fill the fields.
785 */
786 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
787 if (cur == NULL) {
788 xmlGenericError(xmlGenericErrorContext,
789 "xmlNewDtd : malloc failed\n");
790 return(NULL);
791 }
792 memset(cur, 0 , sizeof(xmlDtd));
793 cur->type = XML_DTD_NODE;
794
795 if (name != NULL)
796 cur->name = xmlStrdup(name);
797 if (ExternalID != NULL)
798 cur->ExternalID = xmlStrdup(ExternalID);
799 if (SystemID != NULL)
800 cur->SystemID = xmlStrdup(SystemID);
801 if (doc != NULL)
802 doc->extSubset = cur;
803 cur->doc = doc;
804
Daniel Veillarda880b122003-04-21 21:36:41 +0000805 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000806 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000807 return(cur);
808}
809
810/**
811 * xmlGetIntSubset:
812 * @doc: the document pointer
813 *
814 * Get the internal subset of a document
815 * Returns a pointer to the DTD structure or NULL if not found
816 */
817
818xmlDtdPtr
819xmlGetIntSubset(xmlDocPtr doc) {
820 xmlNodePtr cur;
821
822 if (doc == NULL)
823 return(NULL);
824 cur = doc->children;
825 while (cur != NULL) {
826 if (cur->type == XML_DTD_NODE)
827 return((xmlDtdPtr) cur);
828 cur = cur->next;
829 }
830 return((xmlDtdPtr) doc->intSubset);
831}
832
833/**
834 * xmlCreateIntSubset:
835 * @doc: the document pointer
836 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000837 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000838 * @SystemID: the system ID
839 *
840 * Create the internal subset of a document
841 * Returns a pointer to the new DTD structure
842 */
843xmlDtdPtr
844xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
845 const xmlChar *ExternalID, const xmlChar *SystemID) {
846 xmlDtdPtr cur;
847
848 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
849#ifdef DEBUG_TREE
850 xmlGenericError(xmlGenericErrorContext,
851
852 "xmlCreateIntSubset(): document %s already have an internal subset\n",
853 doc->name);
854#endif
855 return(NULL);
856 }
857
858 /*
859 * Allocate a new DTD and fill the fields.
860 */
861 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
862 if (cur == NULL) {
863 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000864 "xmlCreateIntSubset : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000865 return(NULL);
866 }
867 memset(cur, 0, sizeof(xmlDtd));
868 cur->type = XML_DTD_NODE;
869
870 if (name != NULL)
871 cur->name = xmlStrdup(name);
872 if (ExternalID != NULL)
873 cur->ExternalID = xmlStrdup(ExternalID);
874 if (SystemID != NULL)
875 cur->SystemID = xmlStrdup(SystemID);
876 if (doc != NULL) {
877 doc->intSubset = cur;
878 cur->parent = doc;
879 cur->doc = doc;
880 if (doc->children == NULL) {
881 doc->children = (xmlNodePtr) cur;
882 doc->last = (xmlNodePtr) cur;
883 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000884 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000885 xmlNodePtr prev;
886
Owen Taylor3473f882001-02-23 17:55:21 +0000887 prev = doc->children;
888 prev->prev = (xmlNodePtr) cur;
889 cur->next = prev;
890 doc->children = (xmlNodePtr) cur;
891 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000892 xmlNodePtr next;
893
894 next = doc->children;
895 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
896 next = next->next;
897 if (next == NULL) {
898 cur->prev = doc->last;
899 cur->prev->next = (xmlNodePtr) cur;
900 cur->next = NULL;
901 doc->last = (xmlNodePtr) cur;
902 } else {
903 cur->next = next;
904 cur->prev = next->prev;
905 if (cur->prev == NULL)
906 doc->children = (xmlNodePtr) cur;
907 else
908 cur->prev->next = (xmlNodePtr) cur;
909 next->prev = (xmlNodePtr) cur;
910 }
Owen Taylor3473f882001-02-23 17:55:21 +0000911 }
912 }
913 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000914
Daniel Veillarda880b122003-04-21 21:36:41 +0000915 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000916 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000917 return(cur);
918}
919
920/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000921 * DICT_FREE:
922 * @str: a string
923 *
924 * Free a string if it is not owned by the "dict" dictionnary in the
925 * current scope
926 */
927#define DICT_FREE(str) \
928 if ((str) && ((!dict) || \
929 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
930 xmlFree((char *)(str));
931
932/**
Owen Taylor3473f882001-02-23 17:55:21 +0000933 * xmlFreeDtd:
934 * @cur: the DTD structure to free up
935 *
936 * Free a DTD structure.
937 */
938void
939xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000940 xmlDictPtr dict = NULL;
941
Owen Taylor3473f882001-02-23 17:55:21 +0000942 if (cur == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000943 return;
944 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000945 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +0000946
Daniel Veillarda880b122003-04-21 21:36:41 +0000947 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000948 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
949
Owen Taylor3473f882001-02-23 17:55:21 +0000950 if (cur->children != NULL) {
951 xmlNodePtr next, c = cur->children;
952
953 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000954 * Cleanup all the DTD comments they are not in the DTD
Owen Taylor3473f882001-02-23 17:55:21 +0000955 * indexes.
956 */
957 while (c != NULL) {
958 next = c->next;
Daniel Veillardd72c7e32003-05-12 21:55:03 +0000959 if ((c->type == XML_COMMENT_NODE) || (c->type == XML_PI_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000960 xmlUnlinkNode(c);
961 xmlFreeNode(c);
962 }
963 c = next;
964 }
965 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000966 DICT_FREE(cur->name)
967 DICT_FREE(cur->SystemID)
968 DICT_FREE(cur->ExternalID)
Owen Taylor3473f882001-02-23 17:55:21 +0000969 /* TODO !!! */
970 if (cur->notations != NULL)
971 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
972
973 if (cur->elements != NULL)
974 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
975 if (cur->attributes != NULL)
976 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
977 if (cur->entities != NULL)
978 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
979 if (cur->pentities != NULL)
980 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
981
Owen Taylor3473f882001-02-23 17:55:21 +0000982 xmlFree(cur);
983}
984
985/**
986 * xmlNewDoc:
987 * @version: xmlChar string giving the version of XML "1.0"
988 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000989 * Creates a new XML document
990 *
Owen Taylor3473f882001-02-23 17:55:21 +0000991 * Returns a new document
992 */
993xmlDocPtr
994xmlNewDoc(const xmlChar *version) {
995 xmlDocPtr cur;
996
997 if (version == NULL)
998 version = (const xmlChar *) "1.0";
999
1000 /*
1001 * Allocate a new document and fill the fields.
1002 */
1003 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
1004 if (cur == NULL) {
1005 xmlGenericError(xmlGenericErrorContext,
1006 "xmlNewDoc : malloc failed\n");
1007 return(NULL);
1008 }
1009 memset(cur, 0, sizeof(xmlDoc));
1010 cur->type = XML_DOCUMENT_NODE;
1011
1012 cur->version = xmlStrdup(version);
1013 cur->standalone = -1;
1014 cur->compression = -1; /* not initialized */
1015 cur->doc = cur;
Daniel Veillarda6874ca2003-07-29 16:47:24 +00001016 /*
1017 * The in memory encoding is always UTF8
1018 * This field will never change and would
1019 * be obsolete if not for binary compatibility.
1020 */
Daniel Veillardd2f3ec72001-04-11 07:50:02 +00001021 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001022
Daniel Veillarda880b122003-04-21 21:36:41 +00001023 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001024 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001025 return(cur);
1026}
1027
1028/**
1029 * xmlFreeDoc:
1030 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +00001031 *
1032 * Free up all the structures used by a document, tree included.
1033 */
1034void
1035xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +00001036 xmlDtdPtr extSubset, intSubset;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001037 xmlDictPtr dict = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001038
Owen Taylor3473f882001-02-23 17:55:21 +00001039 if (cur == NULL) {
1040#ifdef DEBUG_TREE
1041 xmlGenericError(xmlGenericErrorContext,
1042 "xmlFreeDoc : document == NULL\n");
1043#endif
1044 return;
1045 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001046 if (cur != NULL) dict = cur->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001047
Daniel Veillarda880b122003-04-21 21:36:41 +00001048 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001049 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1050
Daniel Veillard76d66f42001-05-16 21:05:17 +00001051 /*
1052 * Do this before freeing the children list to avoid ID lookups
1053 */
1054 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1055 cur->ids = NULL;
1056 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1057 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001058 extSubset = cur->extSubset;
1059 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +00001060 if (intSubset == extSubset)
1061 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001062 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001063 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001064 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001065 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001066 }
Daniel Veillarda9142e72001-06-19 11:07:54 +00001067 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001068 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001069 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001070 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001071 }
1072
1073 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001074 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001075
1076 DICT_FREE(cur->version)
1077 DICT_FREE(cur->name)
1078 DICT_FREE(cur->encoding)
1079 DICT_FREE(cur->URL)
Owen Taylor3473f882001-02-23 17:55:21 +00001080 xmlFree(cur);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001081 if (dict) xmlDictFree(dict);
Owen Taylor3473f882001-02-23 17:55:21 +00001082}
1083
1084/**
1085 * xmlStringLenGetNodeList:
1086 * @doc: the document
1087 * @value: the value of the text
1088 * @len: the length of the string value
1089 *
1090 * Parse the value string and build the node list associated. Should
1091 * produce a flat tree with only TEXTs and ENTITY_REFs.
1092 * Returns a pointer to the first child
1093 */
1094xmlNodePtr
1095xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1096 xmlNodePtr ret = NULL, last = NULL;
1097 xmlNodePtr node;
1098 xmlChar *val;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001099 const xmlChar *cur = value, *end = cur + len;
Owen Taylor3473f882001-02-23 17:55:21 +00001100 const xmlChar *q;
1101 xmlEntityPtr ent;
1102
1103 if (value == NULL) return(NULL);
1104
1105 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001106 while ((cur < end) && (*cur != 0)) {
1107 if (cur[0] == '&') {
1108 int charval = 0;
1109 xmlChar tmp;
1110
Owen Taylor3473f882001-02-23 17:55:21 +00001111 /*
1112 * Save the current text.
1113 */
1114 if (cur != q) {
1115 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1116 xmlNodeAddContentLen(last, q, cur - q);
1117 } else {
1118 node = xmlNewDocTextLen(doc, q, cur - q);
1119 if (node == NULL) return(ret);
1120 if (last == NULL)
1121 last = ret = node;
1122 else {
1123 last->next = node;
1124 node->prev = last;
1125 last = node;
1126 }
1127 }
1128 }
Owen Taylor3473f882001-02-23 17:55:21 +00001129 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001130 if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
1131 cur += 3;
1132 if (cur < end)
1133 tmp = *cur;
1134 else
1135 tmp = 0;
1136 while (tmp != ';') { /* Non input consuming loop */
1137 if ((tmp >= '0') && (tmp <= '9'))
1138 charval = charval * 16 + (tmp - '0');
1139 else if ((tmp >= 'a') && (tmp <= 'f'))
1140 charval = charval * 16 + (tmp - 'a') + 10;
1141 else if ((tmp >= 'A') && (tmp <= 'F'))
1142 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001143 else {
Daniel Veillard07cb8222003-09-10 10:51:05 +00001144 xmlGenericError(xmlGenericErrorContext,
1145 "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
1146 charval = 0;
1147 break;
1148 }
1149 cur++;
1150 if (cur < end)
1151 tmp = *cur;
1152 else
1153 tmp = 0;
1154 }
1155 if (tmp == ';')
1156 cur++;
1157 q = cur;
1158 } else if ((cur + 1 < end) && (cur[1] == '#')) {
1159 cur += 2;
1160 if (cur < end)
1161 tmp = *cur;
1162 else
1163 tmp = 0;
1164 while (tmp != ';') { /* Non input consuming loops */
1165 if ((tmp >= '0') && (tmp <= '9'))
1166 charval = charval * 10 + (tmp - '0');
1167 else {
1168 xmlGenericError(xmlGenericErrorContext,
1169 "xmlStringGetNodeList: invalid decimal charvalue\n");
1170 charval = 0;
1171 break;
1172 }
1173 cur++;
1174 if (cur < end)
1175 tmp = *cur;
1176 else
1177 tmp = 0;
1178 }
1179 if (tmp == ';')
1180 cur++;
1181 q = cur;
1182 } else {
1183 /*
1184 * Read the entity string
1185 */
1186 cur++;
1187 q = cur;
1188 while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1189 if ((cur >= end) || (*cur == 0)) {
1190#ifdef DEBUG_TREE
1191 xmlGenericError(xmlGenericErrorContext,
1192 "xmlStringGetNodeList: unterminated entity %30s\n", q);
1193#endif
1194 return(ret);
1195 }
1196 if (cur != q) {
1197 /*
1198 * Predefined entities don't generate nodes
1199 */
1200 val = xmlStrndup(q, cur - q);
1201 ent = xmlGetDocEntity(doc, val);
1202 if ((ent != NULL) &&
1203 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1204 if (last == NULL) {
1205 node = xmlNewDocText(doc, ent->content);
1206 last = ret = node;
1207 } else if (last->type != XML_TEXT_NODE) {
1208 node = xmlNewDocText(doc, ent->content);
1209 last = xmlAddNextSibling(last, node);
1210 } else
1211 xmlNodeAddContent(last, ent->content);
1212
1213 } else {
1214 /*
1215 * Create a new REFERENCE_REF node
1216 */
1217 node = xmlNewReference(doc, val);
1218 if (node == NULL) {
1219 if (val != NULL) xmlFree(val);
1220 return(ret);
1221 }
1222 else if ((ent != NULL) && (ent->children == NULL)) {
1223 xmlNodePtr temp;
1224
1225 ent->children = xmlStringGetNodeList(doc,
1226 (const xmlChar*)node->content);
1227 ent->owner = 1;
1228 temp = ent->children;
1229 while (temp) {
1230 temp->parent = (xmlNodePtr)ent;
1231 temp = temp->next;
1232 }
1233 }
1234 if (last == NULL) {
1235 last = ret = node;
1236 } else {
1237 last = xmlAddNextSibling(last, node);
1238 }
1239 }
1240 xmlFree(val);
1241 }
1242 cur++;
1243 q = cur;
1244 }
1245 if (charval != 0) {
1246 xmlChar buf[10];
1247 int l;
1248
1249 l = xmlCopyCharMultiByte(buf, charval);
1250 buf[l] = 0;
1251 node = xmlNewDocText(doc, buf);
1252 if (node != NULL) {
1253 if (last == NULL) {
1254 last = ret = node;
1255 } else {
1256 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001257 }
1258 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001259 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001260 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001261 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001262 cur++;
1263 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001264 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001265 /*
1266 * Handle the last piece of text.
1267 */
1268 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1269 xmlNodeAddContentLen(last, q, cur - q);
1270 } else {
1271 node = xmlNewDocTextLen(doc, q, cur - q);
1272 if (node == NULL) return(ret);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001273 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001274 last = ret = node;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001275 } else {
1276 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001277 }
1278 }
1279 }
1280 return(ret);
1281}
1282
1283/**
1284 * xmlStringGetNodeList:
1285 * @doc: the document
1286 * @value: the value of the attribute
1287 *
1288 * Parse the value string and build the node list associated. Should
1289 * produce a flat tree with only TEXTs and ENTITY_REFs.
1290 * Returns a pointer to the first child
1291 */
1292xmlNodePtr
1293xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1294 xmlNodePtr ret = NULL, last = NULL;
1295 xmlNodePtr node;
1296 xmlChar *val;
1297 const xmlChar *cur = value;
1298 const xmlChar *q;
1299 xmlEntityPtr ent;
1300
1301 if (value == NULL) return(NULL);
1302
1303 q = cur;
1304 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001305 if (cur[0] == '&') {
1306 int charval = 0;
1307 xmlChar tmp;
1308
Owen Taylor3473f882001-02-23 17:55:21 +00001309 /*
1310 * Save the current text.
1311 */
1312 if (cur != q) {
1313 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1314 xmlNodeAddContentLen(last, q, cur - q);
1315 } else {
1316 node = xmlNewDocTextLen(doc, q, cur - q);
1317 if (node == NULL) return(ret);
1318 if (last == NULL)
1319 last = ret = node;
1320 else {
1321 last->next = node;
1322 node->prev = last;
1323 last = node;
1324 }
1325 }
1326 }
Owen Taylor3473f882001-02-23 17:55:21 +00001327 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001328 if ((cur[1] == '#') && (cur[2] == 'x')) {
1329 cur += 3;
1330 tmp = *cur;
1331 while (tmp != ';') { /* Non input consuming loop */
1332 if ((tmp >= '0') && (tmp <= '9'))
1333 charval = charval * 16 + (tmp - '0');
1334 else if ((tmp >= 'a') && (tmp <= 'f'))
1335 charval = charval * 16 + (tmp - 'a') + 10;
1336 else if ((tmp >= 'A') && (tmp <= 'F'))
1337 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001338 else {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001339 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001340 "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001341 charval = 0;
1342 break;
1343 }
1344 cur++;
1345 tmp = *cur;
1346 }
1347 if (tmp == ';')
1348 cur++;
1349 q = cur;
1350 } else if (cur[1] == '#') {
1351 cur += 2;
1352 tmp = *cur;
1353 while (tmp != ';') { /* Non input consuming loops */
1354 if ((tmp >= '0') && (tmp <= '9'))
1355 charval = charval * 10 + (tmp - '0');
1356 else {
1357 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001358 "xmlStringGetNodeList: invalid decimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001359 charval = 0;
1360 break;
1361 }
1362 cur++;
1363 tmp = *cur;
1364 }
1365 if (tmp == ';')
1366 cur++;
1367 q = cur;
1368 } else {
1369 /*
1370 * Read the entity string
1371 */
1372 cur++;
1373 q = cur;
1374 while ((*cur != 0) && (*cur != ';')) cur++;
1375 if (*cur == 0) {
1376#ifdef DEBUG_TREE
1377 xmlGenericError(xmlGenericErrorContext,
1378 "xmlStringGetNodeList: unterminated entity %30s\n", q);
1379#endif
1380 return(ret);
1381 }
1382 if (cur != q) {
1383 /*
1384 * Predefined entities don't generate nodes
1385 */
1386 val = xmlStrndup(q, cur - q);
1387 ent = xmlGetDocEntity(doc, val);
1388 if ((ent != NULL) &&
1389 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1390 if (last == NULL) {
1391 node = xmlNewDocText(doc, ent->content);
1392 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001393 } else if (last->type != XML_TEXT_NODE) {
1394 node = xmlNewDocText(doc, ent->content);
1395 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001396 } else
1397 xmlNodeAddContent(last, ent->content);
1398
1399 } else {
1400 /*
1401 * Create a new REFERENCE_REF node
1402 */
1403 node = xmlNewReference(doc, val);
1404 if (node == NULL) {
1405 if (val != NULL) xmlFree(val);
1406 return(ret);
1407 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001408 else if ((ent != NULL) && (ent->children == NULL)) {
1409 xmlNodePtr temp;
1410
1411 ent->children = xmlStringGetNodeList(doc,
1412 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001413 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001414 temp = ent->children;
1415 while (temp) {
1416 temp->parent = (xmlNodePtr)ent;
1417 temp = temp->next;
1418 }
1419 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001420 if (last == NULL) {
1421 last = ret = node;
1422 } else {
1423 last = xmlAddNextSibling(last, node);
1424 }
1425 }
1426 xmlFree(val);
1427 }
1428 cur++;
1429 q = cur;
1430 }
1431 if (charval != 0) {
1432 xmlChar buf[10];
1433 int len;
1434
1435 len = xmlCopyCharMultiByte(buf, charval);
1436 buf[len] = 0;
1437 node = xmlNewDocText(doc, buf);
1438 if (node != NULL) {
1439 if (last == NULL) {
1440 last = ret = node;
1441 } else {
1442 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001443 }
1444 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001445
1446 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001447 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001448 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001449 cur++;
1450 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001451 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001452 /*
1453 * Handle the last piece of text.
1454 */
1455 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1456 xmlNodeAddContentLen(last, q, cur - q);
1457 } else {
1458 node = xmlNewDocTextLen(doc, q, cur - q);
1459 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001460 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001461 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001462 } else {
1463 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001464 }
1465 }
1466 }
1467 return(ret);
1468}
1469
1470/**
1471 * xmlNodeListGetString:
1472 * @doc: the document
1473 * @list: a Node list
1474 * @inLine: should we replace entity contents or show their external form
1475 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001476 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001477 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001478 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001479 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001480 */
1481xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001482xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1483{
Owen Taylor3473f882001-02-23 17:55:21 +00001484 xmlNodePtr node = list;
1485 xmlChar *ret = NULL;
1486 xmlEntityPtr ent;
1487
Daniel Veillard7646b182002-04-20 06:41:40 +00001488 if (list == NULL)
1489 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001490
1491 while (node != NULL) {
1492 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001493 (node->type == XML_CDATA_SECTION_NODE)) {
1494 if (inLine) {
1495 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001496 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001497 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001498
Daniel Veillard7646b182002-04-20 06:41:40 +00001499 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1500 if (buffer != NULL) {
1501 ret = xmlStrcat(ret, buffer);
1502 xmlFree(buffer);
1503 }
1504 }
1505 } else if (node->type == XML_ENTITY_REF_NODE) {
1506 if (inLine) {
1507 ent = xmlGetDocEntity(doc, node->name);
1508 if (ent != NULL) {
1509 xmlChar *buffer;
1510
1511 /* an entity content can be any "well balanced chunk",
1512 * i.e. the result of the content [43] production:
1513 * http://www.w3.org/TR/REC-xml#NT-content.
1514 * So it can contain text, CDATA section or nested
1515 * entity reference nodes (among others).
1516 * -> we recursive call xmlNodeListGetString()
1517 * which handles these types */
1518 buffer = xmlNodeListGetString(doc, ent->children, 1);
1519 if (buffer != NULL) {
1520 ret = xmlStrcat(ret, buffer);
1521 xmlFree(buffer);
1522 }
1523 } else {
1524 ret = xmlStrcat(ret, node->content);
1525 }
1526 } else {
1527 xmlChar buf[2];
1528
1529 buf[0] = '&';
1530 buf[1] = 0;
1531 ret = xmlStrncat(ret, buf, 1);
1532 ret = xmlStrcat(ret, node->name);
1533 buf[0] = ';';
1534 buf[1] = 0;
1535 ret = xmlStrncat(ret, buf, 1);
1536 }
1537 }
1538#if 0
1539 else {
1540 xmlGenericError(xmlGenericErrorContext,
1541 "xmlGetNodeListString : invalid node type %d\n",
1542 node->type);
1543 }
1544#endif
1545 node = node->next;
1546 }
1547 return (ret);
1548}
Daniel Veillard652327a2003-09-29 18:02:38 +00001549
1550#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001551/**
1552 * xmlNodeListGetRawString:
1553 * @doc: the document
1554 * @list: a Node list
1555 * @inLine: should we replace entity contents or show their external form
1556 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001557 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001558 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1559 * this function doesn't do any character encoding handling.
1560 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001561 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001562 */
1563xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001564xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1565{
Owen Taylor3473f882001-02-23 17:55:21 +00001566 xmlNodePtr node = list;
1567 xmlChar *ret = NULL;
1568 xmlEntityPtr ent;
1569
Daniel Veillard7646b182002-04-20 06:41:40 +00001570 if (list == NULL)
1571 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001572
1573 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001574 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001575 (node->type == XML_CDATA_SECTION_NODE)) {
1576 if (inLine) {
1577 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001578 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001579 xmlChar *buffer;
1580
1581 buffer = xmlEncodeSpecialChars(doc, node->content);
1582 if (buffer != NULL) {
1583 ret = xmlStrcat(ret, buffer);
1584 xmlFree(buffer);
1585 }
1586 }
1587 } else if (node->type == XML_ENTITY_REF_NODE) {
1588 if (inLine) {
1589 ent = xmlGetDocEntity(doc, node->name);
1590 if (ent != NULL) {
1591 xmlChar *buffer;
1592
1593 /* an entity content can be any "well balanced chunk",
1594 * i.e. the result of the content [43] production:
1595 * http://www.w3.org/TR/REC-xml#NT-content.
1596 * So it can contain text, CDATA section or nested
1597 * entity reference nodes (among others).
1598 * -> we recursive call xmlNodeListGetRawString()
1599 * which handles these types */
1600 buffer =
1601 xmlNodeListGetRawString(doc, ent->children, 1);
1602 if (buffer != NULL) {
1603 ret = xmlStrcat(ret, buffer);
1604 xmlFree(buffer);
1605 }
1606 } else {
1607 ret = xmlStrcat(ret, node->content);
1608 }
1609 } else {
1610 xmlChar buf[2];
1611
1612 buf[0] = '&';
1613 buf[1] = 0;
1614 ret = xmlStrncat(ret, buf, 1);
1615 ret = xmlStrcat(ret, node->name);
1616 buf[0] = ';';
1617 buf[1] = 0;
1618 ret = xmlStrncat(ret, buf, 1);
1619 }
1620 }
Owen Taylor3473f882001-02-23 17:55:21 +00001621#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001622 else {
1623 xmlGenericError(xmlGenericErrorContext,
1624 "xmlGetNodeListString : invalid node type %d\n",
1625 node->type);
1626 }
Owen Taylor3473f882001-02-23 17:55:21 +00001627#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001628 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001629 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001630 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001631}
Daniel Veillard652327a2003-09-29 18:02:38 +00001632#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001633
Daniel Veillard652327a2003-09-29 18:02:38 +00001634#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001635/**
1636 * xmlNewProp:
1637 * @node: the holding node
1638 * @name: the name of the attribute
1639 * @value: the value of the attribute
1640 *
1641 * Create a new property carried by a node.
1642 * Returns a pointer to the attribute
1643 */
1644xmlAttrPtr
1645xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1646 xmlAttrPtr cur;
1647 xmlDocPtr doc = NULL;
1648
1649 if (name == NULL) {
1650#ifdef DEBUG_TREE
1651 xmlGenericError(xmlGenericErrorContext,
1652 "xmlNewProp : name == NULL\n");
1653#endif
1654 return(NULL);
1655 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00001656 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
1657 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001658
1659 /*
1660 * Allocate a new property and fill the fields.
1661 */
1662 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1663 if (cur == NULL) {
1664 xmlGenericError(xmlGenericErrorContext,
1665 "xmlNewProp : malloc failed\n");
1666 return(NULL);
1667 }
1668 memset(cur, 0, sizeof(xmlAttr));
1669 cur->type = XML_ATTRIBUTE_NODE;
1670
1671 cur->parent = node;
1672 if (node != NULL) {
1673 doc = node->doc;
1674 cur->doc = doc;
1675 }
1676 cur->name = xmlStrdup(name);
1677 if (value != NULL) {
1678 xmlChar *buffer;
1679 xmlNodePtr tmp;
1680
1681 buffer = xmlEncodeEntitiesReentrant(doc, value);
1682 cur->children = xmlStringGetNodeList(doc, buffer);
1683 cur->last = NULL;
1684 tmp = cur->children;
1685 while (tmp != NULL) {
1686 tmp->parent = (xmlNodePtr) cur;
1687 tmp->doc = doc;
1688 if (tmp->next == NULL)
1689 cur->last = tmp;
1690 tmp = tmp->next;
1691 }
1692 xmlFree(buffer);
1693 }
1694
1695 /*
1696 * Add it at the end to preserve parsing order ...
1697 */
1698 if (node != NULL) {
1699 if (node->properties == NULL) {
1700 node->properties = cur;
1701 } else {
1702 xmlAttrPtr prev = node->properties;
1703
1704 while (prev->next != NULL) prev = prev->next;
1705 prev->next = cur;
1706 cur->prev = prev;
1707 }
1708 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001709
Daniel Veillarda880b122003-04-21 21:36:41 +00001710 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001711 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001712 return(cur);
1713}
Daniel Veillard652327a2003-09-29 18:02:38 +00001714#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001715
1716/**
1717 * xmlNewNsProp:
1718 * @node: the holding node
1719 * @ns: the namespace
1720 * @name: the name of the attribute
1721 * @value: the value of the attribute
1722 *
1723 * Create a new property tagged with a namespace and carried by a node.
1724 * Returns a pointer to the attribute
1725 */
1726xmlAttrPtr
1727xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1728 const xmlChar *value) {
1729 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001730 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001731
1732 if (name == NULL) {
1733#ifdef DEBUG_TREE
1734 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001735 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001736#endif
1737 return(NULL);
1738 }
1739
1740 /*
1741 * Allocate a new property and fill the fields.
1742 */
1743 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1744 if (cur == NULL) {
1745 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001746 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001747 return(NULL);
1748 }
1749 memset(cur, 0, sizeof(xmlAttr));
1750 cur->type = XML_ATTRIBUTE_NODE;
1751
1752 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001753 if (node != NULL) {
1754 doc = node->doc;
1755 cur->doc = doc;
1756 }
Owen Taylor3473f882001-02-23 17:55:21 +00001757 cur->ns = ns;
1758 cur->name = xmlStrdup(name);
1759 if (value != NULL) {
1760 xmlChar *buffer;
1761 xmlNodePtr tmp;
1762
Daniel Veillarda682b212001-06-07 19:59:42 +00001763 buffer = xmlEncodeEntitiesReentrant(doc, value);
1764 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001765 cur->last = NULL;
1766 tmp = cur->children;
1767 while (tmp != NULL) {
1768 tmp->parent = (xmlNodePtr) cur;
1769 if (tmp->next == NULL)
1770 cur->last = tmp;
1771 tmp = tmp->next;
1772 }
1773 xmlFree(buffer);
1774 }
1775
1776 /*
1777 * Add it at the end to preserve parsing order ...
1778 */
1779 if (node != NULL) {
1780 if (node->properties == NULL) {
1781 node->properties = cur;
1782 } else {
1783 xmlAttrPtr prev = node->properties;
1784
1785 while (prev->next != NULL) prev = prev->next;
1786 prev->next = cur;
1787 cur->prev = prev;
1788 }
1789 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001790
Daniel Veillarda880b122003-04-21 21:36:41 +00001791 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001792 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001793 return(cur);
1794}
1795
1796/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001797 * xmlNewNsPropEatName:
1798 * @node: the holding node
1799 * @ns: the namespace
1800 * @name: the name of the attribute
1801 * @value: the value of the attribute
1802 *
1803 * Create a new property tagged with a namespace and carried by a node.
1804 * Returns a pointer to the attribute
1805 */
1806xmlAttrPtr
1807xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1808 const xmlChar *value) {
1809 xmlAttrPtr cur;
1810 xmlDocPtr doc = NULL;
1811
1812 if (name == NULL) {
1813#ifdef DEBUG_TREE
1814 xmlGenericError(xmlGenericErrorContext,
1815 "xmlNewNsPropEatName : name == NULL\n");
1816#endif
1817 return(NULL);
1818 }
1819
1820 /*
1821 * Allocate a new property and fill the fields.
1822 */
1823 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1824 if (cur == NULL) {
1825 xmlGenericError(xmlGenericErrorContext,
1826 "xmlNewNsPropEatName : malloc failed\n");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001827 xmlFree(name);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001828 return(NULL);
1829 }
1830 memset(cur, 0, sizeof(xmlAttr));
1831 cur->type = XML_ATTRIBUTE_NODE;
1832
1833 cur->parent = node;
1834 if (node != NULL) {
1835 doc = node->doc;
1836 cur->doc = doc;
1837 }
1838 cur->ns = ns;
1839 cur->name = name;
1840 if (value != NULL) {
1841 xmlChar *buffer;
1842 xmlNodePtr tmp;
1843
1844 buffer = xmlEncodeEntitiesReentrant(doc, value);
1845 cur->children = xmlStringGetNodeList(doc, buffer);
1846 cur->last = NULL;
1847 tmp = cur->children;
1848 while (tmp != NULL) {
1849 tmp->parent = (xmlNodePtr) cur;
1850 if (tmp->next == NULL)
1851 cur->last = tmp;
1852 tmp = tmp->next;
1853 }
1854 xmlFree(buffer);
1855 }
1856
1857 /*
1858 * Add it at the end to preserve parsing order ...
1859 */
1860 if (node != NULL) {
1861 if (node->properties == NULL) {
1862 node->properties = cur;
1863 } else {
1864 xmlAttrPtr prev = node->properties;
1865
1866 while (prev->next != NULL) prev = prev->next;
1867 prev->next = cur;
1868 cur->prev = prev;
1869 }
1870 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001871
Daniel Veillarda880b122003-04-21 21:36:41 +00001872 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001873 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001874 return(cur);
1875}
1876
1877/**
Owen Taylor3473f882001-02-23 17:55:21 +00001878 * xmlNewDocProp:
1879 * @doc: the document
1880 * @name: the name of the attribute
1881 * @value: the value of the attribute
1882 *
1883 * Create a new property carried by a document.
1884 * Returns a pointer to the attribute
1885 */
1886xmlAttrPtr
1887xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1888 xmlAttrPtr cur;
1889
1890 if (name == NULL) {
1891#ifdef DEBUG_TREE
1892 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001893 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001894#endif
1895 return(NULL);
1896 }
1897
1898 /*
1899 * Allocate a new property and fill the fields.
1900 */
1901 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1902 if (cur == NULL) {
1903 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001904 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001905 return(NULL);
1906 }
1907 memset(cur, 0, sizeof(xmlAttr));
1908 cur->type = XML_ATTRIBUTE_NODE;
1909
1910 cur->name = xmlStrdup(name);
1911 cur->doc = doc;
1912 if (value != NULL) {
1913 xmlNodePtr tmp;
1914
1915 cur->children = xmlStringGetNodeList(doc, value);
1916 cur->last = NULL;
1917
1918 tmp = cur->children;
1919 while (tmp != NULL) {
1920 tmp->parent = (xmlNodePtr) cur;
1921 if (tmp->next == NULL)
1922 cur->last = tmp;
1923 tmp = tmp->next;
1924 }
1925 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001926
Daniel Veillarda880b122003-04-21 21:36:41 +00001927 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001928 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001929 return(cur);
1930}
1931
1932/**
1933 * xmlFreePropList:
1934 * @cur: the first property in the list
1935 *
1936 * Free a property and all its siblings, all the children are freed too.
1937 */
1938void
1939xmlFreePropList(xmlAttrPtr cur) {
1940 xmlAttrPtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001941 if (cur == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001942 while (cur != NULL) {
1943 next = cur->next;
1944 xmlFreeProp(cur);
1945 cur = next;
1946 }
1947}
1948
1949/**
1950 * xmlFreeProp:
1951 * @cur: an attribute
1952 *
1953 * Free one attribute, all the content is freed too
1954 */
1955void
1956xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001957 xmlDictPtr dict = NULL;
1958 if (cur == NULL) return;
1959
1960 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001961
Daniel Veillarda880b122003-04-21 21:36:41 +00001962 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001963 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1964
Owen Taylor3473f882001-02-23 17:55:21 +00001965 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001966 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1967 ((cur->parent->doc->intSubset != NULL) ||
1968 (cur->parent->doc->extSubset != NULL))) {
1969 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1970 xmlRemoveID(cur->parent->doc, cur);
1971 }
Owen Taylor3473f882001-02-23 17:55:21 +00001972 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001973 DICT_FREE(cur->name)
Owen Taylor3473f882001-02-23 17:55:21 +00001974 xmlFree(cur);
1975}
1976
Daniel Veillard652327a2003-09-29 18:02:38 +00001977#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001978/**
1979 * xmlRemoveProp:
1980 * @cur: an attribute
1981 *
1982 * Unlink and free one attribute, all the content is freed too
1983 * Note this doesn't work for namespace definition attributes
1984 *
1985 * Returns 0 if success and -1 in case of error.
1986 */
1987int
1988xmlRemoveProp(xmlAttrPtr cur) {
1989 xmlAttrPtr tmp;
1990 if (cur == NULL) {
1991#ifdef DEBUG_TREE
1992 xmlGenericError(xmlGenericErrorContext,
1993 "xmlRemoveProp : cur == NULL\n");
1994#endif
1995 return(-1);
1996 }
1997 if (cur->parent == NULL) {
1998#ifdef DEBUG_TREE
1999 xmlGenericError(xmlGenericErrorContext,
2000 "xmlRemoveProp : cur->parent == NULL\n");
2001#endif
2002 return(-1);
2003 }
2004 tmp = cur->parent->properties;
2005 if (tmp == cur) {
2006 cur->parent->properties = cur->next;
2007 xmlFreeProp(cur);
2008 return(0);
2009 }
2010 while (tmp != NULL) {
2011 if (tmp->next == cur) {
2012 tmp->next = cur->next;
2013 if (tmp->next != NULL)
2014 tmp->next->prev = tmp;
2015 xmlFreeProp(cur);
2016 return(0);
2017 }
2018 tmp = tmp->next;
2019 }
2020#ifdef DEBUG_TREE
2021 xmlGenericError(xmlGenericErrorContext,
2022 "xmlRemoveProp : attribute not owned by its node\n");
2023#endif
2024 return(-1);
2025}
Daniel Veillard652327a2003-09-29 18:02:38 +00002026#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002027
2028/**
2029 * xmlNewPI:
2030 * @name: the processing instruction name
2031 * @content: the PI content
2032 *
2033 * Creation of a processing instruction element.
2034 * Returns a pointer to the new node object.
2035 */
2036xmlNodePtr
2037xmlNewPI(const xmlChar *name, const xmlChar *content) {
2038 xmlNodePtr cur;
2039
2040 if (name == NULL) {
2041#ifdef DEBUG_TREE
2042 xmlGenericError(xmlGenericErrorContext,
2043 "xmlNewPI : name == NULL\n");
2044#endif
2045 return(NULL);
2046 }
2047
2048 /*
2049 * Allocate a new node and fill the fields.
2050 */
2051 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2052 if (cur == NULL) {
2053 xmlGenericError(xmlGenericErrorContext,
2054 "xmlNewPI : malloc failed\n");
2055 return(NULL);
2056 }
2057 memset(cur, 0, sizeof(xmlNode));
2058 cur->type = XML_PI_NODE;
2059
2060 cur->name = xmlStrdup(name);
2061 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002062 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002063 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002064
Daniel Veillarda880b122003-04-21 21:36:41 +00002065 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002066 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002067 return(cur);
2068}
2069
2070/**
2071 * xmlNewNode:
2072 * @ns: namespace if any
2073 * @name: the node name
2074 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002075 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002076 *
2077 * Returns a pointer to the new node object.
2078 */
2079xmlNodePtr
2080xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2081 xmlNodePtr cur;
2082
2083 if (name == NULL) {
2084#ifdef DEBUG_TREE
2085 xmlGenericError(xmlGenericErrorContext,
2086 "xmlNewNode : name == NULL\n");
2087#endif
2088 return(NULL);
2089 }
2090
2091 /*
2092 * Allocate a new node and fill the fields.
2093 */
2094 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2095 if (cur == NULL) {
2096 xmlGenericError(xmlGenericErrorContext,
2097 "xmlNewNode : malloc failed\n");
2098 return(NULL);
2099 }
2100 memset(cur, 0, sizeof(xmlNode));
2101 cur->type = XML_ELEMENT_NODE;
2102
2103 cur->name = xmlStrdup(name);
2104 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002105
Daniel Veillarda880b122003-04-21 21:36:41 +00002106 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002107 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002108 return(cur);
2109}
2110
2111/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00002112 * xmlNewNodeEatName:
2113 * @ns: namespace if any
2114 * @name: the node name
2115 *
2116 * Creation of a new node element. @ns is optional (NULL).
2117 *
2118 * Returns a pointer to the new node object.
2119 */
2120xmlNodePtr
2121xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2122 xmlNodePtr cur;
2123
2124 if (name == NULL) {
2125#ifdef DEBUG_TREE
2126 xmlGenericError(xmlGenericErrorContext,
2127 "xmlNewNode : name == NULL\n");
2128#endif
2129 return(NULL);
2130 }
2131
2132 /*
2133 * Allocate a new node and fill the fields.
2134 */
2135 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2136 if (cur == NULL) {
2137 xmlGenericError(xmlGenericErrorContext,
2138 "xmlNewNode : malloc failed\n");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00002139 xmlFree(name);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002140 return(NULL);
2141 }
2142 memset(cur, 0, sizeof(xmlNode));
2143 cur->type = XML_ELEMENT_NODE;
2144
2145 cur->name = name;
2146 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002147
Daniel Veillarda880b122003-04-21 21:36:41 +00002148 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002149 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002150 return(cur);
2151}
2152
2153/**
Owen Taylor3473f882001-02-23 17:55:21 +00002154 * xmlNewDocNode:
2155 * @doc: the document
2156 * @ns: namespace if any
2157 * @name: the node name
2158 * @content: the XML text content if any
2159 *
2160 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002161 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002162 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2163 * references, but XML special chars need to be escaped first by using
2164 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2165 * need entities support.
2166 *
2167 * Returns a pointer to the new node object.
2168 */
2169xmlNodePtr
2170xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2171 const xmlChar *name, const xmlChar *content) {
2172 xmlNodePtr cur;
2173
2174 cur = xmlNewNode(ns, name);
2175 if (cur != NULL) {
2176 cur->doc = doc;
2177 if (content != NULL) {
2178 cur->children = xmlStringGetNodeList(doc, content);
2179 UPDATE_LAST_CHILD_AND_PARENT(cur)
2180 }
2181 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002182
Owen Taylor3473f882001-02-23 17:55:21 +00002183 return(cur);
2184}
2185
Daniel Veillard46de64e2002-05-29 08:21:33 +00002186/**
2187 * xmlNewDocNodeEatName:
2188 * @doc: the document
2189 * @ns: namespace if any
2190 * @name: the node name
2191 * @content: the XML text content if any
2192 *
2193 * Creation of a new node element within a document. @ns and @content
2194 * are optional (NULL).
2195 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2196 * references, but XML special chars need to be escaped first by using
2197 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2198 * need entities support.
2199 *
2200 * Returns a pointer to the new node object.
2201 */
2202xmlNodePtr
2203xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2204 xmlChar *name, const xmlChar *content) {
2205 xmlNodePtr cur;
2206
2207 cur = xmlNewNodeEatName(ns, name);
2208 if (cur != NULL) {
2209 cur->doc = doc;
2210 if (content != NULL) {
2211 cur->children = xmlStringGetNodeList(doc, content);
2212 UPDATE_LAST_CHILD_AND_PARENT(cur)
2213 }
2214 }
2215 return(cur);
2216}
2217
Daniel Veillard652327a2003-09-29 18:02:38 +00002218#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002219/**
2220 * xmlNewDocRawNode:
2221 * @doc: the document
2222 * @ns: namespace if any
2223 * @name: the node name
2224 * @content: the text content if any
2225 *
2226 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002227 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002228 *
2229 * Returns a pointer to the new node object.
2230 */
2231xmlNodePtr
2232xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2233 const xmlChar *name, const xmlChar *content) {
2234 xmlNodePtr cur;
2235
2236 cur = xmlNewNode(ns, name);
2237 if (cur != NULL) {
2238 cur->doc = doc;
2239 if (content != NULL) {
2240 cur->children = xmlNewDocText(doc, content);
2241 UPDATE_LAST_CHILD_AND_PARENT(cur)
2242 }
2243 }
2244 return(cur);
2245}
2246
2247/**
2248 * xmlNewDocFragment:
2249 * @doc: the document owning the fragment
2250 *
2251 * Creation of a new Fragment node.
2252 * Returns a pointer to the new node object.
2253 */
2254xmlNodePtr
2255xmlNewDocFragment(xmlDocPtr doc) {
2256 xmlNodePtr cur;
2257
2258 /*
2259 * Allocate a new DocumentFragment node and fill the fields.
2260 */
2261 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2262 if (cur == NULL) {
2263 xmlGenericError(xmlGenericErrorContext,
2264 "xmlNewDocFragment : malloc failed\n");
2265 return(NULL);
2266 }
2267 memset(cur, 0, sizeof(xmlNode));
2268 cur->type = XML_DOCUMENT_FRAG_NODE;
2269
2270 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002271
Daniel Veillarda880b122003-04-21 21:36:41 +00002272 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002273 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002274 return(cur);
2275}
Daniel Veillard652327a2003-09-29 18:02:38 +00002276#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002277
2278/**
2279 * xmlNewText:
2280 * @content: the text content
2281 *
2282 * Creation of a new text node.
2283 * Returns a pointer to the new node object.
2284 */
2285xmlNodePtr
2286xmlNewText(const xmlChar *content) {
2287 xmlNodePtr cur;
2288
2289 /*
2290 * Allocate a new node and fill the fields.
2291 */
2292 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2293 if (cur == NULL) {
2294 xmlGenericError(xmlGenericErrorContext,
2295 "xmlNewText : malloc failed\n");
2296 return(NULL);
2297 }
2298 memset(cur, 0, sizeof(xmlNode));
2299 cur->type = XML_TEXT_NODE;
2300
2301 cur->name = xmlStringText;
2302 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002303 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002304 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002305
Daniel Veillarda880b122003-04-21 21:36:41 +00002306 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002307 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002308 return(cur);
2309}
2310
Daniel Veillard652327a2003-09-29 18:02:38 +00002311#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002312/**
2313 * xmlNewTextChild:
2314 * @parent: the parent node
2315 * @ns: a namespace if any
2316 * @name: the name of the child
2317 * @content: the text content of the child if any.
2318 *
2319 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002320 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002321 * a child TEXT node will be created containing the string content.
2322 *
2323 * Returns a pointer to the new node object.
2324 */
2325xmlNodePtr
2326xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2327 const xmlChar *name, const xmlChar *content) {
2328 xmlNodePtr cur, prev;
2329
2330 if (parent == NULL) {
2331#ifdef DEBUG_TREE
2332 xmlGenericError(xmlGenericErrorContext,
2333 "xmlNewTextChild : parent == NULL\n");
2334#endif
2335 return(NULL);
2336 }
2337
2338 if (name == NULL) {
2339#ifdef DEBUG_TREE
2340 xmlGenericError(xmlGenericErrorContext,
2341 "xmlNewTextChild : name == NULL\n");
2342#endif
2343 return(NULL);
2344 }
2345
2346 /*
2347 * Allocate a new node
2348 */
2349 if (ns == NULL)
2350 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2351 else
2352 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2353 if (cur == NULL) return(NULL);
2354
2355 /*
2356 * add the new element at the end of the children list.
2357 */
2358 cur->type = XML_ELEMENT_NODE;
2359 cur->parent = parent;
2360 cur->doc = parent->doc;
2361 if (parent->children == NULL) {
2362 parent->children = cur;
2363 parent->last = cur;
2364 } else {
2365 prev = parent->last;
2366 prev->next = cur;
2367 cur->prev = prev;
2368 parent->last = cur;
2369 }
2370
2371 return(cur);
2372}
Daniel Veillard652327a2003-09-29 18:02:38 +00002373#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002374
2375/**
2376 * xmlNewCharRef:
2377 * @doc: the document
2378 * @name: the char ref string, starting with # or "&# ... ;"
2379 *
2380 * Creation of a new character reference node.
2381 * Returns a pointer to the new node object.
2382 */
2383xmlNodePtr
2384xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2385 xmlNodePtr cur;
2386
2387 /*
2388 * Allocate a new node and fill the fields.
2389 */
2390 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2391 if (cur == NULL) {
2392 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002393 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002394 return(NULL);
2395 }
2396 memset(cur, 0, sizeof(xmlNode));
2397 cur->type = XML_ENTITY_REF_NODE;
2398
2399 cur->doc = doc;
2400 if (name[0] == '&') {
2401 int len;
2402 name++;
2403 len = xmlStrlen(name);
2404 if (name[len - 1] == ';')
2405 cur->name = xmlStrndup(name, len - 1);
2406 else
2407 cur->name = xmlStrndup(name, len);
2408 } else
2409 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002410
Daniel Veillarda880b122003-04-21 21:36:41 +00002411 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002412 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002413 return(cur);
2414}
2415
2416/**
2417 * xmlNewReference:
2418 * @doc: the document
2419 * @name: the reference name, or the reference string with & and ;
2420 *
2421 * Creation of a new reference node.
2422 * Returns a pointer to the new node object.
2423 */
2424xmlNodePtr
2425xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2426 xmlNodePtr cur;
2427 xmlEntityPtr ent;
2428
2429 /*
2430 * Allocate a new node and fill the fields.
2431 */
2432 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2433 if (cur == NULL) {
2434 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002435 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002436 return(NULL);
2437 }
2438 memset(cur, 0, sizeof(xmlNode));
2439 cur->type = XML_ENTITY_REF_NODE;
2440
2441 cur->doc = doc;
2442 if (name[0] == '&') {
2443 int len;
2444 name++;
2445 len = xmlStrlen(name);
2446 if (name[len - 1] == ';')
2447 cur->name = xmlStrndup(name, len - 1);
2448 else
2449 cur->name = xmlStrndup(name, len);
2450 } else
2451 cur->name = xmlStrdup(name);
2452
2453 ent = xmlGetDocEntity(doc, cur->name);
2454 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002455 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002456 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002457 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002458 * updated. Not sure if this is 100% correct.
2459 * -George
2460 */
2461 cur->children = (xmlNodePtr) ent;
2462 cur->last = (xmlNodePtr) ent;
2463 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002464
Daniel Veillarda880b122003-04-21 21:36:41 +00002465 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002466 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002467 return(cur);
2468}
2469
2470/**
2471 * xmlNewDocText:
2472 * @doc: the document
2473 * @content: the text content
2474 *
2475 * Creation of a new text node within a document.
2476 * Returns a pointer to the new node object.
2477 */
2478xmlNodePtr
2479xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2480 xmlNodePtr cur;
2481
2482 cur = xmlNewText(content);
2483 if (cur != NULL) cur->doc = doc;
2484 return(cur);
2485}
2486
2487/**
2488 * xmlNewTextLen:
2489 * @content: the text content
2490 * @len: the text len.
2491 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002492 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002493 * Returns a pointer to the new node object.
2494 */
2495xmlNodePtr
2496xmlNewTextLen(const xmlChar *content, int len) {
2497 xmlNodePtr cur;
2498
2499 /*
2500 * Allocate a new node and fill the fields.
2501 */
2502 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2503 if (cur == NULL) {
2504 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002505 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002506 return(NULL);
2507 }
2508 memset(cur, 0, sizeof(xmlNode));
2509 cur->type = XML_TEXT_NODE;
2510
2511 cur->name = xmlStringText;
2512 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002513 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002514 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002515
Daniel Veillarda880b122003-04-21 21:36:41 +00002516 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002517 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002518 return(cur);
2519}
2520
2521/**
2522 * xmlNewDocTextLen:
2523 * @doc: the document
2524 * @content: the text content
2525 * @len: the text len.
2526 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002527 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002528 * text node pertain to a given document.
2529 * Returns a pointer to the new node object.
2530 */
2531xmlNodePtr
2532xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2533 xmlNodePtr cur;
2534
2535 cur = xmlNewTextLen(content, len);
2536 if (cur != NULL) cur->doc = doc;
2537 return(cur);
2538}
2539
2540/**
2541 * xmlNewComment:
2542 * @content: the comment content
2543 *
2544 * Creation of a new node containing a comment.
2545 * Returns a pointer to the new node object.
2546 */
2547xmlNodePtr
2548xmlNewComment(const xmlChar *content) {
2549 xmlNodePtr cur;
2550
2551 /*
2552 * Allocate a new node and fill the fields.
2553 */
2554 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2555 if (cur == NULL) {
2556 xmlGenericError(xmlGenericErrorContext,
2557 "xmlNewComment : malloc failed\n");
2558 return(NULL);
2559 }
2560 memset(cur, 0, sizeof(xmlNode));
2561 cur->type = XML_COMMENT_NODE;
2562
2563 cur->name = xmlStringComment;
2564 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002565 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002566 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002567
Daniel Veillarda880b122003-04-21 21:36:41 +00002568 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002569 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002570 return(cur);
2571}
2572
2573/**
2574 * xmlNewCDataBlock:
2575 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002576 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002577 * @len: the length of the block
2578 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002579 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002580 * Returns a pointer to the new node object.
2581 */
2582xmlNodePtr
2583xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2584 xmlNodePtr cur;
2585
2586 /*
2587 * Allocate a new node and fill the fields.
2588 */
2589 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2590 if (cur == NULL) {
2591 xmlGenericError(xmlGenericErrorContext,
2592 "xmlNewCDataBlock : malloc failed\n");
2593 return(NULL);
2594 }
2595 memset(cur, 0, sizeof(xmlNode));
2596 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002597 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002598
2599 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002600 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002601 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002602
Daniel Veillarda880b122003-04-21 21:36:41 +00002603 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002604 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002605 return(cur);
2606}
2607
2608/**
2609 * xmlNewDocComment:
2610 * @doc: the document
2611 * @content: the comment content
2612 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002613 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002614 * Returns a pointer to the new node object.
2615 */
2616xmlNodePtr
2617xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2618 xmlNodePtr cur;
2619
2620 cur = xmlNewComment(content);
2621 if (cur != NULL) cur->doc = doc;
2622 return(cur);
2623}
2624
2625/**
2626 * xmlSetTreeDoc:
2627 * @tree: the top element
2628 * @doc: the document
2629 *
2630 * update all nodes under the tree to point to the right document
2631 */
2632void
2633xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002634 xmlAttrPtr prop;
2635
Owen Taylor3473f882001-02-23 17:55:21 +00002636 if (tree == NULL)
2637 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002638 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002639 if(tree->type == XML_ELEMENT_NODE) {
2640 prop = tree->properties;
2641 while (prop != NULL) {
2642 prop->doc = doc;
2643 xmlSetListDoc(prop->children, doc);
2644 prop = prop->next;
2645 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002646 }
Owen Taylor3473f882001-02-23 17:55:21 +00002647 if (tree->children != NULL)
2648 xmlSetListDoc(tree->children, doc);
2649 tree->doc = doc;
2650 }
2651}
2652
2653/**
2654 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002655 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002656 * @doc: the document
2657 *
2658 * update all nodes in the list to point to the right document
2659 */
2660void
2661xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2662 xmlNodePtr cur;
2663
2664 if (list == NULL)
2665 return;
2666 cur = list;
2667 while (cur != NULL) {
2668 if (cur->doc != doc)
2669 xmlSetTreeDoc(cur, doc);
2670 cur = cur->next;
2671 }
2672}
2673
Daniel Veillard652327a2003-09-29 18:02:38 +00002674#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002675/**
2676 * xmlNewChild:
2677 * @parent: the parent node
2678 * @ns: a namespace if any
2679 * @name: the name of the child
2680 * @content: the XML content of the child if any.
2681 *
2682 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002683 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002684 * a child list containing the TEXTs and ENTITY_REFs node will be created.
2685 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2686 * references, but XML special chars need to be escaped first by using
2687 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
2688 * support is not needed.
2689 *
2690 * Returns a pointer to the new node object.
2691 */
2692xmlNodePtr
2693xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2694 const xmlChar *name, const xmlChar *content) {
2695 xmlNodePtr cur, prev;
2696
2697 if (parent == NULL) {
2698#ifdef DEBUG_TREE
2699 xmlGenericError(xmlGenericErrorContext,
2700 "xmlNewChild : parent == NULL\n");
2701#endif
2702 return(NULL);
2703 }
2704
2705 if (name == NULL) {
2706#ifdef DEBUG_TREE
2707 xmlGenericError(xmlGenericErrorContext,
2708 "xmlNewChild : name == NULL\n");
2709#endif
2710 return(NULL);
2711 }
2712
2713 /*
2714 * Allocate a new node
2715 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002716 if (parent->type == XML_ELEMENT_NODE) {
2717 if (ns == NULL)
2718 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2719 else
2720 cur = xmlNewDocNode(parent->doc, ns, name, content);
2721 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2722 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2723 if (ns == NULL)
2724 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2725 else
2726 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002727 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2728 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002729 } else {
2730 return(NULL);
2731 }
Owen Taylor3473f882001-02-23 17:55:21 +00002732 if (cur == NULL) return(NULL);
2733
2734 /*
2735 * add the new element at the end of the children list.
2736 */
2737 cur->type = XML_ELEMENT_NODE;
2738 cur->parent = parent;
2739 cur->doc = parent->doc;
2740 if (parent->children == NULL) {
2741 parent->children = cur;
2742 parent->last = cur;
2743 } else {
2744 prev = parent->last;
2745 prev->next = cur;
2746 cur->prev = prev;
2747 parent->last = cur;
2748 }
2749
2750 return(cur);
2751}
Daniel Veillard652327a2003-09-29 18:02:38 +00002752#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002753
2754/**
2755 * xmlAddNextSibling:
2756 * @cur: the child node
2757 * @elem: the new node
2758 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002759 * Add a new node @elem as the next sibling of @cur
2760 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002761 * first unlinked from its existing context.
2762 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002763 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2764 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002765 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002766 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002767 */
2768xmlNodePtr
2769xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2770 if (cur == NULL) {
2771#ifdef DEBUG_TREE
2772 xmlGenericError(xmlGenericErrorContext,
2773 "xmlAddNextSibling : cur == NULL\n");
2774#endif
2775 return(NULL);
2776 }
2777 if (elem == NULL) {
2778#ifdef DEBUG_TREE
2779 xmlGenericError(xmlGenericErrorContext,
2780 "xmlAddNextSibling : elem == NULL\n");
2781#endif
2782 return(NULL);
2783 }
2784
2785 xmlUnlinkNode(elem);
2786
2787 if (elem->type == XML_TEXT_NODE) {
2788 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002789 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002790 xmlFreeNode(elem);
2791 return(cur);
2792 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002793 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2794 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002795 xmlChar *tmp;
2796
2797 tmp = xmlStrdup(elem->content);
2798 tmp = xmlStrcat(tmp, cur->next->content);
2799 xmlNodeSetContent(cur->next, tmp);
2800 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002801 xmlFreeNode(elem);
2802 return(cur->next);
2803 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002804 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2805 /* check if an attribute with the same name exists */
2806 xmlAttrPtr attr;
2807
2808 if (elem->ns == NULL)
2809 attr = xmlHasProp(cur->parent, elem->name);
2810 else
2811 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2812 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2813 /* different instance, destroy it (attributes must be unique) */
2814 xmlFreeProp(attr);
2815 }
Owen Taylor3473f882001-02-23 17:55:21 +00002816 }
2817
2818 if (elem->doc != cur->doc) {
2819 xmlSetTreeDoc(elem, cur->doc);
2820 }
2821 elem->parent = cur->parent;
2822 elem->prev = cur;
2823 elem->next = cur->next;
2824 cur->next = elem;
2825 if (elem->next != NULL)
2826 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002827 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002828 elem->parent->last = elem;
2829 return(elem);
2830}
2831
Daniel Veillard652327a2003-09-29 18:02:38 +00002832#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002833/**
2834 * xmlAddPrevSibling:
2835 * @cur: the child node
2836 * @elem: the new node
2837 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002838 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002839 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002840 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002841 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002842 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2843 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002844 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002845 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002846 */
2847xmlNodePtr
2848xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2849 if (cur == NULL) {
2850#ifdef DEBUG_TREE
2851 xmlGenericError(xmlGenericErrorContext,
2852 "xmlAddPrevSibling : cur == NULL\n");
2853#endif
2854 return(NULL);
2855 }
2856 if (elem == NULL) {
2857#ifdef DEBUG_TREE
2858 xmlGenericError(xmlGenericErrorContext,
2859 "xmlAddPrevSibling : elem == NULL\n");
2860#endif
2861 return(NULL);
2862 }
2863
2864 xmlUnlinkNode(elem);
2865
2866 if (elem->type == XML_TEXT_NODE) {
2867 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002868 xmlChar *tmp;
2869
2870 tmp = xmlStrdup(elem->content);
2871 tmp = xmlStrcat(tmp, cur->content);
2872 xmlNodeSetContent(cur, tmp);
2873 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002874 xmlFreeNode(elem);
2875 return(cur);
2876 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002877 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2878 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002879 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002880 xmlFreeNode(elem);
2881 return(cur->prev);
2882 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002883 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2884 /* check if an attribute with the same name exists */
2885 xmlAttrPtr attr;
2886
2887 if (elem->ns == NULL)
2888 attr = xmlHasProp(cur->parent, elem->name);
2889 else
2890 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2891 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2892 /* different instance, destroy it (attributes must be unique) */
2893 xmlFreeProp(attr);
2894 }
Owen Taylor3473f882001-02-23 17:55:21 +00002895 }
2896
2897 if (elem->doc != cur->doc) {
2898 xmlSetTreeDoc(elem, cur->doc);
2899 }
2900 elem->parent = cur->parent;
2901 elem->next = cur;
2902 elem->prev = cur->prev;
2903 cur->prev = elem;
2904 if (elem->prev != NULL)
2905 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002906 if (elem->parent != NULL) {
2907 if (elem->type == XML_ATTRIBUTE_NODE) {
2908 if (elem->parent->properties == (xmlAttrPtr) cur) {
2909 elem->parent->properties = (xmlAttrPtr) elem;
2910 }
2911 } else {
2912 if (elem->parent->children == cur) {
2913 elem->parent->children = elem;
2914 }
2915 }
2916 }
Owen Taylor3473f882001-02-23 17:55:21 +00002917 return(elem);
2918}
Daniel Veillard652327a2003-09-29 18:02:38 +00002919#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002920
2921/**
2922 * xmlAddSibling:
2923 * @cur: the child node
2924 * @elem: the new node
2925 *
2926 * Add a new element @elem to the list of siblings of @cur
2927 * merging adjacent TEXT nodes (@elem may be freed)
2928 * If the new element was already inserted in a document it is
2929 * first unlinked from its existing context.
2930 *
2931 * Returns the new element or NULL in case of error.
2932 */
2933xmlNodePtr
2934xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2935 xmlNodePtr parent;
2936
2937 if (cur == NULL) {
2938#ifdef DEBUG_TREE
2939 xmlGenericError(xmlGenericErrorContext,
2940 "xmlAddSibling : cur == NULL\n");
2941#endif
2942 return(NULL);
2943 }
2944
2945 if (elem == NULL) {
2946#ifdef DEBUG_TREE
2947 xmlGenericError(xmlGenericErrorContext,
2948 "xmlAddSibling : elem == NULL\n");
2949#endif
2950 return(NULL);
2951 }
2952
2953 /*
2954 * Constant time is we can rely on the ->parent->last to find
2955 * the last sibling.
2956 */
2957 if ((cur->parent != NULL) &&
2958 (cur->parent->children != NULL) &&
2959 (cur->parent->last != NULL) &&
2960 (cur->parent->last->next == NULL)) {
2961 cur = cur->parent->last;
2962 } else {
2963 while (cur->next != NULL) cur = cur->next;
2964 }
2965
2966 xmlUnlinkNode(elem);
2967
2968 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002969 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002970 xmlFreeNode(elem);
2971 return(cur);
2972 }
2973
2974 if (elem->doc != cur->doc) {
2975 xmlSetTreeDoc(elem, cur->doc);
2976 }
2977 parent = cur->parent;
2978 elem->prev = cur;
2979 elem->next = NULL;
2980 elem->parent = parent;
2981 cur->next = elem;
2982 if (parent != NULL)
2983 parent->last = elem;
2984
2985 return(elem);
2986}
2987
2988/**
2989 * xmlAddChildList:
2990 * @parent: the parent node
2991 * @cur: the first node in the list
2992 *
2993 * Add a list of node at the end of the child list of the parent
2994 * merging adjacent TEXT nodes (@cur may be freed)
2995 *
2996 * Returns the last child or NULL in case of error.
2997 */
2998xmlNodePtr
2999xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3000 xmlNodePtr prev;
3001
3002 if (parent == NULL) {
3003#ifdef DEBUG_TREE
3004 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003005 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003006#endif
3007 return(NULL);
3008 }
3009
3010 if (cur == NULL) {
3011#ifdef DEBUG_TREE
3012 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00003013 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003014#endif
3015 return(NULL);
3016 }
3017
3018 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3019 (cur->doc != parent->doc)) {
3020#ifdef DEBUG_TREE
3021 xmlGenericError(xmlGenericErrorContext,
3022 "Elements moved to a different document\n");
3023#endif
3024 }
3025
3026 /*
3027 * add the first element at the end of the children list.
3028 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003029
Owen Taylor3473f882001-02-23 17:55:21 +00003030 if (parent->children == NULL) {
3031 parent->children = cur;
3032 } else {
3033 /*
3034 * If cur and parent->last both are TEXT nodes, then merge them.
3035 */
3036 if ((cur->type == XML_TEXT_NODE) &&
3037 (parent->last->type == XML_TEXT_NODE) &&
3038 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003039 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003040 /*
3041 * if it's the only child, nothing more to be done.
3042 */
3043 if (cur->next == NULL) {
3044 xmlFreeNode(cur);
3045 return(parent->last);
3046 }
3047 prev = cur;
3048 cur = cur->next;
3049 xmlFreeNode(prev);
3050 }
3051 prev = parent->last;
3052 prev->next = cur;
3053 cur->prev = prev;
3054 }
3055 while (cur->next != NULL) {
3056 cur->parent = parent;
3057 if (cur->doc != parent->doc) {
3058 xmlSetTreeDoc(cur, parent->doc);
3059 }
3060 cur = cur->next;
3061 }
3062 cur->parent = parent;
3063 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
3064 parent->last = cur;
3065
3066 return(cur);
3067}
3068
3069/**
3070 * xmlAddChild:
3071 * @parent: the parent node
3072 * @cur: the child node
3073 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003074 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003075 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003076 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3077 * If there is an attribute with equal name, it is first destroyed.
3078 *
Owen Taylor3473f882001-02-23 17:55:21 +00003079 * Returns the child or NULL in case of error.
3080 */
3081xmlNodePtr
3082xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3083 xmlNodePtr prev;
3084
3085 if (parent == NULL) {
3086#ifdef DEBUG_TREE
3087 xmlGenericError(xmlGenericErrorContext,
3088 "xmlAddChild : parent == NULL\n");
3089#endif
3090 return(NULL);
3091 }
3092
3093 if (cur == NULL) {
3094#ifdef DEBUG_TREE
3095 xmlGenericError(xmlGenericErrorContext,
3096 "xmlAddChild : child == NULL\n");
3097#endif
3098 return(NULL);
3099 }
3100
Owen Taylor3473f882001-02-23 17:55:21 +00003101 /*
3102 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003103 * cur is then freed.
3104 */
3105 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003106 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003107 (parent->content != NULL) &&
3108 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003109 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003110 xmlFreeNode(cur);
3111 return(parent);
3112 }
3113 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003114 (parent->last->name == cur->name) &&
3115 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003116 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003117 xmlFreeNode(cur);
3118 return(parent->last);
3119 }
3120 }
3121
3122 /*
3123 * add the new element at the end of the children list.
3124 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003125 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003126 cur->parent = parent;
3127 if (cur->doc != parent->doc) {
3128 xmlSetTreeDoc(cur, parent->doc);
3129 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003130 /* this check prevents a loop on tree-traversions if a developer
3131 * tries to add a node to its parent multiple times
3132 */
3133 if (prev == parent)
3134 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003135
3136 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003137 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003138 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003139 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003140 (parent->content != NULL) &&
3141 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003142 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003143 xmlFreeNode(cur);
3144 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003145 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003146 if (cur->type == XML_ATTRIBUTE_NODE) {
3147 if (parent->properties == NULL) {
3148 parent->properties = (xmlAttrPtr) cur;
3149 } else {
3150 /* check if an attribute with the same name exists */
3151 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003152
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003153 if (cur->ns == NULL)
3154 lastattr = xmlHasProp(parent, cur->name);
3155 else
3156 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3157 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
3158 /* different instance, destroy it (attributes must be unique) */
3159 xmlFreeProp(lastattr);
3160 }
3161 /* find the end */
3162 lastattr = parent->properties;
3163 while (lastattr->next != NULL) {
3164 lastattr = lastattr->next;
3165 }
3166 lastattr->next = (xmlAttrPtr) cur;
3167 ((xmlAttrPtr) cur)->prev = lastattr;
3168 }
3169 } else {
3170 if (parent->children == NULL) {
3171 parent->children = cur;
3172 parent->last = cur;
3173 } else {
3174 prev = parent->last;
3175 prev->next = cur;
3176 cur->prev = prev;
3177 parent->last = cur;
3178 }
3179 }
Owen Taylor3473f882001-02-23 17:55:21 +00003180 return(cur);
3181}
3182
3183/**
3184 * xmlGetLastChild:
3185 * @parent: the parent node
3186 *
3187 * Search the last child of a node.
3188 * Returns the last child or NULL if none.
3189 */
3190xmlNodePtr
3191xmlGetLastChild(xmlNodePtr parent) {
3192 if (parent == NULL) {
3193#ifdef DEBUG_TREE
3194 xmlGenericError(xmlGenericErrorContext,
3195 "xmlGetLastChild : parent == NULL\n");
3196#endif
3197 return(NULL);
3198 }
3199 return(parent->last);
3200}
3201
3202/**
3203 * xmlFreeNodeList:
3204 * @cur: the first node in the list
3205 *
3206 * Free a node and all its siblings, this is a recursive behaviour, all
3207 * the children are freed too.
3208 */
3209void
3210xmlFreeNodeList(xmlNodePtr cur) {
3211 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003212 xmlDictPtr dict = NULL;
3213
3214 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003215 if (cur->type == XML_NAMESPACE_DECL) {
3216 xmlFreeNsList((xmlNsPtr) cur);
3217 return;
3218 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003219 if ((cur->type == XML_DOCUMENT_NODE) ||
3220#ifdef LIBXML_DOCB_ENABLED
3221 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003222#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003223 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003224 xmlFreeDoc((xmlDocPtr) cur);
3225 return;
3226 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003227 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003228 while (cur != NULL) {
3229 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003230 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003231
Daniel Veillarda880b122003-04-21 21:36:41 +00003232 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003233 xmlDeregisterNodeDefaultValue(cur);
3234
Daniel Veillard02141ea2001-04-30 11:46:40 +00003235 if ((cur->children != NULL) &&
3236 (cur->type != XML_ENTITY_REF_NODE))
3237 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003238 if (((cur->type == XML_ELEMENT_NODE) ||
3239 (cur->type == XML_XINCLUDE_START) ||
3240 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003241 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003242 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003243 if ((cur->type != XML_ELEMENT_NODE) &&
3244 (cur->type != XML_XINCLUDE_START) &&
3245 (cur->type != XML_XINCLUDE_END) &&
3246 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003247 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003248 }
3249 if (((cur->type == XML_ELEMENT_NODE) ||
3250 (cur->type == XML_XINCLUDE_START) ||
3251 (cur->type == XML_XINCLUDE_END)) &&
3252 (cur->nsDef != NULL))
3253 xmlFreeNsList(cur->nsDef);
3254
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003255 /*
3256 * When a node is a text node or a comment, it uses a global static
3257 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003258 * Otherwise the node name might come from the document's
3259 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003260 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003261 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003262 (cur->type != XML_TEXT_NODE) &&
3263 (cur->type != XML_COMMENT_NODE))
3264 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003265 xmlFree(cur);
3266 }
Owen Taylor3473f882001-02-23 17:55:21 +00003267 cur = next;
3268 }
3269}
3270
3271/**
3272 * xmlFreeNode:
3273 * @cur: the node
3274 *
3275 * Free a node, this is a recursive behaviour, all the children are freed too.
3276 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3277 */
3278void
3279xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003280 xmlDictPtr dict = NULL;
3281
3282 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003283
Daniel Veillard02141ea2001-04-30 11:46:40 +00003284 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003285 if (cur->type == XML_DTD_NODE) {
3286 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003287 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003288 }
3289 if (cur->type == XML_NAMESPACE_DECL) {
3290 xmlFreeNs((xmlNsPtr) cur);
3291 return;
3292 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003293 if (cur->type == XML_ATTRIBUTE_NODE) {
3294 xmlFreeProp((xmlAttrPtr) cur);
3295 return;
3296 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003297
Daniel Veillarda880b122003-04-21 21:36:41 +00003298 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003299 xmlDeregisterNodeDefaultValue(cur);
3300
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003301 if (cur->doc != NULL) dict = cur->doc->dict;
3302
Owen Taylor3473f882001-02-23 17:55:21 +00003303 if ((cur->children != NULL) &&
3304 (cur->type != XML_ENTITY_REF_NODE))
3305 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003306 if (((cur->type == XML_ELEMENT_NODE) ||
3307 (cur->type == XML_XINCLUDE_START) ||
3308 (cur->type == XML_XINCLUDE_END)) &&
3309 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003310 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003311 if ((cur->type != XML_ELEMENT_NODE) &&
3312 (cur->content != NULL) &&
3313 (cur->type != XML_ENTITY_REF_NODE) &&
3314 (cur->type != XML_XINCLUDE_END) &&
3315 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003316 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003317 }
3318
Daniel Veillardacd370f2001-06-09 17:17:51 +00003319 /*
3320 * When a node is a text node or a comment, it uses a global static
3321 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003322 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003323 */
Owen Taylor3473f882001-02-23 17:55:21 +00003324 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003325 (cur->type != XML_TEXT_NODE) &&
3326 (cur->type != XML_COMMENT_NODE))
3327 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003328
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003329 if (((cur->type == XML_ELEMENT_NODE) ||
3330 (cur->type == XML_XINCLUDE_START) ||
3331 (cur->type == XML_XINCLUDE_END)) &&
3332 (cur->nsDef != NULL))
3333 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003334 xmlFree(cur);
3335}
3336
3337/**
3338 * xmlUnlinkNode:
3339 * @cur: the node
3340 *
3341 * Unlink a node from it's current context, the node is not freed
3342 */
3343void
3344xmlUnlinkNode(xmlNodePtr cur) {
3345 if (cur == NULL) {
3346#ifdef DEBUG_TREE
3347 xmlGenericError(xmlGenericErrorContext,
3348 "xmlUnlinkNode : node == NULL\n");
3349#endif
3350 return;
3351 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003352 if (cur->type == XML_DTD_NODE) {
3353 xmlDocPtr doc;
3354 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003355 if (doc != NULL) {
3356 if (doc->intSubset == (xmlDtdPtr) cur)
3357 doc->intSubset = NULL;
3358 if (doc->extSubset == (xmlDtdPtr) cur)
3359 doc->extSubset = NULL;
3360 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003361 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003362 if (cur->parent != NULL) {
3363 xmlNodePtr parent;
3364 parent = cur->parent;
3365 if (cur->type == XML_ATTRIBUTE_NODE) {
3366 if (parent->properties == (xmlAttrPtr) cur)
3367 parent->properties = ((xmlAttrPtr) cur)->next;
3368 } else {
3369 if (parent->children == cur)
3370 parent->children = cur->next;
3371 if (parent->last == cur)
3372 parent->last = cur->prev;
3373 }
3374 cur->parent = NULL;
3375 }
Owen Taylor3473f882001-02-23 17:55:21 +00003376 if (cur->next != NULL)
3377 cur->next->prev = cur->prev;
3378 if (cur->prev != NULL)
3379 cur->prev->next = cur->next;
3380 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003381}
3382
Daniel Veillard652327a2003-09-29 18:02:38 +00003383#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003384/**
3385 * xmlReplaceNode:
3386 * @old: the old node
3387 * @cur: the node
3388 *
3389 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003390 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003391 * first unlinked from its existing context.
3392 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003393 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003394 */
3395xmlNodePtr
3396xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3397 if (old == NULL) {
3398#ifdef DEBUG_TREE
3399 xmlGenericError(xmlGenericErrorContext,
3400 "xmlReplaceNode : old == NULL\n");
3401#endif
3402 return(NULL);
3403 }
3404 if (cur == NULL) {
3405 xmlUnlinkNode(old);
3406 return(old);
3407 }
3408 if (cur == old) {
3409 return(old);
3410 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003411 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3412#ifdef DEBUG_TREE
3413 xmlGenericError(xmlGenericErrorContext,
3414 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3415#endif
3416 return(old);
3417 }
3418 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3419#ifdef DEBUG_TREE
3420 xmlGenericError(xmlGenericErrorContext,
3421 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3422#endif
3423 return(old);
3424 }
Owen Taylor3473f882001-02-23 17:55:21 +00003425 xmlUnlinkNode(cur);
3426 cur->doc = old->doc;
3427 cur->parent = old->parent;
3428 cur->next = old->next;
3429 if (cur->next != NULL)
3430 cur->next->prev = cur;
3431 cur->prev = old->prev;
3432 if (cur->prev != NULL)
3433 cur->prev->next = cur;
3434 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003435 if (cur->type == XML_ATTRIBUTE_NODE) {
3436 if (cur->parent->properties == (xmlAttrPtr)old)
3437 cur->parent->properties = ((xmlAttrPtr) cur);
3438 } else {
3439 if (cur->parent->children == old)
3440 cur->parent->children = cur;
3441 if (cur->parent->last == old)
3442 cur->parent->last = cur;
3443 }
Owen Taylor3473f882001-02-23 17:55:21 +00003444 }
3445 old->next = old->prev = NULL;
3446 old->parent = NULL;
3447 return(old);
3448}
Daniel Veillard652327a2003-09-29 18:02:38 +00003449#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003450
3451/************************************************************************
3452 * *
3453 * Copy operations *
3454 * *
3455 ************************************************************************/
3456
3457/**
3458 * xmlCopyNamespace:
3459 * @cur: the namespace
3460 *
3461 * Do a copy of the namespace.
3462 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003463 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003464 */
3465xmlNsPtr
3466xmlCopyNamespace(xmlNsPtr cur) {
3467 xmlNsPtr ret;
3468
3469 if (cur == NULL) return(NULL);
3470 switch (cur->type) {
3471 case XML_LOCAL_NAMESPACE:
3472 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3473 break;
3474 default:
3475#ifdef DEBUG_TREE
3476 xmlGenericError(xmlGenericErrorContext,
3477 "xmlCopyNamespace: invalid type %d\n", cur->type);
3478#endif
3479 return(NULL);
3480 }
3481 return(ret);
3482}
3483
3484/**
3485 * xmlCopyNamespaceList:
3486 * @cur: the first namespace
3487 *
3488 * Do a copy of an namespace list.
3489 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003490 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003491 */
3492xmlNsPtr
3493xmlCopyNamespaceList(xmlNsPtr cur) {
3494 xmlNsPtr ret = NULL;
3495 xmlNsPtr p = NULL,q;
3496
3497 while (cur != NULL) {
3498 q = xmlCopyNamespace(cur);
3499 if (p == NULL) {
3500 ret = p = q;
3501 } else {
3502 p->next = q;
3503 p = q;
3504 }
3505 cur = cur->next;
3506 }
3507 return(ret);
3508}
3509
3510static xmlNodePtr
3511xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3512/**
3513 * xmlCopyProp:
3514 * @target: the element where the attribute will be grafted
3515 * @cur: the attribute
3516 *
3517 * Do a copy of the attribute.
3518 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003519 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003520 */
3521xmlAttrPtr
3522xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3523 xmlAttrPtr ret;
3524
3525 if (cur == NULL) return(NULL);
3526 if (target != NULL)
3527 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3528 else if (cur->parent != NULL)
3529 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3530 else if (cur->children != NULL)
3531 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3532 else
3533 ret = xmlNewDocProp(NULL, cur->name, NULL);
3534 if (ret == NULL) return(NULL);
3535 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003536
Owen Taylor3473f882001-02-23 17:55:21 +00003537 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003538 xmlNsPtr ns;
Daniel Veillard652327a2003-09-29 18:02:38 +00003539
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003540 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3541 if (ns == NULL) {
3542 /*
3543 * Humm, we are copying an element whose namespace is defined
3544 * out of the new tree scope. Search it in the original tree
3545 * and add it at the top of the new tree
3546 */
3547 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3548 if (ns != NULL) {
3549 xmlNodePtr root = target;
3550 xmlNodePtr pred = NULL;
3551
3552 while (root->parent != NULL) {
3553 pred = root;
3554 root = root->parent;
3555 }
3556 if (root == (xmlNodePtr) target->doc) {
3557 /* correct possibly cycling above the document elt */
3558 root = pred;
3559 }
3560 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3561 }
3562 } else {
3563 /*
3564 * we have to find something appropriate here since
3565 * we cant be sure, that the namespce we found is identified
3566 * by the prefix
3567 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003568 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003569 /* this is the nice case */
3570 ret->ns = ns;
3571 } else {
3572 /*
3573 * we are in trouble: we need a new reconcilied namespace.
3574 * This is expensive
3575 */
3576 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3577 }
3578 }
3579
Owen Taylor3473f882001-02-23 17:55:21 +00003580 } else
3581 ret->ns = NULL;
3582
3583 if (cur->children != NULL) {
3584 xmlNodePtr tmp;
3585
3586 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3587 ret->last = NULL;
3588 tmp = ret->children;
3589 while (tmp != NULL) {
3590 /* tmp->parent = (xmlNodePtr)ret; */
3591 if (tmp->next == NULL)
3592 ret->last = tmp;
3593 tmp = tmp->next;
3594 }
3595 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003596 /*
3597 * Try to handle IDs
3598 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003599 if ((target!= NULL) && (cur!= NULL) &&
3600 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003601 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3602 if (xmlIsID(cur->doc, cur->parent, cur)) {
3603 xmlChar *id;
3604
3605 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3606 if (id != NULL) {
3607 xmlAddID(NULL, target->doc, id, ret);
3608 xmlFree(id);
3609 }
3610 }
3611 }
Owen Taylor3473f882001-02-23 17:55:21 +00003612 return(ret);
3613}
3614
3615/**
3616 * xmlCopyPropList:
3617 * @target: the element where the attributes will be grafted
3618 * @cur: the first attribute
3619 *
3620 * Do a copy of an attribute list.
3621 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003622 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003623 */
3624xmlAttrPtr
3625xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3626 xmlAttrPtr ret = NULL;
3627 xmlAttrPtr p = NULL,q;
3628
3629 while (cur != NULL) {
3630 q = xmlCopyProp(target, cur);
3631 if (p == NULL) {
3632 ret = p = q;
3633 } else {
3634 p->next = q;
3635 q->prev = p;
3636 p = q;
3637 }
3638 cur = cur->next;
3639 }
3640 return(ret);
3641}
3642
3643/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003644 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003645 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003646 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003647 * tricky reason: namespaces. Doing a direct copy of a node
3648 * say RPM:Copyright without changing the namespace pointer to
3649 * something else can produce stale links. One way to do it is
3650 * to keep a reference counter but this doesn't work as soon
3651 * as one move the element or the subtree out of the scope of
3652 * the existing namespace. The actual solution seems to add
3653 * a copy of the namespace at the top of the copied tree if
3654 * not available in the subtree.
3655 * Hence two functions, the public front-end call the inner ones
3656 */
3657
3658static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003659xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003660 int recursive) {
3661 xmlNodePtr ret;
3662
3663 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003664 switch (node->type) {
3665 case XML_TEXT_NODE:
3666 case XML_CDATA_SECTION_NODE:
3667 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003668 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003669 case XML_ENTITY_REF_NODE:
3670 case XML_ENTITY_NODE:
3671 case XML_PI_NODE:
3672 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003673 case XML_XINCLUDE_START:
3674 case XML_XINCLUDE_END:
3675 break;
3676 case XML_ATTRIBUTE_NODE:
3677 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3678 case XML_NAMESPACE_DECL:
3679 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3680
Daniel Veillard39196eb2001-06-19 18:09:42 +00003681 case XML_DOCUMENT_NODE:
3682 case XML_HTML_DOCUMENT_NODE:
3683#ifdef LIBXML_DOCB_ENABLED
3684 case XML_DOCB_DOCUMENT_NODE:
3685#endif
Daniel Veillard652327a2003-09-29 18:02:38 +00003686#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003687 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard652327a2003-09-29 18:02:38 +00003688#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard39196eb2001-06-19 18:09:42 +00003689 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003690 case XML_NOTATION_NODE:
3691 case XML_DTD_NODE:
3692 case XML_ELEMENT_DECL:
3693 case XML_ATTRIBUTE_DECL:
3694 case XML_ENTITY_DECL:
3695 return(NULL);
3696 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003697
Owen Taylor3473f882001-02-23 17:55:21 +00003698 /*
3699 * Allocate a new node and fill the fields.
3700 */
3701 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3702 if (ret == NULL) {
3703 xmlGenericError(xmlGenericErrorContext,
3704 "xmlStaticCopyNode : malloc failed\n");
3705 return(NULL);
3706 }
3707 memset(ret, 0, sizeof(xmlNode));
3708 ret->type = node->type;
3709
3710 ret->doc = doc;
3711 ret->parent = parent;
3712 if (node->name == xmlStringText)
3713 ret->name = xmlStringText;
3714 else if (node->name == xmlStringTextNoenc)
3715 ret->name = xmlStringTextNoenc;
3716 else if (node->name == xmlStringComment)
3717 ret->name = xmlStringComment;
3718 else if (node->name != NULL)
3719 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003720 if ((node->type != XML_ELEMENT_NODE) &&
3721 (node->content != NULL) &&
3722 (node->type != XML_ENTITY_REF_NODE) &&
3723 (node->type != XML_XINCLUDE_END) &&
3724 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003725 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003726 }else{
3727 if (node->type == XML_ELEMENT_NODE)
3728 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00003729 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003730 if (parent != NULL) {
3731 xmlNodePtr tmp;
3732
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003733 /*
3734 * this is a tricky part for the node register thing:
3735 * in case ret does get coalesced in xmlAddChild
3736 * the deregister-node callback is called; so we register ret now already
3737 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003738 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003739 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3740
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003741 tmp = xmlAddChild(parent, ret);
3742 /* node could have coalesced */
3743 if (tmp != ret)
3744 return(tmp);
3745 }
Owen Taylor3473f882001-02-23 17:55:21 +00003746
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003747 if (!recursive)
3748 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003749 if (node->nsDef != NULL)
3750 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3751
3752 if (node->ns != NULL) {
3753 xmlNsPtr ns;
3754
3755 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3756 if (ns == NULL) {
3757 /*
3758 * Humm, we are copying an element whose namespace is defined
3759 * out of the new tree scope. Search it in the original tree
3760 * and add it at the top of the new tree
3761 */
3762 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3763 if (ns != NULL) {
3764 xmlNodePtr root = ret;
3765
3766 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003767 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003768 }
3769 } else {
3770 /*
3771 * reference the existing namespace definition in our own tree.
3772 */
3773 ret->ns = ns;
3774 }
3775 }
3776 if (node->properties != NULL)
3777 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003778 if (node->type == XML_ENTITY_REF_NODE) {
3779 if ((doc == NULL) || (node->doc != doc)) {
3780 /*
3781 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003782 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003783 * we cannot keep the reference. Try to find it in the
3784 * target document.
3785 */
3786 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3787 } else {
3788 ret->children = node->children;
3789 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003790 ret->last = ret->children;
3791 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003792 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003793 UPDATE_LAST_CHILD_AND_PARENT(ret)
3794 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003795
3796out:
3797 /* if parent != NULL we already registered the node above */
3798 if (parent == NULL && xmlRegisterNodeDefaultValue)
3799 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003800 return(ret);
3801}
3802
3803static xmlNodePtr
3804xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3805 xmlNodePtr ret = NULL;
3806 xmlNodePtr p = NULL,q;
3807
3808 while (node != NULL) {
Daniel Veillard652327a2003-09-29 18:02:38 +00003809#ifdef LIBXML_TREE_ENABLED
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003810 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003811 if (doc == NULL) {
3812 node = node->next;
3813 continue;
3814 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003815 if (doc->intSubset == NULL) {
3816 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3817 q->doc = doc;
3818 q->parent = parent;
3819 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003820 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003821 } else {
3822 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003823 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003824 }
3825 } else
Daniel Veillard652327a2003-09-29 18:02:38 +00003826#endif /* LIBXML_TREE_ENABLED */
Daniel Veillardb33c2012001-04-25 12:59:04 +00003827 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003828 if (ret == NULL) {
3829 q->prev = NULL;
3830 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003831 } else if (p != q) {
3832 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003833 p->next = q;
3834 q->prev = p;
3835 p = q;
3836 }
3837 node = node->next;
3838 }
3839 return(ret);
3840}
3841
3842/**
3843 * xmlCopyNode:
3844 * @node: the node
3845 * @recursive: if 1 do a recursive copy.
3846 *
3847 * Do a copy of the node.
3848 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003849 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003850 */
3851xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003852xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003853 xmlNodePtr ret;
3854
3855 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3856 return(ret);
3857}
3858
3859/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003860 * xmlDocCopyNode:
3861 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003862 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003863 * @recursive: if 1 do a recursive copy.
3864 *
3865 * Do a copy of the node to a given document.
3866 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003867 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003868 */
3869xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003870xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003871 xmlNodePtr ret;
3872
3873 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3874 return(ret);
3875}
3876
3877/**
Owen Taylor3473f882001-02-23 17:55:21 +00003878 * xmlCopyNodeList:
3879 * @node: the first node in the list.
3880 *
3881 * Do a recursive copy of the node list.
3882 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003883 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003884 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003885xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003886 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3887 return(ret);
3888}
3889
Daniel Veillard652327a2003-09-29 18:02:38 +00003890#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003891/**
Owen Taylor3473f882001-02-23 17:55:21 +00003892 * xmlCopyDtd:
3893 * @dtd: the dtd
3894 *
3895 * Do a copy of the dtd.
3896 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003897 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003898 */
3899xmlDtdPtr
3900xmlCopyDtd(xmlDtdPtr dtd) {
3901 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003902 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003903
3904 if (dtd == NULL) return(NULL);
3905 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3906 if (ret == NULL) return(NULL);
3907 if (dtd->entities != NULL)
3908 ret->entities = (void *) xmlCopyEntitiesTable(
3909 (xmlEntitiesTablePtr) dtd->entities);
3910 if (dtd->notations != NULL)
3911 ret->notations = (void *) xmlCopyNotationTable(
3912 (xmlNotationTablePtr) dtd->notations);
3913 if (dtd->elements != NULL)
3914 ret->elements = (void *) xmlCopyElementTable(
3915 (xmlElementTablePtr) dtd->elements);
3916 if (dtd->attributes != NULL)
3917 ret->attributes = (void *) xmlCopyAttributeTable(
3918 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003919 if (dtd->pentities != NULL)
3920 ret->pentities = (void *) xmlCopyEntitiesTable(
3921 (xmlEntitiesTablePtr) dtd->pentities);
3922
3923 cur = dtd->children;
3924 while (cur != NULL) {
3925 q = NULL;
3926
3927 if (cur->type == XML_ENTITY_DECL) {
3928 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3929 switch (tmp->etype) {
3930 case XML_INTERNAL_GENERAL_ENTITY:
3931 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3932 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3933 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3934 break;
3935 case XML_INTERNAL_PARAMETER_ENTITY:
3936 case XML_EXTERNAL_PARAMETER_ENTITY:
3937 q = (xmlNodePtr)
3938 xmlGetParameterEntityFromDtd(ret, tmp->name);
3939 break;
3940 case XML_INTERNAL_PREDEFINED_ENTITY:
3941 break;
3942 }
3943 } else if (cur->type == XML_ELEMENT_DECL) {
3944 xmlElementPtr tmp = (xmlElementPtr) cur;
3945 q = (xmlNodePtr)
3946 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3947 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3948 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3949 q = (xmlNodePtr)
3950 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3951 } else if (cur->type == XML_COMMENT_NODE) {
3952 q = xmlCopyNode(cur, 0);
3953 }
3954
3955 if (q == NULL) {
3956 cur = cur->next;
3957 continue;
3958 }
3959
3960 if (p == NULL)
3961 ret->children = q;
3962 else
3963 p->next = q;
3964
3965 q->prev = p;
3966 q->parent = (xmlNodePtr) ret;
3967 q->next = NULL;
3968 ret->last = q;
3969 p = q;
3970 cur = cur->next;
3971 }
3972
Owen Taylor3473f882001-02-23 17:55:21 +00003973 return(ret);
3974}
3975
3976/**
3977 * xmlCopyDoc:
3978 * @doc: the document
3979 * @recursive: if 1 do a recursive copy.
3980 *
3981 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003982 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003983 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003984 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003985 */
3986xmlDocPtr
3987xmlCopyDoc(xmlDocPtr doc, int recursive) {
3988 xmlDocPtr ret;
3989
3990 if (doc == NULL) return(NULL);
3991 ret = xmlNewDoc(doc->version);
3992 if (ret == NULL) return(NULL);
3993 if (doc->name != NULL)
3994 ret->name = xmlMemStrdup(doc->name);
3995 if (doc->encoding != NULL)
3996 ret->encoding = xmlStrdup(doc->encoding);
3997 ret->charset = doc->charset;
3998 ret->compression = doc->compression;
3999 ret->standalone = doc->standalone;
4000 if (!recursive) return(ret);
4001
Daniel Veillardb33c2012001-04-25 12:59:04 +00004002 ret->last = NULL;
4003 ret->children = NULL;
4004 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004005 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004006 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004007 ret->intSubset->parent = ret;
4008 }
Owen Taylor3473f882001-02-23 17:55:21 +00004009 if (doc->oldNs != NULL)
4010 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4011 if (doc->children != NULL) {
4012 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00004013
4014 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4015 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004016 ret->last = NULL;
4017 tmp = ret->children;
4018 while (tmp != NULL) {
4019 if (tmp->next == NULL)
4020 ret->last = tmp;
4021 tmp = tmp->next;
4022 }
4023 }
4024 return(ret);
4025}
Daniel Veillard652327a2003-09-29 18:02:38 +00004026#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004027
4028/************************************************************************
4029 * *
4030 * Content access functions *
4031 * *
4032 ************************************************************************/
4033
4034/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004035 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004036 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004037 *
4038 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004039 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004040 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004041 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004042 */
4043long
4044xmlGetLineNo(xmlNodePtr node)
4045{
4046 long result = -1;
4047
4048 if (!node)
4049 return result;
4050 if (node->type == XML_ELEMENT_NODE)
4051 result = (long) node->content;
4052 else if ((node->prev != NULL) &&
4053 ((node->prev->type == XML_ELEMENT_NODE) ||
4054 (node->prev->type == XML_TEXT_NODE)))
4055 result = xmlGetLineNo(node->prev);
4056 else if ((node->parent != NULL) &&
4057 ((node->parent->type == XML_ELEMENT_NODE) ||
4058 (node->parent->type == XML_TEXT_NODE)))
4059 result = xmlGetLineNo(node->parent);
4060
4061 return result;
4062}
4063
Daniel Veillard652327a2003-09-29 18:02:38 +00004064#ifdef LIBXML_TREE_ENABLED
Daniel Veillard8faa7832001-11-26 15:58:08 +00004065/**
4066 * xmlGetNodePath:
4067 * @node: a node
4068 *
4069 * Build a structure based Path for the given node
4070 *
4071 * Returns the new path or NULL in case of error. The caller must free
4072 * the returned string
4073 */
4074xmlChar *
4075xmlGetNodePath(xmlNodePtr node)
4076{
4077 xmlNodePtr cur, tmp, next;
4078 xmlChar *buffer = NULL, *temp;
4079 size_t buf_len;
4080 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004081 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004082 const char *name;
4083 char nametemp[100];
4084 int occur = 0;
4085
4086 if (node == NULL)
4087 return (NULL);
4088
4089 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004090 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004091 if (buffer == NULL)
4092 return (NULL);
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004093 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004094 if (buf == NULL) {
4095 xmlFree(buffer);
4096 return (NULL);
4097 }
4098
4099 buffer[0] = 0;
4100 cur = node;
4101 do {
4102 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004103 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004104 occur = 0;
4105 if ((cur->type == XML_DOCUMENT_NODE) ||
4106 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4107 if (buffer[0] == '/')
4108 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004109 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004110 next = NULL;
4111 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004112 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004113 name = (const char *) cur->name;
4114 if (cur->ns) {
4115 snprintf(nametemp, sizeof(nametemp) - 1,
4116 "%s:%s", cur->ns->prefix, cur->name);
4117 nametemp[sizeof(nametemp) - 1] = 0;
4118 name = nametemp;
4119 }
4120 next = cur->parent;
4121
4122 /*
4123 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004124 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004125 */
4126 tmp = cur->prev;
4127 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004128 if ((tmp->type == XML_ELEMENT_NODE) &&
4129 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004130 occur++;
4131 tmp = tmp->prev;
4132 }
4133 if (occur == 0) {
4134 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004135 while (tmp != NULL && occur == 0) {
4136 if ((tmp->type == XML_ELEMENT_NODE) &&
4137 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004138 occur++;
4139 tmp = tmp->next;
4140 }
4141 if (occur != 0)
4142 occur = 1;
4143 } else
4144 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004145 } else if (cur->type == XML_COMMENT_NODE) {
4146 sep = "/";
4147 name = "comment()";
4148 next = cur->parent;
4149
4150 /*
4151 * Thumbler index computation
4152 */
4153 tmp = cur->prev;
4154 while (tmp != NULL) {
4155 if (tmp->type == XML_COMMENT_NODE)
4156 occur++;
4157 tmp = tmp->prev;
4158 }
4159 if (occur == 0) {
4160 tmp = cur->next;
4161 while (tmp != NULL && occur == 0) {
4162 if (tmp->type == XML_COMMENT_NODE)
4163 occur++;
4164 tmp = tmp->next;
4165 }
4166 if (occur != 0)
4167 occur = 1;
4168 } else
4169 occur++;
4170 } else if ((cur->type == XML_TEXT_NODE) ||
4171 (cur->type == XML_CDATA_SECTION_NODE)) {
4172 sep = "/";
4173 name = "text()";
4174 next = cur->parent;
4175
4176 /*
4177 * Thumbler index computation
4178 */
4179 tmp = cur->prev;
4180 while (tmp != NULL) {
4181 if ((cur->type == XML_TEXT_NODE) ||
4182 (cur->type == XML_CDATA_SECTION_NODE))
4183 occur++;
4184 tmp = tmp->prev;
4185 }
4186 if (occur == 0) {
4187 tmp = cur->next;
4188 while (tmp != NULL && occur == 0) {
4189 if ((cur->type == XML_TEXT_NODE) ||
4190 (cur->type == XML_CDATA_SECTION_NODE))
4191 occur++;
4192 tmp = tmp->next;
4193 }
4194 if (occur != 0)
4195 occur = 1;
4196 } else
4197 occur++;
4198 } else if (cur->type == XML_PI_NODE) {
4199 sep = "/";
4200 snprintf(nametemp, sizeof(nametemp) - 1,
4201 "processing-instruction('%s')", cur->name);
4202 nametemp[sizeof(nametemp) - 1] = 0;
4203 name = nametemp;
4204
4205 next = cur->parent;
4206
4207 /*
4208 * Thumbler index computation
4209 */
4210 tmp = cur->prev;
4211 while (tmp != NULL) {
4212 if ((tmp->type == XML_PI_NODE) &&
4213 (xmlStrEqual(cur->name, tmp->name)))
4214 occur++;
4215 tmp = tmp->prev;
4216 }
4217 if (occur == 0) {
4218 tmp = cur->next;
4219 while (tmp != NULL && occur == 0) {
4220 if ((tmp->type == XML_PI_NODE) &&
4221 (xmlStrEqual(cur->name, tmp->name)))
4222 occur++;
4223 tmp = tmp->next;
4224 }
4225 if (occur != 0)
4226 occur = 1;
4227 } else
4228 occur++;
4229
Daniel Veillard8faa7832001-11-26 15:58:08 +00004230 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004231 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004232 name = (const char *) (((xmlAttrPtr) cur)->name);
4233 next = ((xmlAttrPtr) cur)->parent;
4234 } else {
4235 next = cur->parent;
4236 }
4237
4238 /*
4239 * Make sure there is enough room
4240 */
4241 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4242 buf_len =
4243 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4244 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4245 if (temp == NULL) {
4246 xmlFree(buf);
4247 xmlFree(buffer);
4248 return (NULL);
4249 }
4250 buffer = temp;
4251 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4252 if (temp == NULL) {
4253 xmlFree(buf);
4254 xmlFree(buffer);
4255 return (NULL);
4256 }
4257 buf = temp;
4258 }
4259 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004260 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004261 sep, name, (char *) buffer);
4262 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004263 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004264 sep, name, occur, (char *) buffer);
4265 snprintf((char *) buffer, buf_len, "%s", buf);
4266 cur = next;
4267 } while (cur != NULL);
4268 xmlFree(buf);
4269 return (buffer);
4270}
Daniel Veillard652327a2003-09-29 18:02:38 +00004271#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard8faa7832001-11-26 15:58:08 +00004272
4273/**
Owen Taylor3473f882001-02-23 17:55:21 +00004274 * xmlDocGetRootElement:
4275 * @doc: the document
4276 *
4277 * Get the root element of the document (doc->children is a list
4278 * containing possibly comments, PIs, etc ...).
4279 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004280 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004281 */
4282xmlNodePtr
4283xmlDocGetRootElement(xmlDocPtr doc) {
4284 xmlNodePtr ret;
4285
4286 if (doc == NULL) return(NULL);
4287 ret = doc->children;
4288 while (ret != NULL) {
4289 if (ret->type == XML_ELEMENT_NODE)
4290 return(ret);
4291 ret = ret->next;
4292 }
4293 return(ret);
4294}
4295
Daniel Veillard652327a2003-09-29 18:02:38 +00004296#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004297/**
4298 * xmlDocSetRootElement:
4299 * @doc: the document
4300 * @root: the new document root element
4301 *
4302 * Set the root element of the document (doc->children is a list
4303 * containing possibly comments, PIs, etc ...).
4304 *
4305 * Returns the old root element if any was found
4306 */
4307xmlNodePtr
4308xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4309 xmlNodePtr old = NULL;
4310
4311 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004312 if (root == NULL)
4313 return(NULL);
4314 xmlUnlinkNode(root);
4315 root->doc = doc;
4316 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004317 old = doc->children;
4318 while (old != NULL) {
4319 if (old->type == XML_ELEMENT_NODE)
4320 break;
4321 old = old->next;
4322 }
4323 if (old == NULL) {
4324 if (doc->children == NULL) {
4325 doc->children = root;
4326 doc->last = root;
4327 } else {
4328 xmlAddSibling(doc->children, root);
4329 }
4330 } else {
4331 xmlReplaceNode(old, root);
4332 }
4333 return(old);
4334}
4335
4336/**
4337 * xmlNodeSetLang:
4338 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004339 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004340 *
4341 * Set the language of a node, i.e. the values of the xml:lang
4342 * attribute.
4343 */
4344void
4345xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004346 xmlNsPtr ns;
4347
Owen Taylor3473f882001-02-23 17:55:21 +00004348 if (cur == NULL) return;
4349 switch(cur->type) {
4350 case XML_TEXT_NODE:
4351 case XML_CDATA_SECTION_NODE:
4352 case XML_COMMENT_NODE:
4353 case XML_DOCUMENT_NODE:
4354 case XML_DOCUMENT_TYPE_NODE:
4355 case XML_DOCUMENT_FRAG_NODE:
4356 case XML_NOTATION_NODE:
4357 case XML_HTML_DOCUMENT_NODE:
4358 case XML_DTD_NODE:
4359 case XML_ELEMENT_DECL:
4360 case XML_ATTRIBUTE_DECL:
4361 case XML_ENTITY_DECL:
4362 case XML_PI_NODE:
4363 case XML_ENTITY_REF_NODE:
4364 case XML_ENTITY_NODE:
4365 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004366#ifdef LIBXML_DOCB_ENABLED
4367 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004368#endif
4369 case XML_XINCLUDE_START:
4370 case XML_XINCLUDE_END:
4371 return;
4372 case XML_ELEMENT_NODE:
4373 case XML_ATTRIBUTE_NODE:
4374 break;
4375 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004376 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4377 if (ns == NULL)
4378 return;
4379 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004380}
Daniel Veillard652327a2003-09-29 18:02:38 +00004381#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004382
4383/**
4384 * xmlNodeGetLang:
4385 * @cur: the node being checked
4386 *
4387 * Searches the language of a node, i.e. the values of the xml:lang
4388 * attribute or the one carried by the nearest ancestor.
4389 *
4390 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004391 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004392 */
4393xmlChar *
4394xmlNodeGetLang(xmlNodePtr cur) {
4395 xmlChar *lang;
4396
4397 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004398 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004399 if (lang != NULL)
4400 return(lang);
4401 cur = cur->parent;
4402 }
4403 return(NULL);
4404}
4405
4406
Daniel Veillard652327a2003-09-29 18:02:38 +00004407#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004408/**
4409 * xmlNodeSetSpacePreserve:
4410 * @cur: the node being changed
4411 * @val: the xml:space value ("0": default, 1: "preserve")
4412 *
4413 * Set (or reset) the space preserving behaviour of a node, i.e. the
4414 * value of the xml:space attribute.
4415 */
4416void
4417xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004418 xmlNsPtr ns;
4419
Owen Taylor3473f882001-02-23 17:55:21 +00004420 if (cur == NULL) return;
4421 switch(cur->type) {
4422 case XML_TEXT_NODE:
4423 case XML_CDATA_SECTION_NODE:
4424 case XML_COMMENT_NODE:
4425 case XML_DOCUMENT_NODE:
4426 case XML_DOCUMENT_TYPE_NODE:
4427 case XML_DOCUMENT_FRAG_NODE:
4428 case XML_NOTATION_NODE:
4429 case XML_HTML_DOCUMENT_NODE:
4430 case XML_DTD_NODE:
4431 case XML_ELEMENT_DECL:
4432 case XML_ATTRIBUTE_DECL:
4433 case XML_ENTITY_DECL:
4434 case XML_PI_NODE:
4435 case XML_ENTITY_REF_NODE:
4436 case XML_ENTITY_NODE:
4437 case XML_NAMESPACE_DECL:
4438 case XML_XINCLUDE_START:
4439 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004440#ifdef LIBXML_DOCB_ENABLED
4441 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004442#endif
4443 return;
4444 case XML_ELEMENT_NODE:
4445 case XML_ATTRIBUTE_NODE:
4446 break;
4447 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004448 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4449 if (ns == NULL)
4450 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004451 switch (val) {
4452 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004453 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004454 break;
4455 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004456 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004457 break;
4458 }
4459}
Daniel Veillard652327a2003-09-29 18:02:38 +00004460#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004461
4462/**
4463 * xmlNodeGetSpacePreserve:
4464 * @cur: the node being checked
4465 *
4466 * Searches the space preserving behaviour of a node, i.e. the values
4467 * of the xml:space attribute or the one carried by the nearest
4468 * ancestor.
4469 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004470 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004471 */
4472int
4473xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4474 xmlChar *space;
4475
4476 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004477 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004478 if (space != NULL) {
4479 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4480 xmlFree(space);
4481 return(1);
4482 }
4483 if (xmlStrEqual(space, BAD_CAST "default")) {
4484 xmlFree(space);
4485 return(0);
4486 }
4487 xmlFree(space);
4488 }
4489 cur = cur->parent;
4490 }
4491 return(-1);
4492}
4493
Daniel Veillard652327a2003-09-29 18:02:38 +00004494#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004495/**
4496 * xmlNodeSetName:
4497 * @cur: the node being changed
4498 * @name: the new tag name
4499 *
4500 * Set (or reset) the name of a node.
4501 */
4502void
4503xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
4504 if (cur == NULL) return;
4505 if (name == NULL) return;
4506 switch(cur->type) {
4507 case XML_TEXT_NODE:
4508 case XML_CDATA_SECTION_NODE:
4509 case XML_COMMENT_NODE:
4510 case XML_DOCUMENT_TYPE_NODE:
4511 case XML_DOCUMENT_FRAG_NODE:
4512 case XML_NOTATION_NODE:
4513 case XML_HTML_DOCUMENT_NODE:
4514 case XML_NAMESPACE_DECL:
4515 case XML_XINCLUDE_START:
4516 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004517#ifdef LIBXML_DOCB_ENABLED
4518 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004519#endif
4520 return;
4521 case XML_ELEMENT_NODE:
4522 case XML_ATTRIBUTE_NODE:
4523 case XML_PI_NODE:
4524 case XML_ENTITY_REF_NODE:
4525 case XML_ENTITY_NODE:
4526 case XML_DTD_NODE:
4527 case XML_DOCUMENT_NODE:
4528 case XML_ELEMENT_DECL:
4529 case XML_ATTRIBUTE_DECL:
4530 case XML_ENTITY_DECL:
4531 break;
4532 }
4533 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4534 cur->name = xmlStrdup(name);
4535}
4536
4537/**
4538 * xmlNodeSetBase:
4539 * @cur: the node being changed
4540 * @uri: the new base URI
4541 *
4542 * Set (or reset) the base URI of a node, i.e. the value of the
4543 * xml:base attribute.
4544 */
4545void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00004546xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004547 xmlNsPtr ns;
4548
Owen Taylor3473f882001-02-23 17:55:21 +00004549 if (cur == NULL) return;
4550 switch(cur->type) {
4551 case XML_TEXT_NODE:
4552 case XML_CDATA_SECTION_NODE:
4553 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004554 case XML_DOCUMENT_TYPE_NODE:
4555 case XML_DOCUMENT_FRAG_NODE:
4556 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004557 case XML_DTD_NODE:
4558 case XML_ELEMENT_DECL:
4559 case XML_ATTRIBUTE_DECL:
4560 case XML_ENTITY_DECL:
4561 case XML_PI_NODE:
4562 case XML_ENTITY_REF_NODE:
4563 case XML_ENTITY_NODE:
4564 case XML_NAMESPACE_DECL:
4565 case XML_XINCLUDE_START:
4566 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004567 return;
4568 case XML_ELEMENT_NODE:
4569 case XML_ATTRIBUTE_NODE:
4570 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004571 case XML_DOCUMENT_NODE:
4572#ifdef LIBXML_DOCB_ENABLED
4573 case XML_DOCB_DOCUMENT_NODE:
4574#endif
4575 case XML_HTML_DOCUMENT_NODE: {
4576 xmlDocPtr doc = (xmlDocPtr) cur;
4577
4578 if (doc->URL != NULL)
4579 xmlFree((xmlChar *) doc->URL);
4580 if (uri == NULL)
4581 doc->URL = NULL;
4582 else
4583 doc->URL = xmlStrdup(uri);
4584 return;
4585 }
Owen Taylor3473f882001-02-23 17:55:21 +00004586 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004587
4588 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4589 if (ns == NULL)
4590 return;
4591 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004592}
Daniel Veillard652327a2003-09-29 18:02:38 +00004593#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00004594
4595/**
Owen Taylor3473f882001-02-23 17:55:21 +00004596 * xmlNodeGetBase:
4597 * @doc: the document the node pertains to
4598 * @cur: the node being checked
4599 *
4600 * Searches for the BASE URL. The code should work on both XML
4601 * and HTML document even if base mechanisms are completely different.
4602 * It returns the base as defined in RFC 2396 sections
4603 * 5.1.1. Base URI within Document Content
4604 * and
4605 * 5.1.2. Base URI from the Encapsulating Entity
4606 * However it does not return the document base (5.1.3), use
4607 * xmlDocumentGetBase() for this
4608 *
4609 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004610 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004611 */
4612xmlChar *
4613xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004614 xmlChar *oldbase = NULL;
4615 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004616
4617 if ((cur == NULL) && (doc == NULL))
4618 return(NULL);
4619 if (doc == NULL) doc = cur->doc;
4620 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4621 cur = doc->children;
4622 while ((cur != NULL) && (cur->name != NULL)) {
4623 if (cur->type != XML_ELEMENT_NODE) {
4624 cur = cur->next;
4625 continue;
4626 }
4627 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4628 cur = cur->children;
4629 continue;
4630 }
4631 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4632 cur = cur->children;
4633 continue;
4634 }
4635 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4636 return(xmlGetProp(cur, BAD_CAST "href"));
4637 }
4638 cur = cur->next;
4639 }
4640 return(NULL);
4641 }
4642 while (cur != NULL) {
4643 if (cur->type == XML_ENTITY_DECL) {
4644 xmlEntityPtr ent = (xmlEntityPtr) cur;
4645 return(xmlStrdup(ent->URI));
4646 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004647 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004648 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004649 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004650 if (oldbase != NULL) {
4651 newbase = xmlBuildURI(oldbase, base);
4652 if (newbase != NULL) {
4653 xmlFree(oldbase);
4654 xmlFree(base);
4655 oldbase = newbase;
4656 } else {
4657 xmlFree(oldbase);
4658 xmlFree(base);
4659 return(NULL);
4660 }
4661 } else {
4662 oldbase = base;
4663 }
4664 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4665 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4666 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4667 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004668 }
4669 }
Owen Taylor3473f882001-02-23 17:55:21 +00004670 cur = cur->parent;
4671 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004672 if ((doc != NULL) && (doc->URL != NULL)) {
4673 if (oldbase == NULL)
4674 return(xmlStrdup(doc->URL));
4675 newbase = xmlBuildURI(oldbase, doc->URL);
4676 xmlFree(oldbase);
4677 return(newbase);
4678 }
4679 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004680}
4681
4682/**
4683 * xmlNodeGetContent:
4684 * @cur: the node being read
4685 *
4686 * Read the value of a node, this can be either the text carried
4687 * directly by this node if it's a TEXT node or the aggregate string
4688 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004689 * Entity references are substituted.
4690 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004691 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004692 */
4693xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004694xmlNodeGetContent(xmlNodePtr cur)
4695{
4696 if (cur == NULL)
4697 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004698 switch (cur->type) {
4699 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004700 case XML_ELEMENT_NODE:{
4701 xmlNodePtr tmp = cur;
4702 xmlBufferPtr buffer;
4703 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004704
Daniel Veillard814a76d2003-01-23 18:24:20 +00004705 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004706 if (buffer == NULL)
4707 return (NULL);
4708 while (tmp != NULL) {
4709 switch (tmp->type) {
4710 case XML_CDATA_SECTION_NODE:
4711 case XML_TEXT_NODE:
4712 if (tmp->content != NULL)
4713 xmlBufferCat(buffer, tmp->content);
4714 break;
4715 case XML_ENTITY_REF_NODE:{
4716 /* recursive substitution of entity references */
4717 xmlChar *cont = xmlNodeGetContent(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00004718
Daniel Veillard7646b182002-04-20 06:41:40 +00004719 if (cont) {
4720 xmlBufferCat(buffer,
4721 (const xmlChar *) cont);
4722 xmlFree(cont);
4723 }
4724 break;
4725 }
4726 default:
4727 break;
4728 }
4729 /*
4730 * Skip to next node
4731 */
4732 if (tmp->children != NULL) {
4733 if (tmp->children->type != XML_ENTITY_DECL) {
4734 tmp = tmp->children;
4735 continue;
4736 }
4737 }
4738 if (tmp == cur)
4739 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00004740
Daniel Veillard7646b182002-04-20 06:41:40 +00004741 if (tmp->next != NULL) {
4742 tmp = tmp->next;
4743 continue;
4744 }
4745
4746 do {
4747 tmp = tmp->parent;
4748 if (tmp == NULL)
4749 break;
4750 if (tmp == cur) {
4751 tmp = NULL;
4752 break;
4753 }
4754 if (tmp->next != NULL) {
4755 tmp = tmp->next;
4756 break;
4757 }
4758 } while (tmp != NULL);
4759 }
4760 ret = buffer->content;
4761 buffer->content = NULL;
4762 xmlBufferFree(buffer);
4763 return (ret);
4764 }
4765 case XML_ATTRIBUTE_NODE:{
4766 xmlAttrPtr attr = (xmlAttrPtr) cur;
4767
4768 if (attr->parent != NULL)
4769 return (xmlNodeListGetString
4770 (attr->parent->doc, attr->children, 1));
4771 else
4772 return (xmlNodeListGetString(NULL, attr->children, 1));
4773 break;
4774 }
Owen Taylor3473f882001-02-23 17:55:21 +00004775 case XML_COMMENT_NODE:
4776 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004777 if (cur->content != NULL)
4778 return (xmlStrdup(cur->content));
4779 return (NULL);
4780 case XML_ENTITY_REF_NODE:{
4781 xmlEntityPtr ent;
4782 xmlNodePtr tmp;
4783 xmlBufferPtr buffer;
4784 xmlChar *ret;
4785
4786 /* lookup entity declaration */
4787 ent = xmlGetDocEntity(cur->doc, cur->name);
4788 if (ent == NULL)
4789 return (NULL);
4790
4791 buffer = xmlBufferCreate();
4792 if (buffer == NULL)
4793 return (NULL);
4794
4795 /* an entity content can be any "well balanced chunk",
4796 * i.e. the result of the content [43] production:
4797 * http://www.w3.org/TR/REC-xml#NT-content
4798 * -> we iterate through child nodes and recursive call
4799 * xmlNodeGetContent() which handles all possible node types */
4800 tmp = ent->children;
4801 while (tmp) {
4802 xmlChar *cont = xmlNodeGetContent(tmp);
4803
4804 if (cont) {
4805 xmlBufferCat(buffer, (const xmlChar *) cont);
4806 xmlFree(cont);
4807 }
4808 tmp = tmp->next;
4809 }
4810
4811 ret = buffer->content;
4812 buffer->content = NULL;
4813 xmlBufferFree(buffer);
4814 return (ret);
4815 }
Owen Taylor3473f882001-02-23 17:55:21 +00004816 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004817 case XML_DOCUMENT_TYPE_NODE:
4818 case XML_NOTATION_NODE:
4819 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004820 case XML_XINCLUDE_START:
4821 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00004822 return (NULL);
4823 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004824#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004825 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004826#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00004827 case XML_HTML_DOCUMENT_NODE: {
4828 xmlChar *tmp;
4829 xmlChar *res = NULL;
4830
4831 cur = cur->children;
4832 while (cur!= NULL) {
4833 if ((cur->type == XML_ELEMENT_NODE) ||
4834 (cur->type == XML_TEXT_NODE) ||
4835 (cur->type == XML_CDATA_SECTION_NODE)) {
4836 tmp = xmlNodeGetContent(cur);
4837 if (tmp != NULL) {
4838 if (res == NULL)
4839 res = tmp;
4840 else {
4841 res = xmlStrcat(res, tmp);
4842 xmlFree(tmp);
4843 }
4844 }
4845 }
4846 cur = cur->next;
4847 }
4848 return(res);
4849 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004850 case XML_NAMESPACE_DECL: {
4851 xmlChar *tmp;
4852
4853 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4854 return (tmp);
4855 }
Owen Taylor3473f882001-02-23 17:55:21 +00004856 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004857 /* TODO !!! */
4858 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004859 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004860 /* TODO !!! */
4861 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004862 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004863 /* TODO !!! */
4864 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004865 case XML_CDATA_SECTION_NODE:
4866 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004867 if (cur->content != NULL)
4868 return (xmlStrdup(cur->content));
4869 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004870 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004871 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004872}
Daniel Veillard652327a2003-09-29 18:02:38 +00004873
Owen Taylor3473f882001-02-23 17:55:21 +00004874/**
4875 * xmlNodeSetContent:
4876 * @cur: the node being modified
4877 * @content: the new value of the content
4878 *
4879 * Replace the content of a node.
4880 */
4881void
4882xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4883 if (cur == NULL) {
4884#ifdef DEBUG_TREE
4885 xmlGenericError(xmlGenericErrorContext,
4886 "xmlNodeSetContent : node == NULL\n");
4887#endif
4888 return;
4889 }
4890 switch (cur->type) {
4891 case XML_DOCUMENT_FRAG_NODE:
4892 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004893 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004894 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4895 cur->children = xmlStringGetNodeList(cur->doc, content);
4896 UPDATE_LAST_CHILD_AND_PARENT(cur)
4897 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004898 case XML_TEXT_NODE:
4899 case XML_CDATA_SECTION_NODE:
4900 case XML_ENTITY_REF_NODE:
4901 case XML_ENTITY_NODE:
4902 case XML_PI_NODE:
4903 case XML_COMMENT_NODE:
4904 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004905 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004906 }
4907 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4908 cur->last = cur->children = NULL;
4909 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004910 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00004911 } else
4912 cur->content = NULL;
4913 break;
4914 case XML_DOCUMENT_NODE:
4915 case XML_HTML_DOCUMENT_NODE:
4916 case XML_DOCUMENT_TYPE_NODE:
4917 case XML_XINCLUDE_START:
4918 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004919#ifdef LIBXML_DOCB_ENABLED
4920 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004921#endif
4922 break;
4923 case XML_NOTATION_NODE:
4924 break;
4925 case XML_DTD_NODE:
4926 break;
4927 case XML_NAMESPACE_DECL:
4928 break;
4929 case XML_ELEMENT_DECL:
4930 /* TODO !!! */
4931 break;
4932 case XML_ATTRIBUTE_DECL:
4933 /* TODO !!! */
4934 break;
4935 case XML_ENTITY_DECL:
4936 /* TODO !!! */
4937 break;
4938 }
4939}
4940
Daniel Veillard652327a2003-09-29 18:02:38 +00004941#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00004942/**
4943 * xmlNodeSetContentLen:
4944 * @cur: the node being modified
4945 * @content: the new value of the content
4946 * @len: the size of @content
4947 *
4948 * Replace the content of a node.
4949 */
4950void
4951xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4952 if (cur == NULL) {
4953#ifdef DEBUG_TREE
4954 xmlGenericError(xmlGenericErrorContext,
4955 "xmlNodeSetContentLen : node == NULL\n");
4956#endif
4957 return;
4958 }
4959 switch (cur->type) {
4960 case XML_DOCUMENT_FRAG_NODE:
4961 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004962 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004963 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4964 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
4965 UPDATE_LAST_CHILD_AND_PARENT(cur)
4966 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004967 case XML_TEXT_NODE:
4968 case XML_CDATA_SECTION_NODE:
4969 case XML_ENTITY_REF_NODE:
4970 case XML_ENTITY_NODE:
4971 case XML_PI_NODE:
4972 case XML_COMMENT_NODE:
4973 case XML_NOTATION_NODE:
4974 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004975 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004976 }
4977 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4978 cur->children = cur->last = NULL;
4979 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004980 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004981 } else
4982 cur->content = NULL;
4983 break;
4984 case XML_DOCUMENT_NODE:
4985 case XML_DTD_NODE:
4986 case XML_HTML_DOCUMENT_NODE:
4987 case XML_DOCUMENT_TYPE_NODE:
4988 case XML_NAMESPACE_DECL:
4989 case XML_XINCLUDE_START:
4990 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004991#ifdef LIBXML_DOCB_ENABLED
4992 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004993#endif
4994 break;
4995 case XML_ELEMENT_DECL:
4996 /* TODO !!! */
4997 break;
4998 case XML_ATTRIBUTE_DECL:
4999 /* TODO !!! */
5000 break;
5001 case XML_ENTITY_DECL:
5002 /* TODO !!! */
5003 break;
5004 }
5005}
Daniel Veillard652327a2003-09-29 18:02:38 +00005006#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005007
5008/**
5009 * xmlNodeAddContentLen:
5010 * @cur: the node being modified
5011 * @content: extra content
5012 * @len: the size of @content
5013 *
5014 * Append the extra substring to the node content.
5015 */
5016void
5017xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5018 if (cur == NULL) {
5019#ifdef DEBUG_TREE
5020 xmlGenericError(xmlGenericErrorContext,
5021 "xmlNodeAddContentLen : node == NULL\n");
5022#endif
5023 return;
5024 }
5025 if (len <= 0) return;
5026 switch (cur->type) {
5027 case XML_DOCUMENT_FRAG_NODE:
5028 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005029 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005030
Daniel Veillard7db37732001-07-12 01:20:08 +00005031 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005032 newNode = xmlNewTextLen(content, len);
5033 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005034 tmp = xmlAddChild(cur, newNode);
5035 if (tmp != newNode)
5036 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005037 if ((last != NULL) && (last->next == newNode)) {
5038 xmlTextMerge(last, newNode);
5039 }
5040 }
5041 break;
5042 }
5043 case XML_ATTRIBUTE_NODE:
5044 break;
5045 case XML_TEXT_NODE:
5046 case XML_CDATA_SECTION_NODE:
5047 case XML_ENTITY_REF_NODE:
5048 case XML_ENTITY_NODE:
5049 case XML_PI_NODE:
5050 case XML_COMMENT_NODE:
5051 case XML_NOTATION_NODE:
5052 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005053 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005054 }
5055 case XML_DOCUMENT_NODE:
5056 case XML_DTD_NODE:
5057 case XML_HTML_DOCUMENT_NODE:
5058 case XML_DOCUMENT_TYPE_NODE:
5059 case XML_NAMESPACE_DECL:
5060 case XML_XINCLUDE_START:
5061 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005062#ifdef LIBXML_DOCB_ENABLED
5063 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005064#endif
5065 break;
5066 case XML_ELEMENT_DECL:
5067 case XML_ATTRIBUTE_DECL:
5068 case XML_ENTITY_DECL:
5069 break;
5070 }
5071}
5072
5073/**
5074 * xmlNodeAddContent:
5075 * @cur: the node being modified
5076 * @content: extra content
5077 *
5078 * Append the extra substring to the node content.
5079 */
5080void
5081xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5082 int len;
5083
5084 if (cur == NULL) {
5085#ifdef DEBUG_TREE
5086 xmlGenericError(xmlGenericErrorContext,
5087 "xmlNodeAddContent : node == NULL\n");
5088#endif
5089 return;
5090 }
5091 if (content == NULL) return;
5092 len = xmlStrlen(content);
5093 xmlNodeAddContentLen(cur, content, len);
5094}
5095
5096/**
5097 * xmlTextMerge:
5098 * @first: the first text node
5099 * @second: the second text node being merged
5100 *
5101 * Merge two text nodes into one
5102 * Returns the first text node augmented
5103 */
5104xmlNodePtr
5105xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5106 if (first == NULL) return(second);
5107 if (second == NULL) return(first);
5108 if (first->type != XML_TEXT_NODE) return(first);
5109 if (second->type != XML_TEXT_NODE) return(first);
5110 if (second->name != first->name)
5111 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005112 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005113 xmlUnlinkNode(second);
5114 xmlFreeNode(second);
5115 return(first);
5116}
5117
Daniel Veillard652327a2003-09-29 18:02:38 +00005118#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005119/**
5120 * xmlGetNsList:
5121 * @doc: the document
5122 * @node: the current node
5123 *
5124 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005125 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005126 * that need to be freed by the caller or NULL if no
5127 * namespace if defined
5128 */
5129xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005130xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5131{
Owen Taylor3473f882001-02-23 17:55:21 +00005132 xmlNsPtr cur;
5133 xmlNsPtr *ret = NULL;
5134 int nbns = 0;
5135 int maxns = 10;
5136 int i;
5137
5138 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005139 if (node->type == XML_ELEMENT_NODE) {
5140 cur = node->nsDef;
5141 while (cur != NULL) {
5142 if (ret == NULL) {
5143 ret =
5144 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5145 sizeof(xmlNsPtr));
5146 if (ret == NULL) {
5147 xmlGenericError(xmlGenericErrorContext,
5148 "xmlGetNsList : out of memory!\n");
5149 return (NULL);
5150 }
5151 ret[nbns] = NULL;
5152 }
5153 for (i = 0; i < nbns; i++) {
5154 if ((cur->prefix == ret[i]->prefix) ||
5155 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5156 break;
5157 }
5158 if (i >= nbns) {
5159 if (nbns >= maxns) {
5160 maxns *= 2;
5161 ret = (xmlNsPtr *) xmlRealloc(ret,
5162 (maxns +
5163 1) *
5164 sizeof(xmlNsPtr));
5165 if (ret == NULL) {
5166 xmlGenericError(xmlGenericErrorContext,
5167 "xmlGetNsList : realloc failed!\n");
5168 return (NULL);
5169 }
5170 }
5171 ret[nbns++] = cur;
5172 ret[nbns] = NULL;
5173 }
Owen Taylor3473f882001-02-23 17:55:21 +00005174
Daniel Veillard77044732001-06-29 21:31:07 +00005175 cur = cur->next;
5176 }
5177 }
5178 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005179 }
Daniel Veillard77044732001-06-29 21:31:07 +00005180 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005181}
Daniel Veillard652327a2003-09-29 18:02:38 +00005182#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005183
5184/**
5185 * xmlSearchNs:
5186 * @doc: the document
5187 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005188 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005189 *
5190 * Search a Ns registered under a given name space for a document.
5191 * recurse on the parents until it finds the defined namespace
5192 * or return NULL otherwise.
5193 * @nameSpace can be NULL, this is a search for the default namespace.
5194 * We don't allow to cross entities boundaries. If you don't declare
5195 * the namespace within those you will be in troubles !!! A warning
5196 * is generated to cover this case.
5197 *
5198 * Returns the namespace pointer or NULL.
5199 */
5200xmlNsPtr
5201xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
5202 xmlNsPtr cur;
5203
5204 if (node == NULL) return(NULL);
5205 if ((nameSpace != NULL) &&
5206 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005207 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5208 /*
5209 * The XML-1.0 namespace is normally held on the root
5210 * element. In this case exceptionally create it on the
5211 * node element.
5212 */
5213 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5214 if (cur == NULL) {
5215 xmlGenericError(xmlGenericErrorContext,
5216 "xmlSearchNs : malloc failed\n");
5217 return(NULL);
5218 }
5219 memset(cur, 0, sizeof(xmlNs));
5220 cur->type = XML_LOCAL_NAMESPACE;
5221 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5222 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5223 cur->next = node->nsDef;
5224 node->nsDef = cur;
5225 return(cur);
5226 }
Owen Taylor3473f882001-02-23 17:55:21 +00005227 if (doc->oldNs == NULL) {
5228 /*
5229 * Allocate a new Namespace and fill the fields.
5230 */
5231 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5232 if (doc->oldNs == NULL) {
5233 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005234 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005235 return(NULL);
5236 }
5237 memset(doc->oldNs, 0, sizeof(xmlNs));
5238 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5239
5240 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5241 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5242 }
5243 return(doc->oldNs);
5244 }
5245 while (node != NULL) {
5246 if ((node->type == XML_ENTITY_REF_NODE) ||
5247 (node->type == XML_ENTITY_NODE) ||
5248 (node->type == XML_ENTITY_DECL))
5249 return(NULL);
5250 if (node->type == XML_ELEMENT_NODE) {
5251 cur = node->nsDef;
5252 while (cur != NULL) {
5253 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5254 (cur->href != NULL))
5255 return(cur);
5256 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5257 (cur->href != NULL) &&
5258 (xmlStrEqual(cur->prefix, nameSpace)))
5259 return(cur);
5260 cur = cur->next;
5261 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005262 cur = node->ns;
5263 if (cur != NULL) {
5264 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5265 (cur->href != NULL))
5266 return(cur);
5267 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5268 (cur->href != NULL) &&
5269 (xmlStrEqual(cur->prefix, nameSpace)))
5270 return(cur);
5271 }
Owen Taylor3473f882001-02-23 17:55:21 +00005272 }
5273 node = node->parent;
5274 }
5275 return(NULL);
5276}
5277
5278/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005279 * xmlNsInScope:
5280 * @doc: the document
5281 * @node: the current node
5282 * @ancestor: the ancestor carrying the namespace
5283 * @prefix: the namespace prefix
5284 *
5285 * Verify that the given namespace held on @ancestor is still in scope
5286 * on node.
5287 *
5288 * Returns 1 if true, 0 if false and -1 in case of error.
5289 */
5290static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005291xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5292 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005293{
5294 xmlNsPtr tst;
5295
5296 while ((node != NULL) && (node != ancestor)) {
5297 if ((node->type == XML_ENTITY_REF_NODE) ||
5298 (node->type == XML_ENTITY_NODE) ||
5299 (node->type == XML_ENTITY_DECL))
5300 return (-1);
5301 if (node->type == XML_ELEMENT_NODE) {
5302 tst = node->nsDef;
5303 while (tst != NULL) {
5304 if ((tst->prefix == NULL)
5305 && (prefix == NULL))
5306 return (0);
5307 if ((tst->prefix != NULL)
5308 && (prefix != NULL)
5309 && (xmlStrEqual(tst->prefix, prefix)))
5310 return (0);
5311 tst = tst->next;
5312 }
5313 }
5314 node = node->parent;
5315 }
5316 if (node != ancestor)
5317 return (-1);
5318 return (1);
5319}
5320
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005321/**
Owen Taylor3473f882001-02-23 17:55:21 +00005322 * xmlSearchNsByHref:
5323 * @doc: the document
5324 * @node: the current node
5325 * @href: the namespace value
5326 *
5327 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5328 * the defined namespace or return NULL otherwise.
5329 * Returns the namespace pointer or NULL.
5330 */
5331xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005332xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5333{
Owen Taylor3473f882001-02-23 17:55:21 +00005334 xmlNsPtr cur;
5335 xmlNodePtr orig = node;
5336
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005337 if ((node == NULL) || (href == NULL))
5338 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005339 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005340 /*
5341 * Only the document can hold the XML spec namespace.
5342 */
5343 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5344 /*
5345 * The XML-1.0 namespace is normally held on the root
5346 * element. In this case exceptionally create it on the
5347 * node element.
5348 */
5349 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5350 if (cur == NULL) {
5351 xmlGenericError(xmlGenericErrorContext,
5352 "xmlSearchNs : malloc failed\n");
5353 return (NULL);
5354 }
5355 memset(cur, 0, sizeof(xmlNs));
5356 cur->type = XML_LOCAL_NAMESPACE;
5357 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5358 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5359 cur->next = node->nsDef;
5360 node->nsDef = cur;
5361 return (cur);
5362 }
5363 if (doc->oldNs == NULL) {
5364 /*
5365 * Allocate a new Namespace and fill the fields.
5366 */
5367 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5368 if (doc->oldNs == NULL) {
5369 xmlGenericError(xmlGenericErrorContext,
5370 "xmlSearchNsByHref : malloc failed\n");
5371 return (NULL);
5372 }
5373 memset(doc->oldNs, 0, sizeof(xmlNs));
5374 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005375
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005376 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5377 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5378 }
5379 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005380 }
5381 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005382 if ((node->type == XML_ENTITY_REF_NODE) ||
5383 (node->type == XML_ENTITY_NODE) ||
5384 (node->type == XML_ENTITY_DECL))
5385 return (NULL);
5386 if (node->type == XML_ELEMENT_NODE) {
5387 cur = node->nsDef;
5388 while (cur != NULL) {
5389 if ((cur->href != NULL) && (href != NULL) &&
5390 (xmlStrEqual(cur->href, href))) {
5391 if (xmlNsInScope(doc, orig, node, cur->href) == 1)
5392 return (cur);
5393 }
5394 cur = cur->next;
5395 }
5396 cur = node->ns;
5397 if (cur != NULL) {
5398 if ((cur->href != NULL) && (href != NULL) &&
5399 (xmlStrEqual(cur->href, href))) {
5400 if (xmlNsInScope(doc, orig, node, cur->href) == 1)
5401 return (cur);
5402 }
5403 }
5404 }
5405 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005406 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005407 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005408}
5409
5410/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005411 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005412 * @doc: the document
5413 * @tree: a node expected to hold the new namespace
5414 * @ns: the original namespace
5415 *
5416 * This function tries to locate a namespace definition in a tree
5417 * ancestors, or create a new namespace definition node similar to
5418 * @ns trying to reuse the same prefix. However if the given prefix is
5419 * null (default namespace) or reused within the subtree defined by
5420 * @tree or on one of its ancestors then a new prefix is generated.
5421 * Returns the (new) namespace definition or NULL in case of error
5422 */
5423xmlNsPtr
5424xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5425 xmlNsPtr def;
5426 xmlChar prefix[50];
5427 int counter = 1;
5428
5429 if (tree == NULL) {
5430#ifdef DEBUG_TREE
5431 xmlGenericError(xmlGenericErrorContext,
5432 "xmlNewReconciliedNs : tree == NULL\n");
5433#endif
5434 return(NULL);
5435 }
5436 if (ns == NULL) {
5437#ifdef DEBUG_TREE
5438 xmlGenericError(xmlGenericErrorContext,
5439 "xmlNewReconciliedNs : ns == NULL\n");
5440#endif
5441 return(NULL);
5442 }
5443 /*
5444 * Search an existing namespace definition inherited.
5445 */
5446 def = xmlSearchNsByHref(doc, tree, ns->href);
5447 if (def != NULL)
5448 return(def);
5449
5450 /*
5451 * Find a close prefix which is not already in use.
5452 * Let's strip namespace prefixes longer than 20 chars !
5453 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005454 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005455 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005456 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005457 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005458
Owen Taylor3473f882001-02-23 17:55:21 +00005459 def = xmlSearchNs(doc, tree, prefix);
5460 while (def != NULL) {
5461 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005462 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005463 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005464 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005465 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005466 def = xmlSearchNs(doc, tree, prefix);
5467 }
5468
5469 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005470 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005471 */
5472 def = xmlNewNs(tree, ns->href, prefix);
5473 return(def);
5474}
5475
Daniel Veillard652327a2003-09-29 18:02:38 +00005476#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00005477/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005478 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005479 * @doc: the document
5480 * @tree: a node defining the subtree to reconciliate
5481 *
5482 * This function checks that all the namespaces declared within the given
5483 * tree are properly declared. This is needed for example after Copy or Cut
5484 * and then paste operations. The subtree may still hold pointers to
5485 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005486 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005487 * the new environment. If not possible the new namespaces are redeclared
5488 * on @tree at the top of the given subtree.
5489 * Returns the number of namespace declarations created or -1 in case of error.
5490 */
5491int
5492xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5493 xmlNsPtr *oldNs = NULL;
5494 xmlNsPtr *newNs = NULL;
5495 int sizeCache = 0;
5496 int nbCache = 0;
5497
5498 xmlNsPtr n;
5499 xmlNodePtr node = tree;
5500 xmlAttrPtr attr;
5501 int ret = 0, i;
5502
5503 while (node != NULL) {
5504 /*
5505 * Reconciliate the node namespace
5506 */
5507 if (node->ns != NULL) {
5508 /*
5509 * initialize the cache if needed
5510 */
5511 if (sizeCache == 0) {
5512 sizeCache = 10;
5513 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5514 sizeof(xmlNsPtr));
5515 if (oldNs == NULL) {
5516 xmlGenericError(xmlGenericErrorContext,
5517 "xmlReconciliateNs : memory pbm\n");
5518 return(-1);
5519 }
5520 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5521 sizeof(xmlNsPtr));
5522 if (newNs == NULL) {
5523 xmlGenericError(xmlGenericErrorContext,
5524 "xmlReconciliateNs : memory pbm\n");
5525 xmlFree(oldNs);
5526 return(-1);
5527 }
5528 }
5529 for (i = 0;i < nbCache;i++) {
5530 if (oldNs[i] == node->ns) {
5531 node->ns = newNs[i];
5532 break;
5533 }
5534 }
5535 if (i == nbCache) {
5536 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005537 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005538 */
5539 n = xmlNewReconciliedNs(doc, tree, node->ns);
5540 if (n != NULL) { /* :-( what if else ??? */
5541 /*
5542 * check if we need to grow the cache buffers.
5543 */
5544 if (sizeCache <= nbCache) {
5545 sizeCache *= 2;
5546 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5547 sizeof(xmlNsPtr));
5548 if (oldNs == NULL) {
5549 xmlGenericError(xmlGenericErrorContext,
5550 "xmlReconciliateNs : memory pbm\n");
5551 xmlFree(newNs);
5552 return(-1);
5553 }
5554 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5555 sizeof(xmlNsPtr));
5556 if (newNs == NULL) {
5557 xmlGenericError(xmlGenericErrorContext,
5558 "xmlReconciliateNs : memory pbm\n");
5559 xmlFree(oldNs);
5560 return(-1);
5561 }
5562 }
5563 newNs[nbCache] = n;
5564 oldNs[nbCache++] = node->ns;
5565 node->ns = n;
5566 }
5567 }
5568 }
5569 /*
5570 * now check for namespace hold by attributes on the node.
5571 */
5572 attr = node->properties;
5573 while (attr != NULL) {
5574 if (attr->ns != NULL) {
5575 /*
5576 * initialize the cache if needed
5577 */
5578 if (sizeCache == 0) {
5579 sizeCache = 10;
5580 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5581 sizeof(xmlNsPtr));
5582 if (oldNs == NULL) {
5583 xmlGenericError(xmlGenericErrorContext,
5584 "xmlReconciliateNs : memory pbm\n");
5585 return(-1);
5586 }
5587 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5588 sizeof(xmlNsPtr));
5589 if (newNs == NULL) {
5590 xmlGenericError(xmlGenericErrorContext,
5591 "xmlReconciliateNs : memory pbm\n");
5592 xmlFree(oldNs);
5593 return(-1);
5594 }
5595 }
5596 for (i = 0;i < nbCache;i++) {
5597 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005598 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005599 break;
5600 }
5601 }
5602 if (i == nbCache) {
5603 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005604 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005605 */
5606 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5607 if (n != NULL) { /* :-( what if else ??? */
5608 /*
5609 * check if we need to grow the cache buffers.
5610 */
5611 if (sizeCache <= nbCache) {
5612 sizeCache *= 2;
5613 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5614 sizeof(xmlNsPtr));
5615 if (oldNs == NULL) {
5616 xmlGenericError(xmlGenericErrorContext,
5617 "xmlReconciliateNs : memory pbm\n");
5618 xmlFree(newNs);
5619 return(-1);
5620 }
5621 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5622 sizeof(xmlNsPtr));
5623 if (newNs == NULL) {
5624 xmlGenericError(xmlGenericErrorContext,
5625 "xmlReconciliateNs : memory pbm\n");
5626 xmlFree(oldNs);
5627 return(-1);
5628 }
5629 }
5630 newNs[nbCache] = n;
5631 oldNs[nbCache++] = attr->ns;
5632 attr->ns = n;
5633 }
5634 }
5635 }
5636 attr = attr->next;
5637 }
5638
5639 /*
5640 * Browse the full subtree, deep first
5641 */
5642 if (node->children != NULL) {
5643 /* deep first */
5644 node = node->children;
5645 } else if ((node != tree) && (node->next != NULL)) {
5646 /* then siblings */
5647 node = node->next;
5648 } else if (node != tree) {
5649 /* go up to parents->next if needed */
5650 while (node != tree) {
5651 if (node->parent != NULL)
5652 node = node->parent;
5653 if ((node != tree) && (node->next != NULL)) {
5654 node = node->next;
5655 break;
5656 }
5657 if (node->parent == NULL) {
5658 node = NULL;
5659 break;
5660 }
5661 }
5662 /* exit condition */
5663 if (node == tree)
5664 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005665 } else
5666 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005667 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005668 if (oldNs != NULL)
5669 xmlFree(oldNs);
5670 if (newNs != NULL)
5671 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005672 return(ret);
5673}
Daniel Veillard652327a2003-09-29 18:02:38 +00005674#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00005675
5676/**
5677 * xmlHasProp:
5678 * @node: the node
5679 * @name: the attribute name
5680 *
5681 * Search an attribute associated to a node
5682 * This function also looks in DTD attribute declaration for #FIXED or
5683 * default declaration values unless DTD use has been turned off.
5684 *
5685 * Returns the attribute or the attribute declaration or NULL if
5686 * neither was found.
5687 */
5688xmlAttrPtr
5689xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5690 xmlAttrPtr prop;
5691 xmlDocPtr doc;
5692
5693 if ((node == NULL) || (name == NULL)) return(NULL);
5694 /*
5695 * Check on the properties attached to the node
5696 */
5697 prop = node->properties;
5698 while (prop != NULL) {
5699 if (xmlStrEqual(prop->name, name)) {
5700 return(prop);
5701 }
5702 prop = prop->next;
5703 }
5704 if (!xmlCheckDTD) return(NULL);
5705
5706 /*
5707 * Check if there is a default declaration in the internal
5708 * or external subsets
5709 */
5710 doc = node->doc;
5711 if (doc != NULL) {
5712 xmlAttributePtr attrDecl;
5713 if (doc->intSubset != NULL) {
5714 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5715 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5716 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005717 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5718 /* return attribute declaration only if a default value is given
5719 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005720 return((xmlAttrPtr) attrDecl);
5721 }
5722 }
5723 return(NULL);
5724}
5725
5726/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005727 * xmlHasNsProp:
5728 * @node: the node
5729 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005730 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005731 *
5732 * Search for an attribute associated to a node
5733 * This attribute has to be anchored in the namespace specified.
5734 * This does the entity substitution.
5735 * This function looks in DTD attribute declaration for #FIXED or
5736 * default declaration values unless DTD use has been turned off.
5737 *
5738 * Returns the attribute or the attribute declaration or NULL
5739 * if neither was found.
5740 */
5741xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005742xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005743 xmlAttrPtr prop;
Daniel Veillard652327a2003-09-29 18:02:38 +00005744#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005745 xmlDocPtr doc;
Daniel Veillard652327a2003-09-29 18:02:38 +00005746#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005747
5748 if (node == NULL)
5749 return(NULL);
5750
5751 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005752 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005753 return(xmlHasProp(node, name));
5754 while (prop != NULL) {
5755 /*
5756 * One need to have
5757 * - same attribute names
5758 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005759 */
5760 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005761 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5762 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005763 }
5764 prop = prop->next;
5765 }
5766 if (!xmlCheckDTD) return(NULL);
5767
Daniel Veillard652327a2003-09-29 18:02:38 +00005768#ifdef LIBXML_TREE_ENABLED
Daniel Veillarde95e2392001-06-06 10:46:28 +00005769 /*
5770 * Check if there is a default declaration in the internal
5771 * or external subsets
5772 */
5773 doc = node->doc;
5774 if (doc != NULL) {
5775 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005776 xmlAttributePtr attrDecl = NULL;
5777 xmlNsPtr *nsList, *cur;
5778 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005779
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005780 nsList = xmlGetNsList(node->doc, node);
5781 if (nsList == NULL)
5782 return(NULL);
5783 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5784 ename = xmlStrdup(node->ns->prefix);
5785 ename = xmlStrcat(ename, BAD_CAST ":");
5786 ename = xmlStrcat(ename, node->name);
5787 } else {
5788 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005789 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005790 if (ename == NULL) {
5791 xmlFree(nsList);
5792 return(NULL);
5793 }
5794
5795 cur = nsList;
5796 while (*cur != NULL) {
5797 if (xmlStrEqual((*cur)->href, nameSpace)) {
5798 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5799 name, (*cur)->prefix);
5800 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5801 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5802 name, (*cur)->prefix);
5803 }
5804 cur++;
5805 }
5806 xmlFree(nsList);
5807 xmlFree(ename);
5808 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005809 }
5810 }
Daniel Veillard652327a2003-09-29 18:02:38 +00005811#endif /* LIBXML_TREE_ENABLED */
Daniel Veillarde95e2392001-06-06 10:46:28 +00005812 return(NULL);
5813}
5814
5815/**
Owen Taylor3473f882001-02-23 17:55:21 +00005816 * xmlGetProp:
5817 * @node: the node
5818 * @name: the attribute name
5819 *
5820 * Search and get the value of an attribute associated to a node
5821 * This does the entity substitution.
5822 * This function looks in DTD attribute declaration for #FIXED or
5823 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00005824 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00005825 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
5826 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00005827 *
5828 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005829 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005830 */
5831xmlChar *
5832xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5833 xmlAttrPtr prop;
5834 xmlDocPtr doc;
5835
5836 if ((node == NULL) || (name == NULL)) return(NULL);
5837 /*
5838 * Check on the properties attached to the node
5839 */
5840 prop = node->properties;
5841 while (prop != NULL) {
5842 if (xmlStrEqual(prop->name, name)) {
5843 xmlChar *ret;
5844
5845 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5846 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5847 return(ret);
5848 }
5849 prop = prop->next;
5850 }
5851 if (!xmlCheckDTD) return(NULL);
5852
5853 /*
5854 * Check if there is a default declaration in the internal
5855 * or external subsets
5856 */
5857 doc = node->doc;
5858 if (doc != NULL) {
5859 xmlAttributePtr attrDecl;
5860 if (doc->intSubset != NULL) {
5861 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5862 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5863 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005864 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5865 /* return attribute declaration only if a default value is given
5866 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005867 return(xmlStrdup(attrDecl->defaultValue));
5868 }
5869 }
5870 return(NULL);
5871}
5872
5873/**
Daniel Veillard71531f32003-02-05 13:19:53 +00005874 * xmlGetNoNsProp:
5875 * @node: the node
5876 * @name: the attribute name
5877 *
5878 * Search and get the value of an attribute associated to a node
5879 * This does the entity substitution.
5880 * This function looks in DTD attribute declaration for #FIXED or
5881 * default declaration values unless DTD use has been turned off.
5882 * This function is similar to xmlGetProp except it will accept only
5883 * an attribute in no namespace.
5884 *
5885 * Returns the attribute value or NULL if not found.
5886 * It's up to the caller to free the memory with xmlFree().
5887 */
5888xmlChar *
5889xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
5890 xmlAttrPtr prop;
5891 xmlDocPtr doc;
5892
5893 if ((node == NULL) || (name == NULL)) return(NULL);
5894 /*
5895 * Check on the properties attached to the node
5896 */
5897 prop = node->properties;
5898 while (prop != NULL) {
5899 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
5900 xmlChar *ret;
5901
5902 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5903 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5904 return(ret);
5905 }
5906 prop = prop->next;
5907 }
5908 if (!xmlCheckDTD) return(NULL);
5909
5910 /*
5911 * Check if there is a default declaration in the internal
5912 * or external subsets
5913 */
5914 doc = node->doc;
5915 if (doc != NULL) {
5916 xmlAttributePtr attrDecl;
5917 if (doc->intSubset != NULL) {
5918 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5919 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5920 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005921 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5922 /* return attribute declaration only if a default value is given
5923 (that includes #FIXED declarations) */
Daniel Veillard71531f32003-02-05 13:19:53 +00005924 return(xmlStrdup(attrDecl->defaultValue));
5925 }
5926 }
5927 return(NULL);
5928}
5929
5930/**
Owen Taylor3473f882001-02-23 17:55:21 +00005931 * xmlGetNsProp:
5932 * @node: the node
5933 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005934 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005935 *
5936 * Search and get the value of an attribute associated to a node
5937 * This attribute has to be anchored in the namespace specified.
5938 * This does the entity substitution.
5939 * This function looks in DTD attribute declaration for #FIXED or
5940 * default declaration values unless DTD use has been turned off.
5941 *
5942 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005943 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005944 */
5945xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00005946xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00005947 xmlAttrPtr prop;
5948 xmlDocPtr doc;
5949 xmlNsPtr ns;
5950
5951 if (node == NULL)
5952 return(NULL);
5953
5954 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005955 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00005956 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00005957 while (prop != NULL) {
5958 /*
5959 * One need to have
5960 * - same attribute names
5961 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005962 */
5963 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00005964 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00005965 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005966 xmlChar *ret;
5967
5968 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5969 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5970 return(ret);
5971 }
5972 prop = prop->next;
5973 }
5974 if (!xmlCheckDTD) return(NULL);
5975
5976 /*
5977 * Check if there is a default declaration in the internal
5978 * or external subsets
5979 */
5980 doc = node->doc;
5981 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005982 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00005983 xmlAttributePtr attrDecl;
5984
Owen Taylor3473f882001-02-23 17:55:21 +00005985 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5986 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5987 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5988
5989 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
5990 /*
5991 * The DTD declaration only allows a prefix search
5992 */
5993 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00005994 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00005995 return(xmlStrdup(attrDecl->defaultValue));
5996 }
5997 }
5998 }
5999 return(NULL);
6000}
6001
Daniel Veillard652327a2003-09-29 18:02:38 +00006002#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00006003/**
6004 * xmlSetProp:
6005 * @node: the node
6006 * @name: the attribute name
6007 * @value: the attribute value
6008 *
6009 * Set (or reset) an attribute carried by a node.
6010 * Returns the attribute pointer.
6011 */
6012xmlAttrPtr
6013xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006014 xmlAttrPtr prop;
6015 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00006016
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006017 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006018 return(NULL);
6019 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006020 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00006021 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006022 if ((xmlStrEqual(prop->name, name)) &&
6023 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006024 xmlNodePtr oldprop = prop->children;
6025
Owen Taylor3473f882001-02-23 17:55:21 +00006026 prop->children = NULL;
6027 prop->last = NULL;
6028 if (value != NULL) {
6029 xmlChar *buffer;
6030 xmlNodePtr tmp;
6031
6032 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6033 prop->children = xmlStringGetNodeList(node->doc, buffer);
6034 prop->last = NULL;
6035 prop->doc = doc;
6036 tmp = prop->children;
6037 while (tmp != NULL) {
6038 tmp->parent = (xmlNodePtr) prop;
6039 tmp->doc = doc;
6040 if (tmp->next == NULL)
6041 prop->last = tmp;
6042 tmp = tmp->next;
6043 }
6044 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00006045 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006046 if (oldprop != NULL)
6047 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00006048 return(prop);
6049 }
6050 prop = prop->next;
6051 }
6052 prop = xmlNewProp(node, name, value);
6053 return(prop);
6054}
6055
6056/**
Daniel Veillard75bea542001-05-11 17:41:21 +00006057 * xmlUnsetProp:
6058 * @node: the node
6059 * @name: the attribute name
6060 *
6061 * Remove an attribute carried by a node.
6062 * Returns 0 if successful, -1 if not found
6063 */
6064int
6065xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Daniel Veillard814a76d2003-01-23 18:24:20 +00006066 xmlAttrPtr prop, prev = NULL;;
Daniel Veillard75bea542001-05-11 17:41:21 +00006067
6068 if ((node == NULL) || (name == NULL))
6069 return(-1);
Daniel Veillard814a76d2003-01-23 18:24:20 +00006070 prop = node->properties;
Daniel Veillard75bea542001-05-11 17:41:21 +00006071 while (prop != NULL) {
6072 if ((xmlStrEqual(prop->name, name)) &&
6073 (prop->ns == NULL)) {
6074 if (prev == NULL)
6075 node->properties = prop->next;
6076 else
6077 prev->next = prop->next;
6078 xmlFreeProp(prop);
6079 return(0);
6080 }
6081 prev = prop;
6082 prop = prop->next;
6083 }
6084 return(-1);
6085}
6086
6087/**
Owen Taylor3473f882001-02-23 17:55:21 +00006088 * xmlSetNsProp:
6089 * @node: the node
6090 * @ns: the namespace definition
6091 * @name: the attribute name
6092 * @value: the attribute value
6093 *
6094 * Set (or reset) an attribute carried by a node.
6095 * The ns structure must be in scope, this is not checked.
6096 *
6097 * Returns the attribute pointer.
6098 */
6099xmlAttrPtr
6100xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
6101 const xmlChar *value) {
6102 xmlAttrPtr prop;
6103
6104 if ((node == NULL) || (name == NULL))
6105 return(NULL);
6106
6107 if (ns == NULL)
6108 return(xmlSetProp(node, name, value));
6109 if (ns->href == NULL)
6110 return(NULL);
6111 prop = node->properties;
6112
6113 while (prop != NULL) {
6114 /*
6115 * One need to have
6116 * - same attribute names
6117 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006118 */
6119 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00006120 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006121 if (prop->children != NULL)
6122 xmlFreeNodeList(prop->children);
6123 prop->children = NULL;
6124 prop->last = NULL;
6125 prop->ns = ns;
6126 if (value != NULL) {
6127 xmlChar *buffer;
6128 xmlNodePtr tmp;
6129
6130 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6131 prop->children = xmlStringGetNodeList(node->doc, buffer);
6132 prop->last = NULL;
6133 tmp = prop->children;
6134 while (tmp != NULL) {
6135 tmp->parent = (xmlNodePtr) prop;
6136 if (tmp->next == NULL)
6137 prop->last = tmp;
6138 tmp = tmp->next;
6139 }
6140 xmlFree(buffer);
6141 }
6142 return(prop);
6143 }
6144 prop = prop->next;
6145 }
6146 prop = xmlNewNsProp(node, ns, name, value);
6147 return(prop);
6148}
6149
6150/**
Daniel Veillard75bea542001-05-11 17:41:21 +00006151 * xmlUnsetNsProp:
6152 * @node: the node
6153 * @ns: the namespace definition
6154 * @name: the attribute name
6155 *
6156 * Remove an attribute carried by a node.
6157 * Returns 0 if successful, -1 if not found
6158 */
6159int
6160xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
6161 xmlAttrPtr prop = node->properties, prev = NULL;;
6162
6163 if ((node == NULL) || (name == NULL))
6164 return(-1);
6165 if (ns == NULL)
6166 return(xmlUnsetProp(node, name));
6167 if (ns->href == NULL)
6168 return(-1);
6169 while (prop != NULL) {
6170 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00006171 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006172 if (prev == NULL)
6173 node->properties = prop->next;
6174 else
6175 prev->next = prop->next;
6176 xmlFreeProp(prop);
6177 return(0);
6178 }
6179 prev = prop;
6180 prop = prop->next;
6181 }
6182 return(-1);
6183}
Daniel Veillard652327a2003-09-29 18:02:38 +00006184#endif /* LIBXML_TREE_ENABLED */
Daniel Veillard75bea542001-05-11 17:41:21 +00006185
6186/**
Owen Taylor3473f882001-02-23 17:55:21 +00006187 * xmlNodeIsText:
6188 * @node: the node
6189 *
6190 * Is this node a Text node ?
6191 * Returns 1 yes, 0 no
6192 */
6193int
6194xmlNodeIsText(xmlNodePtr node) {
6195 if (node == NULL) return(0);
6196
6197 if (node->type == XML_TEXT_NODE) return(1);
6198 return(0);
6199}
6200
6201/**
6202 * xmlIsBlankNode:
6203 * @node: the node
6204 *
6205 * Checks whether this node is an empty or whitespace only
6206 * (and possibly ignorable) text-node.
6207 *
6208 * Returns 1 yes, 0 no
6209 */
6210int
6211xmlIsBlankNode(xmlNodePtr node) {
6212 const xmlChar *cur;
6213 if (node == NULL) return(0);
6214
Daniel Veillard7db37732001-07-12 01:20:08 +00006215 if ((node->type != XML_TEXT_NODE) &&
6216 (node->type != XML_CDATA_SECTION_NODE))
6217 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006218 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006219 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006220 while (*cur != 0) {
6221 if (!IS_BLANK(*cur)) return(0);
6222 cur++;
6223 }
6224
6225 return(1);
6226}
6227
6228/**
6229 * xmlTextConcat:
6230 * @node: the node
6231 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006232 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006233 *
6234 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006235 *
6236 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006237 */
6238
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006239int
Owen Taylor3473f882001-02-23 17:55:21 +00006240xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006241 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006242
6243 if ((node->type != XML_TEXT_NODE) &&
6244 (node->type != XML_CDATA_SECTION_NODE)) {
6245#ifdef DEBUG_TREE
6246 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006247 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006248#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006249 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006250 }
Owen Taylor3473f882001-02-23 17:55:21 +00006251 node->content = xmlStrncat(node->content, content, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006252 if (node->content == NULL)
6253 return(-1);
6254 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006255}
6256
6257/************************************************************************
6258 * *
6259 * Output : to a FILE or in memory *
6260 * *
6261 ************************************************************************/
6262
Owen Taylor3473f882001-02-23 17:55:21 +00006263/**
6264 * xmlBufferCreate:
6265 *
6266 * routine to create an XML buffer.
6267 * returns the new structure.
6268 */
6269xmlBufferPtr
6270xmlBufferCreate(void) {
6271 xmlBufferPtr ret;
6272
6273 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6274 if (ret == NULL) {
6275 xmlGenericError(xmlGenericErrorContext,
6276 "xmlBufferCreate : out of memory!\n");
6277 return(NULL);
6278 }
6279 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006280 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006281 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006282 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006283 if (ret->content == NULL) {
6284 xmlGenericError(xmlGenericErrorContext,
6285 "xmlBufferCreate : out of memory!\n");
6286 xmlFree(ret);
6287 return(NULL);
6288 }
6289 ret->content[0] = 0;
6290 return(ret);
6291}
6292
6293/**
6294 * xmlBufferCreateSize:
6295 * @size: initial size of buffer
6296 *
6297 * routine to create an XML buffer.
6298 * returns the new structure.
6299 */
6300xmlBufferPtr
6301xmlBufferCreateSize(size_t size) {
6302 xmlBufferPtr ret;
6303
6304 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6305 if (ret == NULL) {
6306 xmlGenericError(xmlGenericErrorContext,
6307 "xmlBufferCreate : out of memory!\n");
6308 return(NULL);
6309 }
6310 ret->use = 0;
6311 ret->alloc = xmlBufferAllocScheme;
6312 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6313 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006314 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006315 if (ret->content == NULL) {
6316 xmlGenericError(xmlGenericErrorContext,
6317 "xmlBufferCreate : out of memory!\n");
6318 xmlFree(ret);
6319 return(NULL);
6320 }
6321 ret->content[0] = 0;
6322 } else
6323 ret->content = NULL;
6324 return(ret);
6325}
6326
6327/**
Daniel Veillard53350552003-09-18 13:35:51 +00006328 * xmlBufferCreateStatic:
6329 * @mem: the memory area
6330 * @size: the size in byte
6331 *
6332 * routine to create an XML buffer from an immutable memory area,
6333 * The are won't be modified nor copied, and is expected to be
6334 * present until the end of the buffer lifetime.
6335 *
6336 * returns the new structure.
6337 */
6338xmlBufferPtr
6339xmlBufferCreateStatic(void *mem, size_t size) {
6340 xmlBufferPtr ret;
6341
6342 if ((mem == NULL) || (size == 0))
6343 return(NULL);
6344
6345 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6346 if (ret == NULL) {
6347 xmlGenericError(xmlGenericErrorContext,
6348 "xmlBufferCreate : out of memory!\n");
6349 return(NULL);
6350 }
6351 ret->use = size;
6352 ret->size = size;
6353 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6354 ret->content = (xmlChar *) mem;
6355 return(ret);
6356}
6357
6358/**
Owen Taylor3473f882001-02-23 17:55:21 +00006359 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006360 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006361 * @scheme: allocation scheme to use
6362 *
6363 * Sets the allocation scheme for this buffer
6364 */
6365void
6366xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6367 xmlBufferAllocationScheme scheme) {
6368 if (buf == NULL) {
6369#ifdef DEBUG_BUFFER
6370 xmlGenericError(xmlGenericErrorContext,
6371 "xmlBufferSetAllocationScheme: buf == NULL\n");
6372#endif
6373 return;
6374 }
Daniel Veillard53350552003-09-18 13:35:51 +00006375 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006376
6377 buf->alloc = scheme;
6378}
6379
6380/**
6381 * xmlBufferFree:
6382 * @buf: the buffer to free
6383 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006384 * Frees an XML buffer. It frees both the content and the structure which
6385 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006386 */
6387void
6388xmlBufferFree(xmlBufferPtr buf) {
6389 if (buf == NULL) {
6390#ifdef DEBUG_BUFFER
6391 xmlGenericError(xmlGenericErrorContext,
6392 "xmlBufferFree: buf == NULL\n");
6393#endif
6394 return;
6395 }
Daniel Veillard53350552003-09-18 13:35:51 +00006396
6397 if ((buf->content != NULL) &&
6398 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006399 xmlFree(buf->content);
6400 }
Owen Taylor3473f882001-02-23 17:55:21 +00006401 xmlFree(buf);
6402}
6403
6404/**
6405 * xmlBufferEmpty:
6406 * @buf: the buffer
6407 *
6408 * empty a buffer.
6409 */
6410void
6411xmlBufferEmpty(xmlBufferPtr buf) {
6412 if (buf->content == NULL) return;
6413 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006414 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00006415 buf->content = BAD_CAST "";
Daniel Veillard53350552003-09-18 13:35:51 +00006416 } else {
6417 memset(buf->content, 0, buf->size);
6418 }
Owen Taylor3473f882001-02-23 17:55:21 +00006419}
6420
6421/**
6422 * xmlBufferShrink:
6423 * @buf: the buffer to dump
6424 * @len: the number of xmlChar to remove
6425 *
6426 * Remove the beginning of an XML buffer.
6427 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006428 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006429 */
6430int
6431xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
6432 if (len == 0) return(0);
6433 if (len > buf->use) return(-1);
6434
6435 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006436 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6437 buf->content += len;
6438 } else {
6439 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6440 buf->content[buf->use] = 0;
6441 }
Owen Taylor3473f882001-02-23 17:55:21 +00006442 return(len);
6443}
6444
6445/**
6446 * xmlBufferGrow:
6447 * @buf: the buffer
6448 * @len: the minimum free size to allocate
6449 *
6450 * Grow the available space of an XML buffer.
6451 *
6452 * Returns the new available space or -1 in case of error
6453 */
6454int
6455xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6456 int size;
6457 xmlChar *newbuf;
6458
Daniel Veillard53350552003-09-18 13:35:51 +00006459 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006460 if (len + buf->use < buf->size) return(0);
6461
6462 size = buf->use + len + 100;
6463
6464 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
6465 if (newbuf == NULL) return(-1);
6466 buf->content = newbuf;
6467 buf->size = size;
6468 return(buf->size - buf->use);
6469}
6470
6471/**
6472 * xmlBufferDump:
6473 * @file: the file output
6474 * @buf: the buffer to dump
6475 *
6476 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006477 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006478 */
6479int
6480xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6481 int ret;
6482
6483 if (buf == NULL) {
6484#ifdef DEBUG_BUFFER
6485 xmlGenericError(xmlGenericErrorContext,
6486 "xmlBufferDump: buf == NULL\n");
6487#endif
6488 return(0);
6489 }
6490 if (buf->content == NULL) {
6491#ifdef DEBUG_BUFFER
6492 xmlGenericError(xmlGenericErrorContext,
6493 "xmlBufferDump: buf->content == NULL\n");
6494#endif
6495 return(0);
6496 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006497 if (file == NULL)
6498 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006499 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6500 return(ret);
6501}
6502
6503/**
6504 * xmlBufferContent:
6505 * @buf: the buffer
6506 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006507 * Function to extract the content of a buffer
6508 *
Owen Taylor3473f882001-02-23 17:55:21 +00006509 * Returns the internal content
6510 */
6511
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006512const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006513xmlBufferContent(const xmlBufferPtr buf)
6514{
6515 if(!buf)
6516 return NULL;
6517
6518 return buf->content;
6519}
6520
6521/**
6522 * xmlBufferLength:
6523 * @buf: the buffer
6524 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006525 * Function to get the length of a buffer
6526 *
Owen Taylor3473f882001-02-23 17:55:21 +00006527 * Returns the length of data in the internal content
6528 */
6529
6530int
6531xmlBufferLength(const xmlBufferPtr buf)
6532{
6533 if(!buf)
6534 return 0;
6535
6536 return buf->use;
6537}
6538
6539/**
6540 * xmlBufferResize:
6541 * @buf: the buffer to resize
6542 * @size: the desired size
6543 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006544 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006545 *
6546 * Returns 0 in case of problems, 1 otherwise
6547 */
6548int
6549xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6550{
6551 unsigned int newSize;
6552 xmlChar* rebuf = NULL;
6553
Daniel Veillard53350552003-09-18 13:35:51 +00006554 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6555
Owen Taylor3473f882001-02-23 17:55:21 +00006556 /*take care of empty case*/
6557 newSize = (buf->size ? buf->size*2 : size);
6558
6559 /* Don't resize if we don't have to */
6560 if (size < buf->size)
6561 return 1;
6562
6563 /* figure out new size */
6564 switch (buf->alloc){
6565 case XML_BUFFER_ALLOC_DOUBLEIT:
6566 while (size > newSize) newSize *= 2;
6567 break;
6568 case XML_BUFFER_ALLOC_EXACT:
6569 newSize = size+10;
6570 break;
6571 default:
6572 newSize = size+10;
6573 break;
6574 }
6575
6576 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006577 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006578 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006579 rebuf = (xmlChar *) xmlRealloc(buf->content,
6580 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006581 } else {
6582 /*
6583 * if we are reallocating a buffer far from being full, it's
6584 * better to make a new allocation and copy only the used range
6585 * and free the old one.
6586 */
6587 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6588 if (rebuf != NULL) {
6589 memcpy(rebuf, buf->content, buf->use);
6590 xmlFree(buf->content);
6591 }
Daniel Veillarde5984082003-08-19 22:21:13 +00006592 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006593 }
Owen Taylor3473f882001-02-23 17:55:21 +00006594 if (rebuf == NULL) {
6595 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006596 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006597 return 0;
6598 }
6599 buf->content = rebuf;
6600 buf->size = newSize;
6601
6602 return 1;
6603}
6604
6605/**
6606 * xmlBufferAdd:
6607 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006608 * @str: the #xmlChar string
6609 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006610 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006611 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006612 * str is recomputed.
6613 */
6614void
6615xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6616 unsigned int needSize;
6617
6618 if (str == NULL) {
6619#ifdef DEBUG_BUFFER
6620 xmlGenericError(xmlGenericErrorContext,
6621 "xmlBufferAdd: str == NULL\n");
6622#endif
6623 return;
6624 }
Daniel Veillard53350552003-09-18 13:35:51 +00006625 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006626 if (len < -1) {
6627#ifdef DEBUG_BUFFER
6628 xmlGenericError(xmlGenericErrorContext,
6629 "xmlBufferAdd: len < 0\n");
6630#endif
6631 return;
6632 }
6633 if (len == 0) return;
6634
6635 if (len < 0)
6636 len = xmlStrlen(str);
6637
6638 if (len <= 0) return;
6639
6640 needSize = buf->use + len + 2;
6641 if (needSize > buf->size){
6642 if (!xmlBufferResize(buf, needSize)){
6643 xmlGenericError(xmlGenericErrorContext,
6644 "xmlBufferAdd : out of memory!\n");
6645 return;
6646 }
6647 }
6648
6649 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6650 buf->use += len;
6651 buf->content[buf->use] = 0;
6652}
6653
6654/**
6655 * xmlBufferAddHead:
6656 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006657 * @str: the #xmlChar string
6658 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006659 *
6660 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006661 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00006662 */
6663void
6664xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6665 unsigned int needSize;
6666
Daniel Veillard53350552003-09-18 13:35:51 +00006667 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006668 if (str == NULL) {
6669#ifdef DEBUG_BUFFER
6670 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006671 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006672#endif
6673 return;
6674 }
6675 if (len < -1) {
6676#ifdef DEBUG_BUFFER
6677 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006678 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006679#endif
6680 return;
6681 }
6682 if (len == 0) return;
6683
6684 if (len < 0)
6685 len = xmlStrlen(str);
6686
6687 if (len <= 0) return;
6688
6689 needSize = buf->use + len + 2;
6690 if (needSize > buf->size){
6691 if (!xmlBufferResize(buf, needSize)){
6692 xmlGenericError(xmlGenericErrorContext,
6693 "xmlBufferAddHead : out of memory!\n");
6694 return;
6695 }
6696 }
6697
6698 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6699 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6700 buf->use += len;
6701 buf->content[buf->use] = 0;
6702}
6703
6704/**
6705 * xmlBufferCat:
6706 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006707 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006708 *
6709 * Append a zero terminated string to an XML buffer.
6710 */
6711void
6712xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillard53350552003-09-18 13:35:51 +00006713 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006714 if (str != NULL)
6715 xmlBufferAdd(buf, str, -1);
6716}
6717
6718/**
6719 * xmlBufferCCat:
6720 * @buf: the buffer to dump
6721 * @str: the C char string
6722 *
6723 * Append a zero terminated C string to an XML buffer.
6724 */
6725void
6726xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6727 const char *cur;
6728
Daniel Veillard53350552003-09-18 13:35:51 +00006729 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006730 if (str == NULL) {
6731#ifdef DEBUG_BUFFER
6732 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006733 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006734#endif
6735 return;
6736 }
6737 for (cur = str;*cur != 0;cur++) {
6738 if (buf->use + 10 >= buf->size) {
6739 if (!xmlBufferResize(buf, buf->use+10)){
6740 xmlGenericError(xmlGenericErrorContext,
6741 "xmlBufferCCat : out of memory!\n");
6742 return;
6743 }
6744 }
6745 buf->content[buf->use++] = *cur;
6746 }
6747 buf->content[buf->use] = 0;
6748}
6749
6750/**
6751 * xmlBufferWriteCHAR:
6752 * @buf: the XML buffer
6753 * @string: the string to add
6754 *
6755 * routine which manages and grows an output buffer. This one adds
6756 * xmlChars at the end of the buffer.
6757 */
6758void
Daniel Veillard53350552003-09-18 13:35:51 +00006759xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
6760 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006761 xmlBufferCat(buf, string);
6762}
6763
6764/**
6765 * xmlBufferWriteChar:
6766 * @buf: the XML buffer output
6767 * @string: the string to add
6768 *
6769 * routine which manage and grows an output buffer. This one add
6770 * C chars at the end of the array.
6771 */
6772void
6773xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillard53350552003-09-18 13:35:51 +00006774 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006775 xmlBufferCCat(buf, string);
6776}
6777
6778
6779/**
6780 * xmlBufferWriteQuotedString:
6781 * @buf: the XML buffer output
6782 * @string: the string to add
6783 *
6784 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00006785 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00006786 * quote or double-quotes internally
6787 */
6788void
6789xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00006790 const xmlChar *cur, *base;
Daniel Veillard53350552003-09-18 13:35:51 +00006791 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00006792 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00006793 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00006794#ifdef DEBUG_BUFFER
6795 xmlGenericError(xmlGenericErrorContext,
6796 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
6797#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00006798 xmlBufferCCat(buf, "\"");
6799 base = cur = string;
6800 while(*cur != 0){
6801 if(*cur == '"'){
6802 if (base != cur)
6803 xmlBufferAdd(buf, base, cur - base);
6804 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6805 cur++;
6806 base = cur;
6807 }
6808 else {
6809 cur++;
6810 }
6811 }
6812 if (base != cur)
6813 xmlBufferAdd(buf, base, cur - base);
6814 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006815 }
Daniel Veillard39057f42003-08-04 01:33:43 +00006816 else{
6817 xmlBufferCCat(buf, "\'");
6818 xmlBufferCat(buf, string);
6819 xmlBufferCCat(buf, "\'");
6820 }
Owen Taylor3473f882001-02-23 17:55:21 +00006821 } else {
6822 xmlBufferCCat(buf, "\"");
6823 xmlBufferCat(buf, string);
6824 xmlBufferCCat(buf, "\"");
6825 }
6826}
6827
6828
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00006829#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00006830/************************************************************************
6831 * *
6832 * Dumping XML tree content to a simple buffer *
6833 * *
6834 ************************************************************************/
6835
Owen Taylor3473f882001-02-23 17:55:21 +00006836/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00006837 * xmlAttrSerializeContent:
6838 * @buf: the XML buffer output
6839 * @doc: the document
6840 * @attr: the attribute pointer
6841 *
6842 * Serialize the attribute in the buffer
6843 */
6844static void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006845xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr)
6846{
Daniel Veillarda6d05382002-02-13 13:07:41 +00006847 const xmlChar *cur, *base;
6848 xmlNodePtr children;
6849
6850 children = attr->children;
6851 while (children != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006852 switch (children->type) {
6853 case XML_TEXT_NODE:
6854 base = cur = children->content;
6855 while (*cur != 0) {
6856 if (*cur == '\n') {
6857 if (base != cur)
6858 xmlBufferAdd(buf, base, cur - base);
6859 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
6860 cur++;
6861 base = cur;
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006862 } else if (*cur == '\r') {
6863 if (base != cur)
6864 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006865 xmlBufferAdd(buf, BAD_CAST "&#13;", 5);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006866 cur++;
6867 base = cur;
6868 } else if (*cur == '\t') {
6869 if (base != cur)
6870 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006871 xmlBufferAdd(buf, BAD_CAST "&#9;", 4);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006872 cur++;
6873 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006874#if 0
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006875 } else if (*cur == '\'') {
6876 if (base != cur)
6877 xmlBufferAdd(buf, base, cur - base);
6878 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
6879 cur++;
6880 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006881#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006882 } else if (*cur == '"') {
6883 if (base != cur)
6884 xmlBufferAdd(buf, base, cur - base);
6885 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6886 cur++;
6887 base = cur;
6888 } else if (*cur == '<') {
6889 if (base != cur)
6890 xmlBufferAdd(buf, base, cur - base);
6891 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
6892 cur++;
6893 base = cur;
6894 } else if (*cur == '>') {
6895 if (base != cur)
6896 xmlBufferAdd(buf, base, cur - base);
6897 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
6898 cur++;
6899 base = cur;
6900 } else if (*cur == '&') {
6901 if (base != cur)
6902 xmlBufferAdd(buf, base, cur - base);
6903 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
6904 cur++;
6905 base = cur;
6906 } else if ((*cur >= 0x80) && ((doc == NULL) ||
6907 (doc->encoding ==
6908 NULL))) {
6909 /*
6910 * We assume we have UTF-8 content.
6911 */
6912 char tmp[10];
6913 int val = 0, l = 1;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006914
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006915 if (base != cur)
6916 xmlBufferAdd(buf, base, cur - base);
6917 if (*cur < 0xC0) {
6918 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6d05382002-02-13 13:07:41 +00006919 "xmlAttrSerializeContent : input not UTF-8\n");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006920 if (doc != NULL)
6921 doc->encoding =
6922 xmlStrdup(BAD_CAST "ISO-8859-1");
6923 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6924 tmp[sizeof(tmp) - 1] = 0;
6925 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6926 cur++;
6927 base = cur;
6928 continue;
6929 } else if (*cur < 0xE0) {
6930 val = (cur[0]) & 0x1F;
6931 val <<= 6;
6932 val |= (cur[1]) & 0x3F;
6933 l = 2;
6934 } else if (*cur < 0xF0) {
6935 val = (cur[0]) & 0x0F;
6936 val <<= 6;
6937 val |= (cur[1]) & 0x3F;
6938 val <<= 6;
6939 val |= (cur[2]) & 0x3F;
6940 l = 3;
6941 } else if (*cur < 0xF8) {
6942 val = (cur[0]) & 0x07;
6943 val <<= 6;
6944 val |= (cur[1]) & 0x3F;
6945 val <<= 6;
6946 val |= (cur[2]) & 0x3F;
6947 val <<= 6;
6948 val |= (cur[3]) & 0x3F;
6949 l = 4;
6950 }
6951 if ((l == 1) || (!IS_CHAR(val))) {
6952 xmlGenericError(xmlGenericErrorContext,
6953 "xmlAttrSerializeContent : char out of range\n");
6954 if (doc != NULL)
6955 doc->encoding =
6956 xmlStrdup(BAD_CAST "ISO-8859-1");
6957 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6958 tmp[sizeof(tmp) - 1] = 0;
6959 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6960 cur++;
6961 base = cur;
6962 continue;
6963 }
6964 /*
6965 * We could do multiple things here. Just save
6966 * as a char ref
6967 */
6968 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
6969 tmp[sizeof(tmp) - 1] = 0;
6970 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6971 cur += l;
6972 base = cur;
6973 } else {
6974 cur++;
6975 }
6976 }
6977 if (base != cur)
6978 xmlBufferAdd(buf, base, cur - base);
6979 break;
6980 case XML_ENTITY_REF_NODE:
6981 xmlBufferAdd(buf, BAD_CAST "&", 1);
6982 xmlBufferAdd(buf, children->name,
6983 xmlStrlen(children->name));
6984 xmlBufferAdd(buf, BAD_CAST ";", 1);
6985 break;
6986 default:
6987 /* should not happen unless we have a badly built tree */
6988 break;
6989 }
6990 children = children->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006991 }
6992}
6993
6994/**
6995 * xmlNodeDump:
6996 * @buf: the XML buffer output
6997 * @doc: the document
6998 * @cur: the current node
6999 * @level: the imbrication level for indenting
7000 * @format: is formatting allowed
7001 *
7002 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007003 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007004 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007005 *
7006 * Returns the number of bytes written to the buffer or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00007007 */
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007008int
Owen Taylor3473f882001-02-23 17:55:21 +00007009xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007010 int format)
7011{
7012 unsigned int use;
7013 int ret;
7014 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00007015
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007016 xmlInitParser();
7017
Owen Taylor3473f882001-02-23 17:55:21 +00007018 if (cur == NULL) {
7019#ifdef DEBUG_TREE
7020 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007021 "xmlNodeDump : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007022#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007023 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007024 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007025 if (buf == NULL) {
7026#ifdef DEBUG_TREE
7027 xmlGenericError(xmlGenericErrorContext,
7028 "xmlNodeDump : buf == NULL\n");
7029#endif
7030 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007031 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007032 outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
7033 if (outbuf == NULL) {
7034 xmlGenericError(xmlGenericErrorContext,
7035 "xmlNodeDump: out of memory!\n");
7036 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007037 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007038 memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
7039 outbuf->buffer = buf;
7040 outbuf->encoder = NULL;
7041 outbuf->writecallback = NULL;
7042 outbuf->closecallback = NULL;
7043 outbuf->context = NULL;
7044 outbuf->written = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007045
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007046 use = buf->use;
7047 xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
7048 xmlFree(outbuf);
7049 ret = buf->use - use;
7050 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00007051}
7052
7053/**
7054 * xmlElemDump:
7055 * @f: the FILE * for the output
7056 * @doc: the document
7057 * @cur: the current node
7058 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007059 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00007060 */
7061void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007062xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur)
7063{
7064 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00007065
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007066 xmlInitParser();
7067
Owen Taylor3473f882001-02-23 17:55:21 +00007068 if (cur == NULL) {
7069#ifdef DEBUG_TREE
7070 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007071 "xmlElemDump : cur == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007072#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007073 return;
Owen Taylor3473f882001-02-23 17:55:21 +00007074 }
Owen Taylor3473f882001-02-23 17:55:21 +00007075#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007076 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00007077 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007078 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007079 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007080#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007081
7082 outbuf = xmlOutputBufferCreateFile(f, NULL);
7083 if (outbuf == NULL)
7084 return;
7085 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007086#ifdef LIBXML_HTML_ENABLED
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007087 htmlNodeDumpOutput(outbuf, doc, cur, NULL);
7088#else
7089 xmlGenericError(xmlGenericErrorContext,
7090 "HTML support not compiled in\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007091#endif /* LIBXML_HTML_ENABLED */
7092 } else
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007093 xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL);
7094 xmlOutputBufferClose(outbuf);
Owen Taylor3473f882001-02-23 17:55:21 +00007095}
7096
7097/************************************************************************
7098 * *
7099 * Dumping XML tree content to an I/O output buffer *
7100 * *
7101 ************************************************************************/
7102
Daniel Veillard4432df22003-09-28 18:58:27 +00007103#ifdef LIBXML_HTML_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00007104static void
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007105xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7106 int level, int format, const char *encoding);
Daniel Veillard4432df22003-09-28 18:58:27 +00007107#endif
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007108static void
Owen Taylor3473f882001-02-23 17:55:21 +00007109xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7110 int level, int format, const char *encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007111static void
7112xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
7113 xmlNodePtr cur, int level, int format, const char *encoding);
7114
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00007115void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
7116
Owen Taylor3473f882001-02-23 17:55:21 +00007117/**
7118 * xmlNsDumpOutput:
7119 * @buf: the XML buffer output
7120 * @cur: a namespace
7121 *
7122 * Dump a local Namespace definition.
7123 * Should be called in the context of attributes dumps.
7124 */
7125static void
7126xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
7127 if (cur == NULL) {
7128#ifdef DEBUG_TREE
7129 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007130 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007131#endif
7132 return;
7133 }
7134 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00007135 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
7136 return;
7137
Owen Taylor3473f882001-02-23 17:55:21 +00007138 /* Within the context of an element attributes */
7139 if (cur->prefix != NULL) {
7140 xmlOutputBufferWriteString(buf, " xmlns:");
7141 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
7142 } else
7143 xmlOutputBufferWriteString(buf, " xmlns");
7144 xmlOutputBufferWriteString(buf, "=");
7145 xmlBufferWriteQuotedString(buf->buffer, cur->href);
7146 }
7147}
7148
7149/**
7150 * xmlNsListDumpOutput:
7151 * @buf: the XML buffer output
7152 * @cur: the first namespace
7153 *
7154 * Dump a list of local Namespace definitions.
7155 * Should be called in the context of attributes dumps.
7156 */
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00007157void
Owen Taylor3473f882001-02-23 17:55:21 +00007158xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
7159 while (cur != NULL) {
7160 xmlNsDumpOutput(buf, cur);
7161 cur = cur->next;
7162 }
7163}
7164
7165/**
7166 * xmlDtdDumpOutput:
7167 * @buf: the XML buffer output
7168 * @doc: the document
7169 * @encoding: an optional encoding string
7170 *
7171 * Dump the XML document DTD, if any.
7172 */
7173static void
7174xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
7175 if (dtd == NULL) {
7176#ifdef DEBUG_TREE
7177 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007178 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007179#endif
7180 return;
7181 }
7182 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
7183 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
7184 if (dtd->ExternalID != NULL) {
7185 xmlOutputBufferWriteString(buf, " PUBLIC ");
7186 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
7187 xmlOutputBufferWriteString(buf, " ");
7188 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
7189 } else if (dtd->SystemID != NULL) {
7190 xmlOutputBufferWriteString(buf, " SYSTEM ");
7191 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
7192 }
7193 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
7194 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
7195 xmlOutputBufferWriteString(buf, ">");
7196 return;
7197 }
7198 xmlOutputBufferWriteString(buf, " [\n");
7199 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
7200 xmlOutputBufferWriteString(buf, "]>");
7201}
7202
7203/**
7204 * xmlAttrDumpOutput:
7205 * @buf: the XML buffer output
7206 * @doc: the document
7207 * @cur: the attribute pointer
7208 * @encoding: an optional encoding string
7209 *
7210 * Dump an XML attribute
7211 */
7212static void
7213xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00007214 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00007215 if (cur == NULL) {
7216#ifdef DEBUG_TREE
7217 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007218 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007219#endif
7220 return;
7221 }
7222 xmlOutputBufferWriteString(buf, " ");
7223 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7224 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7225 xmlOutputBufferWriteString(buf, ":");
7226 }
7227 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00007228 xmlOutputBufferWriteString(buf, "=\"");
7229 xmlAttrSerializeContent(buf->buffer, doc, cur);
7230 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007231}
7232
7233/**
7234 * xmlAttrListDumpOutput:
7235 * @buf: the XML buffer output
7236 * @doc: the document
7237 * @cur: the first attribute pointer
7238 * @encoding: an optional encoding string
7239 *
7240 * Dump a list of XML attributes
7241 */
7242static void
7243xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7244 xmlAttrPtr cur, const char *encoding) {
7245 if (cur == NULL) {
7246#ifdef DEBUG_TREE
7247 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007248 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007249#endif
7250 return;
7251 }
7252 while (cur != NULL) {
7253 xmlAttrDumpOutput(buf, doc, cur, encoding);
7254 cur = cur->next;
7255 }
7256}
7257
7258
7259
7260/**
7261 * xmlNodeListDumpOutput:
7262 * @buf: the XML buffer output
7263 * @doc: the document
7264 * @cur: the first node
7265 * @level: the imbrication level for indenting
7266 * @format: is formatting allowed
7267 * @encoding: an optional encoding string
7268 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007269 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007270 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007271 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007272 */
7273static void
7274xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7275 xmlNodePtr cur, int level, int format, const char *encoding) {
7276 int i;
7277
7278 if (cur == NULL) {
7279#ifdef DEBUG_TREE
7280 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007281 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007282#endif
7283 return;
7284 }
7285 while (cur != NULL) {
7286 if ((format) && (xmlIndentTreeOutput) &&
7287 (cur->type == XML_ELEMENT_NODE))
7288 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007289 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007290 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007291 if (format) {
7292 xmlOutputBufferWriteString(buf, "\n");
7293 }
7294 cur = cur->next;
7295 }
7296}
7297
7298/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007299 * xmlNodeDumpOutputInternal:
Owen Taylor3473f882001-02-23 17:55:21 +00007300 * @buf: the XML buffer output
7301 * @doc: the document
7302 * @cur: the current node
7303 * @level: the imbrication level for indenting
7304 * @format: is formatting allowed
7305 * @encoding: an optional encoding string
7306 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007307 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007308 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007309 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007310 */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007311static void
7312xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
7313 xmlNodePtr cur, int level, int format, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007314 int i;
7315 xmlNodePtr tmp;
Daniel Veillard9475a352003-09-26 12:47:50 +00007316 xmlChar *start, *end;
Owen Taylor3473f882001-02-23 17:55:21 +00007317
7318 if (cur == NULL) {
7319#ifdef DEBUG_TREE
7320 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007321 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007322#endif
7323 return;
7324 }
7325 if (cur->type == XML_XINCLUDE_START)
7326 return;
7327 if (cur->type == XML_XINCLUDE_END)
7328 return;
7329 if (cur->type == XML_DTD_NODE) {
7330 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7331 return;
7332 }
7333 if (cur->type == XML_ELEMENT_DECL) {
7334 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7335 return;
7336 }
7337 if (cur->type == XML_ATTRIBUTE_DECL) {
7338 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7339 return;
7340 }
7341 if (cur->type == XML_ENTITY_DECL) {
7342 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7343 return;
7344 }
7345 if (cur->type == XML_TEXT_NODE) {
7346 if (cur->content != NULL) {
7347 if ((cur->name == xmlStringText) ||
7348 (cur->name != xmlStringTextNoenc)) {
7349 xmlChar *buffer;
7350
Owen Taylor3473f882001-02-23 17:55:21 +00007351 if (encoding == NULL)
7352 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7353 else
7354 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007355 if (buffer != NULL) {
7356 xmlOutputBufferWriteString(buf, (const char *)buffer);
7357 xmlFree(buffer);
7358 }
7359 } else {
7360 /*
7361 * Disable escaping, needed for XSLT
7362 */
Owen Taylor3473f882001-02-23 17:55:21 +00007363 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007364 }
7365 }
7366
7367 return;
7368 }
7369 if (cur->type == XML_PI_NODE) {
7370 if (cur->content != NULL) {
7371 xmlOutputBufferWriteString(buf, "<?");
7372 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7373 if (cur->content != NULL) {
7374 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00007375 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007376 }
7377 xmlOutputBufferWriteString(buf, "?>");
7378 } else {
7379 xmlOutputBufferWriteString(buf, "<?");
7380 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7381 xmlOutputBufferWriteString(buf, "?>");
7382 }
7383 return;
7384 }
7385 if (cur->type == XML_COMMENT_NODE) {
7386 if (cur->content != NULL) {
7387 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00007388 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007389 xmlOutputBufferWriteString(buf, "-->");
7390 }
7391 return;
7392 }
7393 if (cur->type == XML_ENTITY_REF_NODE) {
7394 xmlOutputBufferWriteString(buf, "&");
7395 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7396 xmlOutputBufferWriteString(buf, ";");
7397 return;
7398 }
7399 if (cur->type == XML_CDATA_SECTION_NODE) {
Daniel Veillard9475a352003-09-26 12:47:50 +00007400 start = end = cur->content;
7401 while (*end != '\0') {
7402 if ((*end == ']') && (*(end + 1) == ']') && (*(end + 2) == '>')) {
7403 end = end + 2;
7404 xmlOutputBufferWriteString(buf, "<![CDATA[");
7405 xmlOutputBufferWrite(buf, end - start, (const char *)start);
7406 xmlOutputBufferWriteString(buf, "]]>");
7407 start = end;
7408 }
7409 end++;
7410 }
7411 if (start != end) {
7412 xmlOutputBufferWriteString(buf, "<![CDATA[");
7413 xmlOutputBufferWriteString(buf, (const char *)start);
7414 xmlOutputBufferWriteString(buf, "]]>");
7415 }
Owen Taylor3473f882001-02-23 17:55:21 +00007416 return;
7417 }
Daniel Veillard7b72ee52003-02-27 23:24:53 +00007418 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillarda1a9d042003-03-18 16:53:17 +00007419 xmlAttrDumpOutput(buf,doc, (xmlAttrPtr) cur,encoding);
Daniel Veillard7b72ee52003-02-27 23:24:53 +00007420 return;
7421 }
Daniel Veillard6aa2f602003-02-10 00:01:56 +00007422 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007423 xmlNsDumpOutput(buf, (xmlNsPtr) cur);
Daniel Veillard6aa2f602003-02-10 00:01:56 +00007424 return;
7425 }
Owen Taylor3473f882001-02-23 17:55:21 +00007426
7427 if (format == 1) {
7428 tmp = cur->children;
7429 while (tmp != NULL) {
7430 if ((tmp->type == XML_TEXT_NODE) ||
7431 (tmp->type == XML_ENTITY_REF_NODE)) {
7432 format = 0;
7433 break;
7434 }
7435 tmp = tmp->next;
7436 }
7437 }
7438 xmlOutputBufferWriteString(buf, "<");
7439 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7440 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7441 xmlOutputBufferWriteString(buf, ":");
7442 }
7443
7444 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7445 if (cur->nsDef)
7446 xmlNsListDumpOutput(buf, cur->nsDef);
7447 if (cur->properties != NULL)
7448 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7449
Daniel Veillard7db37732001-07-12 01:20:08 +00007450 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
7451 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007452 xmlOutputBufferWriteString(buf, "/>");
7453 return;
7454 }
7455 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00007456 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007457 xmlChar *buffer;
7458
Owen Taylor3473f882001-02-23 17:55:21 +00007459 if (encoding == NULL)
7460 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7461 else
7462 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007463 if (buffer != NULL) {
7464 xmlOutputBufferWriteString(buf, (const char *)buffer);
7465 xmlFree(buffer);
7466 }
7467 }
7468 if (cur->children != NULL) {
7469 if (format) xmlOutputBufferWriteString(buf, "\n");
7470 xmlNodeListDumpOutput(buf, doc, cur->children,
7471 (level >= 0?level+1:-1), format, encoding);
7472 if ((xmlIndentTreeOutput) && (format))
7473 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007474 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00007475 }
7476 xmlOutputBufferWriteString(buf, "</");
7477 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7478 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7479 xmlOutputBufferWriteString(buf, ":");
7480 }
7481
7482 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7483 xmlOutputBufferWriteString(buf, ">");
7484}
7485
7486/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007487 * xmlNodeDumpOutput:
7488 * @buf: the XML buffer output
7489 * @doc: the document
7490 * @cur: the current node
7491 * @level: the imbrication level for indenting
7492 * @format: is formatting allowed
7493 * @encoding: an optional encoding string
7494 *
7495 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007496 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007497 * or xmlKeepBlanksDefault(0) was called
7498 */
7499void
7500xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007501 int level, int format, const char *encoding)
7502{
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007503#ifdef LIBXML_HTML_ENABLED
7504 xmlDtdPtr dtd;
7505 int is_xhtml = 0;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007506#endif
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007507
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007508 xmlInitParser();
7509
7510#ifdef LIBXML_HTML_ENABLED
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007511 dtd = xmlGetIntSubset(doc);
7512 if (dtd != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007513 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7514 if (is_xhtml < 0)
7515 is_xhtml = 0;
7516 if ((is_xhtml) && (cur->parent == (xmlNodePtr) doc) &&
7517 (cur->type == XML_ELEMENT_NODE) &&
7518 (xmlStrEqual(cur->name, BAD_CAST "html"))) {
7519 if (encoding != NULL)
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007520 htmlSetMetaEncoding((htmlDocPtr) doc,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007521 (const xmlChar *) encoding);
7522 else
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007523 htmlSetMetaEncoding((htmlDocPtr) doc, BAD_CAST "UTF-8");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007524 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007525 }
7526
7527 if (is_xhtml)
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007528 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007529 else
7530#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007531 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007532}
7533
7534/**
Owen Taylor3473f882001-02-23 17:55:21 +00007535 * xmlDocContentDumpOutput:
7536 * @buf: the XML buffer output
7537 * @cur: the document
7538 * @encoding: an optional encoding string
7539 * @format: should formatting spaces been added
7540 *
7541 * Dump an XML document.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007542 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007543 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007544 */
7545static void
7546xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
7547 const char *encoding, int format) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007548#ifdef LIBXML_HTML_ENABLED
7549 xmlDtdPtr dtd;
7550 int is_xhtml = 0;
7551#endif
7552
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007553 xmlInitParser();
7554
Owen Taylor3473f882001-02-23 17:55:21 +00007555 xmlOutputBufferWriteString(buf, "<?xml version=");
7556 if (cur->version != NULL)
7557 xmlBufferWriteQuotedString(buf->buffer, cur->version);
7558 else
7559 xmlOutputBufferWriteString(buf, "\"1.0\"");
7560 if (encoding == NULL) {
7561 if (cur->encoding != NULL)
7562 encoding = (const char *) cur->encoding;
7563 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
7564 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
7565 }
7566 if (encoding != NULL) {
7567 xmlOutputBufferWriteString(buf, " encoding=");
7568 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
7569 }
7570 switch (cur->standalone) {
7571 case 0:
7572 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
7573 break;
7574 case 1:
7575 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
7576 break;
7577 }
7578 xmlOutputBufferWriteString(buf, "?>\n");
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007579
7580#ifdef LIBXML_HTML_ENABLED
7581 dtd = xmlGetIntSubset(cur);
7582 if (dtd != NULL) {
7583 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7584 if (is_xhtml < 0) is_xhtml = 0;
7585 }
7586 if (is_xhtml) {
7587 if (encoding != NULL)
7588 htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
7589 else
7590 htmlSetMetaEncoding(cur, BAD_CAST "UTF-8");
7591 }
7592#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007593 if (cur->children != NULL) {
7594 xmlNodePtr child = cur->children;
7595
7596 while (child != NULL) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007597#ifdef LIBXML_HTML_ENABLED
7598 if (is_xhtml)
7599 xhtmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
7600 else
7601#endif
7602 xmlNodeDumpOutputInternal(buf, cur, child, 0, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007603 xmlOutputBufferWriteString(buf, "\n");
7604 child = child->next;
7605 }
7606 }
7607}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007608#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00007609
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007610#ifdef LIBXML_HTML_ENABLED
7611/************************************************************************
7612 * *
7613 * Functions specific to XHTML serialization *
7614 * *
7615 ************************************************************************/
7616
7617#define XHTML_STRICT_PUBLIC_ID BAD_CAST \
7618 "-//W3C//DTD XHTML 1.0 Strict//EN"
7619#define XHTML_STRICT_SYSTEM_ID BAD_CAST \
7620 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
7621#define XHTML_FRAME_PUBLIC_ID BAD_CAST \
7622 "-//W3C//DTD XHTML 1.0 Frameset//EN"
7623#define XHTML_FRAME_SYSTEM_ID BAD_CAST \
7624 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
7625#define XHTML_TRANS_PUBLIC_ID BAD_CAST \
7626 "-//W3C//DTD XHTML 1.0 Transitional//EN"
7627#define XHTML_TRANS_SYSTEM_ID BAD_CAST \
7628 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
7629
7630#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
7631/**
7632 * xmlIsXHTML:
7633 * @systemID: the system identifier
7634 * @publicID: the public identifier
7635 *
7636 * Try to find if the document correspond to an XHTML DTD
7637 *
7638 * Returns 1 if true, 0 if not and -1 in case of error
7639 */
7640int
7641xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) {
7642 if ((systemID == NULL) && (publicID == NULL))
7643 return(-1);
7644 if (publicID != NULL) {
7645 if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1);
7646 if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1);
7647 if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1);
7648 }
7649 if (systemID != NULL) {
7650 if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1);
7651 if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1);
7652 if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1);
7653 }
7654 return(0);
7655}
7656
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007657#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007658/**
7659 * xhtmlIsEmpty:
7660 * @node: the node
7661 *
7662 * Check if a node is an empty xhtml node
7663 *
7664 * Returns 1 if the node is an empty node, 0 if not and -1 in case of error
7665 */
7666static int
7667xhtmlIsEmpty(xmlNodePtr node) {
7668 if (node == NULL)
7669 return(-1);
7670 if (node->type != XML_ELEMENT_NODE)
7671 return(0);
7672 if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME)))
7673 return(0);
7674 if (node->children != NULL)
7675 return(0);
7676 switch (node->name[0]) {
7677 case 'a':
7678 if (xmlStrEqual(node->name, BAD_CAST "area"))
7679 return(1);
7680 return(0);
7681 case 'b':
7682 if (xmlStrEqual(node->name, BAD_CAST "br"))
7683 return(1);
7684 if (xmlStrEqual(node->name, BAD_CAST "base"))
7685 return(1);
7686 if (xmlStrEqual(node->name, BAD_CAST "basefont"))
7687 return(1);
7688 return(0);
7689 case 'c':
7690 if (xmlStrEqual(node->name, BAD_CAST "col"))
7691 return(1);
7692 return(0);
7693 case 'f':
7694 if (xmlStrEqual(node->name, BAD_CAST "frame"))
7695 return(1);
7696 return(0);
7697 case 'h':
7698 if (xmlStrEqual(node->name, BAD_CAST "hr"))
7699 return(1);
7700 return(0);
7701 case 'i':
7702 if (xmlStrEqual(node->name, BAD_CAST "img"))
7703 return(1);
7704 if (xmlStrEqual(node->name, BAD_CAST "input"))
7705 return(1);
7706 if (xmlStrEqual(node->name, BAD_CAST "isindex"))
7707 return(1);
7708 return(0);
7709 case 'l':
7710 if (xmlStrEqual(node->name, BAD_CAST "link"))
7711 return(1);
7712 return(0);
7713 case 'm':
7714 if (xmlStrEqual(node->name, BAD_CAST "meta"))
7715 return(1);
7716 return(0);
7717 case 'p':
7718 if (xmlStrEqual(node->name, BAD_CAST "param"))
7719 return(1);
7720 return(0);
7721 }
7722 return(0);
7723}
7724
7725/**
7726 * xhtmlAttrListDumpOutput:
7727 * @buf: the XML buffer output
7728 * @doc: the document
7729 * @cur: the first attribute pointer
7730 * @encoding: an optional encoding string
7731 *
7732 * Dump a list of XML attributes
7733 */
7734static void
7735xhtmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7736 xmlAttrPtr cur, const char *encoding) {
7737 xmlAttrPtr xml_lang = NULL;
7738 xmlAttrPtr lang = NULL;
7739 xmlAttrPtr name = NULL;
7740 xmlAttrPtr id = NULL;
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007741 xmlNodePtr parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007742
7743 if (cur == NULL) {
7744#ifdef DEBUG_TREE
7745 xmlGenericError(xmlGenericErrorContext,
7746 "xmlAttrListDumpOutput : property == NULL\n");
7747#endif
7748 return;
7749 }
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007750 parent = cur->parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007751 while (cur != NULL) {
7752 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id")))
7753 id = cur;
7754 else
7755 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name")))
7756 name = cur;
7757 else
7758 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")))
7759 lang = cur;
7760 else
7761 if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) &&
7762 (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml")))
7763 xml_lang = cur;
7764 else if ((cur->ns == NULL) &&
7765 ((cur->children == NULL) ||
7766 (cur->children->content == NULL) ||
7767 (cur->children->content[0] == 0)) &&
7768 (htmlIsBooleanAttr(cur->name))) {
7769 if (cur->children != NULL)
7770 xmlFreeNode(cur->children);
7771 cur->children = xmlNewText(cur->name);
7772 if (cur->children != NULL)
7773 cur->children->parent = (xmlNodePtr) cur;
7774 }
7775 xmlAttrDumpOutput(buf, doc, cur, encoding);
7776 cur = cur->next;
7777 }
7778 /*
7779 * C.8
7780 */
7781 if ((name != NULL) && (id == NULL)) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007782 if ((parent != NULL) && (parent->name != NULL) &&
7783 ((xmlStrEqual(parent->name, BAD_CAST "a")) ||
7784 (xmlStrEqual(parent->name, BAD_CAST "p")) ||
7785 (xmlStrEqual(parent->name, BAD_CAST "div")) ||
7786 (xmlStrEqual(parent->name, BAD_CAST "img")) ||
7787 (xmlStrEqual(parent->name, BAD_CAST "map")) ||
7788 (xmlStrEqual(parent->name, BAD_CAST "applet")) ||
7789 (xmlStrEqual(parent->name, BAD_CAST "form")) ||
7790 (xmlStrEqual(parent->name, BAD_CAST "frame")) ||
7791 (xmlStrEqual(parent->name, BAD_CAST "iframe")))) {
7792 xmlOutputBufferWriteString(buf, " id=\"");
7793 xmlAttrSerializeContent(buf->buffer, doc, name);
7794 xmlOutputBufferWriteString(buf, "\"");
7795 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007796 }
7797 /*
7798 * C.7.
7799 */
7800 if ((lang != NULL) && (xml_lang == NULL)) {
7801 xmlOutputBufferWriteString(buf, " xml:lang=\"");
7802 xmlAttrSerializeContent(buf->buffer, doc, lang);
7803 xmlOutputBufferWriteString(buf, "\"");
7804 } else
7805 if ((xml_lang != NULL) && (lang == NULL)) {
7806 xmlOutputBufferWriteString(buf, " lang=\"");
7807 xmlAttrSerializeContent(buf->buffer, doc, xml_lang);
7808 xmlOutputBufferWriteString(buf, "\"");
7809 }
7810}
7811
7812/**
7813 * xhtmlNodeListDumpOutput:
7814 * @buf: the XML buffer output
7815 * @doc: the XHTML document
7816 * @cur: the first node
7817 * @level: the imbrication level for indenting
7818 * @format: is formatting allowed
7819 * @encoding: an optional encoding string
7820 *
7821 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007822 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007823 * or xmlKeepBlanksDefault(0) was called
7824 */
7825static void
7826xhtmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7827 xmlNodePtr cur, int level, int format, const char *encoding) {
7828 int i;
7829
7830 if (cur == NULL) {
7831#ifdef DEBUG_TREE
7832 xmlGenericError(xmlGenericErrorContext,
7833 "xhtmlNodeListDumpOutput : node == NULL\n");
7834#endif
7835 return;
7836 }
7837 while (cur != NULL) {
7838 if ((format) && (xmlIndentTreeOutput) &&
7839 (cur->type == XML_ELEMENT_NODE))
7840 for (i = 0;i < level;i++)
7841 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7842 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
7843 if (format) {
7844 xmlOutputBufferWriteString(buf, "\n");
7845 }
7846 cur = cur->next;
7847 }
7848}
7849
7850/**
7851 * xhtmlNodeDumpOutput:
7852 * @buf: the XML buffer output
7853 * @doc: the XHTML document
7854 * @cur: the current node
7855 * @level: the imbrication level for indenting
7856 * @format: is formatting allowed
7857 * @encoding: an optional encoding string
7858 *
7859 * Dump an XHTML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007860 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007861 * or xmlKeepBlanksDefault(0) was called
7862 */
7863static void
7864xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7865 int level, int format, const char *encoding) {
7866 int i;
7867 xmlNodePtr tmp;
Daniel Veillard9475a352003-09-26 12:47:50 +00007868 xmlChar *start, *end;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007869
7870 if (cur == NULL) {
7871#ifdef DEBUG_TREE
7872 xmlGenericError(xmlGenericErrorContext,
7873 "xmlNodeDumpOutput : node == NULL\n");
7874#endif
7875 return;
7876 }
7877 if (cur->type == XML_XINCLUDE_START)
7878 return;
7879 if (cur->type == XML_XINCLUDE_END)
7880 return;
7881 if (cur->type == XML_DTD_NODE) {
7882 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7883 return;
7884 }
7885 if (cur->type == XML_ELEMENT_DECL) {
7886 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7887 return;
7888 }
7889 if (cur->type == XML_ATTRIBUTE_DECL) {
7890 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7891 return;
7892 }
7893 if (cur->type == XML_ENTITY_DECL) {
7894 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7895 return;
7896 }
7897 if (cur->type == XML_TEXT_NODE) {
7898 if (cur->content != NULL) {
7899 if ((cur->name == xmlStringText) ||
7900 (cur->name != xmlStringTextNoenc)) {
7901 xmlChar *buffer;
7902
7903 if (encoding == NULL)
7904 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7905 else
7906 buffer = xmlEncodeSpecialChars(doc, cur->content);
7907 if (buffer != NULL) {
7908 xmlOutputBufferWriteString(buf, (const char *)buffer);
7909 xmlFree(buffer);
7910 }
7911 } else {
7912 /*
7913 * Disable escaping, needed for XSLT
7914 */
7915 xmlOutputBufferWriteString(buf, (const char *) cur->content);
7916 }
7917 }
7918
7919 return;
7920 }
7921 if (cur->type == XML_PI_NODE) {
7922 if (cur->content != NULL) {
7923 xmlOutputBufferWriteString(buf, "<?");
7924 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7925 if (cur->content != NULL) {
7926 xmlOutputBufferWriteString(buf, " ");
7927 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7928 }
7929 xmlOutputBufferWriteString(buf, "?>");
7930 } else {
7931 xmlOutputBufferWriteString(buf, "<?");
7932 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7933 xmlOutputBufferWriteString(buf, "?>");
7934 }
7935 return;
7936 }
7937 if (cur->type == XML_COMMENT_NODE) {
7938 if (cur->content != NULL) {
7939 xmlOutputBufferWriteString(buf, "<!--");
7940 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7941 xmlOutputBufferWriteString(buf, "-->");
7942 }
7943 return;
7944 }
7945 if (cur->type == XML_ENTITY_REF_NODE) {
7946 xmlOutputBufferWriteString(buf, "&");
7947 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7948 xmlOutputBufferWriteString(buf, ";");
7949 return;
7950 }
7951 if (cur->type == XML_CDATA_SECTION_NODE) {
Daniel Veillard9475a352003-09-26 12:47:50 +00007952 start = end = cur->content;
7953 while (*end != '\0') {
7954 if (*end == ']' && *(end + 1) == ']' && *(end + 2) == '>') {
7955 end = end + 2;
7956 xmlOutputBufferWriteString(buf, "<![CDATA[");
7957 xmlOutputBufferWrite(buf, end - start, (const char *)start);
7958 xmlOutputBufferWriteString(buf, "]]>");
7959 start = end;
7960 }
7961 end++;
7962 }
7963 if (start != end) {
7964 xmlOutputBufferWriteString(buf, "<![CDATA[");
7965 xmlOutputBufferWriteString(buf, (const char *)start);
7966 xmlOutputBufferWriteString(buf, "]]>");
7967 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007968 return;
7969 }
7970
7971 if (format == 1) {
7972 tmp = cur->children;
7973 while (tmp != NULL) {
7974 if ((tmp->type == XML_TEXT_NODE) ||
7975 (tmp->type == XML_ENTITY_REF_NODE)) {
7976 format = 0;
7977 break;
7978 }
7979 tmp = tmp->next;
7980 }
7981 }
7982 xmlOutputBufferWriteString(buf, "<");
7983 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7984 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7985 xmlOutputBufferWriteString(buf, ":");
7986 }
7987
7988 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7989 if (cur->nsDef)
7990 xmlNsListDumpOutput(buf, cur->nsDef);
7991 if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
7992 (cur->ns == NULL) && (cur->nsDef == NULL))) {
7993 /*
7994 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
7995 */
7996 xmlOutputBufferWriteString(buf,
7997 " xmlns=\"http://www.w3.org/1999/xhtml\"");
7998 }
7999 if (cur->properties != NULL)
8000 xhtmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
8001
8002 if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) {
8003 if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
8004 (xhtmlIsEmpty(cur) == 1)) {
8005 /*
8006 * C.2. Empty Elements
8007 */
8008 xmlOutputBufferWriteString(buf, " />");
8009 } else {
8010 /*
8011 * C.3. Element Minimization and Empty Element Content
8012 */
8013 xmlOutputBufferWriteString(buf, "></");
8014 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
8015 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
8016 xmlOutputBufferWriteString(buf, ":");
8017 }
8018 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8019 xmlOutputBufferWriteString(buf, ">");
8020 }
8021 return;
8022 }
8023 xmlOutputBufferWriteString(buf, ">");
8024 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
8025 xmlChar *buffer;
8026
8027 if (encoding == NULL)
8028 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
8029 else
8030 buffer = xmlEncodeSpecialChars(doc, cur->content);
8031 if (buffer != NULL) {
8032 xmlOutputBufferWriteString(buf, (const char *)buffer);
8033 xmlFree(buffer);
8034 }
8035 }
8036
8037 /*
8038 * 4.8. Script and Style elements
8039 */
8040 if ((cur->type == XML_ELEMENT_NODE) &&
8041 ((xmlStrEqual(cur->name, BAD_CAST "script")) ||
8042 (xmlStrEqual(cur->name, BAD_CAST "style"))) &&
8043 ((cur->ns == NULL) ||
8044 (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) {
8045 xmlNodePtr child = cur->children;
8046
8047 while (child != NULL) {
8048 if ((child->type == XML_TEXT_NODE) ||
8049 (child->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard64b35282002-12-04 15:10:40 +00008050 /*
8051 * Apparently CDATA escaping for style just break on IE,
8052 * mozilla and galeon, so ...
8053 */
8054 if (xmlStrEqual(cur->name, BAD_CAST "style") &&
8055 (xmlStrchr(child->content, '<') == NULL) &&
8056 (xmlStrchr(child->content, '>') == NULL) &&
8057 (xmlStrchr(child->content, '&') == NULL)) {
8058 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
8059 } else {
Daniel Veillard9475a352003-09-26 12:47:50 +00008060 start = end = child->content;
8061 while (*end != '\0') {
8062 if (*end == ']' &&
8063 *(end + 1) == ']' &&
8064 *(end + 2) == '>') {
8065 end = end + 2;
8066 xmlOutputBufferWriteString(buf, "<![CDATA[");
8067 xmlOutputBufferWrite(buf, end - start,
8068 (const char *)start);
8069 xmlOutputBufferWriteString(buf, "]]>");
8070 start = end;
8071 }
8072 end++;
8073 }
8074 if (start != end) {
8075 xmlOutputBufferWriteString(buf, "<![CDATA[");
8076 xmlOutputBufferWriteString(buf, (const char *)start);
8077 xmlOutputBufferWriteString(buf, "]]>");
8078 }
Daniel Veillard64b35282002-12-04 15:10:40 +00008079 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00008080 } else {
8081 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
8082 }
8083 child = child->next;
8084 }
8085 } else if (cur->children != NULL) {
8086 if (format) xmlOutputBufferWriteString(buf, "\n");
8087 xhtmlNodeListDumpOutput(buf, doc, cur->children,
8088 (level >= 0?level+1:-1), format, encoding);
8089 if ((xmlIndentTreeOutput) && (format))
8090 for (i = 0;i < level;i++)
8091 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
8092 }
8093 xmlOutputBufferWriteString(buf, "</");
8094 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
8095 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
8096 xmlOutputBufferWriteString(buf, ":");
8097 }
8098
8099 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8100 xmlOutputBufferWriteString(buf, ">");
8101}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00008102#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00008103#endif
8104
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00008105#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00008106/************************************************************************
8107 * *
8108 * Saving functions front-ends *
8109 * *
8110 ************************************************************************/
8111
8112/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00008113 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00008114 * @out_doc: Document to generate XML text from
8115 * @doc_txt_ptr: Memory pointer for allocated XML text
8116 * @doc_txt_len: Length of the generated XML text
8117 * @txt_encoding: Character encoding to use when generating XML text
8118 * @format: should formatting spaces been added
8119 *
8120 * Dump the current DOM tree into memory using the character encoding specified
8121 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008122 * allocated memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00008123 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00008124 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008125 */
8126
8127void
8128xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008129 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008130 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00008131 int dummy = 0;
8132
Owen Taylor3473f882001-02-23 17:55:21 +00008133 xmlOutputBufferPtr out_buff = NULL;
8134 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
8135
8136 if (doc_txt_len == NULL) {
8137 doc_txt_len = &dummy; /* Continue, caller just won't get length */
8138 }
8139
8140 if (doc_txt_ptr == NULL) {
8141 *doc_txt_len = 0;
8142 xmlGenericError(xmlGenericErrorContext,
8143 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
8144 return;
8145 }
8146
8147 *doc_txt_ptr = NULL;
8148 *doc_txt_len = 0;
8149
8150 if (out_doc == NULL) {
8151 /* No document, no output */
8152 xmlGenericError(xmlGenericErrorContext,
8153 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
8154 return;
8155 }
8156
8157 /*
8158 * Validate the encoding value, if provided.
8159 * This logic is copied from xmlSaveFileEnc.
8160 */
8161
8162 if (txt_encoding == NULL)
8163 txt_encoding = (const char *) out_doc->encoding;
8164 if (txt_encoding != NULL) {
Daniel Veillarde1326112003-06-05 09:32:20 +00008165 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00008166 if ( conv_hdlr == NULL ) {
8167 xmlGenericError(xmlGenericErrorContext,
8168 "%s: %s %s '%s'\n",
8169 "xmlDocDumpFormatMemoryEnc",
8170 "Failed to identify encoding handler for",
8171 "character set",
8172 txt_encoding);
8173 return;
8174 }
8175 }
Owen Taylor3473f882001-02-23 17:55:21 +00008176
8177 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
8178 xmlGenericError(xmlGenericErrorContext,
8179 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
8180 return;
8181 }
8182
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008183 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008184 xmlOutputBufferFlush(out_buff);
8185 if (out_buff->conv != NULL) {
8186 *doc_txt_len = out_buff->conv->use;
8187 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
8188 } else {
8189 *doc_txt_len = out_buff->buffer->use;
8190 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
8191 }
8192 (void)xmlOutputBufferClose(out_buff);
8193
8194 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
8195 *doc_txt_len = 0;
8196 xmlGenericError(xmlGenericErrorContext,
8197 "xmlDocDumpFormatMemoryEnc: %s\n",
8198 "Failed to allocate memory for document text representation.");
8199 }
8200
8201 return;
8202}
8203
8204/**
8205 * xmlDocDumpMemory:
8206 * @cur: the document
8207 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00008208 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00008209 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008210 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008211 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00008212 */
8213void
8214xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
8215 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
8216}
8217
8218/**
8219 * xmlDocDumpFormatMemory:
8220 * @cur: the document
8221 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00008222 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00008223 * @format: should formatting spaces been added
8224 *
8225 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008226 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008227 * It's up to the caller to free the memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00008228 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00008229 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008230 */
8231void
8232xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
8233 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
8234}
8235
8236/**
8237 * xmlDocDumpMemoryEnc:
8238 * @out_doc: Document to generate XML text from
8239 * @doc_txt_ptr: Memory pointer for allocated XML text
8240 * @doc_txt_len: Length of the generated XML text
8241 * @txt_encoding: Character encoding to use when generating XML text
8242 *
8243 * Dump the current DOM tree into memory using the character encoding specified
8244 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008245 * allocated memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00008246 */
8247
8248void
8249xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
8250 int * doc_txt_len, const char * txt_encoding) {
8251 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008252 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008253}
8254
8255/**
Daniel Veillard9e412302002-06-10 15:59:44 +00008256 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00008257 * @f: the FILE*
8258 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00008259 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00008260 *
8261 * Dump an XML document to an open FILE.
8262 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008263 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008264 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8265 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008266 */
8267int
Daniel Veillard9e412302002-06-10 15:59:44 +00008268xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00008269 xmlOutputBufferPtr buf;
8270 const char * encoding;
8271 xmlCharEncodingHandlerPtr handler = NULL;
8272 int ret;
8273
8274 if (cur == NULL) {
8275#ifdef DEBUG_TREE
8276 xmlGenericError(xmlGenericErrorContext,
8277 "xmlDocDump : document == NULL\n");
8278#endif
8279 return(-1);
8280 }
8281 encoding = (const char *) cur->encoding;
8282
8283 if (encoding != NULL) {
Daniel Veillarde1326112003-06-05 09:32:20 +00008284 handler = xmlFindCharEncodingHandler(encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00008285 if (handler == NULL) {
8286 xmlFree((char *) cur->encoding);
8287 cur->encoding = NULL;
8288 }
8289 }
Owen Taylor3473f882001-02-23 17:55:21 +00008290 buf = xmlOutputBufferCreateFile(f, handler);
8291 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00008292 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008293
8294 ret = xmlOutputBufferClose(buf);
8295 return(ret);
8296}
8297
8298/**
Daniel Veillard9e412302002-06-10 15:59:44 +00008299 * xmlDocDump:
8300 * @f: the FILE*
8301 * @cur: the document
8302 *
8303 * Dump an XML document to an open FILE.
8304 *
8305 * returns: the number of bytes written or -1 in case of failure.
8306 */
8307int
8308xmlDocDump(FILE *f, xmlDocPtr cur) {
8309 return(xmlDocFormatDump (f, cur, 0));
8310}
8311
8312/**
Owen Taylor3473f882001-02-23 17:55:21 +00008313 * xmlSaveFileTo:
8314 * @buf: an output I/O buffer
8315 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00008316 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00008317 *
8318 * Dump an XML document to an I/O buffer.
8319 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008320 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008321 */
8322int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00008323xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00008324 int ret;
8325
8326 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008327 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008328 ret = xmlOutputBufferClose(buf);
8329 return(ret);
8330}
8331
8332/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00008333 * xmlSaveFormatFileTo:
8334 * @buf: an output I/O buffer
8335 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00008336 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00008337 * @format: should formatting spaces been added
8338 *
8339 * Dump an XML document to an I/O buffer.
8340 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008341 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008342 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8343 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardeefd4492001-04-28 16:55:50 +00008344 */
8345int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00008346xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00008347 int ret;
8348
8349 if (buf == NULL) return(0);
8350 xmlDocContentDumpOutput(buf, cur, encoding, format);
8351 ret = xmlOutputBufferClose(buf);
8352 return(ret);
8353}
8354
8355/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00008356 * xmlSaveFormatFileEnc:
Daniel Veillardf012a642001-07-23 19:10:52 +00008357 * @filename: the filename or URL to output
8358 * @cur: the document being saved
8359 * @encoding: the name of the encoding to use or NULL.
8360 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00008361 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00008362 * Dump an XML document to a file or an URL.
8363 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008364 * Returns the number of bytes written or -1 in case of error.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008365 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8366 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008367 */
8368int
Daniel Veillardf012a642001-07-23 19:10:52 +00008369xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
8370 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00008371 xmlOutputBufferPtr buf;
8372 xmlCharEncodingHandlerPtr handler = NULL;
8373 int ret;
8374
Daniel Veillard4dbe77a2003-01-14 00:17:42 +00008375 if (cur == NULL)
8376 return(-1);
8377
Daniel Veillardfb25a512002-01-13 20:32:08 +00008378 if (encoding == NULL)
8379 encoding = (const char *) cur->encoding;
8380
Owen Taylor3473f882001-02-23 17:55:21 +00008381 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00008382
Owen Taylor3473f882001-02-23 17:55:21 +00008383 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00008384 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00008385 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00008386 }
8387
Daniel Veillardf012a642001-07-23 19:10:52 +00008388#ifdef HAVE_ZLIB_H
8389 if (cur->compression < 0) cur->compression = xmlCompressMode;
8390#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008391 /*
8392 * save the content to a temp buffer.
8393 */
Daniel Veillardf012a642001-07-23 19:10:52 +00008394 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00008395 if (buf == NULL) return(-1);
8396
Daniel Veillardf012a642001-07-23 19:10:52 +00008397 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008398
8399 ret = xmlOutputBufferClose(buf);
8400 return(ret);
8401}
8402
Daniel Veillardf012a642001-07-23 19:10:52 +00008403
8404/**
8405 * xmlSaveFileEnc:
8406 * @filename: the filename (or URL)
8407 * @cur: the document
8408 * @encoding: the name of an encoding (or NULL)
8409 *
8410 * Dump an XML document, converting it to the given encoding
8411 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008412 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00008413 */
8414int
8415xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
8416 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
8417}
8418
Owen Taylor3473f882001-02-23 17:55:21 +00008419/**
Daniel Veillard67fee942001-04-26 18:59:03 +00008420 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00008421 * @filename: the filename (or URL)
8422 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00008423 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00008424 *
8425 * Dump an XML document to a file. Will use compression if
8426 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00008427 * used. If @format is set then the document will be indented on output.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008428 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8429 * or xmlKeepBlanksDefault(0) was called
Daniel Veillard67fee942001-04-26 18:59:03 +00008430 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008431 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008432 */
8433int
Daniel Veillard67fee942001-04-26 18:59:03 +00008434xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008435 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00008436}
8437
Daniel Veillard67fee942001-04-26 18:59:03 +00008438/**
8439 * xmlSaveFile:
8440 * @filename: the filename (or URL)
8441 * @cur: the document
8442 *
8443 * Dump an XML document to a file. Will use compression if
8444 * compiled in and enabled. If @filename is "-" the stdout file is
8445 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00008446 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00008447 */
8448int
8449xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008450 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00008451}
8452
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00008453#endif /* LIBXML_OUTPUT_ENABLED */
8454
8455/**
8456 * xmlGetDocCompressMode:
8457 * @doc: the document
8458 *
8459 * get the compression ratio for a document, ZLIB based
8460 * Returns 0 (uncompressed) to 9 (max compression)
8461 */
8462int
8463xmlGetDocCompressMode (xmlDocPtr doc) {
8464 if (doc == NULL) return(-1);
8465 return(doc->compression);
8466}
8467
8468/**
8469 * xmlSetDocCompressMode:
8470 * @doc: the document
8471 * @mode: the compression ratio
8472 *
8473 * set the compression ratio for a document, ZLIB based
8474 * Correct values: 0 (uncompressed) to 9 (max compression)
8475 */
8476void
8477xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
8478 if (doc == NULL) return;
8479 if (mode < 0) doc->compression = 0;
8480 else if (mode > 9) doc->compression = 9;
8481 else doc->compression = mode;
8482}
8483
8484/**
8485 * xmlGetCompressMode:
8486 *
8487 * get the default compression mode used, ZLIB based.
8488 * Returns 0 (uncompressed) to 9 (max compression)
8489 */
8490int
8491xmlGetCompressMode(void)
8492{
8493 return (xmlCompressMode);
8494}
8495
8496/**
8497 * xmlSetCompressMode:
8498 * @mode: the compression ratio
8499 *
8500 * set the default compression mode used, ZLIB based
8501 * Correct values: 0 (uncompressed) to 9 (max compression)
8502 */
8503void
8504xmlSetCompressMode(int mode) {
8505 if (mode < 0) xmlCompressMode = 0;
8506 else if (mode > 9) xmlCompressMode = 9;
8507 else xmlCompressMode = mode;
8508}
8509