blob: a65fda8c9b262c1567e2b9e2964e1d54d8ebd420 [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
85/**
86 * xmlGetEntityFromDtd:
87 * @dtd: A pointer to the DTD to search
88 * @name: The entity name
89 *
90 * Do an entity lookup in the DTD entity hash table and
91 * return the corresponding entity, if found.
92 *
93 * Returns A pointer to the entity structure or NULL if not found.
94 */
95static xmlEntityPtr
96xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
97 xmlEntitiesTablePtr table;
98
99 if((dtd != NULL) && (dtd->entities != NULL)) {
100 table = (xmlEntitiesTablePtr) dtd->entities;
101 return((xmlEntityPtr) xmlHashLookup(table, name));
102 /* return(xmlGetEntityFromTable(table, name)); */
103 }
104 return(NULL);
105}
106/**
107 * xmlGetParameterEntityFromDtd:
108 * @dtd: A pointer to the DTD to search
109 * @name: The entity name
110 *
111 * Do an entity lookup in the DTD pararmeter entity hash table and
112 * return the corresponding entity, if found.
113 *
114 * Returns A pointer to the entity structure or NULL if not found.
115 */
116static xmlEntityPtr
117xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
118 xmlEntitiesTablePtr table;
119
120 if ((dtd != NULL) && (dtd->pentities != NULL)) {
121 table = (xmlEntitiesTablePtr) dtd->pentities;
122 return((xmlEntityPtr) xmlHashLookup(table, name));
123 /* return(xmlGetEntityFromTable(table, name)); */
124 }
125 return(NULL);
126}
127
128/************************************************************************
129 * *
Daniel Veillardc00cda82003-04-07 10:22:39 +0000130 * QName handling helper *
131 * *
132 ************************************************************************/
133
134/**
135 * xmlBuildQName:
136 * @ncname: the Name
137 * @prefix: the prefix
138 * @memory: preallocated memory
139 * @len: preallocated memory length
140 *
141 * Builds the QName @prefix:@ncname in @memory if there is enough space
142 * and prefix is not NULL nor empty, otherwise allocate a new string.
143 * If prefix is NULL or empty it returns ncname.
144 *
145 * Returns the new string which must be freed by the caller if different from
146 * @memory and @ncname or NULL in case of error
147 */
148xmlChar *
149xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix,
150 xmlChar *memory, int len) {
151 int lenn, lenp;
152 xmlChar *ret;
153
Daniel Veillard3b7840c2003-09-11 23:42:01 +0000154 if (ncname == NULL) return(NULL);
155 if (prefix == NULL) return((xmlChar *) ncname);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000156
157 lenn = strlen((char *) ncname);
158 lenp = strlen((char *) prefix);
159
160 if ((memory == NULL) || (len < lenn + lenp + 2)) {
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000161 ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000162 if (ret == NULL) return(NULL);
163 } else {
164 ret = memory;
165 }
166 memcpy(&ret[0], prefix, lenp);
167 ret[lenp] = ':';
168 memcpy(&ret[lenp + 1], ncname, lenn);
169 ret[lenn + lenp + 1] = 0;
170 return(ret);
171}
172
173/**
174 * xmlSplitQName2:
175 * @name: the full QName
176 * @prefix: a xmlChar **
177 *
178 * parse an XML qualified name string
179 *
180 * [NS 5] QName ::= (Prefix ':')? LocalPart
181 *
182 * [NS 6] Prefix ::= NCName
183 *
184 * [NS 7] LocalPart ::= NCName
185 *
186 * Returns NULL if not a QName, otherwise the local part, and prefix
187 * is updated to get the Prefix if any.
188 */
189
190xmlChar *
191xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
192 int len = 0;
193 xmlChar *ret = NULL;
194
195 *prefix = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000196 if (name == NULL) return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000197
198#ifndef XML_XML_NAMESPACE
199 /* xml: prefix is not really a namespace */
200 if ((name[0] == 'x') && (name[1] == 'm') &&
201 (name[2] == 'l') && (name[3] == ':'))
202 return(NULL);
203#endif
204
205 /* nasty but valid */
206 if (name[0] == ':')
207 return(NULL);
208
209 /*
210 * we are not trying to validate but just to cut, and yes it will
211 * work even if this is as set of UTF-8 encoded chars
212 */
213 while ((name[len] != 0) && (name[len] != ':'))
214 len++;
215
216 if (name[len] == 0)
217 return(NULL);
218
219 *prefix = xmlStrndup(name, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000220 if (*prefix == NULL) {
221 xmlGenericError(xmlGenericErrorContext,
222 "xmlSplitQName2 : out of memory!\n");
223 return(NULL);
224 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000225 ret = xmlStrdup(&name[len + 1]);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000226 if (ret == NULL) {
227 xmlGenericError(xmlGenericErrorContext,
228 "xmlSplitQName2 : out of memory!\n");
229 if (*prefix != NULL) {
230 xmlFree(*prefix);
231 *prefix = NULL;
232 }
233 return(NULL);
234 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000235
236 return(ret);
237}
238
Daniel Veillard8d73bcb2003-08-04 01:06:15 +0000239/**
240 * xmlSplitQName3:
241 * @name: the full QName
242 * @len: an int *
243 *
244 * parse an XML qualified name string,i
245 *
246 * returns NULL if it is not a Qualified Name, otherwise, update len
247 * with the lenght in byte of the prefix and return a pointer
248 */
249
250const xmlChar *
251xmlSplitQName3(const xmlChar *name, int *len) {
252 int l = 0;
253
254 if (name == NULL) return(NULL);
255 if (len == NULL) return(NULL);
256
257 /* nasty but valid */
258 if (name[0] == ':')
259 return(NULL);
260
261 /*
262 * we are not trying to validate but just to cut, and yes it will
263 * work even if this is as set of UTF-8 encoded chars
264 */
265 while ((name[l] != 0) && (name[l] != ':'))
266 l++;
267
268 if (name[l] == 0)
269 return(NULL);
270
271 *len = l;
272
273 return(&name[l+1]);
274}
275
Daniel Veillardc00cda82003-04-07 10:22:39 +0000276/************************************************************************
277 * *
Daniel Veillardd2298792003-02-14 16:54:11 +0000278 * Check Name, NCName and QName strings *
279 * *
280 ************************************************************************/
281
282#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
283
284/**
285 * xmlValidateNCName:
286 * @value: the value to check
287 * @space: allow spaces in front and end of the string
288 *
289 * Check that a value conforms to the lexical space of NCName
290 *
291 * Returns 0 if this validates, a positive error code number otherwise
292 * and -1 in case of internal or API error.
293 */
294int
295xmlValidateNCName(const xmlChar *value, int space) {
296 const xmlChar *cur = value;
297 int c,l;
298
299 /*
300 * First quick algorithm for ASCII range
301 */
302 if (space)
303 while (IS_BLANK(*cur)) cur++;
304 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
305 (*cur == '_'))
306 cur++;
307 else
308 goto try_complex;
309 while (((*cur >= 'a') && (*cur <= 'z')) ||
310 ((*cur >= 'A') && (*cur <= 'Z')) ||
311 ((*cur >= '0') && (*cur <= '9')) ||
312 (*cur == '_') || (*cur == '-') || (*cur == '.'))
313 cur++;
314 if (space)
315 while (IS_BLANK(*cur)) cur++;
316 if (*cur == 0)
317 return(0);
318
319try_complex:
320 /*
321 * Second check for chars outside the ASCII range
322 */
323 cur = value;
324 c = CUR_SCHAR(cur, l);
325 if (space) {
326 while (IS_BLANK(c)) {
327 cur += l;
328 c = CUR_SCHAR(cur, l);
329 }
330 }
331 if ((!xmlIsLetter(c)) && (c != '_'))
332 return(1);
333 cur += l;
334 c = CUR_SCHAR(cur, l);
335 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') ||
336 (c == '-') || (c == '_') || xmlIsCombining(c) ||
337 xmlIsExtender(c)) {
338 cur += l;
339 c = CUR_SCHAR(cur, l);
340 }
341 if (space) {
342 while (IS_BLANK(c)) {
343 cur += l;
344 c = CUR_SCHAR(cur, l);
345 }
346 }
347 if (c != 0)
348 return(1);
349
350 return(0);
351}
352
353/**
354 * xmlValidateQName:
355 * @value: the value to check
356 * @space: allow spaces in front and end of the string
357 *
358 * Check that a value conforms to the lexical space of QName
359 *
360 * Returns 0 if this validates, a positive error code number otherwise
361 * and -1 in case of internal or API error.
362 */
363int
364xmlValidateQName(const xmlChar *value, int space) {
365 const xmlChar *cur = value;
366 int c,l;
367
368 /*
369 * First quick algorithm for ASCII range
370 */
371 if (space)
372 while (IS_BLANK(*cur)) cur++;
373 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
374 (*cur == '_'))
375 cur++;
376 else
377 goto try_complex;
378 while (((*cur >= 'a') && (*cur <= 'z')) ||
379 ((*cur >= 'A') && (*cur <= 'Z')) ||
380 ((*cur >= '0') && (*cur <= '9')) ||
381 (*cur == '_') || (*cur == '-') || (*cur == '.'))
382 cur++;
383 if (*cur == ':') {
384 cur++;
385 if (((*cur >= 'a') && (*cur <= 'z')) ||
386 ((*cur >= 'A') && (*cur <= 'Z')) ||
387 (*cur == '_'))
388 cur++;
389 else
390 goto try_complex;
391 while (((*cur >= 'a') && (*cur <= 'z')) ||
392 ((*cur >= 'A') && (*cur <= 'Z')) ||
393 ((*cur >= '0') && (*cur <= '9')) ||
394 (*cur == '_') || (*cur == '-') || (*cur == '.'))
395 cur++;
396 }
397 if (space)
398 while (IS_BLANK(*cur)) cur++;
399 if (*cur == 0)
400 return(0);
401
402try_complex:
403 /*
404 * Second check for chars outside the ASCII range
405 */
406 cur = value;
407 c = CUR_SCHAR(cur, l);
408 if (space) {
409 while (IS_BLANK(c)) {
410 cur += l;
411 c = CUR_SCHAR(cur, l);
412 }
413 }
414 if ((!xmlIsLetter(c)) && (c != '_'))
415 return(1);
416 cur += l;
417 c = CUR_SCHAR(cur, l);
418 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') ||
419 (c == '-') || (c == '_') || xmlIsCombining(c) ||
420 xmlIsExtender(c)) {
421 cur += l;
422 c = CUR_SCHAR(cur, l);
423 }
424 if (c == ':') {
425 cur += l;
426 c = CUR_SCHAR(cur, l);
427 if ((!xmlIsLetter(c)) && (c != '_'))
428 return(1);
429 cur += l;
430 c = CUR_SCHAR(cur, l);
431 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') ||
432 (c == '-') || (c == '_') || xmlIsCombining(c) ||
433 xmlIsExtender(c)) {
434 cur += l;
435 c = CUR_SCHAR(cur, l);
436 }
437 }
438 if (space) {
439 while (IS_BLANK(c)) {
440 cur += l;
441 c = CUR_SCHAR(cur, l);
442 }
443 }
444 if (c != 0)
445 return(1);
446 return(0);
447}
448
449/**
450 * xmlValidateName:
451 * @value: the value to check
452 * @space: allow spaces in front and end of the string
453 *
454 * Check that a value conforms to the lexical space of Name
455 *
456 * Returns 0 if this validates, a positive error code number otherwise
457 * and -1 in case of internal or API error.
458 */
459int
460xmlValidateName(const xmlChar *value, int space) {
461 const xmlChar *cur = value;
462 int c,l;
463
464 /*
465 * First quick algorithm for ASCII range
466 */
467 if (space)
468 while (IS_BLANK(*cur)) cur++;
469 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
470 (*cur == '_') || (*cur == ':'))
471 cur++;
472 else
473 goto try_complex;
474 while (((*cur >= 'a') && (*cur <= 'z')) ||
475 ((*cur >= 'A') && (*cur <= 'Z')) ||
476 ((*cur >= '0') && (*cur <= '9')) ||
477 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
478 cur++;
479 if (space)
480 while (IS_BLANK(*cur)) cur++;
481 if (*cur == 0)
482 return(0);
483
484try_complex:
485 /*
486 * Second check for chars outside the ASCII range
487 */
488 cur = value;
489 c = CUR_SCHAR(cur, l);
490 if (space) {
491 while (IS_BLANK(c)) {
492 cur += l;
493 c = CUR_SCHAR(cur, l);
494 }
495 }
496 if ((!xmlIsLetter(c)) && (c != '_') && (c != ':'))
497 return(1);
498 cur += l;
499 c = CUR_SCHAR(cur, l);
500 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') || (c == ':') ||
501 (c == '-') || (c == '_') || xmlIsCombining(c) || xmlIsExtender(c)) {
502 cur += l;
503 c = CUR_SCHAR(cur, l);
504 }
505 if (space) {
506 while (IS_BLANK(c)) {
507 cur += l;
508 c = CUR_SCHAR(cur, l);
509 }
510 }
511 if (c != 0)
512 return(1);
513 return(0);
514}
515
Daniel Veillardd4310742003-02-18 21:12:46 +0000516/**
517 * xmlValidateNMToken:
518 * @value: the value to check
519 * @space: allow spaces in front and end of the string
520 *
521 * Check that a value conforms to the lexical space of NMToken
522 *
523 * Returns 0 if this validates, a positive error code number otherwise
524 * and -1 in case of internal or API error.
525 */
526int
527xmlValidateNMToken(const xmlChar *value, int space) {
528 const xmlChar *cur = value;
529 int c,l;
530
531 /*
532 * First quick algorithm for ASCII range
533 */
534 if (space)
535 while (IS_BLANK(*cur)) cur++;
536 if (((*cur >= 'a') && (*cur <= 'z')) ||
537 ((*cur >= 'A') && (*cur <= 'Z')) ||
538 ((*cur >= '0') && (*cur <= '9')) ||
539 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
540 cur++;
541 else
542 goto try_complex;
543 while (((*cur >= 'a') && (*cur <= 'z')) ||
544 ((*cur >= 'A') && (*cur <= 'Z')) ||
545 ((*cur >= '0') && (*cur <= '9')) ||
546 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
547 cur++;
548 if (space)
549 while (IS_BLANK(*cur)) cur++;
550 if (*cur == 0)
551 return(0);
552
553try_complex:
554 /*
555 * Second check for chars outside the ASCII range
556 */
557 cur = value;
558 c = CUR_SCHAR(cur, l);
559 if (space) {
560 while (IS_BLANK(c)) {
561 cur += l;
562 c = CUR_SCHAR(cur, l);
563 }
564 }
565 if (!(xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') || (c == ':') ||
566 (c == '-') || (c == '_') || xmlIsCombining(c) || xmlIsExtender(c)))
567 return(1);
568 cur += l;
569 c = CUR_SCHAR(cur, l);
570 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') || (c == ':') ||
571 (c == '-') || (c == '_') || xmlIsCombining(c) || xmlIsExtender(c)) {
572 cur += l;
573 c = CUR_SCHAR(cur, l);
574 }
575 if (space) {
576 while (IS_BLANK(c)) {
577 cur += l;
578 c = CUR_SCHAR(cur, l);
579 }
580 }
581 if (c != 0)
582 return(1);
583 return(0);
584}
585
Daniel Veillardd2298792003-02-14 16:54:11 +0000586/************************************************************************
587 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000588 * Allocation and deallocation of basic structures *
589 * *
590 ************************************************************************/
591
592/**
593 * xmlSetBufferAllocationScheme:
594 * @scheme: allocation method to use
595 *
596 * Set the buffer allocation method. Types are
597 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
598 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
599 * improves performance
600 */
601void
602xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
603 xmlBufferAllocScheme = scheme;
604}
605
606/**
607 * xmlGetBufferAllocationScheme:
608 *
609 * Types are
610 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
611 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
612 * improves performance
613 *
614 * Returns the current allocation scheme
615 */
616xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000617xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000618 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000619}
620
621/**
622 * xmlNewNs:
623 * @node: the element carrying the namespace
624 * @href: the URI associated
625 * @prefix: the prefix for the namespace
626 *
627 * Creation of a new Namespace. This function will refuse to create
628 * a namespace with a similar prefix than an existing one present on this
629 * node.
630 * We use href==NULL in the case of an element creation where the namespace
631 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000632 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000633 */
634xmlNsPtr
635xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
636 xmlNsPtr cur;
637
638 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
639 return(NULL);
640
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000641 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
642 return(NULL);
643
Owen Taylor3473f882001-02-23 17:55:21 +0000644 /*
645 * Allocate a new Namespace and fill the fields.
646 */
647 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
648 if (cur == NULL) {
649 xmlGenericError(xmlGenericErrorContext,
650 "xmlNewNs : malloc failed\n");
651 return(NULL);
652 }
653 memset(cur, 0, sizeof(xmlNs));
654 cur->type = XML_LOCAL_NAMESPACE;
655
656 if (href != NULL)
657 cur->href = xmlStrdup(href);
658 if (prefix != NULL)
659 cur->prefix = xmlStrdup(prefix);
660
661 /*
662 * Add it at the end to preserve parsing order ...
663 * and checks for existing use of the prefix
664 */
665 if (node != NULL) {
666 if (node->nsDef == NULL) {
667 node->nsDef = cur;
668 } else {
669 xmlNsPtr prev = node->nsDef;
670
671 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
672 (xmlStrEqual(prev->prefix, cur->prefix))) {
673 xmlFreeNs(cur);
674 return(NULL);
675 }
676 while (prev->next != NULL) {
677 prev = prev->next;
678 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
679 (xmlStrEqual(prev->prefix, cur->prefix))) {
680 xmlFreeNs(cur);
681 return(NULL);
682 }
683 }
684 prev->next = cur;
685 }
686 }
687 return(cur);
688}
689
690/**
691 * xmlSetNs:
692 * @node: a node in the document
693 * @ns: a namespace pointer
694 *
695 * Associate a namespace to a node, a posteriori.
696 */
697void
698xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
699 if (node == NULL) {
700#ifdef DEBUG_TREE
701 xmlGenericError(xmlGenericErrorContext,
702 "xmlSetNs: node == NULL\n");
703#endif
704 return;
705 }
706 node->ns = ns;
707}
708
709/**
710 * xmlFreeNs:
711 * @cur: the namespace pointer
712 *
713 * Free up the structures associated to a namespace
714 */
715void
716xmlFreeNs(xmlNsPtr cur) {
717 if (cur == NULL) {
718#ifdef DEBUG_TREE
719 xmlGenericError(xmlGenericErrorContext,
720 "xmlFreeNs : ns == NULL\n");
721#endif
722 return;
723 }
724 if (cur->href != NULL) xmlFree((char *) cur->href);
725 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000726 xmlFree(cur);
727}
728
729/**
730 * xmlFreeNsList:
731 * @cur: the first namespace pointer
732 *
733 * Free up all the structures associated to the chained namespaces.
734 */
735void
736xmlFreeNsList(xmlNsPtr cur) {
737 xmlNsPtr next;
738 if (cur == NULL) {
739#ifdef DEBUG_TREE
740 xmlGenericError(xmlGenericErrorContext,
741 "xmlFreeNsList : ns == NULL\n");
742#endif
743 return;
744 }
745 while (cur != NULL) {
746 next = cur->next;
747 xmlFreeNs(cur);
748 cur = next;
749 }
750}
751
752/**
753 * xmlNewDtd:
754 * @doc: the document pointer
755 * @name: the DTD name
756 * @ExternalID: the external ID
757 * @SystemID: the system ID
758 *
759 * Creation of a new DTD for the external subset. To create an
760 * internal subset, use xmlCreateIntSubset().
761 *
762 * Returns a pointer to the new DTD structure
763 */
764xmlDtdPtr
765xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
766 const xmlChar *ExternalID, const xmlChar *SystemID) {
767 xmlDtdPtr cur;
768
769 if ((doc != NULL) && (doc->extSubset != NULL)) {
770#ifdef DEBUG_TREE
771 xmlGenericError(xmlGenericErrorContext,
772 "xmlNewDtd(%s): document %s already have a DTD %s\n",
773 /* !!! */ (char *) name, doc->name,
774 /* !!! */ (char *)doc->extSubset->name);
775#endif
776 return(NULL);
777 }
778
779 /*
780 * Allocate a new DTD and fill the fields.
781 */
782 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
783 if (cur == NULL) {
784 xmlGenericError(xmlGenericErrorContext,
785 "xmlNewDtd : malloc failed\n");
786 return(NULL);
787 }
788 memset(cur, 0 , sizeof(xmlDtd));
789 cur->type = XML_DTD_NODE;
790
791 if (name != NULL)
792 cur->name = xmlStrdup(name);
793 if (ExternalID != NULL)
794 cur->ExternalID = xmlStrdup(ExternalID);
795 if (SystemID != NULL)
796 cur->SystemID = xmlStrdup(SystemID);
797 if (doc != NULL)
798 doc->extSubset = cur;
799 cur->doc = doc;
800
Daniel Veillarda880b122003-04-21 21:36:41 +0000801 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000802 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000803 return(cur);
804}
805
806/**
807 * xmlGetIntSubset:
808 * @doc: the document pointer
809 *
810 * Get the internal subset of a document
811 * Returns a pointer to the DTD structure or NULL if not found
812 */
813
814xmlDtdPtr
815xmlGetIntSubset(xmlDocPtr doc) {
816 xmlNodePtr cur;
817
818 if (doc == NULL)
819 return(NULL);
820 cur = doc->children;
821 while (cur != NULL) {
822 if (cur->type == XML_DTD_NODE)
823 return((xmlDtdPtr) cur);
824 cur = cur->next;
825 }
826 return((xmlDtdPtr) doc->intSubset);
827}
828
829/**
830 * xmlCreateIntSubset:
831 * @doc: the document pointer
832 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000833 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000834 * @SystemID: the system ID
835 *
836 * Create the internal subset of a document
837 * Returns a pointer to the new DTD structure
838 */
839xmlDtdPtr
840xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
841 const xmlChar *ExternalID, const xmlChar *SystemID) {
842 xmlDtdPtr cur;
843
844 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
845#ifdef DEBUG_TREE
846 xmlGenericError(xmlGenericErrorContext,
847
848 "xmlCreateIntSubset(): document %s already have an internal subset\n",
849 doc->name);
850#endif
851 return(NULL);
852 }
853
854 /*
855 * Allocate a new DTD and fill the fields.
856 */
857 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
858 if (cur == NULL) {
859 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000860 "xmlCreateIntSubset : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000861 return(NULL);
862 }
863 memset(cur, 0, sizeof(xmlDtd));
864 cur->type = XML_DTD_NODE;
865
866 if (name != NULL)
867 cur->name = xmlStrdup(name);
868 if (ExternalID != NULL)
869 cur->ExternalID = xmlStrdup(ExternalID);
870 if (SystemID != NULL)
871 cur->SystemID = xmlStrdup(SystemID);
872 if (doc != NULL) {
873 doc->intSubset = cur;
874 cur->parent = doc;
875 cur->doc = doc;
876 if (doc->children == NULL) {
877 doc->children = (xmlNodePtr) cur;
878 doc->last = (xmlNodePtr) cur;
879 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000880 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000881 xmlNodePtr prev;
882
Owen Taylor3473f882001-02-23 17:55:21 +0000883 prev = doc->children;
884 prev->prev = (xmlNodePtr) cur;
885 cur->next = prev;
886 doc->children = (xmlNodePtr) cur;
887 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000888 xmlNodePtr next;
889
890 next = doc->children;
891 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
892 next = next->next;
893 if (next == NULL) {
894 cur->prev = doc->last;
895 cur->prev->next = (xmlNodePtr) cur;
896 cur->next = NULL;
897 doc->last = (xmlNodePtr) cur;
898 } else {
899 cur->next = next;
900 cur->prev = next->prev;
901 if (cur->prev == NULL)
902 doc->children = (xmlNodePtr) cur;
903 else
904 cur->prev->next = (xmlNodePtr) cur;
905 next->prev = (xmlNodePtr) cur;
906 }
Owen Taylor3473f882001-02-23 17:55:21 +0000907 }
908 }
909 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000910
Daniel Veillarda880b122003-04-21 21:36:41 +0000911 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000912 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000913 return(cur);
914}
915
916/**
917 * xmlFreeDtd:
918 * @cur: the DTD structure to free up
919 *
920 * Free a DTD structure.
921 */
922void
923xmlFreeDtd(xmlDtdPtr cur) {
924 if (cur == NULL) {
925#ifdef DEBUG_TREE
926 xmlGenericError(xmlGenericErrorContext,
927 "xmlFreeDtd : DTD == NULL\n");
928#endif
929 return;
930 }
Daniel Veillard5335dc52003-01-01 20:59:38 +0000931
Daniel Veillarda880b122003-04-21 21:36:41 +0000932 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000933 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
934
Owen Taylor3473f882001-02-23 17:55:21 +0000935 if (cur->children != NULL) {
936 xmlNodePtr next, c = cur->children;
937
938 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000939 * Cleanup all the DTD comments they are not in the DTD
Owen Taylor3473f882001-02-23 17:55:21 +0000940 * indexes.
941 */
942 while (c != NULL) {
943 next = c->next;
Daniel Veillardd72c7e32003-05-12 21:55:03 +0000944 if ((c->type == XML_COMMENT_NODE) || (c->type == XML_PI_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000945 xmlUnlinkNode(c);
946 xmlFreeNode(c);
947 }
948 c = next;
949 }
950 }
951 if (cur->name != NULL) xmlFree((char *) cur->name);
952 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
953 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
954 /* TODO !!! */
955 if (cur->notations != NULL)
956 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
957
958 if (cur->elements != NULL)
959 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
960 if (cur->attributes != NULL)
961 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
962 if (cur->entities != NULL)
963 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
964 if (cur->pentities != NULL)
965 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
966
Owen Taylor3473f882001-02-23 17:55:21 +0000967 xmlFree(cur);
968}
969
970/**
971 * xmlNewDoc:
972 * @version: xmlChar string giving the version of XML "1.0"
973 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000974 * Creates a new XML document
975 *
Owen Taylor3473f882001-02-23 17:55:21 +0000976 * Returns a new document
977 */
978xmlDocPtr
979xmlNewDoc(const xmlChar *version) {
980 xmlDocPtr cur;
981
982 if (version == NULL)
983 version = (const xmlChar *) "1.0";
984
985 /*
986 * Allocate a new document and fill the fields.
987 */
988 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
989 if (cur == NULL) {
990 xmlGenericError(xmlGenericErrorContext,
991 "xmlNewDoc : malloc failed\n");
992 return(NULL);
993 }
994 memset(cur, 0, sizeof(xmlDoc));
995 cur->type = XML_DOCUMENT_NODE;
996
997 cur->version = xmlStrdup(version);
998 cur->standalone = -1;
999 cur->compression = -1; /* not initialized */
1000 cur->doc = cur;
Daniel Veillarda6874ca2003-07-29 16:47:24 +00001001 /*
1002 * The in memory encoding is always UTF8
1003 * This field will never change and would
1004 * be obsolete if not for binary compatibility.
1005 */
Daniel Veillardd2f3ec72001-04-11 07:50:02 +00001006 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001007
Daniel Veillarda880b122003-04-21 21:36:41 +00001008 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001009 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001010 return(cur);
1011}
1012
1013/**
1014 * xmlFreeDoc:
1015 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +00001016 *
1017 * Free up all the structures used by a document, tree included.
1018 */
1019void
1020xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +00001021 xmlDtdPtr extSubset, intSubset;
1022
Owen Taylor3473f882001-02-23 17:55:21 +00001023 if (cur == NULL) {
1024#ifdef DEBUG_TREE
1025 xmlGenericError(xmlGenericErrorContext,
1026 "xmlFreeDoc : document == NULL\n");
1027#endif
1028 return;
1029 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001030
Daniel Veillarda880b122003-04-21 21:36:41 +00001031 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001032 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1033
Daniel Veillard76d66f42001-05-16 21:05:17 +00001034 /*
1035 * Do this before freeing the children list to avoid ID lookups
1036 */
1037 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1038 cur->ids = NULL;
1039 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1040 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001041 extSubset = cur->extSubset;
1042 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +00001043 if (intSubset == extSubset)
1044 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001045 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001046 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001047 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001048 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001049 }
Daniel Veillarda9142e72001-06-19 11:07:54 +00001050 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001051 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001052 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001053 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001054 }
1055
1056 if (cur->children != NULL) xmlFreeNodeList(cur->children);
1057
Owen Taylor3473f882001-02-23 17:55:21 +00001058 if (cur->version != NULL) xmlFree((char *) cur->version);
1059 if (cur->name != NULL) xmlFree((char *) cur->name);
1060 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00001061 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00001062 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Owen Taylor3473f882001-02-23 17:55:21 +00001063 xmlFree(cur);
1064}
1065
1066/**
1067 * xmlStringLenGetNodeList:
1068 * @doc: the document
1069 * @value: the value of the text
1070 * @len: the length of the string value
1071 *
1072 * Parse the value string and build the node list associated. Should
1073 * produce a flat tree with only TEXTs and ENTITY_REFs.
1074 * Returns a pointer to the first child
1075 */
1076xmlNodePtr
1077xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1078 xmlNodePtr ret = NULL, last = NULL;
1079 xmlNodePtr node;
1080 xmlChar *val;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001081 const xmlChar *cur = value, *end = cur + len;
Owen Taylor3473f882001-02-23 17:55:21 +00001082 const xmlChar *q;
1083 xmlEntityPtr ent;
1084
1085 if (value == NULL) return(NULL);
1086
1087 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001088 while ((cur < end) && (*cur != 0)) {
1089 if (cur[0] == '&') {
1090 int charval = 0;
1091 xmlChar tmp;
1092
Owen Taylor3473f882001-02-23 17:55:21 +00001093 /*
1094 * Save the current text.
1095 */
1096 if (cur != q) {
1097 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1098 xmlNodeAddContentLen(last, q, cur - q);
1099 } else {
1100 node = xmlNewDocTextLen(doc, q, cur - q);
1101 if (node == NULL) return(ret);
1102 if (last == NULL)
1103 last = ret = node;
1104 else {
1105 last->next = node;
1106 node->prev = last;
1107 last = node;
1108 }
1109 }
1110 }
Owen Taylor3473f882001-02-23 17:55:21 +00001111 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001112 if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
1113 cur += 3;
1114 if (cur < end)
1115 tmp = *cur;
1116 else
1117 tmp = 0;
1118 while (tmp != ';') { /* Non input consuming loop */
1119 if ((tmp >= '0') && (tmp <= '9'))
1120 charval = charval * 16 + (tmp - '0');
1121 else if ((tmp >= 'a') && (tmp <= 'f'))
1122 charval = charval * 16 + (tmp - 'a') + 10;
1123 else if ((tmp >= 'A') && (tmp <= 'F'))
1124 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001125 else {
Daniel Veillard07cb8222003-09-10 10:51:05 +00001126 xmlGenericError(xmlGenericErrorContext,
1127 "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
1128 charval = 0;
1129 break;
1130 }
1131 cur++;
1132 if (cur < end)
1133 tmp = *cur;
1134 else
1135 tmp = 0;
1136 }
1137 if (tmp == ';')
1138 cur++;
1139 q = cur;
1140 } else if ((cur + 1 < end) && (cur[1] == '#')) {
1141 cur += 2;
1142 if (cur < end)
1143 tmp = *cur;
1144 else
1145 tmp = 0;
1146 while (tmp != ';') { /* Non input consuming loops */
1147 if ((tmp >= '0') && (tmp <= '9'))
1148 charval = charval * 10 + (tmp - '0');
1149 else {
1150 xmlGenericError(xmlGenericErrorContext,
1151 "xmlStringGetNodeList: invalid decimal charvalue\n");
1152 charval = 0;
1153 break;
1154 }
1155 cur++;
1156 if (cur < end)
1157 tmp = *cur;
1158 else
1159 tmp = 0;
1160 }
1161 if (tmp == ';')
1162 cur++;
1163 q = cur;
1164 } else {
1165 /*
1166 * Read the entity string
1167 */
1168 cur++;
1169 q = cur;
1170 while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1171 if ((cur >= end) || (*cur == 0)) {
1172#ifdef DEBUG_TREE
1173 xmlGenericError(xmlGenericErrorContext,
1174 "xmlStringGetNodeList: unterminated entity %30s\n", q);
1175#endif
1176 return(ret);
1177 }
1178 if (cur != q) {
1179 /*
1180 * Predefined entities don't generate nodes
1181 */
1182 val = xmlStrndup(q, cur - q);
1183 ent = xmlGetDocEntity(doc, val);
1184 if ((ent != NULL) &&
1185 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1186 if (last == NULL) {
1187 node = xmlNewDocText(doc, ent->content);
1188 last = ret = node;
1189 } else if (last->type != XML_TEXT_NODE) {
1190 node = xmlNewDocText(doc, ent->content);
1191 last = xmlAddNextSibling(last, node);
1192 } else
1193 xmlNodeAddContent(last, ent->content);
1194
1195 } else {
1196 /*
1197 * Create a new REFERENCE_REF node
1198 */
1199 node = xmlNewReference(doc, val);
1200 if (node == NULL) {
1201 if (val != NULL) xmlFree(val);
1202 return(ret);
1203 }
1204 else if ((ent != NULL) && (ent->children == NULL)) {
1205 xmlNodePtr temp;
1206
1207 ent->children = xmlStringGetNodeList(doc,
1208 (const xmlChar*)node->content);
1209 ent->owner = 1;
1210 temp = ent->children;
1211 while (temp) {
1212 temp->parent = (xmlNodePtr)ent;
1213 temp = temp->next;
1214 }
1215 }
1216 if (last == NULL) {
1217 last = ret = node;
1218 } else {
1219 last = xmlAddNextSibling(last, node);
1220 }
1221 }
1222 xmlFree(val);
1223 }
1224 cur++;
1225 q = cur;
1226 }
1227 if (charval != 0) {
1228 xmlChar buf[10];
1229 int l;
1230
1231 l = xmlCopyCharMultiByte(buf, charval);
1232 buf[l] = 0;
1233 node = xmlNewDocText(doc, buf);
1234 if (node != NULL) {
1235 if (last == NULL) {
1236 last = ret = node;
1237 } else {
1238 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001239 }
1240 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001241 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001242 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001243 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001244 cur++;
1245 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001246 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001247 /*
1248 * Handle the last piece of text.
1249 */
1250 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1251 xmlNodeAddContentLen(last, q, cur - q);
1252 } else {
1253 node = xmlNewDocTextLen(doc, q, cur - q);
1254 if (node == NULL) return(ret);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001255 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001256 last = ret = node;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001257 } else {
1258 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001259 }
1260 }
1261 }
1262 return(ret);
1263}
1264
1265/**
1266 * xmlStringGetNodeList:
1267 * @doc: the document
1268 * @value: the value of the attribute
1269 *
1270 * Parse the value string and build the node list associated. Should
1271 * produce a flat tree with only TEXTs and ENTITY_REFs.
1272 * Returns a pointer to the first child
1273 */
1274xmlNodePtr
1275xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1276 xmlNodePtr ret = NULL, last = NULL;
1277 xmlNodePtr node;
1278 xmlChar *val;
1279 const xmlChar *cur = value;
1280 const xmlChar *q;
1281 xmlEntityPtr ent;
1282
1283 if (value == NULL) return(NULL);
1284
1285 q = cur;
1286 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001287 if (cur[0] == '&') {
1288 int charval = 0;
1289 xmlChar tmp;
1290
Owen Taylor3473f882001-02-23 17:55:21 +00001291 /*
1292 * Save the current text.
1293 */
1294 if (cur != q) {
1295 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1296 xmlNodeAddContentLen(last, q, cur - q);
1297 } else {
1298 node = xmlNewDocTextLen(doc, q, cur - q);
1299 if (node == NULL) return(ret);
1300 if (last == NULL)
1301 last = ret = node;
1302 else {
1303 last->next = node;
1304 node->prev = last;
1305 last = node;
1306 }
1307 }
1308 }
Owen Taylor3473f882001-02-23 17:55:21 +00001309 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001310 if ((cur[1] == '#') && (cur[2] == 'x')) {
1311 cur += 3;
1312 tmp = *cur;
1313 while (tmp != ';') { /* Non input consuming loop */
1314 if ((tmp >= '0') && (tmp <= '9'))
1315 charval = charval * 16 + (tmp - '0');
1316 else if ((tmp >= 'a') && (tmp <= 'f'))
1317 charval = charval * 16 + (tmp - 'a') + 10;
1318 else if ((tmp >= 'A') && (tmp <= 'F'))
1319 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001320 else {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001321 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001322 "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001323 charval = 0;
1324 break;
1325 }
1326 cur++;
1327 tmp = *cur;
1328 }
1329 if (tmp == ';')
1330 cur++;
1331 q = cur;
1332 } else if (cur[1] == '#') {
1333 cur += 2;
1334 tmp = *cur;
1335 while (tmp != ';') { /* Non input consuming loops */
1336 if ((tmp >= '0') && (tmp <= '9'))
1337 charval = charval * 10 + (tmp - '0');
1338 else {
1339 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001340 "xmlStringGetNodeList: invalid decimal 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 {
1351 /*
1352 * Read the entity string
1353 */
1354 cur++;
1355 q = cur;
1356 while ((*cur != 0) && (*cur != ';')) cur++;
1357 if (*cur == 0) {
1358#ifdef DEBUG_TREE
1359 xmlGenericError(xmlGenericErrorContext,
1360 "xmlStringGetNodeList: unterminated entity %30s\n", q);
1361#endif
1362 return(ret);
1363 }
1364 if (cur != q) {
1365 /*
1366 * Predefined entities don't generate nodes
1367 */
1368 val = xmlStrndup(q, cur - q);
1369 ent = xmlGetDocEntity(doc, val);
1370 if ((ent != NULL) &&
1371 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1372 if (last == NULL) {
1373 node = xmlNewDocText(doc, ent->content);
1374 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001375 } else if (last->type != XML_TEXT_NODE) {
1376 node = xmlNewDocText(doc, ent->content);
1377 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001378 } else
1379 xmlNodeAddContent(last, ent->content);
1380
1381 } else {
1382 /*
1383 * Create a new REFERENCE_REF node
1384 */
1385 node = xmlNewReference(doc, val);
1386 if (node == NULL) {
1387 if (val != NULL) xmlFree(val);
1388 return(ret);
1389 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001390 else if ((ent != NULL) && (ent->children == NULL)) {
1391 xmlNodePtr temp;
1392
1393 ent->children = xmlStringGetNodeList(doc,
1394 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001395 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001396 temp = ent->children;
1397 while (temp) {
1398 temp->parent = (xmlNodePtr)ent;
1399 temp = temp->next;
1400 }
1401 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001402 if (last == NULL) {
1403 last = ret = node;
1404 } else {
1405 last = xmlAddNextSibling(last, node);
1406 }
1407 }
1408 xmlFree(val);
1409 }
1410 cur++;
1411 q = cur;
1412 }
1413 if (charval != 0) {
1414 xmlChar buf[10];
1415 int len;
1416
1417 len = xmlCopyCharMultiByte(buf, charval);
1418 buf[len] = 0;
1419 node = xmlNewDocText(doc, buf);
1420 if (node != NULL) {
1421 if (last == NULL) {
1422 last = ret = node;
1423 } else {
1424 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001425 }
1426 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001427
1428 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001429 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001430 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001431 cur++;
1432 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001433 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001434 /*
1435 * Handle the last piece of text.
1436 */
1437 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1438 xmlNodeAddContentLen(last, q, cur - q);
1439 } else {
1440 node = xmlNewDocTextLen(doc, q, cur - q);
1441 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001442 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001443 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001444 } else {
1445 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001446 }
1447 }
1448 }
1449 return(ret);
1450}
1451
1452/**
1453 * xmlNodeListGetString:
1454 * @doc: the document
1455 * @list: a Node list
1456 * @inLine: should we replace entity contents or show their external form
1457 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001458 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001459 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001460 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001461 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001462 */
1463xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001464xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1465{
Owen Taylor3473f882001-02-23 17:55:21 +00001466 xmlNodePtr node = list;
1467 xmlChar *ret = NULL;
1468 xmlEntityPtr ent;
1469
Daniel Veillard7646b182002-04-20 06:41:40 +00001470 if (list == NULL)
1471 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001472
1473 while (node != NULL) {
1474 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001475 (node->type == XML_CDATA_SECTION_NODE)) {
1476 if (inLine) {
1477 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001478 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001479 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001480
Daniel Veillard7646b182002-04-20 06:41:40 +00001481 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1482 if (buffer != NULL) {
1483 ret = xmlStrcat(ret, buffer);
1484 xmlFree(buffer);
1485 }
1486 }
1487 } else if (node->type == XML_ENTITY_REF_NODE) {
1488 if (inLine) {
1489 ent = xmlGetDocEntity(doc, node->name);
1490 if (ent != NULL) {
1491 xmlChar *buffer;
1492
1493 /* an entity content can be any "well balanced chunk",
1494 * i.e. the result of the content [43] production:
1495 * http://www.w3.org/TR/REC-xml#NT-content.
1496 * So it can contain text, CDATA section or nested
1497 * entity reference nodes (among others).
1498 * -> we recursive call xmlNodeListGetString()
1499 * which handles these types */
1500 buffer = xmlNodeListGetString(doc, ent->children, 1);
1501 if (buffer != NULL) {
1502 ret = xmlStrcat(ret, buffer);
1503 xmlFree(buffer);
1504 }
1505 } else {
1506 ret = xmlStrcat(ret, node->content);
1507 }
1508 } else {
1509 xmlChar buf[2];
1510
1511 buf[0] = '&';
1512 buf[1] = 0;
1513 ret = xmlStrncat(ret, buf, 1);
1514 ret = xmlStrcat(ret, node->name);
1515 buf[0] = ';';
1516 buf[1] = 0;
1517 ret = xmlStrncat(ret, buf, 1);
1518 }
1519 }
1520#if 0
1521 else {
1522 xmlGenericError(xmlGenericErrorContext,
1523 "xmlGetNodeListString : invalid node type %d\n",
1524 node->type);
1525 }
1526#endif
1527 node = node->next;
1528 }
1529 return (ret);
1530}
Owen Taylor3473f882001-02-23 17:55:21 +00001531/**
1532 * xmlNodeListGetRawString:
1533 * @doc: the document
1534 * @list: a Node list
1535 * @inLine: should we replace entity contents or show their external form
1536 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001537 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001538 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1539 * this function doesn't do any character encoding handling.
1540 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001541 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001542 */
1543xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001544xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1545{
Owen Taylor3473f882001-02-23 17:55:21 +00001546 xmlNodePtr node = list;
1547 xmlChar *ret = NULL;
1548 xmlEntityPtr ent;
1549
Daniel Veillard7646b182002-04-20 06:41:40 +00001550 if (list == NULL)
1551 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001552
1553 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001554 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001555 (node->type == XML_CDATA_SECTION_NODE)) {
1556 if (inLine) {
1557 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001558 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001559 xmlChar *buffer;
1560
1561 buffer = xmlEncodeSpecialChars(doc, node->content);
1562 if (buffer != NULL) {
1563 ret = xmlStrcat(ret, buffer);
1564 xmlFree(buffer);
1565 }
1566 }
1567 } else if (node->type == XML_ENTITY_REF_NODE) {
1568 if (inLine) {
1569 ent = xmlGetDocEntity(doc, node->name);
1570 if (ent != NULL) {
1571 xmlChar *buffer;
1572
1573 /* an entity content can be any "well balanced chunk",
1574 * i.e. the result of the content [43] production:
1575 * http://www.w3.org/TR/REC-xml#NT-content.
1576 * So it can contain text, CDATA section or nested
1577 * entity reference nodes (among others).
1578 * -> we recursive call xmlNodeListGetRawString()
1579 * which handles these types */
1580 buffer =
1581 xmlNodeListGetRawString(doc, ent->children, 1);
1582 if (buffer != NULL) {
1583 ret = xmlStrcat(ret, buffer);
1584 xmlFree(buffer);
1585 }
1586 } else {
1587 ret = xmlStrcat(ret, node->content);
1588 }
1589 } else {
1590 xmlChar buf[2];
1591
1592 buf[0] = '&';
1593 buf[1] = 0;
1594 ret = xmlStrncat(ret, buf, 1);
1595 ret = xmlStrcat(ret, node->name);
1596 buf[0] = ';';
1597 buf[1] = 0;
1598 ret = xmlStrncat(ret, buf, 1);
1599 }
1600 }
Owen Taylor3473f882001-02-23 17:55:21 +00001601#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001602 else {
1603 xmlGenericError(xmlGenericErrorContext,
1604 "xmlGetNodeListString : invalid node type %d\n",
1605 node->type);
1606 }
Owen Taylor3473f882001-02-23 17:55:21 +00001607#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001608 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001609 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001610 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001611}
1612
1613/**
1614 * xmlNewProp:
1615 * @node: the holding node
1616 * @name: the name of the attribute
1617 * @value: the value of the attribute
1618 *
1619 * Create a new property carried by a node.
1620 * Returns a pointer to the attribute
1621 */
1622xmlAttrPtr
1623xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1624 xmlAttrPtr cur;
1625 xmlDocPtr doc = NULL;
1626
1627 if (name == NULL) {
1628#ifdef DEBUG_TREE
1629 xmlGenericError(xmlGenericErrorContext,
1630 "xmlNewProp : name == NULL\n");
1631#endif
1632 return(NULL);
1633 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00001634 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
1635 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001636
1637 /*
1638 * Allocate a new property and fill the fields.
1639 */
1640 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1641 if (cur == NULL) {
1642 xmlGenericError(xmlGenericErrorContext,
1643 "xmlNewProp : malloc failed\n");
1644 return(NULL);
1645 }
1646 memset(cur, 0, sizeof(xmlAttr));
1647 cur->type = XML_ATTRIBUTE_NODE;
1648
1649 cur->parent = node;
1650 if (node != NULL) {
1651 doc = node->doc;
1652 cur->doc = doc;
1653 }
1654 cur->name = xmlStrdup(name);
1655 if (value != NULL) {
1656 xmlChar *buffer;
1657 xmlNodePtr tmp;
1658
1659 buffer = xmlEncodeEntitiesReentrant(doc, value);
1660 cur->children = xmlStringGetNodeList(doc, buffer);
1661 cur->last = NULL;
1662 tmp = cur->children;
1663 while (tmp != NULL) {
1664 tmp->parent = (xmlNodePtr) cur;
1665 tmp->doc = doc;
1666 if (tmp->next == NULL)
1667 cur->last = tmp;
1668 tmp = tmp->next;
1669 }
1670 xmlFree(buffer);
1671 }
1672
1673 /*
1674 * Add it at the end to preserve parsing order ...
1675 */
1676 if (node != NULL) {
1677 if (node->properties == NULL) {
1678 node->properties = cur;
1679 } else {
1680 xmlAttrPtr prev = node->properties;
1681
1682 while (prev->next != NULL) prev = prev->next;
1683 prev->next = cur;
1684 cur->prev = prev;
1685 }
1686 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001687
Daniel Veillarda880b122003-04-21 21:36:41 +00001688 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001689 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001690 return(cur);
1691}
1692
1693/**
1694 * xmlNewNsProp:
1695 * @node: the holding node
1696 * @ns: the namespace
1697 * @name: the name of the attribute
1698 * @value: the value of the attribute
1699 *
1700 * Create a new property tagged with a namespace and carried by a node.
1701 * Returns a pointer to the attribute
1702 */
1703xmlAttrPtr
1704xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1705 const xmlChar *value) {
1706 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001707 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001708
1709 if (name == NULL) {
1710#ifdef DEBUG_TREE
1711 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001712 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001713#endif
1714 return(NULL);
1715 }
1716
1717 /*
1718 * Allocate a new property and fill the fields.
1719 */
1720 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1721 if (cur == NULL) {
1722 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001723 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001724 return(NULL);
1725 }
1726 memset(cur, 0, sizeof(xmlAttr));
1727 cur->type = XML_ATTRIBUTE_NODE;
1728
1729 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001730 if (node != NULL) {
1731 doc = node->doc;
1732 cur->doc = doc;
1733 }
Owen Taylor3473f882001-02-23 17:55:21 +00001734 cur->ns = ns;
1735 cur->name = xmlStrdup(name);
1736 if (value != NULL) {
1737 xmlChar *buffer;
1738 xmlNodePtr tmp;
1739
Daniel Veillarda682b212001-06-07 19:59:42 +00001740 buffer = xmlEncodeEntitiesReentrant(doc, value);
1741 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001742 cur->last = NULL;
1743 tmp = cur->children;
1744 while (tmp != NULL) {
1745 tmp->parent = (xmlNodePtr) cur;
1746 if (tmp->next == NULL)
1747 cur->last = tmp;
1748 tmp = tmp->next;
1749 }
1750 xmlFree(buffer);
1751 }
1752
1753 /*
1754 * Add it at the end to preserve parsing order ...
1755 */
1756 if (node != NULL) {
1757 if (node->properties == NULL) {
1758 node->properties = cur;
1759 } else {
1760 xmlAttrPtr prev = node->properties;
1761
1762 while (prev->next != NULL) prev = prev->next;
1763 prev->next = cur;
1764 cur->prev = prev;
1765 }
1766 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001767
Daniel Veillarda880b122003-04-21 21:36:41 +00001768 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001769 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001770 return(cur);
1771}
1772
1773/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001774 * xmlNewNsPropEatName:
1775 * @node: the holding node
1776 * @ns: the namespace
1777 * @name: the name of the attribute
1778 * @value: the value of the attribute
1779 *
1780 * Create a new property tagged with a namespace and carried by a node.
1781 * Returns a pointer to the attribute
1782 */
1783xmlAttrPtr
1784xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1785 const xmlChar *value) {
1786 xmlAttrPtr cur;
1787 xmlDocPtr doc = NULL;
1788
1789 if (name == NULL) {
1790#ifdef DEBUG_TREE
1791 xmlGenericError(xmlGenericErrorContext,
1792 "xmlNewNsPropEatName : name == NULL\n");
1793#endif
1794 return(NULL);
1795 }
1796
1797 /*
1798 * Allocate a new property and fill the fields.
1799 */
1800 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1801 if (cur == NULL) {
1802 xmlGenericError(xmlGenericErrorContext,
1803 "xmlNewNsPropEatName : malloc failed\n");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001804 xmlFree(name);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001805 return(NULL);
1806 }
1807 memset(cur, 0, sizeof(xmlAttr));
1808 cur->type = XML_ATTRIBUTE_NODE;
1809
1810 cur->parent = node;
1811 if (node != NULL) {
1812 doc = node->doc;
1813 cur->doc = doc;
1814 }
1815 cur->ns = ns;
1816 cur->name = name;
1817 if (value != NULL) {
1818 xmlChar *buffer;
1819 xmlNodePtr tmp;
1820
1821 buffer = xmlEncodeEntitiesReentrant(doc, value);
1822 cur->children = xmlStringGetNodeList(doc, buffer);
1823 cur->last = NULL;
1824 tmp = cur->children;
1825 while (tmp != NULL) {
1826 tmp->parent = (xmlNodePtr) cur;
1827 if (tmp->next == NULL)
1828 cur->last = tmp;
1829 tmp = tmp->next;
1830 }
1831 xmlFree(buffer);
1832 }
1833
1834 /*
1835 * Add it at the end to preserve parsing order ...
1836 */
1837 if (node != NULL) {
1838 if (node->properties == NULL) {
1839 node->properties = cur;
1840 } else {
1841 xmlAttrPtr prev = node->properties;
1842
1843 while (prev->next != NULL) prev = prev->next;
1844 prev->next = cur;
1845 cur->prev = prev;
1846 }
1847 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001848
Daniel Veillarda880b122003-04-21 21:36:41 +00001849 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001850 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001851 return(cur);
1852}
1853
1854/**
Owen Taylor3473f882001-02-23 17:55:21 +00001855 * xmlNewDocProp:
1856 * @doc: the document
1857 * @name: the name of the attribute
1858 * @value: the value of the attribute
1859 *
1860 * Create a new property carried by a document.
1861 * Returns a pointer to the attribute
1862 */
1863xmlAttrPtr
1864xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1865 xmlAttrPtr cur;
1866
1867 if (name == NULL) {
1868#ifdef DEBUG_TREE
1869 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001870 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001871#endif
1872 return(NULL);
1873 }
1874
1875 /*
1876 * Allocate a new property and fill the fields.
1877 */
1878 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1879 if (cur == NULL) {
1880 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001881 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001882 return(NULL);
1883 }
1884 memset(cur, 0, sizeof(xmlAttr));
1885 cur->type = XML_ATTRIBUTE_NODE;
1886
1887 cur->name = xmlStrdup(name);
1888 cur->doc = doc;
1889 if (value != NULL) {
1890 xmlNodePtr tmp;
1891
1892 cur->children = xmlStringGetNodeList(doc, value);
1893 cur->last = NULL;
1894
1895 tmp = cur->children;
1896 while (tmp != NULL) {
1897 tmp->parent = (xmlNodePtr) cur;
1898 if (tmp->next == NULL)
1899 cur->last = tmp;
1900 tmp = tmp->next;
1901 }
1902 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001903
Daniel Veillarda880b122003-04-21 21:36:41 +00001904 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001905 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001906 return(cur);
1907}
1908
1909/**
1910 * xmlFreePropList:
1911 * @cur: the first property in the list
1912 *
1913 * Free a property and all its siblings, all the children are freed too.
1914 */
1915void
1916xmlFreePropList(xmlAttrPtr cur) {
1917 xmlAttrPtr next;
1918 if (cur == NULL) {
1919#ifdef DEBUG_TREE
1920 xmlGenericError(xmlGenericErrorContext,
1921 "xmlFreePropList : property == NULL\n");
1922#endif
1923 return;
1924 }
1925 while (cur != NULL) {
1926 next = cur->next;
1927 xmlFreeProp(cur);
1928 cur = next;
1929 }
1930}
1931
1932/**
1933 * xmlFreeProp:
1934 * @cur: an attribute
1935 *
1936 * Free one attribute, all the content is freed too
1937 */
1938void
1939xmlFreeProp(xmlAttrPtr cur) {
1940 if (cur == NULL) {
1941#ifdef DEBUG_TREE
1942 xmlGenericError(xmlGenericErrorContext,
1943 "xmlFreeProp : property == NULL\n");
1944#endif
1945 return;
1946 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001947
Daniel Veillarda880b122003-04-21 21:36:41 +00001948 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001949 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1950
Owen Taylor3473f882001-02-23 17:55:21 +00001951 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001952 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1953 ((cur->parent->doc->intSubset != NULL) ||
1954 (cur->parent->doc->extSubset != NULL))) {
1955 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1956 xmlRemoveID(cur->parent->doc, cur);
1957 }
Owen Taylor3473f882001-02-23 17:55:21 +00001958 if (cur->name != NULL) xmlFree((char *) cur->name);
1959 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001960 xmlFree(cur);
1961}
1962
1963/**
1964 * xmlRemoveProp:
1965 * @cur: an attribute
1966 *
1967 * Unlink and free one attribute, all the content is freed too
1968 * Note this doesn't work for namespace definition attributes
1969 *
1970 * Returns 0 if success and -1 in case of error.
1971 */
1972int
1973xmlRemoveProp(xmlAttrPtr cur) {
1974 xmlAttrPtr tmp;
1975 if (cur == NULL) {
1976#ifdef DEBUG_TREE
1977 xmlGenericError(xmlGenericErrorContext,
1978 "xmlRemoveProp : cur == NULL\n");
1979#endif
1980 return(-1);
1981 }
1982 if (cur->parent == NULL) {
1983#ifdef DEBUG_TREE
1984 xmlGenericError(xmlGenericErrorContext,
1985 "xmlRemoveProp : cur->parent == NULL\n");
1986#endif
1987 return(-1);
1988 }
1989 tmp = cur->parent->properties;
1990 if (tmp == cur) {
1991 cur->parent->properties = cur->next;
1992 xmlFreeProp(cur);
1993 return(0);
1994 }
1995 while (tmp != NULL) {
1996 if (tmp->next == cur) {
1997 tmp->next = cur->next;
1998 if (tmp->next != NULL)
1999 tmp->next->prev = tmp;
2000 xmlFreeProp(cur);
2001 return(0);
2002 }
2003 tmp = tmp->next;
2004 }
2005#ifdef DEBUG_TREE
2006 xmlGenericError(xmlGenericErrorContext,
2007 "xmlRemoveProp : attribute not owned by its node\n");
2008#endif
2009 return(-1);
2010}
2011
2012/**
2013 * xmlNewPI:
2014 * @name: the processing instruction name
2015 * @content: the PI content
2016 *
2017 * Creation of a processing instruction element.
2018 * Returns a pointer to the new node object.
2019 */
2020xmlNodePtr
2021xmlNewPI(const xmlChar *name, const xmlChar *content) {
2022 xmlNodePtr cur;
2023
2024 if (name == NULL) {
2025#ifdef DEBUG_TREE
2026 xmlGenericError(xmlGenericErrorContext,
2027 "xmlNewPI : name == NULL\n");
2028#endif
2029 return(NULL);
2030 }
2031
2032 /*
2033 * Allocate a new node and fill the fields.
2034 */
2035 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2036 if (cur == NULL) {
2037 xmlGenericError(xmlGenericErrorContext,
2038 "xmlNewPI : malloc failed\n");
2039 return(NULL);
2040 }
2041 memset(cur, 0, sizeof(xmlNode));
2042 cur->type = XML_PI_NODE;
2043
2044 cur->name = xmlStrdup(name);
2045 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002046 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002047 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002048
Daniel Veillarda880b122003-04-21 21:36:41 +00002049 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002050 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002051 return(cur);
2052}
2053
2054/**
2055 * xmlNewNode:
2056 * @ns: namespace if any
2057 * @name: the node name
2058 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002059 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002060 *
2061 * Returns a pointer to the new node object.
2062 */
2063xmlNodePtr
2064xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2065 xmlNodePtr cur;
2066
2067 if (name == NULL) {
2068#ifdef DEBUG_TREE
2069 xmlGenericError(xmlGenericErrorContext,
2070 "xmlNewNode : name == NULL\n");
2071#endif
2072 return(NULL);
2073 }
2074
2075 /*
2076 * Allocate a new node and fill the fields.
2077 */
2078 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2079 if (cur == NULL) {
2080 xmlGenericError(xmlGenericErrorContext,
2081 "xmlNewNode : malloc failed\n");
2082 return(NULL);
2083 }
2084 memset(cur, 0, sizeof(xmlNode));
2085 cur->type = XML_ELEMENT_NODE;
2086
2087 cur->name = xmlStrdup(name);
2088 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002089
Daniel Veillarda880b122003-04-21 21:36:41 +00002090 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002091 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002092 return(cur);
2093}
2094
2095/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00002096 * xmlNewNodeEatName:
2097 * @ns: namespace if any
2098 * @name: the node name
2099 *
2100 * Creation of a new node element. @ns is optional (NULL).
2101 *
2102 * Returns a pointer to the new node object.
2103 */
2104xmlNodePtr
2105xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2106 xmlNodePtr cur;
2107
2108 if (name == NULL) {
2109#ifdef DEBUG_TREE
2110 xmlGenericError(xmlGenericErrorContext,
2111 "xmlNewNode : name == NULL\n");
2112#endif
2113 return(NULL);
2114 }
2115
2116 /*
2117 * Allocate a new node and fill the fields.
2118 */
2119 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2120 if (cur == NULL) {
2121 xmlGenericError(xmlGenericErrorContext,
2122 "xmlNewNode : malloc failed\n");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00002123 xmlFree(name);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002124 return(NULL);
2125 }
2126 memset(cur, 0, sizeof(xmlNode));
2127 cur->type = XML_ELEMENT_NODE;
2128
2129 cur->name = name;
2130 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002131
Daniel Veillarda880b122003-04-21 21:36:41 +00002132 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002133 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002134 return(cur);
2135}
2136
2137/**
Owen Taylor3473f882001-02-23 17:55:21 +00002138 * xmlNewDocNode:
2139 * @doc: the document
2140 * @ns: namespace if any
2141 * @name: the node name
2142 * @content: the XML text content if any
2143 *
2144 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002145 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002146 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2147 * references, but XML special chars need to be escaped first by using
2148 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2149 * need entities support.
2150 *
2151 * Returns a pointer to the new node object.
2152 */
2153xmlNodePtr
2154xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2155 const xmlChar *name, const xmlChar *content) {
2156 xmlNodePtr cur;
2157
2158 cur = xmlNewNode(ns, name);
2159 if (cur != NULL) {
2160 cur->doc = doc;
2161 if (content != NULL) {
2162 cur->children = xmlStringGetNodeList(doc, content);
2163 UPDATE_LAST_CHILD_AND_PARENT(cur)
2164 }
2165 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002166
Owen Taylor3473f882001-02-23 17:55:21 +00002167 return(cur);
2168}
2169
Daniel Veillard46de64e2002-05-29 08:21:33 +00002170/**
2171 * xmlNewDocNodeEatName:
2172 * @doc: the document
2173 * @ns: namespace if any
2174 * @name: the node name
2175 * @content: the XML text content if any
2176 *
2177 * Creation of a new node element within a document. @ns and @content
2178 * are optional (NULL).
2179 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2180 * references, but XML special chars need to be escaped first by using
2181 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2182 * need entities support.
2183 *
2184 * Returns a pointer to the new node object.
2185 */
2186xmlNodePtr
2187xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2188 xmlChar *name, const xmlChar *content) {
2189 xmlNodePtr cur;
2190
2191 cur = xmlNewNodeEatName(ns, name);
2192 if (cur != NULL) {
2193 cur->doc = doc;
2194 if (content != NULL) {
2195 cur->children = xmlStringGetNodeList(doc, content);
2196 UPDATE_LAST_CHILD_AND_PARENT(cur)
2197 }
2198 }
2199 return(cur);
2200}
2201
Owen Taylor3473f882001-02-23 17:55:21 +00002202
2203/**
2204 * xmlNewDocRawNode:
2205 * @doc: the document
2206 * @ns: namespace if any
2207 * @name: the node name
2208 * @content: the text content if any
2209 *
2210 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002211 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002212 *
2213 * Returns a pointer to the new node object.
2214 */
2215xmlNodePtr
2216xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2217 const xmlChar *name, const xmlChar *content) {
2218 xmlNodePtr cur;
2219
2220 cur = xmlNewNode(ns, name);
2221 if (cur != NULL) {
2222 cur->doc = doc;
2223 if (content != NULL) {
2224 cur->children = xmlNewDocText(doc, content);
2225 UPDATE_LAST_CHILD_AND_PARENT(cur)
2226 }
2227 }
2228 return(cur);
2229}
2230
2231/**
2232 * xmlNewDocFragment:
2233 * @doc: the document owning the fragment
2234 *
2235 * Creation of a new Fragment node.
2236 * Returns a pointer to the new node object.
2237 */
2238xmlNodePtr
2239xmlNewDocFragment(xmlDocPtr doc) {
2240 xmlNodePtr cur;
2241
2242 /*
2243 * Allocate a new DocumentFragment node and fill the fields.
2244 */
2245 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2246 if (cur == NULL) {
2247 xmlGenericError(xmlGenericErrorContext,
2248 "xmlNewDocFragment : malloc failed\n");
2249 return(NULL);
2250 }
2251 memset(cur, 0, sizeof(xmlNode));
2252 cur->type = XML_DOCUMENT_FRAG_NODE;
2253
2254 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002255
Daniel Veillarda880b122003-04-21 21:36:41 +00002256 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002257 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002258 return(cur);
2259}
2260
2261/**
2262 * xmlNewText:
2263 * @content: the text content
2264 *
2265 * Creation of a new text node.
2266 * Returns a pointer to the new node object.
2267 */
2268xmlNodePtr
2269xmlNewText(const xmlChar *content) {
2270 xmlNodePtr cur;
2271
2272 /*
2273 * Allocate a new node and fill the fields.
2274 */
2275 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2276 if (cur == NULL) {
2277 xmlGenericError(xmlGenericErrorContext,
2278 "xmlNewText : malloc failed\n");
2279 return(NULL);
2280 }
2281 memset(cur, 0, sizeof(xmlNode));
2282 cur->type = XML_TEXT_NODE;
2283
2284 cur->name = xmlStringText;
2285 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002286 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002287 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002288
Daniel Veillarda880b122003-04-21 21:36:41 +00002289 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002290 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002291 return(cur);
2292}
2293
2294/**
2295 * xmlNewTextChild:
2296 * @parent: the parent node
2297 * @ns: a namespace if any
2298 * @name: the name of the child
2299 * @content: the text content of the child if any.
2300 *
2301 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002302 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002303 * a child TEXT node will be created containing the string content.
2304 *
2305 * Returns a pointer to the new node object.
2306 */
2307xmlNodePtr
2308xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2309 const xmlChar *name, const xmlChar *content) {
2310 xmlNodePtr cur, prev;
2311
2312 if (parent == NULL) {
2313#ifdef DEBUG_TREE
2314 xmlGenericError(xmlGenericErrorContext,
2315 "xmlNewTextChild : parent == NULL\n");
2316#endif
2317 return(NULL);
2318 }
2319
2320 if (name == NULL) {
2321#ifdef DEBUG_TREE
2322 xmlGenericError(xmlGenericErrorContext,
2323 "xmlNewTextChild : name == NULL\n");
2324#endif
2325 return(NULL);
2326 }
2327
2328 /*
2329 * Allocate a new node
2330 */
2331 if (ns == NULL)
2332 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2333 else
2334 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2335 if (cur == NULL) return(NULL);
2336
2337 /*
2338 * add the new element at the end of the children list.
2339 */
2340 cur->type = XML_ELEMENT_NODE;
2341 cur->parent = parent;
2342 cur->doc = parent->doc;
2343 if (parent->children == NULL) {
2344 parent->children = cur;
2345 parent->last = cur;
2346 } else {
2347 prev = parent->last;
2348 prev->next = cur;
2349 cur->prev = prev;
2350 parent->last = cur;
2351 }
2352
2353 return(cur);
2354}
2355
2356/**
2357 * xmlNewCharRef:
2358 * @doc: the document
2359 * @name: the char ref string, starting with # or "&# ... ;"
2360 *
2361 * Creation of a new character reference node.
2362 * Returns a pointer to the new node object.
2363 */
2364xmlNodePtr
2365xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2366 xmlNodePtr cur;
2367
2368 /*
2369 * Allocate a new node and fill the fields.
2370 */
2371 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2372 if (cur == NULL) {
2373 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002374 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002375 return(NULL);
2376 }
2377 memset(cur, 0, sizeof(xmlNode));
2378 cur->type = XML_ENTITY_REF_NODE;
2379
2380 cur->doc = doc;
2381 if (name[0] == '&') {
2382 int len;
2383 name++;
2384 len = xmlStrlen(name);
2385 if (name[len - 1] == ';')
2386 cur->name = xmlStrndup(name, len - 1);
2387 else
2388 cur->name = xmlStrndup(name, len);
2389 } else
2390 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002391
Daniel Veillarda880b122003-04-21 21:36:41 +00002392 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002393 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002394 return(cur);
2395}
2396
2397/**
2398 * xmlNewReference:
2399 * @doc: the document
2400 * @name: the reference name, or the reference string with & and ;
2401 *
2402 * Creation of a new reference node.
2403 * Returns a pointer to the new node object.
2404 */
2405xmlNodePtr
2406xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2407 xmlNodePtr cur;
2408 xmlEntityPtr ent;
2409
2410 /*
2411 * Allocate a new node and fill the fields.
2412 */
2413 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2414 if (cur == NULL) {
2415 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002416 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002417 return(NULL);
2418 }
2419 memset(cur, 0, sizeof(xmlNode));
2420 cur->type = XML_ENTITY_REF_NODE;
2421
2422 cur->doc = doc;
2423 if (name[0] == '&') {
2424 int len;
2425 name++;
2426 len = xmlStrlen(name);
2427 if (name[len - 1] == ';')
2428 cur->name = xmlStrndup(name, len - 1);
2429 else
2430 cur->name = xmlStrndup(name, len);
2431 } else
2432 cur->name = xmlStrdup(name);
2433
2434 ent = xmlGetDocEntity(doc, cur->name);
2435 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002436 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002437 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002438 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002439 * updated. Not sure if this is 100% correct.
2440 * -George
2441 */
2442 cur->children = (xmlNodePtr) ent;
2443 cur->last = (xmlNodePtr) ent;
2444 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002445
Daniel Veillarda880b122003-04-21 21:36:41 +00002446 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002447 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002448 return(cur);
2449}
2450
2451/**
2452 * xmlNewDocText:
2453 * @doc: the document
2454 * @content: the text content
2455 *
2456 * Creation of a new text node within a document.
2457 * Returns a pointer to the new node object.
2458 */
2459xmlNodePtr
2460xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2461 xmlNodePtr cur;
2462
2463 cur = xmlNewText(content);
2464 if (cur != NULL) cur->doc = doc;
2465 return(cur);
2466}
2467
2468/**
2469 * xmlNewTextLen:
2470 * @content: the text content
2471 * @len: the text len.
2472 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002473 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002474 * Returns a pointer to the new node object.
2475 */
2476xmlNodePtr
2477xmlNewTextLen(const xmlChar *content, int len) {
2478 xmlNodePtr cur;
2479
2480 /*
2481 * Allocate a new node and fill the fields.
2482 */
2483 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2484 if (cur == NULL) {
2485 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002486 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002487 return(NULL);
2488 }
2489 memset(cur, 0, sizeof(xmlNode));
2490 cur->type = XML_TEXT_NODE;
2491
2492 cur->name = xmlStringText;
2493 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002494 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002495 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002496
Daniel Veillarda880b122003-04-21 21:36:41 +00002497 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002498 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002499 return(cur);
2500}
2501
2502/**
2503 * xmlNewDocTextLen:
2504 * @doc: the document
2505 * @content: the text content
2506 * @len: the text len.
2507 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002508 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002509 * text node pertain to a given document.
2510 * Returns a pointer to the new node object.
2511 */
2512xmlNodePtr
2513xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2514 xmlNodePtr cur;
2515
2516 cur = xmlNewTextLen(content, len);
2517 if (cur != NULL) cur->doc = doc;
2518 return(cur);
2519}
2520
2521/**
2522 * xmlNewComment:
2523 * @content: the comment content
2524 *
2525 * Creation of a new node containing a comment.
2526 * Returns a pointer to the new node object.
2527 */
2528xmlNodePtr
2529xmlNewComment(const xmlChar *content) {
2530 xmlNodePtr cur;
2531
2532 /*
2533 * Allocate a new node and fill the fields.
2534 */
2535 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2536 if (cur == NULL) {
2537 xmlGenericError(xmlGenericErrorContext,
2538 "xmlNewComment : malloc failed\n");
2539 return(NULL);
2540 }
2541 memset(cur, 0, sizeof(xmlNode));
2542 cur->type = XML_COMMENT_NODE;
2543
2544 cur->name = xmlStringComment;
2545 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002546 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002547 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002548
Daniel Veillarda880b122003-04-21 21:36:41 +00002549 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002550 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002551 return(cur);
2552}
2553
2554/**
2555 * xmlNewCDataBlock:
2556 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002557 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002558 * @len: the length of the block
2559 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002560 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002561 * Returns a pointer to the new node object.
2562 */
2563xmlNodePtr
2564xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2565 xmlNodePtr cur;
2566
2567 /*
2568 * Allocate a new node and fill the fields.
2569 */
2570 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2571 if (cur == NULL) {
2572 xmlGenericError(xmlGenericErrorContext,
2573 "xmlNewCDataBlock : malloc failed\n");
2574 return(NULL);
2575 }
2576 memset(cur, 0, sizeof(xmlNode));
2577 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002578 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002579
2580 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002581 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002582 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002583
Daniel Veillarda880b122003-04-21 21:36:41 +00002584 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002585 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002586 return(cur);
2587}
2588
2589/**
2590 * xmlNewDocComment:
2591 * @doc: the document
2592 * @content: the comment content
2593 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002594 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002595 * Returns a pointer to the new node object.
2596 */
2597xmlNodePtr
2598xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2599 xmlNodePtr cur;
2600
2601 cur = xmlNewComment(content);
2602 if (cur != NULL) cur->doc = doc;
2603 return(cur);
2604}
2605
2606/**
2607 * xmlSetTreeDoc:
2608 * @tree: the top element
2609 * @doc: the document
2610 *
2611 * update all nodes under the tree to point to the right document
2612 */
2613void
2614xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002615 xmlAttrPtr prop;
2616
Owen Taylor3473f882001-02-23 17:55:21 +00002617 if (tree == NULL)
2618 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002619 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002620 if(tree->type == XML_ELEMENT_NODE) {
2621 prop = tree->properties;
2622 while (prop != NULL) {
2623 prop->doc = doc;
2624 xmlSetListDoc(prop->children, doc);
2625 prop = prop->next;
2626 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002627 }
Owen Taylor3473f882001-02-23 17:55:21 +00002628 if (tree->children != NULL)
2629 xmlSetListDoc(tree->children, doc);
2630 tree->doc = doc;
2631 }
2632}
2633
2634/**
2635 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002636 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002637 * @doc: the document
2638 *
2639 * update all nodes in the list to point to the right document
2640 */
2641void
2642xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2643 xmlNodePtr cur;
2644
2645 if (list == NULL)
2646 return;
2647 cur = list;
2648 while (cur != NULL) {
2649 if (cur->doc != doc)
2650 xmlSetTreeDoc(cur, doc);
2651 cur = cur->next;
2652 }
2653}
2654
2655
2656/**
2657 * xmlNewChild:
2658 * @parent: the parent node
2659 * @ns: a namespace if any
2660 * @name: the name of the child
2661 * @content: the XML content of the child if any.
2662 *
2663 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002664 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002665 * a child list containing the TEXTs and ENTITY_REFs node will be created.
2666 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2667 * references, but XML special chars need to be escaped first by using
2668 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
2669 * support is not needed.
2670 *
2671 * Returns a pointer to the new node object.
2672 */
2673xmlNodePtr
2674xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2675 const xmlChar *name, const xmlChar *content) {
2676 xmlNodePtr cur, prev;
2677
2678 if (parent == NULL) {
2679#ifdef DEBUG_TREE
2680 xmlGenericError(xmlGenericErrorContext,
2681 "xmlNewChild : parent == NULL\n");
2682#endif
2683 return(NULL);
2684 }
2685
2686 if (name == NULL) {
2687#ifdef DEBUG_TREE
2688 xmlGenericError(xmlGenericErrorContext,
2689 "xmlNewChild : name == NULL\n");
2690#endif
2691 return(NULL);
2692 }
2693
2694 /*
2695 * Allocate a new node
2696 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002697 if (parent->type == XML_ELEMENT_NODE) {
2698 if (ns == NULL)
2699 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2700 else
2701 cur = xmlNewDocNode(parent->doc, ns, name, content);
2702 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2703 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2704 if (ns == NULL)
2705 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2706 else
2707 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002708 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2709 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002710 } else {
2711 return(NULL);
2712 }
Owen Taylor3473f882001-02-23 17:55:21 +00002713 if (cur == NULL) return(NULL);
2714
2715 /*
2716 * add the new element at the end of the children list.
2717 */
2718 cur->type = XML_ELEMENT_NODE;
2719 cur->parent = parent;
2720 cur->doc = parent->doc;
2721 if (parent->children == NULL) {
2722 parent->children = cur;
2723 parent->last = cur;
2724 } else {
2725 prev = parent->last;
2726 prev->next = cur;
2727 cur->prev = prev;
2728 parent->last = cur;
2729 }
2730
2731 return(cur);
2732}
2733
2734/**
2735 * xmlAddNextSibling:
2736 * @cur: the child node
2737 * @elem: the new node
2738 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002739 * Add a new node @elem as the next sibling of @cur
2740 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002741 * first unlinked from its existing context.
2742 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002743 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2744 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002745 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002746 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002747 */
2748xmlNodePtr
2749xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2750 if (cur == NULL) {
2751#ifdef DEBUG_TREE
2752 xmlGenericError(xmlGenericErrorContext,
2753 "xmlAddNextSibling : cur == NULL\n");
2754#endif
2755 return(NULL);
2756 }
2757 if (elem == NULL) {
2758#ifdef DEBUG_TREE
2759 xmlGenericError(xmlGenericErrorContext,
2760 "xmlAddNextSibling : elem == NULL\n");
2761#endif
2762 return(NULL);
2763 }
2764
2765 xmlUnlinkNode(elem);
2766
2767 if (elem->type == XML_TEXT_NODE) {
2768 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002769 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002770 xmlFreeNode(elem);
2771 return(cur);
2772 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002773 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2774 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002775 xmlChar *tmp;
2776
2777 tmp = xmlStrdup(elem->content);
2778 tmp = xmlStrcat(tmp, cur->next->content);
2779 xmlNodeSetContent(cur->next, tmp);
2780 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002781 xmlFreeNode(elem);
2782 return(cur->next);
2783 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002784 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2785 /* check if an attribute with the same name exists */
2786 xmlAttrPtr attr;
2787
2788 if (elem->ns == NULL)
2789 attr = xmlHasProp(cur->parent, elem->name);
2790 else
2791 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2792 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2793 /* different instance, destroy it (attributes must be unique) */
2794 xmlFreeProp(attr);
2795 }
Owen Taylor3473f882001-02-23 17:55:21 +00002796 }
2797
2798 if (elem->doc != cur->doc) {
2799 xmlSetTreeDoc(elem, cur->doc);
2800 }
2801 elem->parent = cur->parent;
2802 elem->prev = cur;
2803 elem->next = cur->next;
2804 cur->next = elem;
2805 if (elem->next != NULL)
2806 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002807 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002808 elem->parent->last = elem;
2809 return(elem);
2810}
2811
2812/**
2813 * xmlAddPrevSibling:
2814 * @cur: the child node
2815 * @elem: the new node
2816 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002817 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002818 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002819 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002820 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002821 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2822 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002823 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002824 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002825 */
2826xmlNodePtr
2827xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2828 if (cur == NULL) {
2829#ifdef DEBUG_TREE
2830 xmlGenericError(xmlGenericErrorContext,
2831 "xmlAddPrevSibling : cur == NULL\n");
2832#endif
2833 return(NULL);
2834 }
2835 if (elem == NULL) {
2836#ifdef DEBUG_TREE
2837 xmlGenericError(xmlGenericErrorContext,
2838 "xmlAddPrevSibling : elem == NULL\n");
2839#endif
2840 return(NULL);
2841 }
2842
2843 xmlUnlinkNode(elem);
2844
2845 if (elem->type == XML_TEXT_NODE) {
2846 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002847 xmlChar *tmp;
2848
2849 tmp = xmlStrdup(elem->content);
2850 tmp = xmlStrcat(tmp, cur->content);
2851 xmlNodeSetContent(cur, tmp);
2852 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002853 xmlFreeNode(elem);
2854 return(cur);
2855 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002856 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2857 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002858 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002859 xmlFreeNode(elem);
2860 return(cur->prev);
2861 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002862 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2863 /* check if an attribute with the same name exists */
2864 xmlAttrPtr attr;
2865
2866 if (elem->ns == NULL)
2867 attr = xmlHasProp(cur->parent, elem->name);
2868 else
2869 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2870 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2871 /* different instance, destroy it (attributes must be unique) */
2872 xmlFreeProp(attr);
2873 }
Owen Taylor3473f882001-02-23 17:55:21 +00002874 }
2875
2876 if (elem->doc != cur->doc) {
2877 xmlSetTreeDoc(elem, cur->doc);
2878 }
2879 elem->parent = cur->parent;
2880 elem->next = cur;
2881 elem->prev = cur->prev;
2882 cur->prev = elem;
2883 if (elem->prev != NULL)
2884 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002885 if (elem->parent != NULL) {
2886 if (elem->type == XML_ATTRIBUTE_NODE) {
2887 if (elem->parent->properties == (xmlAttrPtr) cur) {
2888 elem->parent->properties = (xmlAttrPtr) elem;
2889 }
2890 } else {
2891 if (elem->parent->children == cur) {
2892 elem->parent->children = elem;
2893 }
2894 }
2895 }
Owen Taylor3473f882001-02-23 17:55:21 +00002896 return(elem);
2897}
2898
2899/**
2900 * xmlAddSibling:
2901 * @cur: the child node
2902 * @elem: the new node
2903 *
2904 * Add a new element @elem to the list of siblings of @cur
2905 * merging adjacent TEXT nodes (@elem may be freed)
2906 * If the new element was already inserted in a document it is
2907 * first unlinked from its existing context.
2908 *
2909 * Returns the new element or NULL in case of error.
2910 */
2911xmlNodePtr
2912xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2913 xmlNodePtr parent;
2914
2915 if (cur == NULL) {
2916#ifdef DEBUG_TREE
2917 xmlGenericError(xmlGenericErrorContext,
2918 "xmlAddSibling : cur == NULL\n");
2919#endif
2920 return(NULL);
2921 }
2922
2923 if (elem == NULL) {
2924#ifdef DEBUG_TREE
2925 xmlGenericError(xmlGenericErrorContext,
2926 "xmlAddSibling : elem == NULL\n");
2927#endif
2928 return(NULL);
2929 }
2930
2931 /*
2932 * Constant time is we can rely on the ->parent->last to find
2933 * the last sibling.
2934 */
2935 if ((cur->parent != NULL) &&
2936 (cur->parent->children != NULL) &&
2937 (cur->parent->last != NULL) &&
2938 (cur->parent->last->next == NULL)) {
2939 cur = cur->parent->last;
2940 } else {
2941 while (cur->next != NULL) cur = cur->next;
2942 }
2943
2944 xmlUnlinkNode(elem);
2945
2946 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002947 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002948 xmlFreeNode(elem);
2949 return(cur);
2950 }
2951
2952 if (elem->doc != cur->doc) {
2953 xmlSetTreeDoc(elem, cur->doc);
2954 }
2955 parent = cur->parent;
2956 elem->prev = cur;
2957 elem->next = NULL;
2958 elem->parent = parent;
2959 cur->next = elem;
2960 if (parent != NULL)
2961 parent->last = elem;
2962
2963 return(elem);
2964}
2965
2966/**
2967 * xmlAddChildList:
2968 * @parent: the parent node
2969 * @cur: the first node in the list
2970 *
2971 * Add a list of node at the end of the child list of the parent
2972 * merging adjacent TEXT nodes (@cur may be freed)
2973 *
2974 * Returns the last child or NULL in case of error.
2975 */
2976xmlNodePtr
2977xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2978 xmlNodePtr prev;
2979
2980 if (parent == NULL) {
2981#ifdef DEBUG_TREE
2982 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002983 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002984#endif
2985 return(NULL);
2986 }
2987
2988 if (cur == NULL) {
2989#ifdef DEBUG_TREE
2990 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002991 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002992#endif
2993 return(NULL);
2994 }
2995
2996 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2997 (cur->doc != parent->doc)) {
2998#ifdef DEBUG_TREE
2999 xmlGenericError(xmlGenericErrorContext,
3000 "Elements moved to a different document\n");
3001#endif
3002 }
3003
3004 /*
3005 * add the first element at the end of the children list.
3006 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003007
Owen Taylor3473f882001-02-23 17:55:21 +00003008 if (parent->children == NULL) {
3009 parent->children = cur;
3010 } else {
3011 /*
3012 * If cur and parent->last both are TEXT nodes, then merge them.
3013 */
3014 if ((cur->type == XML_TEXT_NODE) &&
3015 (parent->last->type == XML_TEXT_NODE) &&
3016 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003017 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003018 /*
3019 * if it's the only child, nothing more to be done.
3020 */
3021 if (cur->next == NULL) {
3022 xmlFreeNode(cur);
3023 return(parent->last);
3024 }
3025 prev = cur;
3026 cur = cur->next;
3027 xmlFreeNode(prev);
3028 }
3029 prev = parent->last;
3030 prev->next = cur;
3031 cur->prev = prev;
3032 }
3033 while (cur->next != NULL) {
3034 cur->parent = parent;
3035 if (cur->doc != parent->doc) {
3036 xmlSetTreeDoc(cur, parent->doc);
3037 }
3038 cur = cur->next;
3039 }
3040 cur->parent = parent;
3041 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
3042 parent->last = cur;
3043
3044 return(cur);
3045}
3046
3047/**
3048 * xmlAddChild:
3049 * @parent: the parent node
3050 * @cur: the child node
3051 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003052 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003053 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003054 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3055 * If there is an attribute with equal name, it is first destroyed.
3056 *
Owen Taylor3473f882001-02-23 17:55:21 +00003057 * Returns the child or NULL in case of error.
3058 */
3059xmlNodePtr
3060xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3061 xmlNodePtr prev;
3062
3063 if (parent == NULL) {
3064#ifdef DEBUG_TREE
3065 xmlGenericError(xmlGenericErrorContext,
3066 "xmlAddChild : parent == NULL\n");
3067#endif
3068 return(NULL);
3069 }
3070
3071 if (cur == NULL) {
3072#ifdef DEBUG_TREE
3073 xmlGenericError(xmlGenericErrorContext,
3074 "xmlAddChild : child == NULL\n");
3075#endif
3076 return(NULL);
3077 }
3078
Owen Taylor3473f882001-02-23 17:55:21 +00003079 /*
3080 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003081 * cur is then freed.
3082 */
3083 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003084 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003085 (parent->content != NULL) &&
3086 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003087 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003088 xmlFreeNode(cur);
3089 return(parent);
3090 }
3091 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003092 (parent->last->name == cur->name) &&
3093 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003094 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003095 xmlFreeNode(cur);
3096 return(parent->last);
3097 }
3098 }
3099
3100 /*
3101 * add the new element at the end of the children list.
3102 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003103 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003104 cur->parent = parent;
3105 if (cur->doc != parent->doc) {
3106 xmlSetTreeDoc(cur, parent->doc);
3107 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003108 /* this check prevents a loop on tree-traversions if a developer
3109 * tries to add a node to its parent multiple times
3110 */
3111 if (prev == parent)
3112 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003113
3114 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003115 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003116 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003117 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003118 (parent->content != NULL) &&
3119 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003120 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003121 xmlFreeNode(cur);
3122 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003123 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003124 if (cur->type == XML_ATTRIBUTE_NODE) {
3125 if (parent->properties == NULL) {
3126 parent->properties = (xmlAttrPtr) cur;
3127 } else {
3128 /* check if an attribute with the same name exists */
3129 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003130
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003131 if (cur->ns == NULL)
3132 lastattr = xmlHasProp(parent, cur->name);
3133 else
3134 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3135 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
3136 /* different instance, destroy it (attributes must be unique) */
3137 xmlFreeProp(lastattr);
3138 }
3139 /* find the end */
3140 lastattr = parent->properties;
3141 while (lastattr->next != NULL) {
3142 lastattr = lastattr->next;
3143 }
3144 lastattr->next = (xmlAttrPtr) cur;
3145 ((xmlAttrPtr) cur)->prev = lastattr;
3146 }
3147 } else {
3148 if (parent->children == NULL) {
3149 parent->children = cur;
3150 parent->last = cur;
3151 } else {
3152 prev = parent->last;
3153 prev->next = cur;
3154 cur->prev = prev;
3155 parent->last = cur;
3156 }
3157 }
Owen Taylor3473f882001-02-23 17:55:21 +00003158 return(cur);
3159}
3160
3161/**
3162 * xmlGetLastChild:
3163 * @parent: the parent node
3164 *
3165 * Search the last child of a node.
3166 * Returns the last child or NULL if none.
3167 */
3168xmlNodePtr
3169xmlGetLastChild(xmlNodePtr parent) {
3170 if (parent == NULL) {
3171#ifdef DEBUG_TREE
3172 xmlGenericError(xmlGenericErrorContext,
3173 "xmlGetLastChild : parent == NULL\n");
3174#endif
3175 return(NULL);
3176 }
3177 return(parent->last);
3178}
3179
3180/**
3181 * xmlFreeNodeList:
3182 * @cur: the first node in the list
3183 *
3184 * Free a node and all its siblings, this is a recursive behaviour, all
3185 * the children are freed too.
3186 */
3187void
3188xmlFreeNodeList(xmlNodePtr cur) {
3189 xmlNodePtr next;
3190 if (cur == NULL) {
3191#ifdef DEBUG_TREE
3192 xmlGenericError(xmlGenericErrorContext,
3193 "xmlFreeNodeList : node == NULL\n");
3194#endif
3195 return;
3196 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00003197 if (cur->type == XML_NAMESPACE_DECL) {
3198 xmlFreeNsList((xmlNsPtr) cur);
3199 return;
3200 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003201 if ((cur->type == XML_DOCUMENT_NODE) ||
3202#ifdef LIBXML_DOCB_ENABLED
3203 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003204#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003205 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003206 xmlFreeDoc((xmlDocPtr) cur);
3207 return;
3208 }
Owen Taylor3473f882001-02-23 17:55:21 +00003209 while (cur != NULL) {
3210 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003211 /* unroll to speed up freeing the document */
3212 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003213
Daniel Veillarda880b122003-04-21 21:36:41 +00003214 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003215 xmlDeregisterNodeDefaultValue(cur);
3216
Daniel Veillard02141ea2001-04-30 11:46:40 +00003217 if ((cur->children != NULL) &&
3218 (cur->type != XML_ENTITY_REF_NODE))
3219 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003220 if (((cur->type == XML_ELEMENT_NODE) ||
3221 (cur->type == XML_XINCLUDE_START) ||
3222 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003223 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003224 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003225 if ((cur->type != XML_ELEMENT_NODE) &&
3226 (cur->type != XML_XINCLUDE_START) &&
3227 (cur->type != XML_XINCLUDE_END) &&
3228 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00003229 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003230 }
3231 if (((cur->type == XML_ELEMENT_NODE) ||
3232 (cur->type == XML_XINCLUDE_START) ||
3233 (cur->type == XML_XINCLUDE_END)) &&
3234 (cur->nsDef != NULL))
3235 xmlFreeNsList(cur->nsDef);
3236
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003237 /*
3238 * When a node is a text node or a comment, it uses a global static
3239 * variable for the name of the node.
3240 *
3241 * The xmlStrEqual comparisons need to be done when (happened with
3242 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003243 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00003244 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003245 * the string addresses compare are not sufficient.
3246 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003247 if ((cur->name != NULL) &&
3248 (cur->name != xmlStringText) &&
3249 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003250 (cur->name != xmlStringComment)) {
3251 if (cur->type == XML_TEXT_NODE) {
3252 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
3253 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
3254 xmlFree((char *) cur->name);
3255 } else if (cur->type == XML_COMMENT_NODE) {
3256 if (!xmlStrEqual(cur->name, xmlStringComment))
3257 xmlFree((char *) cur->name);
3258 } else
3259 xmlFree((char *) cur->name);
3260 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00003261 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003262 xmlFree(cur);
3263 }
Owen Taylor3473f882001-02-23 17:55:21 +00003264 cur = next;
3265 }
3266}
3267
3268/**
3269 * xmlFreeNode:
3270 * @cur: the node
3271 *
3272 * Free a node, this is a recursive behaviour, all the children are freed too.
3273 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3274 */
3275void
3276xmlFreeNode(xmlNodePtr cur) {
3277 if (cur == NULL) {
3278#ifdef DEBUG_TREE
3279 xmlGenericError(xmlGenericErrorContext,
3280 "xmlFreeNode : node == NULL\n");
3281#endif
3282 return;
3283 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003284
Daniel Veillard02141ea2001-04-30 11:46:40 +00003285 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003286 if (cur->type == XML_DTD_NODE) {
3287 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003288 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003289 }
3290 if (cur->type == XML_NAMESPACE_DECL) {
3291 xmlFreeNs((xmlNsPtr) cur);
3292 return;
3293 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003294 if (cur->type == XML_ATTRIBUTE_NODE) {
3295 xmlFreeProp((xmlAttrPtr) cur);
3296 return;
3297 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003298
Daniel Veillarda880b122003-04-21 21:36:41 +00003299 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003300 xmlDeregisterNodeDefaultValue(cur);
3301
Owen Taylor3473f882001-02-23 17:55:21 +00003302 if ((cur->children != NULL) &&
3303 (cur->type != XML_ENTITY_REF_NODE))
3304 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003305 if (((cur->type == XML_ELEMENT_NODE) ||
3306 (cur->type == XML_XINCLUDE_START) ||
3307 (cur->type == XML_XINCLUDE_END)) &&
3308 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003309 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003310 if ((cur->type != XML_ELEMENT_NODE) &&
3311 (cur->content != NULL) &&
3312 (cur->type != XML_ENTITY_REF_NODE) &&
3313 (cur->type != XML_XINCLUDE_END) &&
3314 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003315 xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003316 }
3317
Daniel Veillardacd370f2001-06-09 17:17:51 +00003318 /*
3319 * When a node is a text node or a comment, it uses a global static
3320 * variable for the name of the node.
3321 *
3322 * The xmlStrEqual comparisons need to be done when (happened with
3323 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003324 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00003325 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00003326 * are not sufficient.
3327 */
Owen Taylor3473f882001-02-23 17:55:21 +00003328 if ((cur->name != NULL) &&
3329 (cur->name != xmlStringText) &&
3330 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00003331 (cur->name != xmlStringComment)) {
3332 if (cur->type == XML_TEXT_NODE) {
3333 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
3334 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
3335 xmlFree((char *) cur->name);
3336 } else if (cur->type == XML_COMMENT_NODE) {
3337 if (!xmlStrEqual(cur->name, xmlStringComment))
3338 xmlFree((char *) cur->name);
3339 } else
3340 xmlFree((char *) cur->name);
3341 }
3342
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003343 if (((cur->type == XML_ELEMENT_NODE) ||
3344 (cur->type == XML_XINCLUDE_START) ||
3345 (cur->type == XML_XINCLUDE_END)) &&
3346 (cur->nsDef != NULL))
3347 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003348 xmlFree(cur);
3349}
3350
3351/**
3352 * xmlUnlinkNode:
3353 * @cur: the node
3354 *
3355 * Unlink a node from it's current context, the node is not freed
3356 */
3357void
3358xmlUnlinkNode(xmlNodePtr cur) {
3359 if (cur == NULL) {
3360#ifdef DEBUG_TREE
3361 xmlGenericError(xmlGenericErrorContext,
3362 "xmlUnlinkNode : node == NULL\n");
3363#endif
3364 return;
3365 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003366 if (cur->type == XML_DTD_NODE) {
3367 xmlDocPtr doc;
3368 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003369 if (doc != NULL) {
3370 if (doc->intSubset == (xmlDtdPtr) cur)
3371 doc->intSubset = NULL;
3372 if (doc->extSubset == (xmlDtdPtr) cur)
3373 doc->extSubset = NULL;
3374 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003375 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003376 if (cur->parent != NULL) {
3377 xmlNodePtr parent;
3378 parent = cur->parent;
3379 if (cur->type == XML_ATTRIBUTE_NODE) {
3380 if (parent->properties == (xmlAttrPtr) cur)
3381 parent->properties = ((xmlAttrPtr) cur)->next;
3382 } else {
3383 if (parent->children == cur)
3384 parent->children = cur->next;
3385 if (parent->last == cur)
3386 parent->last = cur->prev;
3387 }
3388 cur->parent = NULL;
3389 }
Owen Taylor3473f882001-02-23 17:55:21 +00003390 if (cur->next != NULL)
3391 cur->next->prev = cur->prev;
3392 if (cur->prev != NULL)
3393 cur->prev->next = cur->next;
3394 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003395}
3396
3397/**
3398 * xmlReplaceNode:
3399 * @old: the old node
3400 * @cur: the node
3401 *
3402 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003403 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003404 * first unlinked from its existing context.
3405 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003406 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003407 */
3408xmlNodePtr
3409xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3410 if (old == NULL) {
3411#ifdef DEBUG_TREE
3412 xmlGenericError(xmlGenericErrorContext,
3413 "xmlReplaceNode : old == NULL\n");
3414#endif
3415 return(NULL);
3416 }
3417 if (cur == NULL) {
3418 xmlUnlinkNode(old);
3419 return(old);
3420 }
3421 if (cur == old) {
3422 return(old);
3423 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003424 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3425#ifdef DEBUG_TREE
3426 xmlGenericError(xmlGenericErrorContext,
3427 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3428#endif
3429 return(old);
3430 }
3431 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3432#ifdef DEBUG_TREE
3433 xmlGenericError(xmlGenericErrorContext,
3434 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3435#endif
3436 return(old);
3437 }
Owen Taylor3473f882001-02-23 17:55:21 +00003438 xmlUnlinkNode(cur);
3439 cur->doc = old->doc;
3440 cur->parent = old->parent;
3441 cur->next = old->next;
3442 if (cur->next != NULL)
3443 cur->next->prev = cur;
3444 cur->prev = old->prev;
3445 if (cur->prev != NULL)
3446 cur->prev->next = cur;
3447 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003448 if (cur->type == XML_ATTRIBUTE_NODE) {
3449 if (cur->parent->properties == (xmlAttrPtr)old)
3450 cur->parent->properties = ((xmlAttrPtr) cur);
3451 } else {
3452 if (cur->parent->children == old)
3453 cur->parent->children = cur;
3454 if (cur->parent->last == old)
3455 cur->parent->last = cur;
3456 }
Owen Taylor3473f882001-02-23 17:55:21 +00003457 }
3458 old->next = old->prev = NULL;
3459 old->parent = NULL;
3460 return(old);
3461}
3462
3463/************************************************************************
3464 * *
3465 * Copy operations *
3466 * *
3467 ************************************************************************/
3468
3469/**
3470 * xmlCopyNamespace:
3471 * @cur: the namespace
3472 *
3473 * Do a copy of the namespace.
3474 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003475 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003476 */
3477xmlNsPtr
3478xmlCopyNamespace(xmlNsPtr cur) {
3479 xmlNsPtr ret;
3480
3481 if (cur == NULL) return(NULL);
3482 switch (cur->type) {
3483 case XML_LOCAL_NAMESPACE:
3484 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3485 break;
3486 default:
3487#ifdef DEBUG_TREE
3488 xmlGenericError(xmlGenericErrorContext,
3489 "xmlCopyNamespace: invalid type %d\n", cur->type);
3490#endif
3491 return(NULL);
3492 }
3493 return(ret);
3494}
3495
3496/**
3497 * xmlCopyNamespaceList:
3498 * @cur: the first namespace
3499 *
3500 * Do a copy of an namespace list.
3501 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003502 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003503 */
3504xmlNsPtr
3505xmlCopyNamespaceList(xmlNsPtr cur) {
3506 xmlNsPtr ret = NULL;
3507 xmlNsPtr p = NULL,q;
3508
3509 while (cur != NULL) {
3510 q = xmlCopyNamespace(cur);
3511 if (p == NULL) {
3512 ret = p = q;
3513 } else {
3514 p->next = q;
3515 p = q;
3516 }
3517 cur = cur->next;
3518 }
3519 return(ret);
3520}
3521
3522static xmlNodePtr
3523xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3524/**
3525 * xmlCopyProp:
3526 * @target: the element where the attribute will be grafted
3527 * @cur: the attribute
3528 *
3529 * Do a copy of the attribute.
3530 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003531 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003532 */
3533xmlAttrPtr
3534xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3535 xmlAttrPtr ret;
3536
3537 if (cur == NULL) return(NULL);
3538 if (target != NULL)
3539 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3540 else if (cur->parent != NULL)
3541 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3542 else if (cur->children != NULL)
3543 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3544 else
3545 ret = xmlNewDocProp(NULL, cur->name, NULL);
3546 if (ret == NULL) return(NULL);
3547 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003548
Owen Taylor3473f882001-02-23 17:55:21 +00003549 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003550 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003551/*
3552 * if (target->doc)
3553 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3554 * else if (cur->doc) / * target may not yet have a doc : KPI * /
3555 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
3556 * else
3557 * ns = NULL;
3558 * ret->ns = ns;
3559 */
3560 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3561 if (ns == NULL) {
3562 /*
3563 * Humm, we are copying an element whose namespace is defined
3564 * out of the new tree scope. Search it in the original tree
3565 * and add it at the top of the new tree
3566 */
3567 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3568 if (ns != NULL) {
3569 xmlNodePtr root = target;
3570 xmlNodePtr pred = NULL;
3571
3572 while (root->parent != NULL) {
3573 pred = root;
3574 root = root->parent;
3575 }
3576 if (root == (xmlNodePtr) target->doc) {
3577 /* correct possibly cycling above the document elt */
3578 root = pred;
3579 }
3580 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3581 }
3582 } else {
3583 /*
3584 * we have to find something appropriate here since
3585 * we cant be sure, that the namespce we found is identified
3586 * by the prefix
3587 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003588 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003589 /* this is the nice case */
3590 ret->ns = ns;
3591 } else {
3592 /*
3593 * we are in trouble: we need a new reconcilied namespace.
3594 * This is expensive
3595 */
3596 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3597 }
3598 }
3599
Owen Taylor3473f882001-02-23 17:55:21 +00003600 } else
3601 ret->ns = NULL;
3602
3603 if (cur->children != NULL) {
3604 xmlNodePtr tmp;
3605
3606 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3607 ret->last = NULL;
3608 tmp = ret->children;
3609 while (tmp != NULL) {
3610 /* tmp->parent = (xmlNodePtr)ret; */
3611 if (tmp->next == NULL)
3612 ret->last = tmp;
3613 tmp = tmp->next;
3614 }
3615 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003616 /*
3617 * Try to handle IDs
3618 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003619 if ((target!= NULL) && (cur!= NULL) &&
3620 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003621 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3622 if (xmlIsID(cur->doc, cur->parent, cur)) {
3623 xmlChar *id;
3624
3625 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3626 if (id != NULL) {
3627 xmlAddID(NULL, target->doc, id, ret);
3628 xmlFree(id);
3629 }
3630 }
3631 }
Owen Taylor3473f882001-02-23 17:55:21 +00003632 return(ret);
3633}
3634
3635/**
3636 * xmlCopyPropList:
3637 * @target: the element where the attributes will be grafted
3638 * @cur: the first attribute
3639 *
3640 * Do a copy of an attribute list.
3641 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003642 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003643 */
3644xmlAttrPtr
3645xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3646 xmlAttrPtr ret = NULL;
3647 xmlAttrPtr p = NULL,q;
3648
3649 while (cur != NULL) {
3650 q = xmlCopyProp(target, cur);
3651 if (p == NULL) {
3652 ret = p = q;
3653 } else {
3654 p->next = q;
3655 q->prev = p;
3656 p = q;
3657 }
3658 cur = cur->next;
3659 }
3660 return(ret);
3661}
3662
3663/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003664 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003665 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003666 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003667 * tricky reason: namespaces. Doing a direct copy of a node
3668 * say RPM:Copyright without changing the namespace pointer to
3669 * something else can produce stale links. One way to do it is
3670 * to keep a reference counter but this doesn't work as soon
3671 * as one move the element or the subtree out of the scope of
3672 * the existing namespace. The actual solution seems to add
3673 * a copy of the namespace at the top of the copied tree if
3674 * not available in the subtree.
3675 * Hence two functions, the public front-end call the inner ones
3676 */
3677
3678static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003679xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003680 int recursive) {
3681 xmlNodePtr ret;
3682
3683 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003684 switch (node->type) {
3685 case XML_TEXT_NODE:
3686 case XML_CDATA_SECTION_NODE:
3687 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003688 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003689 case XML_ENTITY_REF_NODE:
3690 case XML_ENTITY_NODE:
3691 case XML_PI_NODE:
3692 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003693 case XML_XINCLUDE_START:
3694 case XML_XINCLUDE_END:
3695 break;
3696 case XML_ATTRIBUTE_NODE:
3697 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3698 case XML_NAMESPACE_DECL:
3699 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3700
Daniel Veillard39196eb2001-06-19 18:09:42 +00003701 case XML_DOCUMENT_NODE:
3702 case XML_HTML_DOCUMENT_NODE:
3703#ifdef LIBXML_DOCB_ENABLED
3704 case XML_DOCB_DOCUMENT_NODE:
3705#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003706 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00003707 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003708 case XML_NOTATION_NODE:
3709 case XML_DTD_NODE:
3710 case XML_ELEMENT_DECL:
3711 case XML_ATTRIBUTE_DECL:
3712 case XML_ENTITY_DECL:
3713 return(NULL);
3714 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003715
Owen Taylor3473f882001-02-23 17:55:21 +00003716 /*
3717 * Allocate a new node and fill the fields.
3718 */
3719 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3720 if (ret == NULL) {
3721 xmlGenericError(xmlGenericErrorContext,
3722 "xmlStaticCopyNode : malloc failed\n");
3723 return(NULL);
3724 }
3725 memset(ret, 0, sizeof(xmlNode));
3726 ret->type = node->type;
3727
3728 ret->doc = doc;
3729 ret->parent = parent;
3730 if (node->name == xmlStringText)
3731 ret->name = xmlStringText;
3732 else if (node->name == xmlStringTextNoenc)
3733 ret->name = xmlStringTextNoenc;
3734 else if (node->name == xmlStringComment)
3735 ret->name = xmlStringComment;
3736 else if (node->name != NULL)
3737 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003738 if ((node->type != XML_ELEMENT_NODE) &&
3739 (node->content != NULL) &&
3740 (node->type != XML_ENTITY_REF_NODE) &&
3741 (node->type != XML_XINCLUDE_END) &&
3742 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003743 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003744 }else{
3745 if (node->type == XML_ELEMENT_NODE)
3746 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00003747 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003748 if (parent != NULL) {
3749 xmlNodePtr tmp;
3750
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003751 /*
3752 * this is a tricky part for the node register thing:
3753 * in case ret does get coalesced in xmlAddChild
3754 * the deregister-node callback is called; so we register ret now already
3755 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003756 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003757 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3758
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003759 tmp = xmlAddChild(parent, ret);
3760 /* node could have coalesced */
3761 if (tmp != ret)
3762 return(tmp);
3763 }
Owen Taylor3473f882001-02-23 17:55:21 +00003764
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003765 if (!recursive)
3766 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003767 if (node->nsDef != NULL)
3768 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3769
3770 if (node->ns != NULL) {
3771 xmlNsPtr ns;
3772
3773 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3774 if (ns == NULL) {
3775 /*
3776 * Humm, we are copying an element whose namespace is defined
3777 * out of the new tree scope. Search it in the original tree
3778 * and add it at the top of the new tree
3779 */
3780 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3781 if (ns != NULL) {
3782 xmlNodePtr root = ret;
3783
3784 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003785 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003786 }
3787 } else {
3788 /*
3789 * reference the existing namespace definition in our own tree.
3790 */
3791 ret->ns = ns;
3792 }
3793 }
3794 if (node->properties != NULL)
3795 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003796 if (node->type == XML_ENTITY_REF_NODE) {
3797 if ((doc == NULL) || (node->doc != doc)) {
3798 /*
3799 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003800 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003801 * we cannot keep the reference. Try to find it in the
3802 * target document.
3803 */
3804 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3805 } else {
3806 ret->children = node->children;
3807 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003808 ret->last = ret->children;
3809 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003810 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003811 UPDATE_LAST_CHILD_AND_PARENT(ret)
3812 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003813
3814out:
3815 /* if parent != NULL we already registered the node above */
3816 if (parent == NULL && xmlRegisterNodeDefaultValue)
3817 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003818 return(ret);
3819}
3820
3821static xmlNodePtr
3822xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3823 xmlNodePtr ret = NULL;
3824 xmlNodePtr p = NULL,q;
3825
3826 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003827 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003828 if (doc == NULL) {
3829 node = node->next;
3830 continue;
3831 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003832 if (doc->intSubset == NULL) {
3833 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3834 q->doc = doc;
3835 q->parent = parent;
3836 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003837 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003838 } else {
3839 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003840 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003841 }
3842 } else
3843 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003844 if (ret == NULL) {
3845 q->prev = NULL;
3846 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003847 } else if (p != q) {
3848 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003849 p->next = q;
3850 q->prev = p;
3851 p = q;
3852 }
3853 node = node->next;
3854 }
3855 return(ret);
3856}
3857
3858/**
3859 * xmlCopyNode:
3860 * @node: the node
3861 * @recursive: if 1 do a recursive copy.
3862 *
3863 * Do a copy of the node.
3864 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003865 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003866 */
3867xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003868xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003869 xmlNodePtr ret;
3870
3871 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3872 return(ret);
3873}
3874
3875/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003876 * xmlDocCopyNode:
3877 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003878 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003879 * @recursive: if 1 do a recursive copy.
3880 *
3881 * Do a copy of the node to a given document.
3882 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003883 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003884 */
3885xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003886xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003887 xmlNodePtr ret;
3888
3889 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3890 return(ret);
3891}
3892
3893/**
Owen Taylor3473f882001-02-23 17:55:21 +00003894 * xmlCopyNodeList:
3895 * @node: the first node in the list.
3896 *
3897 * Do a recursive copy of the node list.
3898 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003899 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003900 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003901xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003902 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3903 return(ret);
3904}
3905
3906/**
Owen Taylor3473f882001-02-23 17:55:21 +00003907 * xmlCopyDtd:
3908 * @dtd: the dtd
3909 *
3910 * Do a copy of the dtd.
3911 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003912 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003913 */
3914xmlDtdPtr
3915xmlCopyDtd(xmlDtdPtr dtd) {
3916 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003917 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003918
3919 if (dtd == NULL) return(NULL);
3920 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3921 if (ret == NULL) return(NULL);
3922 if (dtd->entities != NULL)
3923 ret->entities = (void *) xmlCopyEntitiesTable(
3924 (xmlEntitiesTablePtr) dtd->entities);
3925 if (dtd->notations != NULL)
3926 ret->notations = (void *) xmlCopyNotationTable(
3927 (xmlNotationTablePtr) dtd->notations);
3928 if (dtd->elements != NULL)
3929 ret->elements = (void *) xmlCopyElementTable(
3930 (xmlElementTablePtr) dtd->elements);
3931 if (dtd->attributes != NULL)
3932 ret->attributes = (void *) xmlCopyAttributeTable(
3933 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003934 if (dtd->pentities != NULL)
3935 ret->pentities = (void *) xmlCopyEntitiesTable(
3936 (xmlEntitiesTablePtr) dtd->pentities);
3937
3938 cur = dtd->children;
3939 while (cur != NULL) {
3940 q = NULL;
3941
3942 if (cur->type == XML_ENTITY_DECL) {
3943 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3944 switch (tmp->etype) {
3945 case XML_INTERNAL_GENERAL_ENTITY:
3946 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3947 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3948 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3949 break;
3950 case XML_INTERNAL_PARAMETER_ENTITY:
3951 case XML_EXTERNAL_PARAMETER_ENTITY:
3952 q = (xmlNodePtr)
3953 xmlGetParameterEntityFromDtd(ret, tmp->name);
3954 break;
3955 case XML_INTERNAL_PREDEFINED_ENTITY:
3956 break;
3957 }
3958 } else if (cur->type == XML_ELEMENT_DECL) {
3959 xmlElementPtr tmp = (xmlElementPtr) cur;
3960 q = (xmlNodePtr)
3961 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3962 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3963 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3964 q = (xmlNodePtr)
3965 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3966 } else if (cur->type == XML_COMMENT_NODE) {
3967 q = xmlCopyNode(cur, 0);
3968 }
3969
3970 if (q == NULL) {
3971 cur = cur->next;
3972 continue;
3973 }
3974
3975 if (p == NULL)
3976 ret->children = q;
3977 else
3978 p->next = q;
3979
3980 q->prev = p;
3981 q->parent = (xmlNodePtr) ret;
3982 q->next = NULL;
3983 ret->last = q;
3984 p = q;
3985 cur = cur->next;
3986 }
3987
Owen Taylor3473f882001-02-23 17:55:21 +00003988 return(ret);
3989}
3990
3991/**
3992 * xmlCopyDoc:
3993 * @doc: the document
3994 * @recursive: if 1 do a recursive copy.
3995 *
3996 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003997 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003998 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003999 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004000 */
4001xmlDocPtr
4002xmlCopyDoc(xmlDocPtr doc, int recursive) {
4003 xmlDocPtr ret;
4004
4005 if (doc == NULL) return(NULL);
4006 ret = xmlNewDoc(doc->version);
4007 if (ret == NULL) return(NULL);
4008 if (doc->name != NULL)
4009 ret->name = xmlMemStrdup(doc->name);
4010 if (doc->encoding != NULL)
4011 ret->encoding = xmlStrdup(doc->encoding);
4012 ret->charset = doc->charset;
4013 ret->compression = doc->compression;
4014 ret->standalone = doc->standalone;
4015 if (!recursive) return(ret);
4016
Daniel Veillardb33c2012001-04-25 12:59:04 +00004017 ret->last = NULL;
4018 ret->children = NULL;
4019 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004020 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004021 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004022 ret->intSubset->parent = ret;
4023 }
Owen Taylor3473f882001-02-23 17:55:21 +00004024 if (doc->oldNs != NULL)
4025 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4026 if (doc->children != NULL) {
4027 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00004028
4029 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4030 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004031 ret->last = NULL;
4032 tmp = ret->children;
4033 while (tmp != NULL) {
4034 if (tmp->next == NULL)
4035 ret->last = tmp;
4036 tmp = tmp->next;
4037 }
4038 }
4039 return(ret);
4040}
4041
4042/************************************************************************
4043 * *
4044 * Content access functions *
4045 * *
4046 ************************************************************************/
4047
4048/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004049 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004050 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004051 *
4052 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004053 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004054 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004055 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004056 */
4057long
4058xmlGetLineNo(xmlNodePtr node)
4059{
4060 long result = -1;
4061
4062 if (!node)
4063 return result;
4064 if (node->type == XML_ELEMENT_NODE)
4065 result = (long) node->content;
4066 else if ((node->prev != NULL) &&
4067 ((node->prev->type == XML_ELEMENT_NODE) ||
4068 (node->prev->type == XML_TEXT_NODE)))
4069 result = xmlGetLineNo(node->prev);
4070 else if ((node->parent != NULL) &&
4071 ((node->parent->type == XML_ELEMENT_NODE) ||
4072 (node->parent->type == XML_TEXT_NODE)))
4073 result = xmlGetLineNo(node->parent);
4074
4075 return result;
4076}
4077
4078/**
4079 * xmlGetNodePath:
4080 * @node: a node
4081 *
4082 * Build a structure based Path for the given node
4083 *
4084 * Returns the new path or NULL in case of error. The caller must free
4085 * the returned string
4086 */
4087xmlChar *
4088xmlGetNodePath(xmlNodePtr node)
4089{
4090 xmlNodePtr cur, tmp, next;
4091 xmlChar *buffer = NULL, *temp;
4092 size_t buf_len;
4093 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004094 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004095 const char *name;
4096 char nametemp[100];
4097 int occur = 0;
4098
4099 if (node == NULL)
4100 return (NULL);
4101
4102 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004103 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004104 if (buffer == NULL)
4105 return (NULL);
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004106 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004107 if (buf == NULL) {
4108 xmlFree(buffer);
4109 return (NULL);
4110 }
4111
4112 buffer[0] = 0;
4113 cur = node;
4114 do {
4115 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004116 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004117 occur = 0;
4118 if ((cur->type == XML_DOCUMENT_NODE) ||
4119 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4120 if (buffer[0] == '/')
4121 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004122 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004123 next = NULL;
4124 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004125 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004126 name = (const char *) cur->name;
4127 if (cur->ns) {
4128 snprintf(nametemp, sizeof(nametemp) - 1,
4129 "%s:%s", cur->ns->prefix, cur->name);
4130 nametemp[sizeof(nametemp) - 1] = 0;
4131 name = nametemp;
4132 }
4133 next = cur->parent;
4134
4135 /*
4136 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004137 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004138 */
4139 tmp = cur->prev;
4140 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004141 if ((tmp->type == XML_ELEMENT_NODE) &&
4142 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004143 occur++;
4144 tmp = tmp->prev;
4145 }
4146 if (occur == 0) {
4147 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004148 while (tmp != NULL && occur == 0) {
4149 if ((tmp->type == XML_ELEMENT_NODE) &&
4150 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004151 occur++;
4152 tmp = tmp->next;
4153 }
4154 if (occur != 0)
4155 occur = 1;
4156 } else
4157 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004158 } else if (cur->type == XML_COMMENT_NODE) {
4159 sep = "/";
4160 name = "comment()";
4161 next = cur->parent;
4162
4163 /*
4164 * Thumbler index computation
4165 */
4166 tmp = cur->prev;
4167 while (tmp != NULL) {
4168 if (tmp->type == XML_COMMENT_NODE)
4169 occur++;
4170 tmp = tmp->prev;
4171 }
4172 if (occur == 0) {
4173 tmp = cur->next;
4174 while (tmp != NULL && occur == 0) {
4175 if (tmp->type == XML_COMMENT_NODE)
4176 occur++;
4177 tmp = tmp->next;
4178 }
4179 if (occur != 0)
4180 occur = 1;
4181 } else
4182 occur++;
4183 } else if ((cur->type == XML_TEXT_NODE) ||
4184 (cur->type == XML_CDATA_SECTION_NODE)) {
4185 sep = "/";
4186 name = "text()";
4187 next = cur->parent;
4188
4189 /*
4190 * Thumbler index computation
4191 */
4192 tmp = cur->prev;
4193 while (tmp != NULL) {
4194 if ((cur->type == XML_TEXT_NODE) ||
4195 (cur->type == XML_CDATA_SECTION_NODE))
4196 occur++;
4197 tmp = tmp->prev;
4198 }
4199 if (occur == 0) {
4200 tmp = cur->next;
4201 while (tmp != NULL && occur == 0) {
4202 if ((cur->type == XML_TEXT_NODE) ||
4203 (cur->type == XML_CDATA_SECTION_NODE))
4204 occur++;
4205 tmp = tmp->next;
4206 }
4207 if (occur != 0)
4208 occur = 1;
4209 } else
4210 occur++;
4211 } else if (cur->type == XML_PI_NODE) {
4212 sep = "/";
4213 snprintf(nametemp, sizeof(nametemp) - 1,
4214 "processing-instruction('%s')", cur->name);
4215 nametemp[sizeof(nametemp) - 1] = 0;
4216 name = nametemp;
4217
4218 next = cur->parent;
4219
4220 /*
4221 * Thumbler index computation
4222 */
4223 tmp = cur->prev;
4224 while (tmp != NULL) {
4225 if ((tmp->type == XML_PI_NODE) &&
4226 (xmlStrEqual(cur->name, tmp->name)))
4227 occur++;
4228 tmp = tmp->prev;
4229 }
4230 if (occur == 0) {
4231 tmp = cur->next;
4232 while (tmp != NULL && occur == 0) {
4233 if ((tmp->type == XML_PI_NODE) &&
4234 (xmlStrEqual(cur->name, tmp->name)))
4235 occur++;
4236 tmp = tmp->next;
4237 }
4238 if (occur != 0)
4239 occur = 1;
4240 } else
4241 occur++;
4242
Daniel Veillard8faa7832001-11-26 15:58:08 +00004243 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004244 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004245 name = (const char *) (((xmlAttrPtr) cur)->name);
4246 next = ((xmlAttrPtr) cur)->parent;
4247 } else {
4248 next = cur->parent;
4249 }
4250
4251 /*
4252 * Make sure there is enough room
4253 */
4254 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4255 buf_len =
4256 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4257 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4258 if (temp == NULL) {
4259 xmlFree(buf);
4260 xmlFree(buffer);
4261 return (NULL);
4262 }
4263 buffer = temp;
4264 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4265 if (temp == NULL) {
4266 xmlFree(buf);
4267 xmlFree(buffer);
4268 return (NULL);
4269 }
4270 buf = temp;
4271 }
4272 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004273 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004274 sep, name, (char *) buffer);
4275 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004276 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004277 sep, name, occur, (char *) buffer);
4278 snprintf((char *) buffer, buf_len, "%s", buf);
4279 cur = next;
4280 } while (cur != NULL);
4281 xmlFree(buf);
4282 return (buffer);
4283}
4284
4285/**
Owen Taylor3473f882001-02-23 17:55:21 +00004286 * xmlDocGetRootElement:
4287 * @doc: the document
4288 *
4289 * Get the root element of the document (doc->children is a list
4290 * containing possibly comments, PIs, etc ...).
4291 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004292 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004293 */
4294xmlNodePtr
4295xmlDocGetRootElement(xmlDocPtr doc) {
4296 xmlNodePtr ret;
4297
4298 if (doc == NULL) return(NULL);
4299 ret = doc->children;
4300 while (ret != NULL) {
4301 if (ret->type == XML_ELEMENT_NODE)
4302 return(ret);
4303 ret = ret->next;
4304 }
4305 return(ret);
4306}
4307
4308/**
4309 * xmlDocSetRootElement:
4310 * @doc: the document
4311 * @root: the new document root element
4312 *
4313 * Set the root element of the document (doc->children is a list
4314 * containing possibly comments, PIs, etc ...).
4315 *
4316 * Returns the old root element if any was found
4317 */
4318xmlNodePtr
4319xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4320 xmlNodePtr old = NULL;
4321
4322 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004323 if (root == NULL)
4324 return(NULL);
4325 xmlUnlinkNode(root);
4326 root->doc = doc;
4327 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004328 old = doc->children;
4329 while (old != NULL) {
4330 if (old->type == XML_ELEMENT_NODE)
4331 break;
4332 old = old->next;
4333 }
4334 if (old == NULL) {
4335 if (doc->children == NULL) {
4336 doc->children = root;
4337 doc->last = root;
4338 } else {
4339 xmlAddSibling(doc->children, root);
4340 }
4341 } else {
4342 xmlReplaceNode(old, root);
4343 }
4344 return(old);
4345}
4346
4347/**
4348 * xmlNodeSetLang:
4349 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004350 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004351 *
4352 * Set the language of a node, i.e. the values of the xml:lang
4353 * attribute.
4354 */
4355void
4356xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004357 xmlNsPtr ns;
4358
Owen Taylor3473f882001-02-23 17:55:21 +00004359 if (cur == NULL) return;
4360 switch(cur->type) {
4361 case XML_TEXT_NODE:
4362 case XML_CDATA_SECTION_NODE:
4363 case XML_COMMENT_NODE:
4364 case XML_DOCUMENT_NODE:
4365 case XML_DOCUMENT_TYPE_NODE:
4366 case XML_DOCUMENT_FRAG_NODE:
4367 case XML_NOTATION_NODE:
4368 case XML_HTML_DOCUMENT_NODE:
4369 case XML_DTD_NODE:
4370 case XML_ELEMENT_DECL:
4371 case XML_ATTRIBUTE_DECL:
4372 case XML_ENTITY_DECL:
4373 case XML_PI_NODE:
4374 case XML_ENTITY_REF_NODE:
4375 case XML_ENTITY_NODE:
4376 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004377#ifdef LIBXML_DOCB_ENABLED
4378 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004379#endif
4380 case XML_XINCLUDE_START:
4381 case XML_XINCLUDE_END:
4382 return;
4383 case XML_ELEMENT_NODE:
4384 case XML_ATTRIBUTE_NODE:
4385 break;
4386 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004387 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4388 if (ns == NULL)
4389 return;
4390 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004391}
4392
4393/**
4394 * xmlNodeGetLang:
4395 * @cur: the node being checked
4396 *
4397 * Searches the language of a node, i.e. the values of the xml:lang
4398 * attribute or the one carried by the nearest ancestor.
4399 *
4400 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004401 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004402 */
4403xmlChar *
4404xmlNodeGetLang(xmlNodePtr cur) {
4405 xmlChar *lang;
4406
4407 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004408 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004409 if (lang != NULL)
4410 return(lang);
4411 cur = cur->parent;
4412 }
4413 return(NULL);
4414}
4415
4416
4417/**
4418 * xmlNodeSetSpacePreserve:
4419 * @cur: the node being changed
4420 * @val: the xml:space value ("0": default, 1: "preserve")
4421 *
4422 * Set (or reset) the space preserving behaviour of a node, i.e. the
4423 * value of the xml:space attribute.
4424 */
4425void
4426xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004427 xmlNsPtr ns;
4428
Owen Taylor3473f882001-02-23 17:55:21 +00004429 if (cur == NULL) return;
4430 switch(cur->type) {
4431 case XML_TEXT_NODE:
4432 case XML_CDATA_SECTION_NODE:
4433 case XML_COMMENT_NODE:
4434 case XML_DOCUMENT_NODE:
4435 case XML_DOCUMENT_TYPE_NODE:
4436 case XML_DOCUMENT_FRAG_NODE:
4437 case XML_NOTATION_NODE:
4438 case XML_HTML_DOCUMENT_NODE:
4439 case XML_DTD_NODE:
4440 case XML_ELEMENT_DECL:
4441 case XML_ATTRIBUTE_DECL:
4442 case XML_ENTITY_DECL:
4443 case XML_PI_NODE:
4444 case XML_ENTITY_REF_NODE:
4445 case XML_ENTITY_NODE:
4446 case XML_NAMESPACE_DECL:
4447 case XML_XINCLUDE_START:
4448 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004449#ifdef LIBXML_DOCB_ENABLED
4450 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004451#endif
4452 return;
4453 case XML_ELEMENT_NODE:
4454 case XML_ATTRIBUTE_NODE:
4455 break;
4456 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004457 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4458 if (ns == NULL)
4459 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004460 switch (val) {
4461 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004462 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004463 break;
4464 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004465 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004466 break;
4467 }
4468}
4469
4470/**
4471 * xmlNodeGetSpacePreserve:
4472 * @cur: the node being checked
4473 *
4474 * Searches the space preserving behaviour of a node, i.e. the values
4475 * of the xml:space attribute or the one carried by the nearest
4476 * ancestor.
4477 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004478 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004479 */
4480int
4481xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4482 xmlChar *space;
4483
4484 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004485 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004486 if (space != NULL) {
4487 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4488 xmlFree(space);
4489 return(1);
4490 }
4491 if (xmlStrEqual(space, BAD_CAST "default")) {
4492 xmlFree(space);
4493 return(0);
4494 }
4495 xmlFree(space);
4496 }
4497 cur = cur->parent;
4498 }
4499 return(-1);
4500}
4501
4502/**
4503 * xmlNodeSetName:
4504 * @cur: the node being changed
4505 * @name: the new tag name
4506 *
4507 * Set (or reset) the name of a node.
4508 */
4509void
4510xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
4511 if (cur == NULL) return;
4512 if (name == NULL) return;
4513 switch(cur->type) {
4514 case XML_TEXT_NODE:
4515 case XML_CDATA_SECTION_NODE:
4516 case XML_COMMENT_NODE:
4517 case XML_DOCUMENT_TYPE_NODE:
4518 case XML_DOCUMENT_FRAG_NODE:
4519 case XML_NOTATION_NODE:
4520 case XML_HTML_DOCUMENT_NODE:
4521 case XML_NAMESPACE_DECL:
4522 case XML_XINCLUDE_START:
4523 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004524#ifdef LIBXML_DOCB_ENABLED
4525 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004526#endif
4527 return;
4528 case XML_ELEMENT_NODE:
4529 case XML_ATTRIBUTE_NODE:
4530 case XML_PI_NODE:
4531 case XML_ENTITY_REF_NODE:
4532 case XML_ENTITY_NODE:
4533 case XML_DTD_NODE:
4534 case XML_DOCUMENT_NODE:
4535 case XML_ELEMENT_DECL:
4536 case XML_ATTRIBUTE_DECL:
4537 case XML_ENTITY_DECL:
4538 break;
4539 }
4540 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4541 cur->name = xmlStrdup(name);
4542}
4543
4544/**
4545 * xmlNodeSetBase:
4546 * @cur: the node being changed
4547 * @uri: the new base URI
4548 *
4549 * Set (or reset) the base URI of a node, i.e. the value of the
4550 * xml:base attribute.
4551 */
4552void
4553xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004554 xmlNsPtr ns;
4555
Owen Taylor3473f882001-02-23 17:55:21 +00004556 if (cur == NULL) return;
4557 switch(cur->type) {
4558 case XML_TEXT_NODE:
4559 case XML_CDATA_SECTION_NODE:
4560 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004561 case XML_DOCUMENT_TYPE_NODE:
4562 case XML_DOCUMENT_FRAG_NODE:
4563 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004564 case XML_DTD_NODE:
4565 case XML_ELEMENT_DECL:
4566 case XML_ATTRIBUTE_DECL:
4567 case XML_ENTITY_DECL:
4568 case XML_PI_NODE:
4569 case XML_ENTITY_REF_NODE:
4570 case XML_ENTITY_NODE:
4571 case XML_NAMESPACE_DECL:
4572 case XML_XINCLUDE_START:
4573 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004574 return;
4575 case XML_ELEMENT_NODE:
4576 case XML_ATTRIBUTE_NODE:
4577 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004578 case XML_DOCUMENT_NODE:
4579#ifdef LIBXML_DOCB_ENABLED
4580 case XML_DOCB_DOCUMENT_NODE:
4581#endif
4582 case XML_HTML_DOCUMENT_NODE: {
4583 xmlDocPtr doc = (xmlDocPtr) cur;
4584
4585 if (doc->URL != NULL)
4586 xmlFree((xmlChar *) doc->URL);
4587 if (uri == NULL)
4588 doc->URL = NULL;
4589 else
4590 doc->URL = xmlStrdup(uri);
4591 return;
4592 }
Owen Taylor3473f882001-02-23 17:55:21 +00004593 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004594
4595 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4596 if (ns == NULL)
4597 return;
4598 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004599}
4600
4601/**
Owen Taylor3473f882001-02-23 17:55:21 +00004602 * xmlNodeGetBase:
4603 * @doc: the document the node pertains to
4604 * @cur: the node being checked
4605 *
4606 * Searches for the BASE URL. The code should work on both XML
4607 * and HTML document even if base mechanisms are completely different.
4608 * It returns the base as defined in RFC 2396 sections
4609 * 5.1.1. Base URI within Document Content
4610 * and
4611 * 5.1.2. Base URI from the Encapsulating Entity
4612 * However it does not return the document base (5.1.3), use
4613 * xmlDocumentGetBase() for this
4614 *
4615 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004616 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004617 */
4618xmlChar *
4619xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004620 xmlChar *oldbase = NULL;
4621 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004622
4623 if ((cur == NULL) && (doc == NULL))
4624 return(NULL);
4625 if (doc == NULL) doc = cur->doc;
4626 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4627 cur = doc->children;
4628 while ((cur != NULL) && (cur->name != NULL)) {
4629 if (cur->type != XML_ELEMENT_NODE) {
4630 cur = cur->next;
4631 continue;
4632 }
4633 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4634 cur = cur->children;
4635 continue;
4636 }
4637 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4638 cur = cur->children;
4639 continue;
4640 }
4641 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4642 return(xmlGetProp(cur, BAD_CAST "href"));
4643 }
4644 cur = cur->next;
4645 }
4646 return(NULL);
4647 }
4648 while (cur != NULL) {
4649 if (cur->type == XML_ENTITY_DECL) {
4650 xmlEntityPtr ent = (xmlEntityPtr) cur;
4651 return(xmlStrdup(ent->URI));
4652 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004653 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004654 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004655 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004656 if (oldbase != NULL) {
4657 newbase = xmlBuildURI(oldbase, base);
4658 if (newbase != NULL) {
4659 xmlFree(oldbase);
4660 xmlFree(base);
4661 oldbase = newbase;
4662 } else {
4663 xmlFree(oldbase);
4664 xmlFree(base);
4665 return(NULL);
4666 }
4667 } else {
4668 oldbase = base;
4669 }
4670 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4671 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4672 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4673 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004674 }
4675 }
Owen Taylor3473f882001-02-23 17:55:21 +00004676 cur = cur->parent;
4677 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004678 if ((doc != NULL) && (doc->URL != NULL)) {
4679 if (oldbase == NULL)
4680 return(xmlStrdup(doc->URL));
4681 newbase = xmlBuildURI(oldbase, doc->URL);
4682 xmlFree(oldbase);
4683 return(newbase);
4684 }
4685 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004686}
4687
4688/**
4689 * xmlNodeGetContent:
4690 * @cur: the node being read
4691 *
4692 * Read the value of a node, this can be either the text carried
4693 * directly by this node if it's a TEXT node or the aggregate string
4694 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004695 * Entity references are substituted.
4696 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004697 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004698 */
4699xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004700xmlNodeGetContent(xmlNodePtr cur)
4701{
4702 if (cur == NULL)
4703 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004704 switch (cur->type) {
4705 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004706 case XML_ELEMENT_NODE:{
4707 xmlNodePtr tmp = cur;
4708 xmlBufferPtr buffer;
4709 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004710
Daniel Veillard814a76d2003-01-23 18:24:20 +00004711 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004712 if (buffer == NULL)
4713 return (NULL);
4714 while (tmp != NULL) {
4715 switch (tmp->type) {
4716 case XML_CDATA_SECTION_NODE:
4717 case XML_TEXT_NODE:
4718 if (tmp->content != NULL)
4719 xmlBufferCat(buffer, tmp->content);
4720 break;
4721 case XML_ENTITY_REF_NODE:{
4722 /* recursive substitution of entity references */
4723 xmlChar *cont = xmlNodeGetContent(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00004724
Daniel Veillard7646b182002-04-20 06:41:40 +00004725 if (cont) {
4726 xmlBufferCat(buffer,
4727 (const xmlChar *) cont);
4728 xmlFree(cont);
4729 }
4730 break;
4731 }
4732 default:
4733 break;
4734 }
4735 /*
4736 * Skip to next node
4737 */
4738 if (tmp->children != NULL) {
4739 if (tmp->children->type != XML_ENTITY_DECL) {
4740 tmp = tmp->children;
4741 continue;
4742 }
4743 }
4744 if (tmp == cur)
4745 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00004746
Daniel Veillard7646b182002-04-20 06:41:40 +00004747 if (tmp->next != NULL) {
4748 tmp = tmp->next;
4749 continue;
4750 }
4751
4752 do {
4753 tmp = tmp->parent;
4754 if (tmp == NULL)
4755 break;
4756 if (tmp == cur) {
4757 tmp = NULL;
4758 break;
4759 }
4760 if (tmp->next != NULL) {
4761 tmp = tmp->next;
4762 break;
4763 }
4764 } while (tmp != NULL);
4765 }
4766 ret = buffer->content;
4767 buffer->content = NULL;
4768 xmlBufferFree(buffer);
4769 return (ret);
4770 }
4771 case XML_ATTRIBUTE_NODE:{
4772 xmlAttrPtr attr = (xmlAttrPtr) cur;
4773
4774 if (attr->parent != NULL)
4775 return (xmlNodeListGetString
4776 (attr->parent->doc, attr->children, 1));
4777 else
4778 return (xmlNodeListGetString(NULL, attr->children, 1));
4779 break;
4780 }
Owen Taylor3473f882001-02-23 17:55:21 +00004781 case XML_COMMENT_NODE:
4782 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004783 if (cur->content != NULL)
4784 return (xmlStrdup(cur->content));
4785 return (NULL);
4786 case XML_ENTITY_REF_NODE:{
4787 xmlEntityPtr ent;
4788 xmlNodePtr tmp;
4789 xmlBufferPtr buffer;
4790 xmlChar *ret;
4791
4792 /* lookup entity declaration */
4793 ent = xmlGetDocEntity(cur->doc, cur->name);
4794 if (ent == NULL)
4795 return (NULL);
4796
4797 buffer = xmlBufferCreate();
4798 if (buffer == NULL)
4799 return (NULL);
4800
4801 /* an entity content can be any "well balanced chunk",
4802 * i.e. the result of the content [43] production:
4803 * http://www.w3.org/TR/REC-xml#NT-content
4804 * -> we iterate through child nodes and recursive call
4805 * xmlNodeGetContent() which handles all possible node types */
4806 tmp = ent->children;
4807 while (tmp) {
4808 xmlChar *cont = xmlNodeGetContent(tmp);
4809
4810 if (cont) {
4811 xmlBufferCat(buffer, (const xmlChar *) cont);
4812 xmlFree(cont);
4813 }
4814 tmp = tmp->next;
4815 }
4816
4817 ret = buffer->content;
4818 buffer->content = NULL;
4819 xmlBufferFree(buffer);
4820 return (ret);
4821 }
Owen Taylor3473f882001-02-23 17:55:21 +00004822 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004823 case XML_DOCUMENT_TYPE_NODE:
4824 case XML_NOTATION_NODE:
4825 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004826 case XML_XINCLUDE_START:
4827 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00004828 return (NULL);
4829 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004830#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004831 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004832#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00004833 case XML_HTML_DOCUMENT_NODE: {
4834 xmlChar *tmp;
4835 xmlChar *res = NULL;
4836
4837 cur = cur->children;
4838 while (cur!= NULL) {
4839 if ((cur->type == XML_ELEMENT_NODE) ||
4840 (cur->type == XML_TEXT_NODE) ||
4841 (cur->type == XML_CDATA_SECTION_NODE)) {
4842 tmp = xmlNodeGetContent(cur);
4843 if (tmp != NULL) {
4844 if (res == NULL)
4845 res = tmp;
4846 else {
4847 res = xmlStrcat(res, tmp);
4848 xmlFree(tmp);
4849 }
4850 }
4851 }
4852 cur = cur->next;
4853 }
4854 return(res);
4855 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004856 case XML_NAMESPACE_DECL: {
4857 xmlChar *tmp;
4858
4859 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4860 return (tmp);
4861 }
Owen Taylor3473f882001-02-23 17:55:21 +00004862 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004863 /* TODO !!! */
4864 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004865 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004866 /* TODO !!! */
4867 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004868 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004869 /* TODO !!! */
4870 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004871 case XML_CDATA_SECTION_NODE:
4872 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004873 if (cur->content != NULL)
4874 return (xmlStrdup(cur->content));
4875 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004876 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004877 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004878}
Owen Taylor3473f882001-02-23 17:55:21 +00004879/**
4880 * xmlNodeSetContent:
4881 * @cur: the node being modified
4882 * @content: the new value of the content
4883 *
4884 * Replace the content of a node.
4885 */
4886void
4887xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4888 if (cur == NULL) {
4889#ifdef DEBUG_TREE
4890 xmlGenericError(xmlGenericErrorContext,
4891 "xmlNodeSetContent : node == NULL\n");
4892#endif
4893 return;
4894 }
4895 switch (cur->type) {
4896 case XML_DOCUMENT_FRAG_NODE:
4897 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004898 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004899 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4900 cur->children = xmlStringGetNodeList(cur->doc, content);
4901 UPDATE_LAST_CHILD_AND_PARENT(cur)
4902 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004903 case XML_TEXT_NODE:
4904 case XML_CDATA_SECTION_NODE:
4905 case XML_ENTITY_REF_NODE:
4906 case XML_ENTITY_NODE:
4907 case XML_PI_NODE:
4908 case XML_COMMENT_NODE:
4909 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004910 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004911 }
4912 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4913 cur->last = cur->children = NULL;
4914 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004915 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00004916 } else
4917 cur->content = NULL;
4918 break;
4919 case XML_DOCUMENT_NODE:
4920 case XML_HTML_DOCUMENT_NODE:
4921 case XML_DOCUMENT_TYPE_NODE:
4922 case XML_XINCLUDE_START:
4923 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004924#ifdef LIBXML_DOCB_ENABLED
4925 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004926#endif
4927 break;
4928 case XML_NOTATION_NODE:
4929 break;
4930 case XML_DTD_NODE:
4931 break;
4932 case XML_NAMESPACE_DECL:
4933 break;
4934 case XML_ELEMENT_DECL:
4935 /* TODO !!! */
4936 break;
4937 case XML_ATTRIBUTE_DECL:
4938 /* TODO !!! */
4939 break;
4940 case XML_ENTITY_DECL:
4941 /* TODO !!! */
4942 break;
4943 }
4944}
4945
4946/**
4947 * xmlNodeSetContentLen:
4948 * @cur: the node being modified
4949 * @content: the new value of the content
4950 * @len: the size of @content
4951 *
4952 * Replace the content of a node.
4953 */
4954void
4955xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4956 if (cur == NULL) {
4957#ifdef DEBUG_TREE
4958 xmlGenericError(xmlGenericErrorContext,
4959 "xmlNodeSetContentLen : node == NULL\n");
4960#endif
4961 return;
4962 }
4963 switch (cur->type) {
4964 case XML_DOCUMENT_FRAG_NODE:
4965 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004966 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004967 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4968 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
4969 UPDATE_LAST_CHILD_AND_PARENT(cur)
4970 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004971 case XML_TEXT_NODE:
4972 case XML_CDATA_SECTION_NODE:
4973 case XML_ENTITY_REF_NODE:
4974 case XML_ENTITY_NODE:
4975 case XML_PI_NODE:
4976 case XML_COMMENT_NODE:
4977 case XML_NOTATION_NODE:
4978 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004979 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004980 }
4981 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4982 cur->children = cur->last = NULL;
4983 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004984 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004985 } else
4986 cur->content = NULL;
4987 break;
4988 case XML_DOCUMENT_NODE:
4989 case XML_DTD_NODE:
4990 case XML_HTML_DOCUMENT_NODE:
4991 case XML_DOCUMENT_TYPE_NODE:
4992 case XML_NAMESPACE_DECL:
4993 case XML_XINCLUDE_START:
4994 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004995#ifdef LIBXML_DOCB_ENABLED
4996 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004997#endif
4998 break;
4999 case XML_ELEMENT_DECL:
5000 /* TODO !!! */
5001 break;
5002 case XML_ATTRIBUTE_DECL:
5003 /* TODO !!! */
5004 break;
5005 case XML_ENTITY_DECL:
5006 /* TODO !!! */
5007 break;
5008 }
5009}
5010
5011/**
5012 * xmlNodeAddContentLen:
5013 * @cur: the node being modified
5014 * @content: extra content
5015 * @len: the size of @content
5016 *
5017 * Append the extra substring to the node content.
5018 */
5019void
5020xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5021 if (cur == NULL) {
5022#ifdef DEBUG_TREE
5023 xmlGenericError(xmlGenericErrorContext,
5024 "xmlNodeAddContentLen : node == NULL\n");
5025#endif
5026 return;
5027 }
5028 if (len <= 0) return;
5029 switch (cur->type) {
5030 case XML_DOCUMENT_FRAG_NODE:
5031 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005032 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005033
Daniel Veillard7db37732001-07-12 01:20:08 +00005034 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005035 newNode = xmlNewTextLen(content, len);
5036 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005037 tmp = xmlAddChild(cur, newNode);
5038 if (tmp != newNode)
5039 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005040 if ((last != NULL) && (last->next == newNode)) {
5041 xmlTextMerge(last, newNode);
5042 }
5043 }
5044 break;
5045 }
5046 case XML_ATTRIBUTE_NODE:
5047 break;
5048 case XML_TEXT_NODE:
5049 case XML_CDATA_SECTION_NODE:
5050 case XML_ENTITY_REF_NODE:
5051 case XML_ENTITY_NODE:
5052 case XML_PI_NODE:
5053 case XML_COMMENT_NODE:
5054 case XML_NOTATION_NODE:
5055 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005056 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005057 }
5058 case XML_DOCUMENT_NODE:
5059 case XML_DTD_NODE:
5060 case XML_HTML_DOCUMENT_NODE:
5061 case XML_DOCUMENT_TYPE_NODE:
5062 case XML_NAMESPACE_DECL:
5063 case XML_XINCLUDE_START:
5064 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005065#ifdef LIBXML_DOCB_ENABLED
5066 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005067#endif
5068 break;
5069 case XML_ELEMENT_DECL:
5070 case XML_ATTRIBUTE_DECL:
5071 case XML_ENTITY_DECL:
5072 break;
5073 }
5074}
5075
5076/**
5077 * xmlNodeAddContent:
5078 * @cur: the node being modified
5079 * @content: extra content
5080 *
5081 * Append the extra substring to the node content.
5082 */
5083void
5084xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5085 int len;
5086
5087 if (cur == NULL) {
5088#ifdef DEBUG_TREE
5089 xmlGenericError(xmlGenericErrorContext,
5090 "xmlNodeAddContent : node == NULL\n");
5091#endif
5092 return;
5093 }
5094 if (content == NULL) return;
5095 len = xmlStrlen(content);
5096 xmlNodeAddContentLen(cur, content, len);
5097}
5098
5099/**
5100 * xmlTextMerge:
5101 * @first: the first text node
5102 * @second: the second text node being merged
5103 *
5104 * Merge two text nodes into one
5105 * Returns the first text node augmented
5106 */
5107xmlNodePtr
5108xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5109 if (first == NULL) return(second);
5110 if (second == NULL) return(first);
5111 if (first->type != XML_TEXT_NODE) return(first);
5112 if (second->type != XML_TEXT_NODE) return(first);
5113 if (second->name != first->name)
5114 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005115 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005116 xmlUnlinkNode(second);
5117 xmlFreeNode(second);
5118 return(first);
5119}
5120
5121/**
5122 * xmlGetNsList:
5123 * @doc: the document
5124 * @node: the current node
5125 *
5126 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005127 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005128 * that need to be freed by the caller or NULL if no
5129 * namespace if defined
5130 */
5131xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005132xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5133{
Owen Taylor3473f882001-02-23 17:55:21 +00005134 xmlNsPtr cur;
5135 xmlNsPtr *ret = NULL;
5136 int nbns = 0;
5137 int maxns = 10;
5138 int i;
5139
5140 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005141 if (node->type == XML_ELEMENT_NODE) {
5142 cur = node->nsDef;
5143 while (cur != NULL) {
5144 if (ret == NULL) {
5145 ret =
5146 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5147 sizeof(xmlNsPtr));
5148 if (ret == NULL) {
5149 xmlGenericError(xmlGenericErrorContext,
5150 "xmlGetNsList : out of memory!\n");
5151 return (NULL);
5152 }
5153 ret[nbns] = NULL;
5154 }
5155 for (i = 0; i < nbns; i++) {
5156 if ((cur->prefix == ret[i]->prefix) ||
5157 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5158 break;
5159 }
5160 if (i >= nbns) {
5161 if (nbns >= maxns) {
5162 maxns *= 2;
5163 ret = (xmlNsPtr *) xmlRealloc(ret,
5164 (maxns +
5165 1) *
5166 sizeof(xmlNsPtr));
5167 if (ret == NULL) {
5168 xmlGenericError(xmlGenericErrorContext,
5169 "xmlGetNsList : realloc failed!\n");
5170 return (NULL);
5171 }
5172 }
5173 ret[nbns++] = cur;
5174 ret[nbns] = NULL;
5175 }
Owen Taylor3473f882001-02-23 17:55:21 +00005176
Daniel Veillard77044732001-06-29 21:31:07 +00005177 cur = cur->next;
5178 }
5179 }
5180 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005181 }
Daniel Veillard77044732001-06-29 21:31:07 +00005182 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005183}
5184
5185/**
5186 * xmlSearchNs:
5187 * @doc: the document
5188 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005189 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005190 *
5191 * Search a Ns registered under a given name space for a document.
5192 * recurse on the parents until it finds the defined namespace
5193 * or return NULL otherwise.
5194 * @nameSpace can be NULL, this is a search for the default namespace.
5195 * We don't allow to cross entities boundaries. If you don't declare
5196 * the namespace within those you will be in troubles !!! A warning
5197 * is generated to cover this case.
5198 *
5199 * Returns the namespace pointer or NULL.
5200 */
5201xmlNsPtr
5202xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
5203 xmlNsPtr cur;
5204
5205 if (node == NULL) return(NULL);
5206 if ((nameSpace != NULL) &&
5207 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005208 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5209 /*
5210 * The XML-1.0 namespace is normally held on the root
5211 * element. In this case exceptionally create it on the
5212 * node element.
5213 */
5214 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5215 if (cur == NULL) {
5216 xmlGenericError(xmlGenericErrorContext,
5217 "xmlSearchNs : malloc failed\n");
5218 return(NULL);
5219 }
5220 memset(cur, 0, sizeof(xmlNs));
5221 cur->type = XML_LOCAL_NAMESPACE;
5222 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5223 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5224 cur->next = node->nsDef;
5225 node->nsDef = cur;
5226 return(cur);
5227 }
Owen Taylor3473f882001-02-23 17:55:21 +00005228 if (doc->oldNs == NULL) {
5229 /*
5230 * Allocate a new Namespace and fill the fields.
5231 */
5232 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5233 if (doc->oldNs == NULL) {
5234 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005235 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005236 return(NULL);
5237 }
5238 memset(doc->oldNs, 0, sizeof(xmlNs));
5239 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5240
5241 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5242 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5243 }
5244 return(doc->oldNs);
5245 }
5246 while (node != NULL) {
5247 if ((node->type == XML_ENTITY_REF_NODE) ||
5248 (node->type == XML_ENTITY_NODE) ||
5249 (node->type == XML_ENTITY_DECL))
5250 return(NULL);
5251 if (node->type == XML_ELEMENT_NODE) {
5252 cur = node->nsDef;
5253 while (cur != NULL) {
5254 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5255 (cur->href != NULL))
5256 return(cur);
5257 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5258 (cur->href != NULL) &&
5259 (xmlStrEqual(cur->prefix, nameSpace)))
5260 return(cur);
5261 cur = cur->next;
5262 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005263 cur = node->ns;
5264 if (cur != NULL) {
5265 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5266 (cur->href != NULL))
5267 return(cur);
5268 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5269 (cur->href != NULL) &&
5270 (xmlStrEqual(cur->prefix, nameSpace)))
5271 return(cur);
5272 }
Owen Taylor3473f882001-02-23 17:55:21 +00005273 }
5274 node = node->parent;
5275 }
5276 return(NULL);
5277}
5278
5279/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005280 * xmlNsInScope:
5281 * @doc: the document
5282 * @node: the current node
5283 * @ancestor: the ancestor carrying the namespace
5284 * @prefix: the namespace prefix
5285 *
5286 * Verify that the given namespace held on @ancestor is still in scope
5287 * on node.
5288 *
5289 * Returns 1 if true, 0 if false and -1 in case of error.
5290 */
5291static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005292xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5293 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005294{
5295 xmlNsPtr tst;
5296
5297 while ((node != NULL) && (node != ancestor)) {
5298 if ((node->type == XML_ENTITY_REF_NODE) ||
5299 (node->type == XML_ENTITY_NODE) ||
5300 (node->type == XML_ENTITY_DECL))
5301 return (-1);
5302 if (node->type == XML_ELEMENT_NODE) {
5303 tst = node->nsDef;
5304 while (tst != NULL) {
5305 if ((tst->prefix == NULL)
5306 && (prefix == NULL))
5307 return (0);
5308 if ((tst->prefix != NULL)
5309 && (prefix != NULL)
5310 && (xmlStrEqual(tst->prefix, prefix)))
5311 return (0);
5312 tst = tst->next;
5313 }
5314 }
5315 node = node->parent;
5316 }
5317 if (node != ancestor)
5318 return (-1);
5319 return (1);
5320}
5321
5322
5323/**
Owen Taylor3473f882001-02-23 17:55:21 +00005324 * xmlSearchNsByHref:
5325 * @doc: the document
5326 * @node: the current node
5327 * @href: the namespace value
5328 *
5329 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5330 * the defined namespace or return NULL otherwise.
5331 * Returns the namespace pointer or NULL.
5332 */
5333xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005334xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5335{
Owen Taylor3473f882001-02-23 17:55:21 +00005336 xmlNsPtr cur;
5337 xmlNodePtr orig = node;
5338
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005339 if ((node == NULL) || (href == NULL))
5340 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005341 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005342 /*
5343 * Only the document can hold the XML spec namespace.
5344 */
5345 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5346 /*
5347 * The XML-1.0 namespace is normally held on the root
5348 * element. In this case exceptionally create it on the
5349 * node element.
5350 */
5351 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5352 if (cur == NULL) {
5353 xmlGenericError(xmlGenericErrorContext,
5354 "xmlSearchNs : malloc failed\n");
5355 return (NULL);
5356 }
5357 memset(cur, 0, sizeof(xmlNs));
5358 cur->type = XML_LOCAL_NAMESPACE;
5359 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5360 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5361 cur->next = node->nsDef;
5362 node->nsDef = cur;
5363 return (cur);
5364 }
5365 if (doc->oldNs == NULL) {
5366 /*
5367 * Allocate a new Namespace and fill the fields.
5368 */
5369 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5370 if (doc->oldNs == NULL) {
5371 xmlGenericError(xmlGenericErrorContext,
5372 "xmlSearchNsByHref : malloc failed\n");
5373 return (NULL);
5374 }
5375 memset(doc->oldNs, 0, sizeof(xmlNs));
5376 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005377
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005378 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5379 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5380 }
5381 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005382 }
5383 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005384 if ((node->type == XML_ENTITY_REF_NODE) ||
5385 (node->type == XML_ENTITY_NODE) ||
5386 (node->type == XML_ENTITY_DECL))
5387 return (NULL);
5388 if (node->type == XML_ELEMENT_NODE) {
5389 cur = node->nsDef;
5390 while (cur != NULL) {
5391 if ((cur->href != NULL) && (href != NULL) &&
5392 (xmlStrEqual(cur->href, href))) {
5393 if (xmlNsInScope(doc, orig, node, cur->href) == 1)
5394 return (cur);
5395 }
5396 cur = cur->next;
5397 }
5398 cur = node->ns;
5399 if (cur != NULL) {
5400 if ((cur->href != NULL) && (href != NULL) &&
5401 (xmlStrEqual(cur->href, href))) {
5402 if (xmlNsInScope(doc, orig, node, cur->href) == 1)
5403 return (cur);
5404 }
5405 }
5406 }
5407 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005408 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005409 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005410}
5411
5412/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005413 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005414 * @doc: the document
5415 * @tree: a node expected to hold the new namespace
5416 * @ns: the original namespace
5417 *
5418 * This function tries to locate a namespace definition in a tree
5419 * ancestors, or create a new namespace definition node similar to
5420 * @ns trying to reuse the same prefix. However if the given prefix is
5421 * null (default namespace) or reused within the subtree defined by
5422 * @tree or on one of its ancestors then a new prefix is generated.
5423 * Returns the (new) namespace definition or NULL in case of error
5424 */
5425xmlNsPtr
5426xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5427 xmlNsPtr def;
5428 xmlChar prefix[50];
5429 int counter = 1;
5430
5431 if (tree == NULL) {
5432#ifdef DEBUG_TREE
5433 xmlGenericError(xmlGenericErrorContext,
5434 "xmlNewReconciliedNs : tree == NULL\n");
5435#endif
5436 return(NULL);
5437 }
5438 if (ns == NULL) {
5439#ifdef DEBUG_TREE
5440 xmlGenericError(xmlGenericErrorContext,
5441 "xmlNewReconciliedNs : ns == NULL\n");
5442#endif
5443 return(NULL);
5444 }
5445 /*
5446 * Search an existing namespace definition inherited.
5447 */
5448 def = xmlSearchNsByHref(doc, tree, ns->href);
5449 if (def != NULL)
5450 return(def);
5451
5452 /*
5453 * Find a close prefix which is not already in use.
5454 * Let's strip namespace prefixes longer than 20 chars !
5455 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005456 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005457 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005458 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005459 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005460
Owen Taylor3473f882001-02-23 17:55:21 +00005461 def = xmlSearchNs(doc, tree, prefix);
5462 while (def != NULL) {
5463 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005464 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005465 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005466 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005467 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005468 def = xmlSearchNs(doc, tree, prefix);
5469 }
5470
5471 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005472 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005473 */
5474 def = xmlNewNs(tree, ns->href, prefix);
5475 return(def);
5476}
5477
5478/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005479 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005480 * @doc: the document
5481 * @tree: a node defining the subtree to reconciliate
5482 *
5483 * This function checks that all the namespaces declared within the given
5484 * tree are properly declared. This is needed for example after Copy or Cut
5485 * and then paste operations. The subtree may still hold pointers to
5486 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005487 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005488 * the new environment. If not possible the new namespaces are redeclared
5489 * on @tree at the top of the given subtree.
5490 * Returns the number of namespace declarations created or -1 in case of error.
5491 */
5492int
5493xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5494 xmlNsPtr *oldNs = NULL;
5495 xmlNsPtr *newNs = NULL;
5496 int sizeCache = 0;
5497 int nbCache = 0;
5498
5499 xmlNsPtr n;
5500 xmlNodePtr node = tree;
5501 xmlAttrPtr attr;
5502 int ret = 0, i;
5503
5504 while (node != NULL) {
5505 /*
5506 * Reconciliate the node namespace
5507 */
5508 if (node->ns != NULL) {
5509 /*
5510 * initialize the cache if needed
5511 */
5512 if (sizeCache == 0) {
5513 sizeCache = 10;
5514 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5515 sizeof(xmlNsPtr));
5516 if (oldNs == NULL) {
5517 xmlGenericError(xmlGenericErrorContext,
5518 "xmlReconciliateNs : memory pbm\n");
5519 return(-1);
5520 }
5521 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5522 sizeof(xmlNsPtr));
5523 if (newNs == NULL) {
5524 xmlGenericError(xmlGenericErrorContext,
5525 "xmlReconciliateNs : memory pbm\n");
5526 xmlFree(oldNs);
5527 return(-1);
5528 }
5529 }
5530 for (i = 0;i < nbCache;i++) {
5531 if (oldNs[i] == node->ns) {
5532 node->ns = newNs[i];
5533 break;
5534 }
5535 }
5536 if (i == nbCache) {
5537 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005538 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005539 */
5540 n = xmlNewReconciliedNs(doc, tree, node->ns);
5541 if (n != NULL) { /* :-( what if else ??? */
5542 /*
5543 * check if we need to grow the cache buffers.
5544 */
5545 if (sizeCache <= nbCache) {
5546 sizeCache *= 2;
5547 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5548 sizeof(xmlNsPtr));
5549 if (oldNs == NULL) {
5550 xmlGenericError(xmlGenericErrorContext,
5551 "xmlReconciliateNs : memory pbm\n");
5552 xmlFree(newNs);
5553 return(-1);
5554 }
5555 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5556 sizeof(xmlNsPtr));
5557 if (newNs == NULL) {
5558 xmlGenericError(xmlGenericErrorContext,
5559 "xmlReconciliateNs : memory pbm\n");
5560 xmlFree(oldNs);
5561 return(-1);
5562 }
5563 }
5564 newNs[nbCache] = n;
5565 oldNs[nbCache++] = node->ns;
5566 node->ns = n;
5567 }
5568 }
5569 }
5570 /*
5571 * now check for namespace hold by attributes on the node.
5572 */
5573 attr = node->properties;
5574 while (attr != NULL) {
5575 if (attr->ns != NULL) {
5576 /*
5577 * initialize the cache if needed
5578 */
5579 if (sizeCache == 0) {
5580 sizeCache = 10;
5581 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5582 sizeof(xmlNsPtr));
5583 if (oldNs == NULL) {
5584 xmlGenericError(xmlGenericErrorContext,
5585 "xmlReconciliateNs : memory pbm\n");
5586 return(-1);
5587 }
5588 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5589 sizeof(xmlNsPtr));
5590 if (newNs == NULL) {
5591 xmlGenericError(xmlGenericErrorContext,
5592 "xmlReconciliateNs : memory pbm\n");
5593 xmlFree(oldNs);
5594 return(-1);
5595 }
5596 }
5597 for (i = 0;i < nbCache;i++) {
5598 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005599 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005600 break;
5601 }
5602 }
5603 if (i == nbCache) {
5604 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005605 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005606 */
5607 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5608 if (n != NULL) { /* :-( what if else ??? */
5609 /*
5610 * check if we need to grow the cache buffers.
5611 */
5612 if (sizeCache <= nbCache) {
5613 sizeCache *= 2;
5614 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5615 sizeof(xmlNsPtr));
5616 if (oldNs == NULL) {
5617 xmlGenericError(xmlGenericErrorContext,
5618 "xmlReconciliateNs : memory pbm\n");
5619 xmlFree(newNs);
5620 return(-1);
5621 }
5622 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5623 sizeof(xmlNsPtr));
5624 if (newNs == NULL) {
5625 xmlGenericError(xmlGenericErrorContext,
5626 "xmlReconciliateNs : memory pbm\n");
5627 xmlFree(oldNs);
5628 return(-1);
5629 }
5630 }
5631 newNs[nbCache] = n;
5632 oldNs[nbCache++] = attr->ns;
5633 attr->ns = n;
5634 }
5635 }
5636 }
5637 attr = attr->next;
5638 }
5639
5640 /*
5641 * Browse the full subtree, deep first
5642 */
5643 if (node->children != NULL) {
5644 /* deep first */
5645 node = node->children;
5646 } else if ((node != tree) && (node->next != NULL)) {
5647 /* then siblings */
5648 node = node->next;
5649 } else if (node != tree) {
5650 /* go up to parents->next if needed */
5651 while (node != tree) {
5652 if (node->parent != NULL)
5653 node = node->parent;
5654 if ((node != tree) && (node->next != NULL)) {
5655 node = node->next;
5656 break;
5657 }
5658 if (node->parent == NULL) {
5659 node = NULL;
5660 break;
5661 }
5662 }
5663 /* exit condition */
5664 if (node == tree)
5665 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005666 } else
5667 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005668 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005669 if (oldNs != NULL)
5670 xmlFree(oldNs);
5671 if (newNs != NULL)
5672 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005673 return(ret);
5674}
5675
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;
5744 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005745
5746 if (node == NULL)
5747 return(NULL);
5748
5749 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005750 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005751 return(xmlHasProp(node, name));
5752 while (prop != NULL) {
5753 /*
5754 * One need to have
5755 * - same attribute names
5756 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005757 */
5758 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005759 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5760 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005761 }
5762 prop = prop->next;
5763 }
5764 if (!xmlCheckDTD) return(NULL);
5765
5766 /*
5767 * Check if there is a default declaration in the internal
5768 * or external subsets
5769 */
5770 doc = node->doc;
5771 if (doc != NULL) {
5772 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005773 xmlAttributePtr attrDecl = NULL;
5774 xmlNsPtr *nsList, *cur;
5775 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005776
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005777 nsList = xmlGetNsList(node->doc, node);
5778 if (nsList == NULL)
5779 return(NULL);
5780 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5781 ename = xmlStrdup(node->ns->prefix);
5782 ename = xmlStrcat(ename, BAD_CAST ":");
5783 ename = xmlStrcat(ename, node->name);
5784 } else {
5785 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005786 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005787 if (ename == NULL) {
5788 xmlFree(nsList);
5789 return(NULL);
5790 }
5791
5792 cur = nsList;
5793 while (*cur != NULL) {
5794 if (xmlStrEqual((*cur)->href, nameSpace)) {
5795 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5796 name, (*cur)->prefix);
5797 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5798 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5799 name, (*cur)->prefix);
5800 }
5801 cur++;
5802 }
5803 xmlFree(nsList);
5804 xmlFree(ename);
5805 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005806 }
5807 }
5808 return(NULL);
5809}
5810
5811/**
Owen Taylor3473f882001-02-23 17:55:21 +00005812 * xmlGetProp:
5813 * @node: the node
5814 * @name: the attribute name
5815 *
5816 * Search and get the value of an attribute associated to a node
5817 * This does the entity substitution.
5818 * This function looks in DTD attribute declaration for #FIXED or
5819 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00005820 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00005821 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
5822 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00005823 *
5824 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005825 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005826 */
5827xmlChar *
5828xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5829 xmlAttrPtr prop;
5830 xmlDocPtr doc;
5831
5832 if ((node == NULL) || (name == NULL)) return(NULL);
5833 /*
5834 * Check on the properties attached to the node
5835 */
5836 prop = node->properties;
5837 while (prop != NULL) {
5838 if (xmlStrEqual(prop->name, name)) {
5839 xmlChar *ret;
5840
5841 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5842 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5843 return(ret);
5844 }
5845 prop = prop->next;
5846 }
5847 if (!xmlCheckDTD) return(NULL);
5848
5849 /*
5850 * Check if there is a default declaration in the internal
5851 * or external subsets
5852 */
5853 doc = node->doc;
5854 if (doc != NULL) {
5855 xmlAttributePtr attrDecl;
5856 if (doc->intSubset != NULL) {
5857 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5858 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5859 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005860 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5861 /* return attribute declaration only if a default value is given
5862 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005863 return(xmlStrdup(attrDecl->defaultValue));
5864 }
5865 }
5866 return(NULL);
5867}
5868
5869/**
Daniel Veillard71531f32003-02-05 13:19:53 +00005870 * xmlGetNoNsProp:
5871 * @node: the node
5872 * @name: the attribute name
5873 *
5874 * Search and get the value of an attribute associated to a node
5875 * This does the entity substitution.
5876 * This function looks in DTD attribute declaration for #FIXED or
5877 * default declaration values unless DTD use has been turned off.
5878 * This function is similar to xmlGetProp except it will accept only
5879 * an attribute in no namespace.
5880 *
5881 * Returns the attribute value or NULL if not found.
5882 * It's up to the caller to free the memory with xmlFree().
5883 */
5884xmlChar *
5885xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
5886 xmlAttrPtr prop;
5887 xmlDocPtr doc;
5888
5889 if ((node == NULL) || (name == NULL)) return(NULL);
5890 /*
5891 * Check on the properties attached to the node
5892 */
5893 prop = node->properties;
5894 while (prop != NULL) {
5895 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
5896 xmlChar *ret;
5897
5898 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5899 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5900 return(ret);
5901 }
5902 prop = prop->next;
5903 }
5904 if (!xmlCheckDTD) return(NULL);
5905
5906 /*
5907 * Check if there is a default declaration in the internal
5908 * or external subsets
5909 */
5910 doc = node->doc;
5911 if (doc != NULL) {
5912 xmlAttributePtr attrDecl;
5913 if (doc->intSubset != NULL) {
5914 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5915 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5916 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005917 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5918 /* return attribute declaration only if a default value is given
5919 (that includes #FIXED declarations) */
Daniel Veillard71531f32003-02-05 13:19:53 +00005920 return(xmlStrdup(attrDecl->defaultValue));
5921 }
5922 }
5923 return(NULL);
5924}
5925
5926/**
Owen Taylor3473f882001-02-23 17:55:21 +00005927 * xmlGetNsProp:
5928 * @node: the node
5929 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005930 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005931 *
5932 * Search and get the value of an attribute associated to a node
5933 * This attribute has to be anchored in the namespace specified.
5934 * This does the entity substitution.
5935 * This function looks in DTD attribute declaration for #FIXED or
5936 * default declaration values unless DTD use has been turned off.
5937 *
5938 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005939 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005940 */
5941xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00005942xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00005943 xmlAttrPtr prop;
5944 xmlDocPtr doc;
5945 xmlNsPtr ns;
5946
5947 if (node == NULL)
5948 return(NULL);
5949
5950 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005951 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00005952 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00005953 while (prop != NULL) {
5954 /*
5955 * One need to have
5956 * - same attribute names
5957 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005958 */
5959 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00005960 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00005961 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005962 xmlChar *ret;
5963
5964 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5965 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5966 return(ret);
5967 }
5968 prop = prop->next;
5969 }
5970 if (!xmlCheckDTD) return(NULL);
5971
5972 /*
5973 * Check if there is a default declaration in the internal
5974 * or external subsets
5975 */
5976 doc = node->doc;
5977 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005978 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00005979 xmlAttributePtr attrDecl;
5980
Owen Taylor3473f882001-02-23 17:55:21 +00005981 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5982 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5983 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5984
5985 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
5986 /*
5987 * The DTD declaration only allows a prefix search
5988 */
5989 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00005990 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00005991 return(xmlStrdup(attrDecl->defaultValue));
5992 }
5993 }
5994 }
5995 return(NULL);
5996}
5997
5998/**
5999 * xmlSetProp:
6000 * @node: the node
6001 * @name: the attribute name
6002 * @value: the attribute value
6003 *
6004 * Set (or reset) an attribute carried by a node.
6005 * Returns the attribute pointer.
6006 */
6007xmlAttrPtr
6008xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006009 xmlAttrPtr prop;
6010 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00006011
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006012 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006013 return(NULL);
6014 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006015 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00006016 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006017 if ((xmlStrEqual(prop->name, name)) &&
6018 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006019 xmlNodePtr oldprop = prop->children;
6020
Owen Taylor3473f882001-02-23 17:55:21 +00006021 prop->children = NULL;
6022 prop->last = NULL;
6023 if (value != NULL) {
6024 xmlChar *buffer;
6025 xmlNodePtr tmp;
6026
6027 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6028 prop->children = xmlStringGetNodeList(node->doc, buffer);
6029 prop->last = NULL;
6030 prop->doc = doc;
6031 tmp = prop->children;
6032 while (tmp != NULL) {
6033 tmp->parent = (xmlNodePtr) prop;
6034 tmp->doc = doc;
6035 if (tmp->next == NULL)
6036 prop->last = tmp;
6037 tmp = tmp->next;
6038 }
6039 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00006040 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006041 if (oldprop != NULL)
6042 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00006043 return(prop);
6044 }
6045 prop = prop->next;
6046 }
6047 prop = xmlNewProp(node, name, value);
6048 return(prop);
6049}
6050
6051/**
Daniel Veillard75bea542001-05-11 17:41:21 +00006052 * xmlUnsetProp:
6053 * @node: the node
6054 * @name: the attribute name
6055 *
6056 * Remove an attribute carried by a node.
6057 * Returns 0 if successful, -1 if not found
6058 */
6059int
6060xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Daniel Veillard814a76d2003-01-23 18:24:20 +00006061 xmlAttrPtr prop, prev = NULL;;
Daniel Veillard75bea542001-05-11 17:41:21 +00006062
6063 if ((node == NULL) || (name == NULL))
6064 return(-1);
Daniel Veillard814a76d2003-01-23 18:24:20 +00006065 prop = node->properties;
Daniel Veillard75bea542001-05-11 17:41:21 +00006066 while (prop != NULL) {
6067 if ((xmlStrEqual(prop->name, name)) &&
6068 (prop->ns == NULL)) {
6069 if (prev == NULL)
6070 node->properties = prop->next;
6071 else
6072 prev->next = prop->next;
6073 xmlFreeProp(prop);
6074 return(0);
6075 }
6076 prev = prop;
6077 prop = prop->next;
6078 }
6079 return(-1);
6080}
6081
6082/**
Owen Taylor3473f882001-02-23 17:55:21 +00006083 * xmlSetNsProp:
6084 * @node: the node
6085 * @ns: the namespace definition
6086 * @name: the attribute name
6087 * @value: the attribute value
6088 *
6089 * Set (or reset) an attribute carried by a node.
6090 * The ns structure must be in scope, this is not checked.
6091 *
6092 * Returns the attribute pointer.
6093 */
6094xmlAttrPtr
6095xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
6096 const xmlChar *value) {
6097 xmlAttrPtr prop;
6098
6099 if ((node == NULL) || (name == NULL))
6100 return(NULL);
6101
6102 if (ns == NULL)
6103 return(xmlSetProp(node, name, value));
6104 if (ns->href == NULL)
6105 return(NULL);
6106 prop = node->properties;
6107
6108 while (prop != NULL) {
6109 /*
6110 * One need to have
6111 * - same attribute names
6112 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006113 */
6114 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00006115 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006116 if (prop->children != NULL)
6117 xmlFreeNodeList(prop->children);
6118 prop->children = NULL;
6119 prop->last = NULL;
6120 prop->ns = ns;
6121 if (value != NULL) {
6122 xmlChar *buffer;
6123 xmlNodePtr tmp;
6124
6125 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6126 prop->children = xmlStringGetNodeList(node->doc, buffer);
6127 prop->last = NULL;
6128 tmp = prop->children;
6129 while (tmp != NULL) {
6130 tmp->parent = (xmlNodePtr) prop;
6131 if (tmp->next == NULL)
6132 prop->last = tmp;
6133 tmp = tmp->next;
6134 }
6135 xmlFree(buffer);
6136 }
6137 return(prop);
6138 }
6139 prop = prop->next;
6140 }
6141 prop = xmlNewNsProp(node, ns, name, value);
6142 return(prop);
6143}
6144
6145/**
Daniel Veillard75bea542001-05-11 17:41:21 +00006146 * xmlUnsetNsProp:
6147 * @node: the node
6148 * @ns: the namespace definition
6149 * @name: the attribute name
6150 *
6151 * Remove an attribute carried by a node.
6152 * Returns 0 if successful, -1 if not found
6153 */
6154int
6155xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
6156 xmlAttrPtr prop = node->properties, prev = NULL;;
6157
6158 if ((node == NULL) || (name == NULL))
6159 return(-1);
6160 if (ns == NULL)
6161 return(xmlUnsetProp(node, name));
6162 if (ns->href == NULL)
6163 return(-1);
6164 while (prop != NULL) {
6165 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00006166 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006167 if (prev == NULL)
6168 node->properties = prop->next;
6169 else
6170 prev->next = prop->next;
6171 xmlFreeProp(prop);
6172 return(0);
6173 }
6174 prev = prop;
6175 prop = prop->next;
6176 }
6177 return(-1);
6178}
6179
6180/**
Owen Taylor3473f882001-02-23 17:55:21 +00006181 * xmlNodeIsText:
6182 * @node: the node
6183 *
6184 * Is this node a Text node ?
6185 * Returns 1 yes, 0 no
6186 */
6187int
6188xmlNodeIsText(xmlNodePtr node) {
6189 if (node == NULL) return(0);
6190
6191 if (node->type == XML_TEXT_NODE) return(1);
6192 return(0);
6193}
6194
6195/**
6196 * xmlIsBlankNode:
6197 * @node: the node
6198 *
6199 * Checks whether this node is an empty or whitespace only
6200 * (and possibly ignorable) text-node.
6201 *
6202 * Returns 1 yes, 0 no
6203 */
6204int
6205xmlIsBlankNode(xmlNodePtr node) {
6206 const xmlChar *cur;
6207 if (node == NULL) return(0);
6208
Daniel Veillard7db37732001-07-12 01:20:08 +00006209 if ((node->type != XML_TEXT_NODE) &&
6210 (node->type != XML_CDATA_SECTION_NODE))
6211 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006212 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006213 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006214 while (*cur != 0) {
6215 if (!IS_BLANK(*cur)) return(0);
6216 cur++;
6217 }
6218
6219 return(1);
6220}
6221
6222/**
6223 * xmlTextConcat:
6224 * @node: the node
6225 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006226 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006227 *
6228 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006229 *
6230 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006231 */
6232
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006233int
Owen Taylor3473f882001-02-23 17:55:21 +00006234xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006235 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006236
6237 if ((node->type != XML_TEXT_NODE) &&
6238 (node->type != XML_CDATA_SECTION_NODE)) {
6239#ifdef DEBUG_TREE
6240 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006241 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006242#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006243 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006244 }
Owen Taylor3473f882001-02-23 17:55:21 +00006245 node->content = xmlStrncat(node->content, content, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006246 if (node->content == NULL)
6247 return(-1);
6248 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006249}
6250
6251/************************************************************************
6252 * *
6253 * Output : to a FILE or in memory *
6254 * *
6255 ************************************************************************/
6256
Owen Taylor3473f882001-02-23 17:55:21 +00006257/**
6258 * xmlBufferCreate:
6259 *
6260 * routine to create an XML buffer.
6261 * returns the new structure.
6262 */
6263xmlBufferPtr
6264xmlBufferCreate(void) {
6265 xmlBufferPtr ret;
6266
6267 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6268 if (ret == NULL) {
6269 xmlGenericError(xmlGenericErrorContext,
6270 "xmlBufferCreate : out of memory!\n");
6271 return(NULL);
6272 }
6273 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006274 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006275 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006276 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006277 if (ret->content == NULL) {
6278 xmlGenericError(xmlGenericErrorContext,
6279 "xmlBufferCreate : out of memory!\n");
6280 xmlFree(ret);
6281 return(NULL);
6282 }
6283 ret->content[0] = 0;
6284 return(ret);
6285}
6286
6287/**
6288 * xmlBufferCreateSize:
6289 * @size: initial size of buffer
6290 *
6291 * routine to create an XML buffer.
6292 * returns the new structure.
6293 */
6294xmlBufferPtr
6295xmlBufferCreateSize(size_t size) {
6296 xmlBufferPtr ret;
6297
6298 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6299 if (ret == NULL) {
6300 xmlGenericError(xmlGenericErrorContext,
6301 "xmlBufferCreate : out of memory!\n");
6302 return(NULL);
6303 }
6304 ret->use = 0;
6305 ret->alloc = xmlBufferAllocScheme;
6306 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6307 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006308 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006309 if (ret->content == NULL) {
6310 xmlGenericError(xmlGenericErrorContext,
6311 "xmlBufferCreate : out of memory!\n");
6312 xmlFree(ret);
6313 return(NULL);
6314 }
6315 ret->content[0] = 0;
6316 } else
6317 ret->content = NULL;
6318 return(ret);
6319}
6320
6321/**
Daniel Veillard53350552003-09-18 13:35:51 +00006322 * xmlBufferCreateStatic:
6323 * @mem: the memory area
6324 * @size: the size in byte
6325 *
6326 * routine to create an XML buffer from an immutable memory area,
6327 * The are won't be modified nor copied, and is expected to be
6328 * present until the end of the buffer lifetime.
6329 *
6330 * returns the new structure.
6331 */
6332xmlBufferPtr
6333xmlBufferCreateStatic(void *mem, size_t size) {
6334 xmlBufferPtr ret;
6335
6336 if ((mem == NULL) || (size == 0))
6337 return(NULL);
6338
6339 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6340 if (ret == NULL) {
6341 xmlGenericError(xmlGenericErrorContext,
6342 "xmlBufferCreate : out of memory!\n");
6343 return(NULL);
6344 }
6345 ret->use = size;
6346 ret->size = size;
6347 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6348 ret->content = (xmlChar *) mem;
6349 return(ret);
6350}
6351
6352/**
Owen Taylor3473f882001-02-23 17:55:21 +00006353 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006354 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006355 * @scheme: allocation scheme to use
6356 *
6357 * Sets the allocation scheme for this buffer
6358 */
6359void
6360xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6361 xmlBufferAllocationScheme scheme) {
6362 if (buf == NULL) {
6363#ifdef DEBUG_BUFFER
6364 xmlGenericError(xmlGenericErrorContext,
6365 "xmlBufferSetAllocationScheme: buf == NULL\n");
6366#endif
6367 return;
6368 }
Daniel Veillard53350552003-09-18 13:35:51 +00006369 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006370
6371 buf->alloc = scheme;
6372}
6373
6374/**
6375 * xmlBufferFree:
6376 * @buf: the buffer to free
6377 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006378 * Frees an XML buffer. It frees both the content and the structure which
6379 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006380 */
6381void
6382xmlBufferFree(xmlBufferPtr buf) {
6383 if (buf == NULL) {
6384#ifdef DEBUG_BUFFER
6385 xmlGenericError(xmlGenericErrorContext,
6386 "xmlBufferFree: buf == NULL\n");
6387#endif
6388 return;
6389 }
Daniel Veillard53350552003-09-18 13:35:51 +00006390
6391 if ((buf->content != NULL) &&
6392 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006393 xmlFree(buf->content);
6394 }
Owen Taylor3473f882001-02-23 17:55:21 +00006395 xmlFree(buf);
6396}
6397
6398/**
6399 * xmlBufferEmpty:
6400 * @buf: the buffer
6401 *
6402 * empty a buffer.
6403 */
6404void
6405xmlBufferEmpty(xmlBufferPtr buf) {
6406 if (buf->content == NULL) return;
6407 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006408 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillarde72c5082003-09-19 12:44:05 +00006409 buf->content = "";
Daniel Veillard53350552003-09-18 13:35:51 +00006410 } else {
6411 memset(buf->content, 0, buf->size);
6412 }
Owen Taylor3473f882001-02-23 17:55:21 +00006413}
6414
6415/**
6416 * xmlBufferShrink:
6417 * @buf: the buffer to dump
6418 * @len: the number of xmlChar to remove
6419 *
6420 * Remove the beginning of an XML buffer.
6421 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006422 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006423 */
6424int
6425xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
6426 if (len == 0) return(0);
6427 if (len > buf->use) return(-1);
6428
6429 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006430 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6431 buf->content += len;
6432 } else {
6433 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6434 buf->content[buf->use] = 0;
6435 }
Owen Taylor3473f882001-02-23 17:55:21 +00006436 return(len);
6437}
6438
6439/**
6440 * xmlBufferGrow:
6441 * @buf: the buffer
6442 * @len: the minimum free size to allocate
6443 *
6444 * Grow the available space of an XML buffer.
6445 *
6446 * Returns the new available space or -1 in case of error
6447 */
6448int
6449xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6450 int size;
6451 xmlChar *newbuf;
6452
Daniel Veillard53350552003-09-18 13:35:51 +00006453 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006454 if (len + buf->use < buf->size) return(0);
6455
6456 size = buf->use + len + 100;
6457
6458 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
6459 if (newbuf == NULL) return(-1);
6460 buf->content = newbuf;
6461 buf->size = size;
6462 return(buf->size - buf->use);
6463}
6464
6465/**
6466 * xmlBufferDump:
6467 * @file: the file output
6468 * @buf: the buffer to dump
6469 *
6470 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006471 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006472 */
6473int
6474xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6475 int ret;
6476
6477 if (buf == NULL) {
6478#ifdef DEBUG_BUFFER
6479 xmlGenericError(xmlGenericErrorContext,
6480 "xmlBufferDump: buf == NULL\n");
6481#endif
6482 return(0);
6483 }
6484 if (buf->content == NULL) {
6485#ifdef DEBUG_BUFFER
6486 xmlGenericError(xmlGenericErrorContext,
6487 "xmlBufferDump: buf->content == NULL\n");
6488#endif
6489 return(0);
6490 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006491 if (file == NULL)
6492 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006493 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6494 return(ret);
6495}
6496
6497/**
6498 * xmlBufferContent:
6499 * @buf: the buffer
6500 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006501 * Function to extract the content of a buffer
6502 *
Owen Taylor3473f882001-02-23 17:55:21 +00006503 * Returns the internal content
6504 */
6505
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006506const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006507xmlBufferContent(const xmlBufferPtr buf)
6508{
6509 if(!buf)
6510 return NULL;
6511
6512 return buf->content;
6513}
6514
6515/**
6516 * xmlBufferLength:
6517 * @buf: the buffer
6518 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006519 * Function to get the length of a buffer
6520 *
Owen Taylor3473f882001-02-23 17:55:21 +00006521 * Returns the length of data in the internal content
6522 */
6523
6524int
6525xmlBufferLength(const xmlBufferPtr buf)
6526{
6527 if(!buf)
6528 return 0;
6529
6530 return buf->use;
6531}
6532
6533/**
6534 * xmlBufferResize:
6535 * @buf: the buffer to resize
6536 * @size: the desired size
6537 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006538 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006539 *
6540 * Returns 0 in case of problems, 1 otherwise
6541 */
6542int
6543xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6544{
6545 unsigned int newSize;
6546 xmlChar* rebuf = NULL;
6547
Daniel Veillard53350552003-09-18 13:35:51 +00006548 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6549
Owen Taylor3473f882001-02-23 17:55:21 +00006550 /*take care of empty case*/
6551 newSize = (buf->size ? buf->size*2 : size);
6552
6553 /* Don't resize if we don't have to */
6554 if (size < buf->size)
6555 return 1;
6556
6557 /* figure out new size */
6558 switch (buf->alloc){
6559 case XML_BUFFER_ALLOC_DOUBLEIT:
6560 while (size > newSize) newSize *= 2;
6561 break;
6562 case XML_BUFFER_ALLOC_EXACT:
6563 newSize = size+10;
6564 break;
6565 default:
6566 newSize = size+10;
6567 break;
6568 }
6569
6570 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006571 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006572 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006573 rebuf = (xmlChar *) xmlRealloc(buf->content,
6574 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006575 } else {
6576 /*
6577 * if we are reallocating a buffer far from being full, it's
6578 * better to make a new allocation and copy only the used range
6579 * and free the old one.
6580 */
6581 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6582 if (rebuf != NULL) {
6583 memcpy(rebuf, buf->content, buf->use);
6584 xmlFree(buf->content);
6585 }
Daniel Veillarde5984082003-08-19 22:21:13 +00006586 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006587 }
Owen Taylor3473f882001-02-23 17:55:21 +00006588 if (rebuf == NULL) {
6589 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006590 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006591 return 0;
6592 }
6593 buf->content = rebuf;
6594 buf->size = newSize;
6595
6596 return 1;
6597}
6598
6599/**
6600 * xmlBufferAdd:
6601 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006602 * @str: the #xmlChar string
6603 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006604 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006605 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006606 * str is recomputed.
6607 */
6608void
6609xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6610 unsigned int needSize;
6611
6612 if (str == NULL) {
6613#ifdef DEBUG_BUFFER
6614 xmlGenericError(xmlGenericErrorContext,
6615 "xmlBufferAdd: str == NULL\n");
6616#endif
6617 return;
6618 }
Daniel Veillard53350552003-09-18 13:35:51 +00006619 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006620 if (len < -1) {
6621#ifdef DEBUG_BUFFER
6622 xmlGenericError(xmlGenericErrorContext,
6623 "xmlBufferAdd: len < 0\n");
6624#endif
6625 return;
6626 }
6627 if (len == 0) return;
6628
6629 if (len < 0)
6630 len = xmlStrlen(str);
6631
6632 if (len <= 0) return;
6633
6634 needSize = buf->use + len + 2;
6635 if (needSize > buf->size){
6636 if (!xmlBufferResize(buf, needSize)){
6637 xmlGenericError(xmlGenericErrorContext,
6638 "xmlBufferAdd : out of memory!\n");
6639 return;
6640 }
6641 }
6642
6643 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6644 buf->use += len;
6645 buf->content[buf->use] = 0;
6646}
6647
6648/**
6649 * xmlBufferAddHead:
6650 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006651 * @str: the #xmlChar string
6652 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006653 *
6654 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006655 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00006656 */
6657void
6658xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6659 unsigned int needSize;
6660
Daniel Veillard53350552003-09-18 13:35:51 +00006661 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006662 if (str == NULL) {
6663#ifdef DEBUG_BUFFER
6664 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006665 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006666#endif
6667 return;
6668 }
6669 if (len < -1) {
6670#ifdef DEBUG_BUFFER
6671 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006672 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006673#endif
6674 return;
6675 }
6676 if (len == 0) return;
6677
6678 if (len < 0)
6679 len = xmlStrlen(str);
6680
6681 if (len <= 0) return;
6682
6683 needSize = buf->use + len + 2;
6684 if (needSize > buf->size){
6685 if (!xmlBufferResize(buf, needSize)){
6686 xmlGenericError(xmlGenericErrorContext,
6687 "xmlBufferAddHead : out of memory!\n");
6688 return;
6689 }
6690 }
6691
6692 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6693 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6694 buf->use += len;
6695 buf->content[buf->use] = 0;
6696}
6697
6698/**
6699 * xmlBufferCat:
6700 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006701 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006702 *
6703 * Append a zero terminated string to an XML buffer.
6704 */
6705void
6706xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillard53350552003-09-18 13:35:51 +00006707 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006708 if (str != NULL)
6709 xmlBufferAdd(buf, str, -1);
6710}
6711
6712/**
6713 * xmlBufferCCat:
6714 * @buf: the buffer to dump
6715 * @str: the C char string
6716 *
6717 * Append a zero terminated C string to an XML buffer.
6718 */
6719void
6720xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6721 const char *cur;
6722
Daniel Veillard53350552003-09-18 13:35:51 +00006723 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006724 if (str == NULL) {
6725#ifdef DEBUG_BUFFER
6726 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006727 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006728#endif
6729 return;
6730 }
6731 for (cur = str;*cur != 0;cur++) {
6732 if (buf->use + 10 >= buf->size) {
6733 if (!xmlBufferResize(buf, buf->use+10)){
6734 xmlGenericError(xmlGenericErrorContext,
6735 "xmlBufferCCat : out of memory!\n");
6736 return;
6737 }
6738 }
6739 buf->content[buf->use++] = *cur;
6740 }
6741 buf->content[buf->use] = 0;
6742}
6743
6744/**
6745 * xmlBufferWriteCHAR:
6746 * @buf: the XML buffer
6747 * @string: the string to add
6748 *
6749 * routine which manages and grows an output buffer. This one adds
6750 * xmlChars at the end of the buffer.
6751 */
6752void
Daniel Veillard53350552003-09-18 13:35:51 +00006753xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
6754 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006755 xmlBufferCat(buf, string);
6756}
6757
6758/**
6759 * xmlBufferWriteChar:
6760 * @buf: the XML buffer output
6761 * @string: the string to add
6762 *
6763 * routine which manage and grows an output buffer. This one add
6764 * C chars at the end of the array.
6765 */
6766void
6767xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillard53350552003-09-18 13:35:51 +00006768 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006769 xmlBufferCCat(buf, string);
6770}
6771
6772
6773/**
6774 * xmlBufferWriteQuotedString:
6775 * @buf: the XML buffer output
6776 * @string: the string to add
6777 *
6778 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00006779 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00006780 * quote or double-quotes internally
6781 */
6782void
6783xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00006784 const xmlChar *cur, *base;
Daniel Veillard53350552003-09-18 13:35:51 +00006785 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00006786 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00006787 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00006788#ifdef DEBUG_BUFFER
6789 xmlGenericError(xmlGenericErrorContext,
6790 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
6791#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00006792 xmlBufferCCat(buf, "\"");
6793 base = cur = string;
6794 while(*cur != 0){
6795 if(*cur == '"'){
6796 if (base != cur)
6797 xmlBufferAdd(buf, base, cur - base);
6798 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6799 cur++;
6800 base = cur;
6801 }
6802 else {
6803 cur++;
6804 }
6805 }
6806 if (base != cur)
6807 xmlBufferAdd(buf, base, cur - base);
6808 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006809 }
Daniel Veillard39057f42003-08-04 01:33:43 +00006810 else{
6811 xmlBufferCCat(buf, "\'");
6812 xmlBufferCat(buf, string);
6813 xmlBufferCCat(buf, "\'");
6814 }
Owen Taylor3473f882001-02-23 17:55:21 +00006815 } else {
6816 xmlBufferCCat(buf, "\"");
6817 xmlBufferCat(buf, string);
6818 xmlBufferCCat(buf, "\"");
6819 }
6820}
6821
6822
6823/************************************************************************
6824 * *
6825 * Dumping XML tree content to a simple buffer *
6826 * *
6827 ************************************************************************/
6828
Owen Taylor3473f882001-02-23 17:55:21 +00006829/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00006830 * xmlAttrSerializeContent:
6831 * @buf: the XML buffer output
6832 * @doc: the document
6833 * @attr: the attribute pointer
6834 *
6835 * Serialize the attribute in the buffer
6836 */
6837static void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006838xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr)
6839{
Daniel Veillarda6d05382002-02-13 13:07:41 +00006840 const xmlChar *cur, *base;
6841 xmlNodePtr children;
6842
6843 children = attr->children;
6844 while (children != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006845 switch (children->type) {
6846 case XML_TEXT_NODE:
6847 base = cur = children->content;
6848 while (*cur != 0) {
6849 if (*cur == '\n') {
6850 if (base != cur)
6851 xmlBufferAdd(buf, base, cur - base);
6852 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
6853 cur++;
6854 base = cur;
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006855 } else if (*cur == '\r') {
6856 if (base != cur)
6857 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006858 xmlBufferAdd(buf, BAD_CAST "&#13;", 5);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006859 cur++;
6860 base = cur;
6861 } else if (*cur == '\t') {
6862 if (base != cur)
6863 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006864 xmlBufferAdd(buf, BAD_CAST "&#9;", 4);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006865 cur++;
6866 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006867#if 0
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006868 } else if (*cur == '\'') {
6869 if (base != cur)
6870 xmlBufferAdd(buf, base, cur - base);
6871 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
6872 cur++;
6873 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006874#endif
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 "&quot;", 6);
6879 cur++;
6880 base = cur;
6881 } else if (*cur == '<') {
6882 if (base != cur)
6883 xmlBufferAdd(buf, base, cur - base);
6884 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
6885 cur++;
6886 base = cur;
6887 } else if (*cur == '>') {
6888 if (base != cur)
6889 xmlBufferAdd(buf, base, cur - base);
6890 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
6891 cur++;
6892 base = cur;
6893 } else if (*cur == '&') {
6894 if (base != cur)
6895 xmlBufferAdd(buf, base, cur - base);
6896 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
6897 cur++;
6898 base = cur;
6899 } else if ((*cur >= 0x80) && ((doc == NULL) ||
6900 (doc->encoding ==
6901 NULL))) {
6902 /*
6903 * We assume we have UTF-8 content.
6904 */
6905 char tmp[10];
6906 int val = 0, l = 1;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006907
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006908 if (base != cur)
6909 xmlBufferAdd(buf, base, cur - base);
6910 if (*cur < 0xC0) {
6911 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6d05382002-02-13 13:07:41 +00006912 "xmlAttrSerializeContent : input not UTF-8\n");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006913 if (doc != NULL)
6914 doc->encoding =
6915 xmlStrdup(BAD_CAST "ISO-8859-1");
6916 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6917 tmp[sizeof(tmp) - 1] = 0;
6918 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6919 cur++;
6920 base = cur;
6921 continue;
6922 } else if (*cur < 0xE0) {
6923 val = (cur[0]) & 0x1F;
6924 val <<= 6;
6925 val |= (cur[1]) & 0x3F;
6926 l = 2;
6927 } else if (*cur < 0xF0) {
6928 val = (cur[0]) & 0x0F;
6929 val <<= 6;
6930 val |= (cur[1]) & 0x3F;
6931 val <<= 6;
6932 val |= (cur[2]) & 0x3F;
6933 l = 3;
6934 } else if (*cur < 0xF8) {
6935 val = (cur[0]) & 0x07;
6936 val <<= 6;
6937 val |= (cur[1]) & 0x3F;
6938 val <<= 6;
6939 val |= (cur[2]) & 0x3F;
6940 val <<= 6;
6941 val |= (cur[3]) & 0x3F;
6942 l = 4;
6943 }
6944 if ((l == 1) || (!IS_CHAR(val))) {
6945 xmlGenericError(xmlGenericErrorContext,
6946 "xmlAttrSerializeContent : char out of range\n");
6947 if (doc != NULL)
6948 doc->encoding =
6949 xmlStrdup(BAD_CAST "ISO-8859-1");
6950 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6951 tmp[sizeof(tmp) - 1] = 0;
6952 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6953 cur++;
6954 base = cur;
6955 continue;
6956 }
6957 /*
6958 * We could do multiple things here. Just save
6959 * as a char ref
6960 */
6961 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
6962 tmp[sizeof(tmp) - 1] = 0;
6963 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6964 cur += l;
6965 base = cur;
6966 } else {
6967 cur++;
6968 }
6969 }
6970 if (base != cur)
6971 xmlBufferAdd(buf, base, cur - base);
6972 break;
6973 case XML_ENTITY_REF_NODE:
6974 xmlBufferAdd(buf, BAD_CAST "&", 1);
6975 xmlBufferAdd(buf, children->name,
6976 xmlStrlen(children->name));
6977 xmlBufferAdd(buf, BAD_CAST ";", 1);
6978 break;
6979 default:
6980 /* should not happen unless we have a badly built tree */
6981 break;
6982 }
6983 children = children->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006984 }
6985}
6986
6987/**
6988 * xmlNodeDump:
6989 * @buf: the XML buffer output
6990 * @doc: the document
6991 * @cur: the current node
6992 * @level: the imbrication level for indenting
6993 * @format: is formatting allowed
6994 *
6995 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00006996 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006997 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006998 *
6999 * Returns the number of bytes written to the buffer or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00007000 */
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007001int
Owen Taylor3473f882001-02-23 17:55:21 +00007002xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007003 int format)
7004{
7005 unsigned int use;
7006 int ret;
7007 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00007008
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007009 xmlInitParser();
7010
Owen Taylor3473f882001-02-23 17:55:21 +00007011 if (cur == NULL) {
7012#ifdef DEBUG_TREE
7013 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007014 "xmlNodeDump : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007015#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007016 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007017 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007018 if (buf == NULL) {
7019#ifdef DEBUG_TREE
7020 xmlGenericError(xmlGenericErrorContext,
7021 "xmlNodeDump : buf == NULL\n");
7022#endif
7023 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007024 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007025 outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
7026 if (outbuf == NULL) {
7027 xmlGenericError(xmlGenericErrorContext,
7028 "xmlNodeDump: out of memory!\n");
7029 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007030 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007031 memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
7032 outbuf->buffer = buf;
7033 outbuf->encoder = NULL;
7034 outbuf->writecallback = NULL;
7035 outbuf->closecallback = NULL;
7036 outbuf->context = NULL;
7037 outbuf->written = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007038
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007039 use = buf->use;
7040 xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
7041 xmlFree(outbuf);
7042 ret = buf->use - use;
7043 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00007044}
7045
7046/**
7047 * xmlElemDump:
7048 * @f: the FILE * for the output
7049 * @doc: the document
7050 * @cur: the current node
7051 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007052 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00007053 */
7054void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007055xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur)
7056{
7057 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00007058
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007059 xmlInitParser();
7060
Owen Taylor3473f882001-02-23 17:55:21 +00007061 if (cur == NULL) {
7062#ifdef DEBUG_TREE
7063 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007064 "xmlElemDump : cur == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007065#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007066 return;
Owen Taylor3473f882001-02-23 17:55:21 +00007067 }
Owen Taylor3473f882001-02-23 17:55:21 +00007068#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007069 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00007070 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007071 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007072 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007073#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007074
7075 outbuf = xmlOutputBufferCreateFile(f, NULL);
7076 if (outbuf == NULL)
7077 return;
7078 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007079#ifdef LIBXML_HTML_ENABLED
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007080 htmlNodeDumpOutput(outbuf, doc, cur, NULL);
7081#else
7082 xmlGenericError(xmlGenericErrorContext,
7083 "HTML support not compiled in\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007084#endif /* LIBXML_HTML_ENABLED */
7085 } else
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007086 xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL);
7087 xmlOutputBufferClose(outbuf);
Owen Taylor3473f882001-02-23 17:55:21 +00007088}
7089
7090/************************************************************************
7091 * *
7092 * Dumping XML tree content to an I/O output buffer *
7093 * *
7094 ************************************************************************/
7095
Owen Taylor3473f882001-02-23 17:55:21 +00007096static void
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007097xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7098 int level, int format, const char *encoding);
7099static void
Owen Taylor3473f882001-02-23 17:55:21 +00007100xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7101 int level, int format, const char *encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007102static void
7103xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
7104 xmlNodePtr cur, int level, int format, const char *encoding);
7105
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00007106void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
7107
Owen Taylor3473f882001-02-23 17:55:21 +00007108/**
7109 * xmlNsDumpOutput:
7110 * @buf: the XML buffer output
7111 * @cur: a namespace
7112 *
7113 * Dump a local Namespace definition.
7114 * Should be called in the context of attributes dumps.
7115 */
7116static void
7117xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
7118 if (cur == NULL) {
7119#ifdef DEBUG_TREE
7120 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007121 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007122#endif
7123 return;
7124 }
7125 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00007126 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
7127 return;
7128
Owen Taylor3473f882001-02-23 17:55:21 +00007129 /* Within the context of an element attributes */
7130 if (cur->prefix != NULL) {
7131 xmlOutputBufferWriteString(buf, " xmlns:");
7132 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
7133 } else
7134 xmlOutputBufferWriteString(buf, " xmlns");
7135 xmlOutputBufferWriteString(buf, "=");
7136 xmlBufferWriteQuotedString(buf->buffer, cur->href);
7137 }
7138}
7139
7140/**
7141 * xmlNsListDumpOutput:
7142 * @buf: the XML buffer output
7143 * @cur: the first namespace
7144 *
7145 * Dump a list of local Namespace definitions.
7146 * Should be called in the context of attributes dumps.
7147 */
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00007148void
Owen Taylor3473f882001-02-23 17:55:21 +00007149xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
7150 while (cur != NULL) {
7151 xmlNsDumpOutput(buf, cur);
7152 cur = cur->next;
7153 }
7154}
7155
7156/**
7157 * xmlDtdDumpOutput:
7158 * @buf: the XML buffer output
7159 * @doc: the document
7160 * @encoding: an optional encoding string
7161 *
7162 * Dump the XML document DTD, if any.
7163 */
7164static void
7165xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
7166 if (dtd == NULL) {
7167#ifdef DEBUG_TREE
7168 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007169 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007170#endif
7171 return;
7172 }
7173 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
7174 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
7175 if (dtd->ExternalID != NULL) {
7176 xmlOutputBufferWriteString(buf, " PUBLIC ");
7177 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
7178 xmlOutputBufferWriteString(buf, " ");
7179 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
7180 } else if (dtd->SystemID != NULL) {
7181 xmlOutputBufferWriteString(buf, " SYSTEM ");
7182 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
7183 }
7184 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
7185 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
7186 xmlOutputBufferWriteString(buf, ">");
7187 return;
7188 }
7189 xmlOutputBufferWriteString(buf, " [\n");
7190 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
7191 xmlOutputBufferWriteString(buf, "]>");
7192}
7193
7194/**
7195 * xmlAttrDumpOutput:
7196 * @buf: the XML buffer output
7197 * @doc: the document
7198 * @cur: the attribute pointer
7199 * @encoding: an optional encoding string
7200 *
7201 * Dump an XML attribute
7202 */
7203static void
7204xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00007205 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00007206 if (cur == NULL) {
7207#ifdef DEBUG_TREE
7208 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007209 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007210#endif
7211 return;
7212 }
7213 xmlOutputBufferWriteString(buf, " ");
7214 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7215 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7216 xmlOutputBufferWriteString(buf, ":");
7217 }
7218 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00007219 xmlOutputBufferWriteString(buf, "=\"");
7220 xmlAttrSerializeContent(buf->buffer, doc, cur);
7221 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007222}
7223
7224/**
7225 * xmlAttrListDumpOutput:
7226 * @buf: the XML buffer output
7227 * @doc: the document
7228 * @cur: the first attribute pointer
7229 * @encoding: an optional encoding string
7230 *
7231 * Dump a list of XML attributes
7232 */
7233static void
7234xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7235 xmlAttrPtr cur, const char *encoding) {
7236 if (cur == NULL) {
7237#ifdef DEBUG_TREE
7238 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007239 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007240#endif
7241 return;
7242 }
7243 while (cur != NULL) {
7244 xmlAttrDumpOutput(buf, doc, cur, encoding);
7245 cur = cur->next;
7246 }
7247}
7248
7249
7250
7251/**
7252 * xmlNodeListDumpOutput:
7253 * @buf: the XML buffer output
7254 * @doc: the document
7255 * @cur: the first node
7256 * @level: the imbrication level for indenting
7257 * @format: is formatting allowed
7258 * @encoding: an optional encoding string
7259 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007260 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007261 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007262 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007263 */
7264static void
7265xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7266 xmlNodePtr cur, int level, int format, const char *encoding) {
7267 int i;
7268
7269 if (cur == NULL) {
7270#ifdef DEBUG_TREE
7271 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007272 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007273#endif
7274 return;
7275 }
7276 while (cur != NULL) {
7277 if ((format) && (xmlIndentTreeOutput) &&
7278 (cur->type == XML_ELEMENT_NODE))
7279 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007280 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007281 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007282 if (format) {
7283 xmlOutputBufferWriteString(buf, "\n");
7284 }
7285 cur = cur->next;
7286 }
7287}
7288
7289/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007290 * xmlNodeDumpOutputInternal:
Owen Taylor3473f882001-02-23 17:55:21 +00007291 * @buf: the XML buffer output
7292 * @doc: the document
7293 * @cur: the current node
7294 * @level: the imbrication level for indenting
7295 * @format: is formatting allowed
7296 * @encoding: an optional encoding string
7297 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007298 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007299 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007300 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007301 */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007302static void
7303xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
7304 xmlNodePtr cur, int level, int format, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007305 int i;
7306 xmlNodePtr tmp;
7307
7308 if (cur == NULL) {
7309#ifdef DEBUG_TREE
7310 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007311 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007312#endif
7313 return;
7314 }
7315 if (cur->type == XML_XINCLUDE_START)
7316 return;
7317 if (cur->type == XML_XINCLUDE_END)
7318 return;
7319 if (cur->type == XML_DTD_NODE) {
7320 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7321 return;
7322 }
7323 if (cur->type == XML_ELEMENT_DECL) {
7324 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7325 return;
7326 }
7327 if (cur->type == XML_ATTRIBUTE_DECL) {
7328 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7329 return;
7330 }
7331 if (cur->type == XML_ENTITY_DECL) {
7332 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7333 return;
7334 }
7335 if (cur->type == XML_TEXT_NODE) {
7336 if (cur->content != NULL) {
7337 if ((cur->name == xmlStringText) ||
7338 (cur->name != xmlStringTextNoenc)) {
7339 xmlChar *buffer;
7340
Owen Taylor3473f882001-02-23 17:55:21 +00007341 if (encoding == NULL)
7342 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7343 else
7344 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007345 if (buffer != NULL) {
7346 xmlOutputBufferWriteString(buf, (const char *)buffer);
7347 xmlFree(buffer);
7348 }
7349 } else {
7350 /*
7351 * Disable escaping, needed for XSLT
7352 */
Owen Taylor3473f882001-02-23 17:55:21 +00007353 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007354 }
7355 }
7356
7357 return;
7358 }
7359 if (cur->type == XML_PI_NODE) {
7360 if (cur->content != NULL) {
7361 xmlOutputBufferWriteString(buf, "<?");
7362 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7363 if (cur->content != NULL) {
7364 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00007365 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007366 }
7367 xmlOutputBufferWriteString(buf, "?>");
7368 } else {
7369 xmlOutputBufferWriteString(buf, "<?");
7370 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7371 xmlOutputBufferWriteString(buf, "?>");
7372 }
7373 return;
7374 }
7375 if (cur->type == XML_COMMENT_NODE) {
7376 if (cur->content != NULL) {
7377 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00007378 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007379 xmlOutputBufferWriteString(buf, "-->");
7380 }
7381 return;
7382 }
7383 if (cur->type == XML_ENTITY_REF_NODE) {
7384 xmlOutputBufferWriteString(buf, "&");
7385 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7386 xmlOutputBufferWriteString(buf, ";");
7387 return;
7388 }
7389 if (cur->type == XML_CDATA_SECTION_NODE) {
7390 xmlOutputBufferWriteString(buf, "<![CDATA[");
7391 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007392 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007393 xmlOutputBufferWriteString(buf, "]]>");
7394 return;
7395 }
Daniel Veillard7b72ee52003-02-27 23:24:53 +00007396 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillarda1a9d042003-03-18 16:53:17 +00007397 xmlAttrDumpOutput(buf,doc, (xmlAttrPtr) cur,encoding);
Daniel Veillard7b72ee52003-02-27 23:24:53 +00007398 return;
7399 }
Daniel Veillard6aa2f602003-02-10 00:01:56 +00007400 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007401 xmlNsDumpOutput(buf, (xmlNsPtr) cur);
Daniel Veillard6aa2f602003-02-10 00:01:56 +00007402 return;
7403 }
Owen Taylor3473f882001-02-23 17:55:21 +00007404
7405 if (format == 1) {
7406 tmp = cur->children;
7407 while (tmp != NULL) {
7408 if ((tmp->type == XML_TEXT_NODE) ||
7409 (tmp->type == XML_ENTITY_REF_NODE)) {
7410 format = 0;
7411 break;
7412 }
7413 tmp = tmp->next;
7414 }
7415 }
7416 xmlOutputBufferWriteString(buf, "<");
7417 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7418 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7419 xmlOutputBufferWriteString(buf, ":");
7420 }
7421
7422 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7423 if (cur->nsDef)
7424 xmlNsListDumpOutput(buf, cur->nsDef);
7425 if (cur->properties != NULL)
7426 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7427
Daniel Veillard7db37732001-07-12 01:20:08 +00007428 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
7429 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007430 xmlOutputBufferWriteString(buf, "/>");
7431 return;
7432 }
7433 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00007434 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007435 xmlChar *buffer;
7436
Owen Taylor3473f882001-02-23 17:55:21 +00007437 if (encoding == NULL)
7438 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7439 else
7440 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007441 if (buffer != NULL) {
7442 xmlOutputBufferWriteString(buf, (const char *)buffer);
7443 xmlFree(buffer);
7444 }
7445 }
7446 if (cur->children != NULL) {
7447 if (format) xmlOutputBufferWriteString(buf, "\n");
7448 xmlNodeListDumpOutput(buf, doc, cur->children,
7449 (level >= 0?level+1:-1), format, encoding);
7450 if ((xmlIndentTreeOutput) && (format))
7451 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007452 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00007453 }
7454 xmlOutputBufferWriteString(buf, "</");
7455 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7456 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7457 xmlOutputBufferWriteString(buf, ":");
7458 }
7459
7460 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7461 xmlOutputBufferWriteString(buf, ">");
7462}
7463
7464/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007465 * xmlNodeDumpOutput:
7466 * @buf: the XML buffer output
7467 * @doc: the document
7468 * @cur: the current node
7469 * @level: the imbrication level for indenting
7470 * @format: is formatting allowed
7471 * @encoding: an optional encoding string
7472 *
7473 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007474 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007475 * or xmlKeepBlanksDefault(0) was called
7476 */
7477void
7478xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007479 int level, int format, const char *encoding)
7480{
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007481#ifdef LIBXML_HTML_ENABLED
7482 xmlDtdPtr dtd;
7483 int is_xhtml = 0;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007484#endif
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007485
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007486 xmlInitParser();
7487
7488#ifdef LIBXML_HTML_ENABLED
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007489 dtd = xmlGetIntSubset(doc);
7490 if (dtd != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007491 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7492 if (is_xhtml < 0)
7493 is_xhtml = 0;
7494 if ((is_xhtml) && (cur->parent == (xmlNodePtr) doc) &&
7495 (cur->type == XML_ELEMENT_NODE) &&
7496 (xmlStrEqual(cur->name, BAD_CAST "html"))) {
7497 if (encoding != NULL)
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007498 htmlSetMetaEncoding((htmlDocPtr) doc,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007499 (const xmlChar *) encoding);
7500 else
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007501 htmlSetMetaEncoding((htmlDocPtr) doc, BAD_CAST "UTF-8");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007502 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007503 }
7504
7505 if (is_xhtml)
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007506 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007507 else
7508#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007509 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007510}
7511
7512/**
Owen Taylor3473f882001-02-23 17:55:21 +00007513 * xmlDocContentDumpOutput:
7514 * @buf: the XML buffer output
7515 * @cur: the document
7516 * @encoding: an optional encoding string
7517 * @format: should formatting spaces been added
7518 *
7519 * Dump an XML document.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007520 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007521 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007522 */
7523static void
7524xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
7525 const char *encoding, int format) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007526#ifdef LIBXML_HTML_ENABLED
7527 xmlDtdPtr dtd;
7528 int is_xhtml = 0;
7529#endif
7530
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007531 xmlInitParser();
7532
Owen Taylor3473f882001-02-23 17:55:21 +00007533 xmlOutputBufferWriteString(buf, "<?xml version=");
7534 if (cur->version != NULL)
7535 xmlBufferWriteQuotedString(buf->buffer, cur->version);
7536 else
7537 xmlOutputBufferWriteString(buf, "\"1.0\"");
7538 if (encoding == NULL) {
7539 if (cur->encoding != NULL)
7540 encoding = (const char *) cur->encoding;
7541 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
7542 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
7543 }
7544 if (encoding != NULL) {
7545 xmlOutputBufferWriteString(buf, " encoding=");
7546 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
7547 }
7548 switch (cur->standalone) {
7549 case 0:
7550 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
7551 break;
7552 case 1:
7553 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
7554 break;
7555 }
7556 xmlOutputBufferWriteString(buf, "?>\n");
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007557
7558#ifdef LIBXML_HTML_ENABLED
7559 dtd = xmlGetIntSubset(cur);
7560 if (dtd != NULL) {
7561 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7562 if (is_xhtml < 0) is_xhtml = 0;
7563 }
7564 if (is_xhtml) {
7565 if (encoding != NULL)
7566 htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
7567 else
7568 htmlSetMetaEncoding(cur, BAD_CAST "UTF-8");
7569 }
7570#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007571 if (cur->children != NULL) {
7572 xmlNodePtr child = cur->children;
7573
7574 while (child != NULL) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007575#ifdef LIBXML_HTML_ENABLED
7576 if (is_xhtml)
7577 xhtmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
7578 else
7579#endif
7580 xmlNodeDumpOutputInternal(buf, cur, child, 0, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007581 xmlOutputBufferWriteString(buf, "\n");
7582 child = child->next;
7583 }
7584 }
7585}
7586
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007587#ifdef LIBXML_HTML_ENABLED
7588/************************************************************************
7589 * *
7590 * Functions specific to XHTML serialization *
7591 * *
7592 ************************************************************************/
7593
7594#define XHTML_STRICT_PUBLIC_ID BAD_CAST \
7595 "-//W3C//DTD XHTML 1.0 Strict//EN"
7596#define XHTML_STRICT_SYSTEM_ID BAD_CAST \
7597 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
7598#define XHTML_FRAME_PUBLIC_ID BAD_CAST \
7599 "-//W3C//DTD XHTML 1.0 Frameset//EN"
7600#define XHTML_FRAME_SYSTEM_ID BAD_CAST \
7601 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
7602#define XHTML_TRANS_PUBLIC_ID BAD_CAST \
7603 "-//W3C//DTD XHTML 1.0 Transitional//EN"
7604#define XHTML_TRANS_SYSTEM_ID BAD_CAST \
7605 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
7606
7607#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
7608/**
7609 * xmlIsXHTML:
7610 * @systemID: the system identifier
7611 * @publicID: the public identifier
7612 *
7613 * Try to find if the document correspond to an XHTML DTD
7614 *
7615 * Returns 1 if true, 0 if not and -1 in case of error
7616 */
7617int
7618xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) {
7619 if ((systemID == NULL) && (publicID == NULL))
7620 return(-1);
7621 if (publicID != NULL) {
7622 if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1);
7623 if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1);
7624 if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1);
7625 }
7626 if (systemID != NULL) {
7627 if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1);
7628 if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1);
7629 if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1);
7630 }
7631 return(0);
7632}
7633
7634/**
7635 * xhtmlIsEmpty:
7636 * @node: the node
7637 *
7638 * Check if a node is an empty xhtml node
7639 *
7640 * Returns 1 if the node is an empty node, 0 if not and -1 in case of error
7641 */
7642static int
7643xhtmlIsEmpty(xmlNodePtr node) {
7644 if (node == NULL)
7645 return(-1);
7646 if (node->type != XML_ELEMENT_NODE)
7647 return(0);
7648 if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME)))
7649 return(0);
7650 if (node->children != NULL)
7651 return(0);
7652 switch (node->name[0]) {
7653 case 'a':
7654 if (xmlStrEqual(node->name, BAD_CAST "area"))
7655 return(1);
7656 return(0);
7657 case 'b':
7658 if (xmlStrEqual(node->name, BAD_CAST "br"))
7659 return(1);
7660 if (xmlStrEqual(node->name, BAD_CAST "base"))
7661 return(1);
7662 if (xmlStrEqual(node->name, BAD_CAST "basefont"))
7663 return(1);
7664 return(0);
7665 case 'c':
7666 if (xmlStrEqual(node->name, BAD_CAST "col"))
7667 return(1);
7668 return(0);
7669 case 'f':
7670 if (xmlStrEqual(node->name, BAD_CAST "frame"))
7671 return(1);
7672 return(0);
7673 case 'h':
7674 if (xmlStrEqual(node->name, BAD_CAST "hr"))
7675 return(1);
7676 return(0);
7677 case 'i':
7678 if (xmlStrEqual(node->name, BAD_CAST "img"))
7679 return(1);
7680 if (xmlStrEqual(node->name, BAD_CAST "input"))
7681 return(1);
7682 if (xmlStrEqual(node->name, BAD_CAST "isindex"))
7683 return(1);
7684 return(0);
7685 case 'l':
7686 if (xmlStrEqual(node->name, BAD_CAST "link"))
7687 return(1);
7688 return(0);
7689 case 'm':
7690 if (xmlStrEqual(node->name, BAD_CAST "meta"))
7691 return(1);
7692 return(0);
7693 case 'p':
7694 if (xmlStrEqual(node->name, BAD_CAST "param"))
7695 return(1);
7696 return(0);
7697 }
7698 return(0);
7699}
7700
7701/**
7702 * xhtmlAttrListDumpOutput:
7703 * @buf: the XML buffer output
7704 * @doc: the document
7705 * @cur: the first attribute pointer
7706 * @encoding: an optional encoding string
7707 *
7708 * Dump a list of XML attributes
7709 */
7710static void
7711xhtmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7712 xmlAttrPtr cur, const char *encoding) {
7713 xmlAttrPtr xml_lang = NULL;
7714 xmlAttrPtr lang = NULL;
7715 xmlAttrPtr name = NULL;
7716 xmlAttrPtr id = NULL;
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007717 xmlNodePtr parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007718
7719 if (cur == NULL) {
7720#ifdef DEBUG_TREE
7721 xmlGenericError(xmlGenericErrorContext,
7722 "xmlAttrListDumpOutput : property == NULL\n");
7723#endif
7724 return;
7725 }
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007726 parent = cur->parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007727 while (cur != NULL) {
7728 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id")))
7729 id = cur;
7730 else
7731 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name")))
7732 name = cur;
7733 else
7734 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")))
7735 lang = cur;
7736 else
7737 if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) &&
7738 (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml")))
7739 xml_lang = cur;
7740 else if ((cur->ns == NULL) &&
7741 ((cur->children == NULL) ||
7742 (cur->children->content == NULL) ||
7743 (cur->children->content[0] == 0)) &&
7744 (htmlIsBooleanAttr(cur->name))) {
7745 if (cur->children != NULL)
7746 xmlFreeNode(cur->children);
7747 cur->children = xmlNewText(cur->name);
7748 if (cur->children != NULL)
7749 cur->children->parent = (xmlNodePtr) cur;
7750 }
7751 xmlAttrDumpOutput(buf, doc, cur, encoding);
7752 cur = cur->next;
7753 }
7754 /*
7755 * C.8
7756 */
7757 if ((name != NULL) && (id == NULL)) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007758 if ((parent != NULL) && (parent->name != NULL) &&
7759 ((xmlStrEqual(parent->name, BAD_CAST "a")) ||
7760 (xmlStrEqual(parent->name, BAD_CAST "p")) ||
7761 (xmlStrEqual(parent->name, BAD_CAST "div")) ||
7762 (xmlStrEqual(parent->name, BAD_CAST "img")) ||
7763 (xmlStrEqual(parent->name, BAD_CAST "map")) ||
7764 (xmlStrEqual(parent->name, BAD_CAST "applet")) ||
7765 (xmlStrEqual(parent->name, BAD_CAST "form")) ||
7766 (xmlStrEqual(parent->name, BAD_CAST "frame")) ||
7767 (xmlStrEqual(parent->name, BAD_CAST "iframe")))) {
7768 xmlOutputBufferWriteString(buf, " id=\"");
7769 xmlAttrSerializeContent(buf->buffer, doc, name);
7770 xmlOutputBufferWriteString(buf, "\"");
7771 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007772 }
7773 /*
7774 * C.7.
7775 */
7776 if ((lang != NULL) && (xml_lang == NULL)) {
7777 xmlOutputBufferWriteString(buf, " xml:lang=\"");
7778 xmlAttrSerializeContent(buf->buffer, doc, lang);
7779 xmlOutputBufferWriteString(buf, "\"");
7780 } else
7781 if ((xml_lang != NULL) && (lang == NULL)) {
7782 xmlOutputBufferWriteString(buf, " lang=\"");
7783 xmlAttrSerializeContent(buf->buffer, doc, xml_lang);
7784 xmlOutputBufferWriteString(buf, "\"");
7785 }
7786}
7787
7788/**
7789 * xhtmlNodeListDumpOutput:
7790 * @buf: the XML buffer output
7791 * @doc: the XHTML document
7792 * @cur: the first node
7793 * @level: the imbrication level for indenting
7794 * @format: is formatting allowed
7795 * @encoding: an optional encoding string
7796 *
7797 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007798 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007799 * or xmlKeepBlanksDefault(0) was called
7800 */
7801static void
7802xhtmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7803 xmlNodePtr cur, int level, int format, const char *encoding) {
7804 int i;
7805
7806 if (cur == NULL) {
7807#ifdef DEBUG_TREE
7808 xmlGenericError(xmlGenericErrorContext,
7809 "xhtmlNodeListDumpOutput : node == NULL\n");
7810#endif
7811 return;
7812 }
7813 while (cur != NULL) {
7814 if ((format) && (xmlIndentTreeOutput) &&
7815 (cur->type == XML_ELEMENT_NODE))
7816 for (i = 0;i < level;i++)
7817 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7818 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
7819 if (format) {
7820 xmlOutputBufferWriteString(buf, "\n");
7821 }
7822 cur = cur->next;
7823 }
7824}
7825
7826/**
7827 * xhtmlNodeDumpOutput:
7828 * @buf: the XML buffer output
7829 * @doc: the XHTML document
7830 * @cur: the current node
7831 * @level: the imbrication level for indenting
7832 * @format: is formatting allowed
7833 * @encoding: an optional encoding string
7834 *
7835 * Dump an XHTML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007836 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007837 * or xmlKeepBlanksDefault(0) was called
7838 */
7839static void
7840xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7841 int level, int format, const char *encoding) {
7842 int i;
7843 xmlNodePtr tmp;
7844
7845 if (cur == NULL) {
7846#ifdef DEBUG_TREE
7847 xmlGenericError(xmlGenericErrorContext,
7848 "xmlNodeDumpOutput : node == NULL\n");
7849#endif
7850 return;
7851 }
7852 if (cur->type == XML_XINCLUDE_START)
7853 return;
7854 if (cur->type == XML_XINCLUDE_END)
7855 return;
7856 if (cur->type == XML_DTD_NODE) {
7857 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7858 return;
7859 }
7860 if (cur->type == XML_ELEMENT_DECL) {
7861 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7862 return;
7863 }
7864 if (cur->type == XML_ATTRIBUTE_DECL) {
7865 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7866 return;
7867 }
7868 if (cur->type == XML_ENTITY_DECL) {
7869 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7870 return;
7871 }
7872 if (cur->type == XML_TEXT_NODE) {
7873 if (cur->content != NULL) {
7874 if ((cur->name == xmlStringText) ||
7875 (cur->name != xmlStringTextNoenc)) {
7876 xmlChar *buffer;
7877
7878 if (encoding == NULL)
7879 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7880 else
7881 buffer = xmlEncodeSpecialChars(doc, cur->content);
7882 if (buffer != NULL) {
7883 xmlOutputBufferWriteString(buf, (const char *)buffer);
7884 xmlFree(buffer);
7885 }
7886 } else {
7887 /*
7888 * Disable escaping, needed for XSLT
7889 */
7890 xmlOutputBufferWriteString(buf, (const char *) cur->content);
7891 }
7892 }
7893
7894 return;
7895 }
7896 if (cur->type == XML_PI_NODE) {
7897 if (cur->content != NULL) {
7898 xmlOutputBufferWriteString(buf, "<?");
7899 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7900 if (cur->content != NULL) {
7901 xmlOutputBufferWriteString(buf, " ");
7902 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7903 }
7904 xmlOutputBufferWriteString(buf, "?>");
7905 } else {
7906 xmlOutputBufferWriteString(buf, "<?");
7907 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7908 xmlOutputBufferWriteString(buf, "?>");
7909 }
7910 return;
7911 }
7912 if (cur->type == XML_COMMENT_NODE) {
7913 if (cur->content != NULL) {
7914 xmlOutputBufferWriteString(buf, "<!--");
7915 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7916 xmlOutputBufferWriteString(buf, "-->");
7917 }
7918 return;
7919 }
7920 if (cur->type == XML_ENTITY_REF_NODE) {
7921 xmlOutputBufferWriteString(buf, "&");
7922 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7923 xmlOutputBufferWriteString(buf, ";");
7924 return;
7925 }
7926 if (cur->type == XML_CDATA_SECTION_NODE) {
7927 xmlOutputBufferWriteString(buf, "<![CDATA[");
7928 if (cur->content != NULL)
7929 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7930 xmlOutputBufferWriteString(buf, "]]>");
7931 return;
7932 }
7933
7934 if (format == 1) {
7935 tmp = cur->children;
7936 while (tmp != NULL) {
7937 if ((tmp->type == XML_TEXT_NODE) ||
7938 (tmp->type == XML_ENTITY_REF_NODE)) {
7939 format = 0;
7940 break;
7941 }
7942 tmp = tmp->next;
7943 }
7944 }
7945 xmlOutputBufferWriteString(buf, "<");
7946 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7947 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7948 xmlOutputBufferWriteString(buf, ":");
7949 }
7950
7951 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7952 if (cur->nsDef)
7953 xmlNsListDumpOutput(buf, cur->nsDef);
7954 if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
7955 (cur->ns == NULL) && (cur->nsDef == NULL))) {
7956 /*
7957 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
7958 */
7959 xmlOutputBufferWriteString(buf,
7960 " xmlns=\"http://www.w3.org/1999/xhtml\"");
7961 }
7962 if (cur->properties != NULL)
7963 xhtmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7964
7965 if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) {
7966 if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
7967 (xhtmlIsEmpty(cur) == 1)) {
7968 /*
7969 * C.2. Empty Elements
7970 */
7971 xmlOutputBufferWriteString(buf, " />");
7972 } else {
7973 /*
7974 * C.3. Element Minimization and Empty Element Content
7975 */
7976 xmlOutputBufferWriteString(buf, "></");
7977 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7978 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7979 xmlOutputBufferWriteString(buf, ":");
7980 }
7981 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7982 xmlOutputBufferWriteString(buf, ">");
7983 }
7984 return;
7985 }
7986 xmlOutputBufferWriteString(buf, ">");
7987 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
7988 xmlChar *buffer;
7989
7990 if (encoding == NULL)
7991 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7992 else
7993 buffer = xmlEncodeSpecialChars(doc, cur->content);
7994 if (buffer != NULL) {
7995 xmlOutputBufferWriteString(buf, (const char *)buffer);
7996 xmlFree(buffer);
7997 }
7998 }
7999
8000 /*
8001 * 4.8. Script and Style elements
8002 */
8003 if ((cur->type == XML_ELEMENT_NODE) &&
8004 ((xmlStrEqual(cur->name, BAD_CAST "script")) ||
8005 (xmlStrEqual(cur->name, BAD_CAST "style"))) &&
8006 ((cur->ns == NULL) ||
8007 (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) {
8008 xmlNodePtr child = cur->children;
8009
8010 while (child != NULL) {
8011 if ((child->type == XML_TEXT_NODE) ||
8012 (child->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard64b35282002-12-04 15:10:40 +00008013 /*
8014 * Apparently CDATA escaping for style just break on IE,
8015 * mozilla and galeon, so ...
8016 */
8017 if (xmlStrEqual(cur->name, BAD_CAST "style") &&
8018 (xmlStrchr(child->content, '<') == NULL) &&
8019 (xmlStrchr(child->content, '>') == NULL) &&
8020 (xmlStrchr(child->content, '&') == NULL)) {
8021 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
8022 } else {
8023 xmlOutputBufferWriteString(buf, "<![CDATA[");
8024 if (child->content != NULL)
8025 xmlOutputBufferWriteString(buf,
8026 (const char *)child->content);
8027 xmlOutputBufferWriteString(buf, "]]>");
8028 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00008029 } else {
8030 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
8031 }
8032 child = child->next;
8033 }
8034 } else if (cur->children != NULL) {
8035 if (format) xmlOutputBufferWriteString(buf, "\n");
8036 xhtmlNodeListDumpOutput(buf, doc, cur->children,
8037 (level >= 0?level+1:-1), format, encoding);
8038 if ((xmlIndentTreeOutput) && (format))
8039 for (i = 0;i < level;i++)
8040 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
8041 }
8042 xmlOutputBufferWriteString(buf, "</");
8043 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
8044 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
8045 xmlOutputBufferWriteString(buf, ":");
8046 }
8047
8048 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8049 xmlOutputBufferWriteString(buf, ">");
8050}
8051#endif
8052
Owen Taylor3473f882001-02-23 17:55:21 +00008053/************************************************************************
8054 * *
8055 * Saving functions front-ends *
8056 * *
8057 ************************************************************************/
8058
8059/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00008060 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00008061 * @out_doc: Document to generate XML text from
8062 * @doc_txt_ptr: Memory pointer for allocated XML text
8063 * @doc_txt_len: Length of the generated XML text
8064 * @txt_encoding: Character encoding to use when generating XML text
8065 * @format: should formatting spaces been added
8066 *
8067 * Dump the current DOM tree into memory using the character encoding specified
8068 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008069 * allocated memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00008070 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00008071 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008072 */
8073
8074void
8075xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008076 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008077 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00008078 int dummy = 0;
8079
Owen Taylor3473f882001-02-23 17:55:21 +00008080 xmlOutputBufferPtr out_buff = NULL;
8081 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
8082
8083 if (doc_txt_len == NULL) {
8084 doc_txt_len = &dummy; /* Continue, caller just won't get length */
8085 }
8086
8087 if (doc_txt_ptr == NULL) {
8088 *doc_txt_len = 0;
8089 xmlGenericError(xmlGenericErrorContext,
8090 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
8091 return;
8092 }
8093
8094 *doc_txt_ptr = NULL;
8095 *doc_txt_len = 0;
8096
8097 if (out_doc == NULL) {
8098 /* No document, no output */
8099 xmlGenericError(xmlGenericErrorContext,
8100 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
8101 return;
8102 }
8103
8104 /*
8105 * Validate the encoding value, if provided.
8106 * This logic is copied from xmlSaveFileEnc.
8107 */
8108
8109 if (txt_encoding == NULL)
8110 txt_encoding = (const char *) out_doc->encoding;
8111 if (txt_encoding != NULL) {
Daniel Veillarde1326112003-06-05 09:32:20 +00008112 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00008113 if ( conv_hdlr == NULL ) {
8114 xmlGenericError(xmlGenericErrorContext,
8115 "%s: %s %s '%s'\n",
8116 "xmlDocDumpFormatMemoryEnc",
8117 "Failed to identify encoding handler for",
8118 "character set",
8119 txt_encoding);
8120 return;
8121 }
8122 }
Owen Taylor3473f882001-02-23 17:55:21 +00008123
8124 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
8125 xmlGenericError(xmlGenericErrorContext,
8126 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
8127 return;
8128 }
8129
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008130 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008131 xmlOutputBufferFlush(out_buff);
8132 if (out_buff->conv != NULL) {
8133 *doc_txt_len = out_buff->conv->use;
8134 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
8135 } else {
8136 *doc_txt_len = out_buff->buffer->use;
8137 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
8138 }
8139 (void)xmlOutputBufferClose(out_buff);
8140
8141 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
8142 *doc_txt_len = 0;
8143 xmlGenericError(xmlGenericErrorContext,
8144 "xmlDocDumpFormatMemoryEnc: %s\n",
8145 "Failed to allocate memory for document text representation.");
8146 }
8147
8148 return;
8149}
8150
8151/**
8152 * xmlDocDumpMemory:
8153 * @cur: the document
8154 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00008155 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00008156 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008157 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008158 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00008159 */
8160void
8161xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
8162 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
8163}
8164
8165/**
8166 * xmlDocDumpFormatMemory:
8167 * @cur: the document
8168 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00008169 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00008170 * @format: should formatting spaces been added
8171 *
8172 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008173 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008174 * It's up to the caller to free the memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00008175 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00008176 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008177 */
8178void
8179xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
8180 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
8181}
8182
8183/**
8184 * xmlDocDumpMemoryEnc:
8185 * @out_doc: Document to generate XML text from
8186 * @doc_txt_ptr: Memory pointer for allocated XML text
8187 * @doc_txt_len: Length of the generated XML text
8188 * @txt_encoding: Character encoding to use when generating XML text
8189 *
8190 * Dump the current DOM tree into memory using the character encoding specified
8191 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008192 * allocated memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00008193 */
8194
8195void
8196xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
8197 int * doc_txt_len, const char * txt_encoding) {
8198 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008199 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008200}
8201
8202/**
8203 * xmlGetDocCompressMode:
8204 * @doc: the document
8205 *
8206 * get the compression ratio for a document, ZLIB based
8207 * Returns 0 (uncompressed) to 9 (max compression)
8208 */
8209int
8210xmlGetDocCompressMode (xmlDocPtr doc) {
8211 if (doc == NULL) return(-1);
8212 return(doc->compression);
8213}
8214
8215/**
8216 * xmlSetDocCompressMode:
8217 * @doc: the document
8218 * @mode: the compression ratio
8219 *
8220 * set the compression ratio for a document, ZLIB based
8221 * Correct values: 0 (uncompressed) to 9 (max compression)
8222 */
8223void
8224xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
8225 if (doc == NULL) return;
8226 if (mode < 0) doc->compression = 0;
8227 else if (mode > 9) doc->compression = 9;
8228 else doc->compression = mode;
8229}
8230
8231/**
8232 * xmlGetCompressMode:
8233 *
8234 * get the default compression mode used, ZLIB based.
8235 * Returns 0 (uncompressed) to 9 (max compression)
8236 */
8237int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008238xmlGetCompressMode(void)
8239{
8240 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00008241}
8242
8243/**
8244 * xmlSetCompressMode:
8245 * @mode: the compression ratio
8246 *
8247 * set the default compression mode used, ZLIB based
8248 * Correct values: 0 (uncompressed) to 9 (max compression)
8249 */
8250void
8251xmlSetCompressMode(int mode) {
8252 if (mode < 0) xmlCompressMode = 0;
8253 else if (mode > 9) xmlCompressMode = 9;
8254 else xmlCompressMode = mode;
8255}
8256
8257/**
Daniel Veillard9e412302002-06-10 15:59:44 +00008258 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00008259 * @f: the FILE*
8260 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00008261 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00008262 *
8263 * Dump an XML document to an open FILE.
8264 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008265 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008266 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8267 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008268 */
8269int
Daniel Veillard9e412302002-06-10 15:59:44 +00008270xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00008271 xmlOutputBufferPtr buf;
8272 const char * encoding;
8273 xmlCharEncodingHandlerPtr handler = NULL;
8274 int ret;
8275
8276 if (cur == NULL) {
8277#ifdef DEBUG_TREE
8278 xmlGenericError(xmlGenericErrorContext,
8279 "xmlDocDump : document == NULL\n");
8280#endif
8281 return(-1);
8282 }
8283 encoding = (const char *) cur->encoding;
8284
8285 if (encoding != NULL) {
Daniel Veillarde1326112003-06-05 09:32:20 +00008286 handler = xmlFindCharEncodingHandler(encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00008287 if (handler == NULL) {
8288 xmlFree((char *) cur->encoding);
8289 cur->encoding = NULL;
8290 }
8291 }
Owen Taylor3473f882001-02-23 17:55:21 +00008292 buf = xmlOutputBufferCreateFile(f, handler);
8293 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00008294 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008295
8296 ret = xmlOutputBufferClose(buf);
8297 return(ret);
8298}
8299
8300/**
Daniel Veillard9e412302002-06-10 15:59:44 +00008301 * xmlDocDump:
8302 * @f: the FILE*
8303 * @cur: the document
8304 *
8305 * Dump an XML document to an open FILE.
8306 *
8307 * returns: the number of bytes written or -1 in case of failure.
8308 */
8309int
8310xmlDocDump(FILE *f, xmlDocPtr cur) {
8311 return(xmlDocFormatDump (f, cur, 0));
8312}
8313
8314/**
Owen Taylor3473f882001-02-23 17:55:21 +00008315 * xmlSaveFileTo:
8316 * @buf: an output I/O buffer
8317 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00008318 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00008319 *
8320 * Dump an XML document to an I/O buffer.
8321 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008322 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008323 */
8324int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00008325xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00008326 int ret;
8327
8328 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008329 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008330 ret = xmlOutputBufferClose(buf);
8331 return(ret);
8332}
8333
8334/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00008335 * xmlSaveFormatFileTo:
8336 * @buf: an output I/O buffer
8337 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00008338 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00008339 * @format: should formatting spaces been added
8340 *
8341 * Dump an XML document to an I/O buffer.
8342 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008343 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008344 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8345 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardeefd4492001-04-28 16:55:50 +00008346 */
8347int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00008348xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00008349 int ret;
8350
8351 if (buf == NULL) return(0);
8352 xmlDocContentDumpOutput(buf, cur, encoding, format);
8353 ret = xmlOutputBufferClose(buf);
8354 return(ret);
8355}
8356
8357/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00008358 * xmlSaveFormatFileEnc:
Daniel Veillardf012a642001-07-23 19:10:52 +00008359 * @filename: the filename or URL to output
8360 * @cur: the document being saved
8361 * @encoding: the name of the encoding to use or NULL.
8362 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00008363 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00008364 * Dump an XML document to a file or an URL.
8365 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008366 * Returns the number of bytes written or -1 in case of error.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008367 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8368 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008369 */
8370int
Daniel Veillardf012a642001-07-23 19:10:52 +00008371xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
8372 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00008373 xmlOutputBufferPtr buf;
8374 xmlCharEncodingHandlerPtr handler = NULL;
8375 int ret;
8376
Daniel Veillard4dbe77a2003-01-14 00:17:42 +00008377 if (cur == NULL)
8378 return(-1);
8379
Daniel Veillardfb25a512002-01-13 20:32:08 +00008380 if (encoding == NULL)
8381 encoding = (const char *) cur->encoding;
8382
Owen Taylor3473f882001-02-23 17:55:21 +00008383 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00008384
Owen Taylor3473f882001-02-23 17:55:21 +00008385 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00008386 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00008387 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00008388 }
8389
Daniel Veillardf012a642001-07-23 19:10:52 +00008390#ifdef HAVE_ZLIB_H
8391 if (cur->compression < 0) cur->compression = xmlCompressMode;
8392#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008393 /*
8394 * save the content to a temp buffer.
8395 */
Daniel Veillardf012a642001-07-23 19:10:52 +00008396 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00008397 if (buf == NULL) return(-1);
8398
Daniel Veillardf012a642001-07-23 19:10:52 +00008399 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008400
8401 ret = xmlOutputBufferClose(buf);
8402 return(ret);
8403}
8404
Daniel Veillardf012a642001-07-23 19:10:52 +00008405
8406/**
8407 * xmlSaveFileEnc:
8408 * @filename: the filename (or URL)
8409 * @cur: the document
8410 * @encoding: the name of an encoding (or NULL)
8411 *
8412 * Dump an XML document, converting it to the given encoding
8413 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008414 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00008415 */
8416int
8417xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
8418 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
8419}
8420
Owen Taylor3473f882001-02-23 17:55:21 +00008421/**
Daniel Veillard67fee942001-04-26 18:59:03 +00008422 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00008423 * @filename: the filename (or URL)
8424 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00008425 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00008426 *
8427 * Dump an XML document to a file. Will use compression if
8428 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00008429 * used. If @format is set then the document will be indented on output.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008430 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8431 * or xmlKeepBlanksDefault(0) was called
Daniel Veillard67fee942001-04-26 18:59:03 +00008432 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008433 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008434 */
8435int
Daniel Veillard67fee942001-04-26 18:59:03 +00008436xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008437 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00008438}
8439
Daniel Veillard67fee942001-04-26 18:59:03 +00008440/**
8441 * xmlSaveFile:
8442 * @filename: the filename (or URL)
8443 * @cur: the document
8444 *
8445 * Dump an XML document to a file. Will use compression if
8446 * compiled in and enabled. If @filename is "-" the stdout file is
8447 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00008448 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00008449 */
8450int
8451xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008452 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00008453}
8454