blob: 0e4a6f42f11e5f9d12202cfa5e7ba1618dc7d581 [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 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003438 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3439#ifdef DEBUG_TREE
3440 xmlGenericError(xmlGenericErrorContext,
3441 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3442#endif
3443 return(old);
3444 }
3445 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3446#ifdef DEBUG_TREE
3447 xmlGenericError(xmlGenericErrorContext,
3448 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3449#endif
3450 return(old);
3451 }
Owen Taylor3473f882001-02-23 17:55:21 +00003452 xmlUnlinkNode(cur);
3453 cur->doc = old->doc;
3454 cur->parent = old->parent;
3455 cur->next = old->next;
3456 if (cur->next != NULL)
3457 cur->next->prev = cur;
3458 cur->prev = old->prev;
3459 if (cur->prev != NULL)
3460 cur->prev->next = cur;
3461 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003462 if (cur->type == XML_ATTRIBUTE_NODE) {
3463 if (cur->parent->properties == (xmlAttrPtr)old)
3464 cur->parent->properties = ((xmlAttrPtr) cur);
3465 } else {
3466 if (cur->parent->children == old)
3467 cur->parent->children = cur;
3468 if (cur->parent->last == old)
3469 cur->parent->last = cur;
3470 }
Owen Taylor3473f882001-02-23 17:55:21 +00003471 }
3472 old->next = old->prev = NULL;
3473 old->parent = NULL;
3474 return(old);
3475}
3476
3477/************************************************************************
3478 * *
3479 * Copy operations *
3480 * *
3481 ************************************************************************/
3482
3483/**
3484 * xmlCopyNamespace:
3485 * @cur: the namespace
3486 *
3487 * Do a copy of the namespace.
3488 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003489 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003490 */
3491xmlNsPtr
3492xmlCopyNamespace(xmlNsPtr cur) {
3493 xmlNsPtr ret;
3494
3495 if (cur == NULL) return(NULL);
3496 switch (cur->type) {
3497 case XML_LOCAL_NAMESPACE:
3498 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3499 break;
3500 default:
3501#ifdef DEBUG_TREE
3502 xmlGenericError(xmlGenericErrorContext,
3503 "xmlCopyNamespace: invalid type %d\n", cur->type);
3504#endif
3505 return(NULL);
3506 }
3507 return(ret);
3508}
3509
3510/**
3511 * xmlCopyNamespaceList:
3512 * @cur: the first namespace
3513 *
3514 * Do a copy of an namespace list.
3515 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003516 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003517 */
3518xmlNsPtr
3519xmlCopyNamespaceList(xmlNsPtr cur) {
3520 xmlNsPtr ret = NULL;
3521 xmlNsPtr p = NULL,q;
3522
3523 while (cur != NULL) {
3524 q = xmlCopyNamespace(cur);
3525 if (p == NULL) {
3526 ret = p = q;
3527 } else {
3528 p->next = q;
3529 p = q;
3530 }
3531 cur = cur->next;
3532 }
3533 return(ret);
3534}
3535
3536static xmlNodePtr
3537xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3538/**
3539 * xmlCopyProp:
3540 * @target: the element where the attribute will be grafted
3541 * @cur: the attribute
3542 *
3543 * Do a copy of the attribute.
3544 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003545 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003546 */
3547xmlAttrPtr
3548xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3549 xmlAttrPtr ret;
3550
3551 if (cur == NULL) return(NULL);
3552 if (target != NULL)
3553 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3554 else if (cur->parent != NULL)
3555 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3556 else if (cur->children != NULL)
3557 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3558 else
3559 ret = xmlNewDocProp(NULL, cur->name, NULL);
3560 if (ret == NULL) return(NULL);
3561 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003562
Owen Taylor3473f882001-02-23 17:55:21 +00003563 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003564 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003565/*
3566 * if (target->doc)
3567 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3568 * else if (cur->doc) / * target may not yet have a doc : KPI * /
3569 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
3570 * else
3571 * ns = NULL;
3572 * ret->ns = ns;
3573 */
3574 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3575 if (ns == NULL) {
3576 /*
3577 * Humm, we are copying an element whose namespace is defined
3578 * out of the new tree scope. Search it in the original tree
3579 * and add it at the top of the new tree
3580 */
3581 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3582 if (ns != NULL) {
3583 xmlNodePtr root = target;
3584 xmlNodePtr pred = NULL;
3585
3586 while (root->parent != NULL) {
3587 pred = root;
3588 root = root->parent;
3589 }
3590 if (root == (xmlNodePtr) target->doc) {
3591 /* correct possibly cycling above the document elt */
3592 root = pred;
3593 }
3594 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3595 }
3596 } else {
3597 /*
3598 * we have to find something appropriate here since
3599 * we cant be sure, that the namespce we found is identified
3600 * by the prefix
3601 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003602 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003603 /* this is the nice case */
3604 ret->ns = ns;
3605 } else {
3606 /*
3607 * we are in trouble: we need a new reconcilied namespace.
3608 * This is expensive
3609 */
3610 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3611 }
3612 }
3613
Owen Taylor3473f882001-02-23 17:55:21 +00003614 } else
3615 ret->ns = NULL;
3616
3617 if (cur->children != NULL) {
3618 xmlNodePtr tmp;
3619
3620 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3621 ret->last = NULL;
3622 tmp = ret->children;
3623 while (tmp != NULL) {
3624 /* tmp->parent = (xmlNodePtr)ret; */
3625 if (tmp->next == NULL)
3626 ret->last = tmp;
3627 tmp = tmp->next;
3628 }
3629 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003630 /*
3631 * Try to handle IDs
3632 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003633 if ((target!= NULL) && (cur!= NULL) &&
3634 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003635 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3636 if (xmlIsID(cur->doc, cur->parent, cur)) {
3637 xmlChar *id;
3638
3639 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3640 if (id != NULL) {
3641 xmlAddID(NULL, target->doc, id, ret);
3642 xmlFree(id);
3643 }
3644 }
3645 }
Owen Taylor3473f882001-02-23 17:55:21 +00003646 return(ret);
3647}
3648
3649/**
3650 * xmlCopyPropList:
3651 * @target: the element where the attributes will be grafted
3652 * @cur: the first attribute
3653 *
3654 * Do a copy of an attribute list.
3655 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003656 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003657 */
3658xmlAttrPtr
3659xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3660 xmlAttrPtr ret = NULL;
3661 xmlAttrPtr p = NULL,q;
3662
3663 while (cur != NULL) {
3664 q = xmlCopyProp(target, cur);
3665 if (p == NULL) {
3666 ret = p = q;
3667 } else {
3668 p->next = q;
3669 q->prev = p;
3670 p = q;
3671 }
3672 cur = cur->next;
3673 }
3674 return(ret);
3675}
3676
3677/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003678 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003679 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003680 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003681 * tricky reason: namespaces. Doing a direct copy of a node
3682 * say RPM:Copyright without changing the namespace pointer to
3683 * something else can produce stale links. One way to do it is
3684 * to keep a reference counter but this doesn't work as soon
3685 * as one move the element or the subtree out of the scope of
3686 * the existing namespace. The actual solution seems to add
3687 * a copy of the namespace at the top of the copied tree if
3688 * not available in the subtree.
3689 * Hence two functions, the public front-end call the inner ones
3690 */
3691
3692static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003693xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003694 int recursive) {
3695 xmlNodePtr ret;
3696
3697 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003698 switch (node->type) {
3699 case XML_TEXT_NODE:
3700 case XML_CDATA_SECTION_NODE:
3701 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003702 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003703 case XML_ENTITY_REF_NODE:
3704 case XML_ENTITY_NODE:
3705 case XML_PI_NODE:
3706 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003707 case XML_XINCLUDE_START:
3708 case XML_XINCLUDE_END:
3709 break;
3710 case XML_ATTRIBUTE_NODE:
3711 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3712 case XML_NAMESPACE_DECL:
3713 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3714
Daniel Veillard39196eb2001-06-19 18:09:42 +00003715 case XML_DOCUMENT_NODE:
3716 case XML_HTML_DOCUMENT_NODE:
3717#ifdef LIBXML_DOCB_ENABLED
3718 case XML_DOCB_DOCUMENT_NODE:
3719#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003720 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00003721 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003722 case XML_NOTATION_NODE:
3723 case XML_DTD_NODE:
3724 case XML_ELEMENT_DECL:
3725 case XML_ATTRIBUTE_DECL:
3726 case XML_ENTITY_DECL:
3727 return(NULL);
3728 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003729
Owen Taylor3473f882001-02-23 17:55:21 +00003730 /*
3731 * Allocate a new node and fill the fields.
3732 */
3733 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3734 if (ret == NULL) {
3735 xmlGenericError(xmlGenericErrorContext,
3736 "xmlStaticCopyNode : malloc failed\n");
3737 return(NULL);
3738 }
3739 memset(ret, 0, sizeof(xmlNode));
3740 ret->type = node->type;
3741
3742 ret->doc = doc;
3743 ret->parent = parent;
3744 if (node->name == xmlStringText)
3745 ret->name = xmlStringText;
3746 else if (node->name == xmlStringTextNoenc)
3747 ret->name = xmlStringTextNoenc;
3748 else if (node->name == xmlStringComment)
3749 ret->name = xmlStringComment;
3750 else if (node->name != NULL)
3751 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003752 if ((node->type != XML_ELEMENT_NODE) &&
3753 (node->content != NULL) &&
3754 (node->type != XML_ENTITY_REF_NODE) &&
3755 (node->type != XML_XINCLUDE_END) &&
3756 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003757 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003758 }else{
3759 if (node->type == XML_ELEMENT_NODE)
3760 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00003761 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003762 if (parent != NULL) {
3763 xmlNodePtr tmp;
3764
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003765 /*
3766 * this is a tricky part for the node register thing:
3767 * in case ret does get coalesced in xmlAddChild
3768 * the deregister-node callback is called; so we register ret now already
3769 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003770 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003771 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3772
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003773 tmp = xmlAddChild(parent, ret);
3774 /* node could have coalesced */
3775 if (tmp != ret)
3776 return(tmp);
3777 }
Owen Taylor3473f882001-02-23 17:55:21 +00003778
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003779 if (!recursive)
3780 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003781 if (node->nsDef != NULL)
3782 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3783
3784 if (node->ns != NULL) {
3785 xmlNsPtr ns;
3786
3787 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3788 if (ns == NULL) {
3789 /*
3790 * Humm, we are copying an element whose namespace is defined
3791 * out of the new tree scope. Search it in the original tree
3792 * and add it at the top of the new tree
3793 */
3794 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3795 if (ns != NULL) {
3796 xmlNodePtr root = ret;
3797
3798 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003799 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003800 }
3801 } else {
3802 /*
3803 * reference the existing namespace definition in our own tree.
3804 */
3805 ret->ns = ns;
3806 }
3807 }
3808 if (node->properties != NULL)
3809 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003810 if (node->type == XML_ENTITY_REF_NODE) {
3811 if ((doc == NULL) || (node->doc != doc)) {
3812 /*
3813 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003814 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003815 * we cannot keep the reference. Try to find it in the
3816 * target document.
3817 */
3818 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3819 } else {
3820 ret->children = node->children;
3821 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003822 ret->last = ret->children;
3823 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003824 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003825 UPDATE_LAST_CHILD_AND_PARENT(ret)
3826 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003827
3828out:
3829 /* if parent != NULL we already registered the node above */
3830 if (parent == NULL && xmlRegisterNodeDefaultValue)
3831 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003832 return(ret);
3833}
3834
3835static xmlNodePtr
3836xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3837 xmlNodePtr ret = NULL;
3838 xmlNodePtr p = NULL,q;
3839
3840 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003841 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003842 if (doc == NULL) {
3843 node = node->next;
3844 continue;
3845 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003846 if (doc->intSubset == NULL) {
3847 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3848 q->doc = doc;
3849 q->parent = parent;
3850 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003851 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003852 } else {
3853 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003854 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003855 }
3856 } else
3857 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003858 if (ret == NULL) {
3859 q->prev = NULL;
3860 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003861 } else if (p != q) {
3862 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003863 p->next = q;
3864 q->prev = p;
3865 p = q;
3866 }
3867 node = node->next;
3868 }
3869 return(ret);
3870}
3871
3872/**
3873 * xmlCopyNode:
3874 * @node: the node
3875 * @recursive: if 1 do a recursive copy.
3876 *
3877 * Do a copy of the node.
3878 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003879 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003880 */
3881xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003882xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003883 xmlNodePtr ret;
3884
3885 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3886 return(ret);
3887}
3888
3889/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003890 * xmlDocCopyNode:
3891 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003892 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003893 * @recursive: if 1 do a recursive copy.
3894 *
3895 * Do a copy of the node to a given document.
3896 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003897 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003898 */
3899xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003900xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003901 xmlNodePtr ret;
3902
3903 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3904 return(ret);
3905}
3906
3907/**
Owen Taylor3473f882001-02-23 17:55:21 +00003908 * xmlCopyNodeList:
3909 * @node: the first node in the list.
3910 *
3911 * Do a recursive copy of the node list.
3912 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003913 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003914 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003915xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003916 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3917 return(ret);
3918}
3919
3920/**
Owen Taylor3473f882001-02-23 17:55:21 +00003921 * xmlCopyDtd:
3922 * @dtd: the dtd
3923 *
3924 * Do a copy of the dtd.
3925 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003926 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003927 */
3928xmlDtdPtr
3929xmlCopyDtd(xmlDtdPtr dtd) {
3930 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003931 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003932
3933 if (dtd == NULL) return(NULL);
3934 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3935 if (ret == NULL) return(NULL);
3936 if (dtd->entities != NULL)
3937 ret->entities = (void *) xmlCopyEntitiesTable(
3938 (xmlEntitiesTablePtr) dtd->entities);
3939 if (dtd->notations != NULL)
3940 ret->notations = (void *) xmlCopyNotationTable(
3941 (xmlNotationTablePtr) dtd->notations);
3942 if (dtd->elements != NULL)
3943 ret->elements = (void *) xmlCopyElementTable(
3944 (xmlElementTablePtr) dtd->elements);
3945 if (dtd->attributes != NULL)
3946 ret->attributes = (void *) xmlCopyAttributeTable(
3947 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003948 if (dtd->pentities != NULL)
3949 ret->pentities = (void *) xmlCopyEntitiesTable(
3950 (xmlEntitiesTablePtr) dtd->pentities);
3951
3952 cur = dtd->children;
3953 while (cur != NULL) {
3954 q = NULL;
3955
3956 if (cur->type == XML_ENTITY_DECL) {
3957 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3958 switch (tmp->etype) {
3959 case XML_INTERNAL_GENERAL_ENTITY:
3960 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3961 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3962 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3963 break;
3964 case XML_INTERNAL_PARAMETER_ENTITY:
3965 case XML_EXTERNAL_PARAMETER_ENTITY:
3966 q = (xmlNodePtr)
3967 xmlGetParameterEntityFromDtd(ret, tmp->name);
3968 break;
3969 case XML_INTERNAL_PREDEFINED_ENTITY:
3970 break;
3971 }
3972 } else if (cur->type == XML_ELEMENT_DECL) {
3973 xmlElementPtr tmp = (xmlElementPtr) cur;
3974 q = (xmlNodePtr)
3975 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3976 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3977 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3978 q = (xmlNodePtr)
3979 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3980 } else if (cur->type == XML_COMMENT_NODE) {
3981 q = xmlCopyNode(cur, 0);
3982 }
3983
3984 if (q == NULL) {
3985 cur = cur->next;
3986 continue;
3987 }
3988
3989 if (p == NULL)
3990 ret->children = q;
3991 else
3992 p->next = q;
3993
3994 q->prev = p;
3995 q->parent = (xmlNodePtr) ret;
3996 q->next = NULL;
3997 ret->last = q;
3998 p = q;
3999 cur = cur->next;
4000 }
4001
Owen Taylor3473f882001-02-23 17:55:21 +00004002 return(ret);
4003}
4004
4005/**
4006 * xmlCopyDoc:
4007 * @doc: the document
4008 * @recursive: if 1 do a recursive copy.
4009 *
4010 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004011 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00004012 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004013 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00004014 */
4015xmlDocPtr
4016xmlCopyDoc(xmlDocPtr doc, int recursive) {
4017 xmlDocPtr ret;
4018
4019 if (doc == NULL) return(NULL);
4020 ret = xmlNewDoc(doc->version);
4021 if (ret == NULL) return(NULL);
4022 if (doc->name != NULL)
4023 ret->name = xmlMemStrdup(doc->name);
4024 if (doc->encoding != NULL)
4025 ret->encoding = xmlStrdup(doc->encoding);
4026 ret->charset = doc->charset;
4027 ret->compression = doc->compression;
4028 ret->standalone = doc->standalone;
4029 if (!recursive) return(ret);
4030
Daniel Veillardb33c2012001-04-25 12:59:04 +00004031 ret->last = NULL;
4032 ret->children = NULL;
4033 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004034 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00004035 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00004036 ret->intSubset->parent = ret;
4037 }
Owen Taylor3473f882001-02-23 17:55:21 +00004038 if (doc->oldNs != NULL)
4039 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4040 if (doc->children != NULL) {
4041 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00004042
4043 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4044 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004045 ret->last = NULL;
4046 tmp = ret->children;
4047 while (tmp != NULL) {
4048 if (tmp->next == NULL)
4049 ret->last = tmp;
4050 tmp = tmp->next;
4051 }
4052 }
4053 return(ret);
4054}
4055
4056/************************************************************************
4057 * *
4058 * Content access functions *
4059 * *
4060 ************************************************************************/
4061
4062/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004063 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004064 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004065 *
4066 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004067 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004068 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004069 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004070 */
4071long
4072xmlGetLineNo(xmlNodePtr node)
4073{
4074 long result = -1;
4075
4076 if (!node)
4077 return result;
4078 if (node->type == XML_ELEMENT_NODE)
4079 result = (long) node->content;
4080 else if ((node->prev != NULL) &&
4081 ((node->prev->type == XML_ELEMENT_NODE) ||
4082 (node->prev->type == XML_TEXT_NODE)))
4083 result = xmlGetLineNo(node->prev);
4084 else if ((node->parent != NULL) &&
4085 ((node->parent->type == XML_ELEMENT_NODE) ||
4086 (node->parent->type == XML_TEXT_NODE)))
4087 result = xmlGetLineNo(node->parent);
4088
4089 return result;
4090}
4091
4092/**
4093 * xmlGetNodePath:
4094 * @node: a node
4095 *
4096 * Build a structure based Path for the given node
4097 *
4098 * Returns the new path or NULL in case of error. The caller must free
4099 * the returned string
4100 */
4101xmlChar *
4102xmlGetNodePath(xmlNodePtr node)
4103{
4104 xmlNodePtr cur, tmp, next;
4105 xmlChar *buffer = NULL, *temp;
4106 size_t buf_len;
4107 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004108 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004109 const char *name;
4110 char nametemp[100];
4111 int occur = 0;
4112
4113 if (node == NULL)
4114 return (NULL);
4115
4116 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004117 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004118 if (buffer == NULL)
4119 return (NULL);
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004120 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004121 if (buf == NULL) {
4122 xmlFree(buffer);
4123 return (NULL);
4124 }
4125
4126 buffer[0] = 0;
4127 cur = node;
4128 do {
4129 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004130 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004131 occur = 0;
4132 if ((cur->type == XML_DOCUMENT_NODE) ||
4133 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4134 if (buffer[0] == '/')
4135 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004136 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004137 next = NULL;
4138 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004139 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004140 name = (const char *) cur->name;
4141 if (cur->ns) {
4142 snprintf(nametemp, sizeof(nametemp) - 1,
4143 "%s:%s", cur->ns->prefix, cur->name);
4144 nametemp[sizeof(nametemp) - 1] = 0;
4145 name = nametemp;
4146 }
4147 next = cur->parent;
4148
4149 /*
4150 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004151 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004152 */
4153 tmp = cur->prev;
4154 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004155 if ((tmp->type == XML_ELEMENT_NODE) &&
4156 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004157 occur++;
4158 tmp = tmp->prev;
4159 }
4160 if (occur == 0) {
4161 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004162 while (tmp != NULL && occur == 0) {
4163 if ((tmp->type == XML_ELEMENT_NODE) &&
4164 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004165 occur++;
4166 tmp = tmp->next;
4167 }
4168 if (occur != 0)
4169 occur = 1;
4170 } else
4171 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004172 } else if (cur->type == XML_COMMENT_NODE) {
4173 sep = "/";
4174 name = "comment()";
4175 next = cur->parent;
4176
4177 /*
4178 * Thumbler index computation
4179 */
4180 tmp = cur->prev;
4181 while (tmp != NULL) {
4182 if (tmp->type == XML_COMMENT_NODE)
4183 occur++;
4184 tmp = tmp->prev;
4185 }
4186 if (occur == 0) {
4187 tmp = cur->next;
4188 while (tmp != NULL && occur == 0) {
4189 if (tmp->type == XML_COMMENT_NODE)
4190 occur++;
4191 tmp = tmp->next;
4192 }
4193 if (occur != 0)
4194 occur = 1;
4195 } else
4196 occur++;
4197 } else if ((cur->type == XML_TEXT_NODE) ||
4198 (cur->type == XML_CDATA_SECTION_NODE)) {
4199 sep = "/";
4200 name = "text()";
4201 next = cur->parent;
4202
4203 /*
4204 * Thumbler index computation
4205 */
4206 tmp = cur->prev;
4207 while (tmp != NULL) {
4208 if ((cur->type == XML_TEXT_NODE) ||
4209 (cur->type == XML_CDATA_SECTION_NODE))
4210 occur++;
4211 tmp = tmp->prev;
4212 }
4213 if (occur == 0) {
4214 tmp = cur->next;
4215 while (tmp != NULL && occur == 0) {
4216 if ((cur->type == XML_TEXT_NODE) ||
4217 (cur->type == XML_CDATA_SECTION_NODE))
4218 occur++;
4219 tmp = tmp->next;
4220 }
4221 if (occur != 0)
4222 occur = 1;
4223 } else
4224 occur++;
4225 } else if (cur->type == XML_PI_NODE) {
4226 sep = "/";
4227 snprintf(nametemp, sizeof(nametemp) - 1,
4228 "processing-instruction('%s')", cur->name);
4229 nametemp[sizeof(nametemp) - 1] = 0;
4230 name = nametemp;
4231
4232 next = cur->parent;
4233
4234 /*
4235 * Thumbler index computation
4236 */
4237 tmp = cur->prev;
4238 while (tmp != NULL) {
4239 if ((tmp->type == XML_PI_NODE) &&
4240 (xmlStrEqual(cur->name, tmp->name)))
4241 occur++;
4242 tmp = tmp->prev;
4243 }
4244 if (occur == 0) {
4245 tmp = cur->next;
4246 while (tmp != NULL && occur == 0) {
4247 if ((tmp->type == XML_PI_NODE) &&
4248 (xmlStrEqual(cur->name, tmp->name)))
4249 occur++;
4250 tmp = tmp->next;
4251 }
4252 if (occur != 0)
4253 occur = 1;
4254 } else
4255 occur++;
4256
Daniel Veillard8faa7832001-11-26 15:58:08 +00004257 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004258 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004259 name = (const char *) (((xmlAttrPtr) cur)->name);
4260 next = ((xmlAttrPtr) cur)->parent;
4261 } else {
4262 next = cur->parent;
4263 }
4264
4265 /*
4266 * Make sure there is enough room
4267 */
4268 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4269 buf_len =
4270 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4271 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4272 if (temp == NULL) {
4273 xmlFree(buf);
4274 xmlFree(buffer);
4275 return (NULL);
4276 }
4277 buffer = temp;
4278 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4279 if (temp == NULL) {
4280 xmlFree(buf);
4281 xmlFree(buffer);
4282 return (NULL);
4283 }
4284 buf = temp;
4285 }
4286 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004287 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004288 sep, name, (char *) buffer);
4289 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004290 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004291 sep, name, occur, (char *) buffer);
4292 snprintf((char *) buffer, buf_len, "%s", buf);
4293 cur = next;
4294 } while (cur != NULL);
4295 xmlFree(buf);
4296 return (buffer);
4297}
4298
4299/**
Owen Taylor3473f882001-02-23 17:55:21 +00004300 * xmlDocGetRootElement:
4301 * @doc: the document
4302 *
4303 * Get the root element of the document (doc->children is a list
4304 * containing possibly comments, PIs, etc ...).
4305 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004306 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004307 */
4308xmlNodePtr
4309xmlDocGetRootElement(xmlDocPtr doc) {
4310 xmlNodePtr ret;
4311
4312 if (doc == NULL) return(NULL);
4313 ret = doc->children;
4314 while (ret != NULL) {
4315 if (ret->type == XML_ELEMENT_NODE)
4316 return(ret);
4317 ret = ret->next;
4318 }
4319 return(ret);
4320}
4321
4322/**
4323 * xmlDocSetRootElement:
4324 * @doc: the document
4325 * @root: the new document root element
4326 *
4327 * Set the root element of the document (doc->children is a list
4328 * containing possibly comments, PIs, etc ...).
4329 *
4330 * Returns the old root element if any was found
4331 */
4332xmlNodePtr
4333xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4334 xmlNodePtr old = NULL;
4335
4336 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004337 if (root == NULL)
4338 return(NULL);
4339 xmlUnlinkNode(root);
4340 root->doc = doc;
4341 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004342 old = doc->children;
4343 while (old != NULL) {
4344 if (old->type == XML_ELEMENT_NODE)
4345 break;
4346 old = old->next;
4347 }
4348 if (old == NULL) {
4349 if (doc->children == NULL) {
4350 doc->children = root;
4351 doc->last = root;
4352 } else {
4353 xmlAddSibling(doc->children, root);
4354 }
4355 } else {
4356 xmlReplaceNode(old, root);
4357 }
4358 return(old);
4359}
4360
4361/**
4362 * xmlNodeSetLang:
4363 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004364 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004365 *
4366 * Set the language of a node, i.e. the values of the xml:lang
4367 * attribute.
4368 */
4369void
4370xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004371 xmlNsPtr ns;
4372
Owen Taylor3473f882001-02-23 17:55:21 +00004373 if (cur == NULL) return;
4374 switch(cur->type) {
4375 case XML_TEXT_NODE:
4376 case XML_CDATA_SECTION_NODE:
4377 case XML_COMMENT_NODE:
4378 case XML_DOCUMENT_NODE:
4379 case XML_DOCUMENT_TYPE_NODE:
4380 case XML_DOCUMENT_FRAG_NODE:
4381 case XML_NOTATION_NODE:
4382 case XML_HTML_DOCUMENT_NODE:
4383 case XML_DTD_NODE:
4384 case XML_ELEMENT_DECL:
4385 case XML_ATTRIBUTE_DECL:
4386 case XML_ENTITY_DECL:
4387 case XML_PI_NODE:
4388 case XML_ENTITY_REF_NODE:
4389 case XML_ENTITY_NODE:
4390 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004391#ifdef LIBXML_DOCB_ENABLED
4392 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004393#endif
4394 case XML_XINCLUDE_START:
4395 case XML_XINCLUDE_END:
4396 return;
4397 case XML_ELEMENT_NODE:
4398 case XML_ATTRIBUTE_NODE:
4399 break;
4400 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004401 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4402 if (ns == NULL)
4403 return;
4404 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004405}
4406
4407/**
4408 * xmlNodeGetLang:
4409 * @cur: the node being checked
4410 *
4411 * Searches the language of a node, i.e. the values of the xml:lang
4412 * attribute or the one carried by the nearest ancestor.
4413 *
4414 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004415 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004416 */
4417xmlChar *
4418xmlNodeGetLang(xmlNodePtr cur) {
4419 xmlChar *lang;
4420
4421 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004422 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004423 if (lang != NULL)
4424 return(lang);
4425 cur = cur->parent;
4426 }
4427 return(NULL);
4428}
4429
4430
4431/**
4432 * xmlNodeSetSpacePreserve:
4433 * @cur: the node being changed
4434 * @val: the xml:space value ("0": default, 1: "preserve")
4435 *
4436 * Set (or reset) the space preserving behaviour of a node, i.e. the
4437 * value of the xml:space attribute.
4438 */
4439void
4440xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004441 xmlNsPtr ns;
4442
Owen Taylor3473f882001-02-23 17:55:21 +00004443 if (cur == NULL) return;
4444 switch(cur->type) {
4445 case XML_TEXT_NODE:
4446 case XML_CDATA_SECTION_NODE:
4447 case XML_COMMENT_NODE:
4448 case XML_DOCUMENT_NODE:
4449 case XML_DOCUMENT_TYPE_NODE:
4450 case XML_DOCUMENT_FRAG_NODE:
4451 case XML_NOTATION_NODE:
4452 case XML_HTML_DOCUMENT_NODE:
4453 case XML_DTD_NODE:
4454 case XML_ELEMENT_DECL:
4455 case XML_ATTRIBUTE_DECL:
4456 case XML_ENTITY_DECL:
4457 case XML_PI_NODE:
4458 case XML_ENTITY_REF_NODE:
4459 case XML_ENTITY_NODE:
4460 case XML_NAMESPACE_DECL:
4461 case XML_XINCLUDE_START:
4462 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004463#ifdef LIBXML_DOCB_ENABLED
4464 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004465#endif
4466 return;
4467 case XML_ELEMENT_NODE:
4468 case XML_ATTRIBUTE_NODE:
4469 break;
4470 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004471 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4472 if (ns == NULL)
4473 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004474 switch (val) {
4475 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004476 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004477 break;
4478 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004479 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004480 break;
4481 }
4482}
4483
4484/**
4485 * xmlNodeGetSpacePreserve:
4486 * @cur: the node being checked
4487 *
4488 * Searches the space preserving behaviour of a node, i.e. the values
4489 * of the xml:space attribute or the one carried by the nearest
4490 * ancestor.
4491 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004492 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004493 */
4494int
4495xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4496 xmlChar *space;
4497
4498 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004499 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004500 if (space != NULL) {
4501 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4502 xmlFree(space);
4503 return(1);
4504 }
4505 if (xmlStrEqual(space, BAD_CAST "default")) {
4506 xmlFree(space);
4507 return(0);
4508 }
4509 xmlFree(space);
4510 }
4511 cur = cur->parent;
4512 }
4513 return(-1);
4514}
4515
4516/**
4517 * xmlNodeSetName:
4518 * @cur: the node being changed
4519 * @name: the new tag name
4520 *
4521 * Set (or reset) the name of a node.
4522 */
4523void
4524xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
4525 if (cur == NULL) return;
4526 if (name == NULL) return;
4527 switch(cur->type) {
4528 case XML_TEXT_NODE:
4529 case XML_CDATA_SECTION_NODE:
4530 case XML_COMMENT_NODE:
4531 case XML_DOCUMENT_TYPE_NODE:
4532 case XML_DOCUMENT_FRAG_NODE:
4533 case XML_NOTATION_NODE:
4534 case XML_HTML_DOCUMENT_NODE:
4535 case XML_NAMESPACE_DECL:
4536 case XML_XINCLUDE_START:
4537 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004538#ifdef LIBXML_DOCB_ENABLED
4539 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004540#endif
4541 return;
4542 case XML_ELEMENT_NODE:
4543 case XML_ATTRIBUTE_NODE:
4544 case XML_PI_NODE:
4545 case XML_ENTITY_REF_NODE:
4546 case XML_ENTITY_NODE:
4547 case XML_DTD_NODE:
4548 case XML_DOCUMENT_NODE:
4549 case XML_ELEMENT_DECL:
4550 case XML_ATTRIBUTE_DECL:
4551 case XML_ENTITY_DECL:
4552 break;
4553 }
4554 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4555 cur->name = xmlStrdup(name);
4556}
4557
4558/**
4559 * xmlNodeSetBase:
4560 * @cur: the node being changed
4561 * @uri: the new base URI
4562 *
4563 * Set (or reset) the base URI of a node, i.e. the value of the
4564 * xml:base attribute.
4565 */
4566void
4567xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004568 xmlNsPtr ns;
4569
Owen Taylor3473f882001-02-23 17:55:21 +00004570 if (cur == NULL) return;
4571 switch(cur->type) {
4572 case XML_TEXT_NODE:
4573 case XML_CDATA_SECTION_NODE:
4574 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004575 case XML_DOCUMENT_TYPE_NODE:
4576 case XML_DOCUMENT_FRAG_NODE:
4577 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004578 case XML_DTD_NODE:
4579 case XML_ELEMENT_DECL:
4580 case XML_ATTRIBUTE_DECL:
4581 case XML_ENTITY_DECL:
4582 case XML_PI_NODE:
4583 case XML_ENTITY_REF_NODE:
4584 case XML_ENTITY_NODE:
4585 case XML_NAMESPACE_DECL:
4586 case XML_XINCLUDE_START:
4587 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004588 return;
4589 case XML_ELEMENT_NODE:
4590 case XML_ATTRIBUTE_NODE:
4591 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004592 case XML_DOCUMENT_NODE:
4593#ifdef LIBXML_DOCB_ENABLED
4594 case XML_DOCB_DOCUMENT_NODE:
4595#endif
4596 case XML_HTML_DOCUMENT_NODE: {
4597 xmlDocPtr doc = (xmlDocPtr) cur;
4598
4599 if (doc->URL != NULL)
4600 xmlFree((xmlChar *) doc->URL);
4601 if (uri == NULL)
4602 doc->URL = NULL;
4603 else
4604 doc->URL = xmlStrdup(uri);
4605 return;
4606 }
Owen Taylor3473f882001-02-23 17:55:21 +00004607 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004608
4609 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4610 if (ns == NULL)
4611 return;
4612 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004613}
4614
4615/**
Owen Taylor3473f882001-02-23 17:55:21 +00004616 * xmlNodeGetBase:
4617 * @doc: the document the node pertains to
4618 * @cur: the node being checked
4619 *
4620 * Searches for the BASE URL. The code should work on both XML
4621 * and HTML document even if base mechanisms are completely different.
4622 * It returns the base as defined in RFC 2396 sections
4623 * 5.1.1. Base URI within Document Content
4624 * and
4625 * 5.1.2. Base URI from the Encapsulating Entity
4626 * However it does not return the document base (5.1.3), use
4627 * xmlDocumentGetBase() for this
4628 *
4629 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004630 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004631 */
4632xmlChar *
4633xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004634 xmlChar *oldbase = NULL;
4635 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004636
4637 if ((cur == NULL) && (doc == NULL))
4638 return(NULL);
4639 if (doc == NULL) doc = cur->doc;
4640 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4641 cur = doc->children;
4642 while ((cur != NULL) && (cur->name != NULL)) {
4643 if (cur->type != XML_ELEMENT_NODE) {
4644 cur = cur->next;
4645 continue;
4646 }
4647 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4648 cur = cur->children;
4649 continue;
4650 }
4651 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4652 cur = cur->children;
4653 continue;
4654 }
4655 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4656 return(xmlGetProp(cur, BAD_CAST "href"));
4657 }
4658 cur = cur->next;
4659 }
4660 return(NULL);
4661 }
4662 while (cur != NULL) {
4663 if (cur->type == XML_ENTITY_DECL) {
4664 xmlEntityPtr ent = (xmlEntityPtr) cur;
4665 return(xmlStrdup(ent->URI));
4666 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004667 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004668 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004669 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004670 if (oldbase != NULL) {
4671 newbase = xmlBuildURI(oldbase, base);
4672 if (newbase != NULL) {
4673 xmlFree(oldbase);
4674 xmlFree(base);
4675 oldbase = newbase;
4676 } else {
4677 xmlFree(oldbase);
4678 xmlFree(base);
4679 return(NULL);
4680 }
4681 } else {
4682 oldbase = base;
4683 }
4684 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4685 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4686 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4687 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004688 }
4689 }
Owen Taylor3473f882001-02-23 17:55:21 +00004690 cur = cur->parent;
4691 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004692 if ((doc != NULL) && (doc->URL != NULL)) {
4693 if (oldbase == NULL)
4694 return(xmlStrdup(doc->URL));
4695 newbase = xmlBuildURI(oldbase, doc->URL);
4696 xmlFree(oldbase);
4697 return(newbase);
4698 }
4699 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004700}
4701
4702/**
4703 * xmlNodeGetContent:
4704 * @cur: the node being read
4705 *
4706 * Read the value of a node, this can be either the text carried
4707 * directly by this node if it's a TEXT node or the aggregate string
4708 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004709 * Entity references are substituted.
4710 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004711 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004712 */
4713xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004714xmlNodeGetContent(xmlNodePtr cur)
4715{
4716 if (cur == NULL)
4717 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004718 switch (cur->type) {
4719 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004720 case XML_ELEMENT_NODE:{
4721 xmlNodePtr tmp = cur;
4722 xmlBufferPtr buffer;
4723 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004724
Daniel Veillard814a76d2003-01-23 18:24:20 +00004725 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004726 if (buffer == NULL)
4727 return (NULL);
4728 while (tmp != NULL) {
4729 switch (tmp->type) {
4730 case XML_CDATA_SECTION_NODE:
4731 case XML_TEXT_NODE:
4732 if (tmp->content != NULL)
4733 xmlBufferCat(buffer, tmp->content);
4734 break;
4735 case XML_ENTITY_REF_NODE:{
4736 /* recursive substitution of entity references */
4737 xmlChar *cont = xmlNodeGetContent(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00004738
Daniel Veillard7646b182002-04-20 06:41:40 +00004739 if (cont) {
4740 xmlBufferCat(buffer,
4741 (const xmlChar *) cont);
4742 xmlFree(cont);
4743 }
4744 break;
4745 }
4746 default:
4747 break;
4748 }
4749 /*
4750 * Skip to next node
4751 */
4752 if (tmp->children != NULL) {
4753 if (tmp->children->type != XML_ENTITY_DECL) {
4754 tmp = tmp->children;
4755 continue;
4756 }
4757 }
4758 if (tmp == cur)
4759 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00004760
Daniel Veillard7646b182002-04-20 06:41:40 +00004761 if (tmp->next != NULL) {
4762 tmp = tmp->next;
4763 continue;
4764 }
4765
4766 do {
4767 tmp = tmp->parent;
4768 if (tmp == NULL)
4769 break;
4770 if (tmp == cur) {
4771 tmp = NULL;
4772 break;
4773 }
4774 if (tmp->next != NULL) {
4775 tmp = tmp->next;
4776 break;
4777 }
4778 } while (tmp != NULL);
4779 }
4780 ret = buffer->content;
4781 buffer->content = NULL;
4782 xmlBufferFree(buffer);
4783 return (ret);
4784 }
4785 case XML_ATTRIBUTE_NODE:{
4786 xmlAttrPtr attr = (xmlAttrPtr) cur;
4787
4788 if (attr->parent != NULL)
4789 return (xmlNodeListGetString
4790 (attr->parent->doc, attr->children, 1));
4791 else
4792 return (xmlNodeListGetString(NULL, attr->children, 1));
4793 break;
4794 }
Owen Taylor3473f882001-02-23 17:55:21 +00004795 case XML_COMMENT_NODE:
4796 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004797 if (cur->content != NULL)
4798 return (xmlStrdup(cur->content));
4799 return (NULL);
4800 case XML_ENTITY_REF_NODE:{
4801 xmlEntityPtr ent;
4802 xmlNodePtr tmp;
4803 xmlBufferPtr buffer;
4804 xmlChar *ret;
4805
4806 /* lookup entity declaration */
4807 ent = xmlGetDocEntity(cur->doc, cur->name);
4808 if (ent == NULL)
4809 return (NULL);
4810
4811 buffer = xmlBufferCreate();
4812 if (buffer == NULL)
4813 return (NULL);
4814
4815 /* an entity content can be any "well balanced chunk",
4816 * i.e. the result of the content [43] production:
4817 * http://www.w3.org/TR/REC-xml#NT-content
4818 * -> we iterate through child nodes and recursive call
4819 * xmlNodeGetContent() which handles all possible node types */
4820 tmp = ent->children;
4821 while (tmp) {
4822 xmlChar *cont = xmlNodeGetContent(tmp);
4823
4824 if (cont) {
4825 xmlBufferCat(buffer, (const xmlChar *) cont);
4826 xmlFree(cont);
4827 }
4828 tmp = tmp->next;
4829 }
4830
4831 ret = buffer->content;
4832 buffer->content = NULL;
4833 xmlBufferFree(buffer);
4834 return (ret);
4835 }
Owen Taylor3473f882001-02-23 17:55:21 +00004836 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004837 case XML_DOCUMENT_TYPE_NODE:
4838 case XML_NOTATION_NODE:
4839 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004840 case XML_XINCLUDE_START:
4841 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00004842 return (NULL);
4843 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004844#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004845 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004846#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00004847 case XML_HTML_DOCUMENT_NODE: {
4848 xmlChar *tmp;
4849 xmlChar *res = NULL;
4850
4851 cur = cur->children;
4852 while (cur!= NULL) {
4853 if ((cur->type == XML_ELEMENT_NODE) ||
4854 (cur->type == XML_TEXT_NODE) ||
4855 (cur->type == XML_CDATA_SECTION_NODE)) {
4856 tmp = xmlNodeGetContent(cur);
4857 if (tmp != NULL) {
4858 if (res == NULL)
4859 res = tmp;
4860 else {
4861 res = xmlStrcat(res, tmp);
4862 xmlFree(tmp);
4863 }
4864 }
4865 }
4866 cur = cur->next;
4867 }
4868 return(res);
4869 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004870 case XML_NAMESPACE_DECL: {
4871 xmlChar *tmp;
4872
4873 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4874 return (tmp);
4875 }
Owen Taylor3473f882001-02-23 17:55:21 +00004876 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004877 /* TODO !!! */
4878 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004879 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004880 /* TODO !!! */
4881 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004882 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004883 /* TODO !!! */
4884 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004885 case XML_CDATA_SECTION_NODE:
4886 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004887 if (cur->content != NULL)
4888 return (xmlStrdup(cur->content));
4889 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004890 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004891 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004892}
Owen Taylor3473f882001-02-23 17:55:21 +00004893/**
4894 * xmlNodeSetContent:
4895 * @cur: the node being modified
4896 * @content: the new value of the content
4897 *
4898 * Replace the content of a node.
4899 */
4900void
4901xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4902 if (cur == NULL) {
4903#ifdef DEBUG_TREE
4904 xmlGenericError(xmlGenericErrorContext,
4905 "xmlNodeSetContent : node == NULL\n");
4906#endif
4907 return;
4908 }
4909 switch (cur->type) {
4910 case XML_DOCUMENT_FRAG_NODE:
4911 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004912 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004913 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4914 cur->children = xmlStringGetNodeList(cur->doc, content);
4915 UPDATE_LAST_CHILD_AND_PARENT(cur)
4916 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004917 case XML_TEXT_NODE:
4918 case XML_CDATA_SECTION_NODE:
4919 case XML_ENTITY_REF_NODE:
4920 case XML_ENTITY_NODE:
4921 case XML_PI_NODE:
4922 case XML_COMMENT_NODE:
4923 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004924 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004925 }
4926 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4927 cur->last = cur->children = NULL;
4928 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004929 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00004930 } else
4931 cur->content = NULL;
4932 break;
4933 case XML_DOCUMENT_NODE:
4934 case XML_HTML_DOCUMENT_NODE:
4935 case XML_DOCUMENT_TYPE_NODE:
4936 case XML_XINCLUDE_START:
4937 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004938#ifdef LIBXML_DOCB_ENABLED
4939 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004940#endif
4941 break;
4942 case XML_NOTATION_NODE:
4943 break;
4944 case XML_DTD_NODE:
4945 break;
4946 case XML_NAMESPACE_DECL:
4947 break;
4948 case XML_ELEMENT_DECL:
4949 /* TODO !!! */
4950 break;
4951 case XML_ATTRIBUTE_DECL:
4952 /* TODO !!! */
4953 break;
4954 case XML_ENTITY_DECL:
4955 /* TODO !!! */
4956 break;
4957 }
4958}
4959
4960/**
4961 * xmlNodeSetContentLen:
4962 * @cur: the node being modified
4963 * @content: the new value of the content
4964 * @len: the size of @content
4965 *
4966 * Replace the content of a node.
4967 */
4968void
4969xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4970 if (cur == NULL) {
4971#ifdef DEBUG_TREE
4972 xmlGenericError(xmlGenericErrorContext,
4973 "xmlNodeSetContentLen : node == NULL\n");
4974#endif
4975 return;
4976 }
4977 switch (cur->type) {
4978 case XML_DOCUMENT_FRAG_NODE:
4979 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004980 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004981 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4982 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
4983 UPDATE_LAST_CHILD_AND_PARENT(cur)
4984 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004985 case XML_TEXT_NODE:
4986 case XML_CDATA_SECTION_NODE:
4987 case XML_ENTITY_REF_NODE:
4988 case XML_ENTITY_NODE:
4989 case XML_PI_NODE:
4990 case XML_COMMENT_NODE:
4991 case XML_NOTATION_NODE:
4992 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004993 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004994 }
4995 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4996 cur->children = cur->last = NULL;
4997 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004998 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004999 } else
5000 cur->content = NULL;
5001 break;
5002 case XML_DOCUMENT_NODE:
5003 case XML_DTD_NODE:
5004 case XML_HTML_DOCUMENT_NODE:
5005 case XML_DOCUMENT_TYPE_NODE:
5006 case XML_NAMESPACE_DECL:
5007 case XML_XINCLUDE_START:
5008 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005009#ifdef LIBXML_DOCB_ENABLED
5010 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005011#endif
5012 break;
5013 case XML_ELEMENT_DECL:
5014 /* TODO !!! */
5015 break;
5016 case XML_ATTRIBUTE_DECL:
5017 /* TODO !!! */
5018 break;
5019 case XML_ENTITY_DECL:
5020 /* TODO !!! */
5021 break;
5022 }
5023}
5024
5025/**
5026 * xmlNodeAddContentLen:
5027 * @cur: the node being modified
5028 * @content: extra content
5029 * @len: the size of @content
5030 *
5031 * Append the extra substring to the node content.
5032 */
5033void
5034xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5035 if (cur == NULL) {
5036#ifdef DEBUG_TREE
5037 xmlGenericError(xmlGenericErrorContext,
5038 "xmlNodeAddContentLen : node == NULL\n");
5039#endif
5040 return;
5041 }
5042 if (len <= 0) return;
5043 switch (cur->type) {
5044 case XML_DOCUMENT_FRAG_NODE:
5045 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005046 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005047
Daniel Veillard7db37732001-07-12 01:20:08 +00005048 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005049 newNode = xmlNewTextLen(content, len);
5050 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005051 tmp = xmlAddChild(cur, newNode);
5052 if (tmp != newNode)
5053 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005054 if ((last != NULL) && (last->next == newNode)) {
5055 xmlTextMerge(last, newNode);
5056 }
5057 }
5058 break;
5059 }
5060 case XML_ATTRIBUTE_NODE:
5061 break;
5062 case XML_TEXT_NODE:
5063 case XML_CDATA_SECTION_NODE:
5064 case XML_ENTITY_REF_NODE:
5065 case XML_ENTITY_NODE:
5066 case XML_PI_NODE:
5067 case XML_COMMENT_NODE:
5068 case XML_NOTATION_NODE:
5069 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005070 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005071 }
5072 case XML_DOCUMENT_NODE:
5073 case XML_DTD_NODE:
5074 case XML_HTML_DOCUMENT_NODE:
5075 case XML_DOCUMENT_TYPE_NODE:
5076 case XML_NAMESPACE_DECL:
5077 case XML_XINCLUDE_START:
5078 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005079#ifdef LIBXML_DOCB_ENABLED
5080 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005081#endif
5082 break;
5083 case XML_ELEMENT_DECL:
5084 case XML_ATTRIBUTE_DECL:
5085 case XML_ENTITY_DECL:
5086 break;
5087 }
5088}
5089
5090/**
5091 * xmlNodeAddContent:
5092 * @cur: the node being modified
5093 * @content: extra content
5094 *
5095 * Append the extra substring to the node content.
5096 */
5097void
5098xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5099 int len;
5100
5101 if (cur == NULL) {
5102#ifdef DEBUG_TREE
5103 xmlGenericError(xmlGenericErrorContext,
5104 "xmlNodeAddContent : node == NULL\n");
5105#endif
5106 return;
5107 }
5108 if (content == NULL) return;
5109 len = xmlStrlen(content);
5110 xmlNodeAddContentLen(cur, content, len);
5111}
5112
5113/**
5114 * xmlTextMerge:
5115 * @first: the first text node
5116 * @second: the second text node being merged
5117 *
5118 * Merge two text nodes into one
5119 * Returns the first text node augmented
5120 */
5121xmlNodePtr
5122xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5123 if (first == NULL) return(second);
5124 if (second == NULL) return(first);
5125 if (first->type != XML_TEXT_NODE) return(first);
5126 if (second->type != XML_TEXT_NODE) return(first);
5127 if (second->name != first->name)
5128 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005129 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005130 xmlUnlinkNode(second);
5131 xmlFreeNode(second);
5132 return(first);
5133}
5134
5135/**
5136 * xmlGetNsList:
5137 * @doc: the document
5138 * @node: the current node
5139 *
5140 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005141 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005142 * that need to be freed by the caller or NULL if no
5143 * namespace if defined
5144 */
5145xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005146xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5147{
Owen Taylor3473f882001-02-23 17:55:21 +00005148 xmlNsPtr cur;
5149 xmlNsPtr *ret = NULL;
5150 int nbns = 0;
5151 int maxns = 10;
5152 int i;
5153
5154 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005155 if (node->type == XML_ELEMENT_NODE) {
5156 cur = node->nsDef;
5157 while (cur != NULL) {
5158 if (ret == NULL) {
5159 ret =
5160 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5161 sizeof(xmlNsPtr));
5162 if (ret == NULL) {
5163 xmlGenericError(xmlGenericErrorContext,
5164 "xmlGetNsList : out of memory!\n");
5165 return (NULL);
5166 }
5167 ret[nbns] = NULL;
5168 }
5169 for (i = 0; i < nbns; i++) {
5170 if ((cur->prefix == ret[i]->prefix) ||
5171 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5172 break;
5173 }
5174 if (i >= nbns) {
5175 if (nbns >= maxns) {
5176 maxns *= 2;
5177 ret = (xmlNsPtr *) xmlRealloc(ret,
5178 (maxns +
5179 1) *
5180 sizeof(xmlNsPtr));
5181 if (ret == NULL) {
5182 xmlGenericError(xmlGenericErrorContext,
5183 "xmlGetNsList : realloc failed!\n");
5184 return (NULL);
5185 }
5186 }
5187 ret[nbns++] = cur;
5188 ret[nbns] = NULL;
5189 }
Owen Taylor3473f882001-02-23 17:55:21 +00005190
Daniel Veillard77044732001-06-29 21:31:07 +00005191 cur = cur->next;
5192 }
5193 }
5194 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005195 }
Daniel Veillard77044732001-06-29 21:31:07 +00005196 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005197}
5198
5199/**
5200 * xmlSearchNs:
5201 * @doc: the document
5202 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005203 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005204 *
5205 * Search a Ns registered under a given name space for a document.
5206 * recurse on the parents until it finds the defined namespace
5207 * or return NULL otherwise.
5208 * @nameSpace can be NULL, this is a search for the default namespace.
5209 * We don't allow to cross entities boundaries. If you don't declare
5210 * the namespace within those you will be in troubles !!! A warning
5211 * is generated to cover this case.
5212 *
5213 * Returns the namespace pointer or NULL.
5214 */
5215xmlNsPtr
5216xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
5217 xmlNsPtr cur;
5218
5219 if (node == NULL) return(NULL);
5220 if ((nameSpace != NULL) &&
5221 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005222 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5223 /*
5224 * The XML-1.0 namespace is normally held on the root
5225 * element. In this case exceptionally create it on the
5226 * node element.
5227 */
5228 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5229 if (cur == NULL) {
5230 xmlGenericError(xmlGenericErrorContext,
5231 "xmlSearchNs : malloc failed\n");
5232 return(NULL);
5233 }
5234 memset(cur, 0, sizeof(xmlNs));
5235 cur->type = XML_LOCAL_NAMESPACE;
5236 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5237 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5238 cur->next = node->nsDef;
5239 node->nsDef = cur;
5240 return(cur);
5241 }
Owen Taylor3473f882001-02-23 17:55:21 +00005242 if (doc->oldNs == NULL) {
5243 /*
5244 * Allocate a new Namespace and fill the fields.
5245 */
5246 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5247 if (doc->oldNs == NULL) {
5248 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005249 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005250 return(NULL);
5251 }
5252 memset(doc->oldNs, 0, sizeof(xmlNs));
5253 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5254
5255 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5256 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5257 }
5258 return(doc->oldNs);
5259 }
5260 while (node != NULL) {
5261 if ((node->type == XML_ENTITY_REF_NODE) ||
5262 (node->type == XML_ENTITY_NODE) ||
5263 (node->type == XML_ENTITY_DECL))
5264 return(NULL);
5265 if (node->type == XML_ELEMENT_NODE) {
5266 cur = node->nsDef;
5267 while (cur != NULL) {
5268 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5269 (cur->href != NULL))
5270 return(cur);
5271 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5272 (cur->href != NULL) &&
5273 (xmlStrEqual(cur->prefix, nameSpace)))
5274 return(cur);
5275 cur = cur->next;
5276 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005277 cur = node->ns;
5278 if (cur != NULL) {
5279 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5280 (cur->href != NULL))
5281 return(cur);
5282 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5283 (cur->href != NULL) &&
5284 (xmlStrEqual(cur->prefix, nameSpace)))
5285 return(cur);
5286 }
Owen Taylor3473f882001-02-23 17:55:21 +00005287 }
5288 node = node->parent;
5289 }
5290 return(NULL);
5291}
5292
5293/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005294 * xmlNsInScope:
5295 * @doc: the document
5296 * @node: the current node
5297 * @ancestor: the ancestor carrying the namespace
5298 * @prefix: the namespace prefix
5299 *
5300 * Verify that the given namespace held on @ancestor is still in scope
5301 * on node.
5302 *
5303 * Returns 1 if true, 0 if false and -1 in case of error.
5304 */
5305static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005306xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5307 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005308{
5309 xmlNsPtr tst;
5310
5311 while ((node != NULL) && (node != ancestor)) {
5312 if ((node->type == XML_ENTITY_REF_NODE) ||
5313 (node->type == XML_ENTITY_NODE) ||
5314 (node->type == XML_ENTITY_DECL))
5315 return (-1);
5316 if (node->type == XML_ELEMENT_NODE) {
5317 tst = node->nsDef;
5318 while (tst != NULL) {
5319 if ((tst->prefix == NULL)
5320 && (prefix == NULL))
5321 return (0);
5322 if ((tst->prefix != NULL)
5323 && (prefix != NULL)
5324 && (xmlStrEqual(tst->prefix, prefix)))
5325 return (0);
5326 tst = tst->next;
5327 }
5328 }
5329 node = node->parent;
5330 }
5331 if (node != ancestor)
5332 return (-1);
5333 return (1);
5334}
5335
5336
5337/**
Owen Taylor3473f882001-02-23 17:55:21 +00005338 * xmlSearchNsByHref:
5339 * @doc: the document
5340 * @node: the current node
5341 * @href: the namespace value
5342 *
5343 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5344 * the defined namespace or return NULL otherwise.
5345 * Returns the namespace pointer or NULL.
5346 */
5347xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005348xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5349{
Owen Taylor3473f882001-02-23 17:55:21 +00005350 xmlNsPtr cur;
5351 xmlNodePtr orig = node;
5352
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005353 if ((node == NULL) || (href == NULL))
5354 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005355 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005356 /*
5357 * Only the document can hold the XML spec namespace.
5358 */
5359 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5360 /*
5361 * The XML-1.0 namespace is normally held on the root
5362 * element. In this case exceptionally create it on the
5363 * node element.
5364 */
5365 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5366 if (cur == NULL) {
5367 xmlGenericError(xmlGenericErrorContext,
5368 "xmlSearchNs : malloc failed\n");
5369 return (NULL);
5370 }
5371 memset(cur, 0, sizeof(xmlNs));
5372 cur->type = XML_LOCAL_NAMESPACE;
5373 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5374 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5375 cur->next = node->nsDef;
5376 node->nsDef = cur;
5377 return (cur);
5378 }
5379 if (doc->oldNs == NULL) {
5380 /*
5381 * Allocate a new Namespace and fill the fields.
5382 */
5383 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5384 if (doc->oldNs == NULL) {
5385 xmlGenericError(xmlGenericErrorContext,
5386 "xmlSearchNsByHref : malloc failed\n");
5387 return (NULL);
5388 }
5389 memset(doc->oldNs, 0, sizeof(xmlNs));
5390 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005391
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005392 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5393 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5394 }
5395 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005396 }
5397 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005398 if ((node->type == XML_ENTITY_REF_NODE) ||
5399 (node->type == XML_ENTITY_NODE) ||
5400 (node->type == XML_ENTITY_DECL))
5401 return (NULL);
5402 if (node->type == XML_ELEMENT_NODE) {
5403 cur = node->nsDef;
5404 while (cur != NULL) {
5405 if ((cur->href != NULL) && (href != NULL) &&
5406 (xmlStrEqual(cur->href, href))) {
5407 if (xmlNsInScope(doc, orig, node, cur->href) == 1)
5408 return (cur);
5409 }
5410 cur = cur->next;
5411 }
5412 cur = node->ns;
5413 if (cur != NULL) {
5414 if ((cur->href != NULL) && (href != NULL) &&
5415 (xmlStrEqual(cur->href, href))) {
5416 if (xmlNsInScope(doc, orig, node, cur->href) == 1)
5417 return (cur);
5418 }
5419 }
5420 }
5421 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005422 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005423 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005424}
5425
5426/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005427 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005428 * @doc: the document
5429 * @tree: a node expected to hold the new namespace
5430 * @ns: the original namespace
5431 *
5432 * This function tries to locate a namespace definition in a tree
5433 * ancestors, or create a new namespace definition node similar to
5434 * @ns trying to reuse the same prefix. However if the given prefix is
5435 * null (default namespace) or reused within the subtree defined by
5436 * @tree or on one of its ancestors then a new prefix is generated.
5437 * Returns the (new) namespace definition or NULL in case of error
5438 */
5439xmlNsPtr
5440xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5441 xmlNsPtr def;
5442 xmlChar prefix[50];
5443 int counter = 1;
5444
5445 if (tree == NULL) {
5446#ifdef DEBUG_TREE
5447 xmlGenericError(xmlGenericErrorContext,
5448 "xmlNewReconciliedNs : tree == NULL\n");
5449#endif
5450 return(NULL);
5451 }
5452 if (ns == NULL) {
5453#ifdef DEBUG_TREE
5454 xmlGenericError(xmlGenericErrorContext,
5455 "xmlNewReconciliedNs : ns == NULL\n");
5456#endif
5457 return(NULL);
5458 }
5459 /*
5460 * Search an existing namespace definition inherited.
5461 */
5462 def = xmlSearchNsByHref(doc, tree, ns->href);
5463 if (def != NULL)
5464 return(def);
5465
5466 /*
5467 * Find a close prefix which is not already in use.
5468 * Let's strip namespace prefixes longer than 20 chars !
5469 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005470 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005471 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005472 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005473 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005474
Owen Taylor3473f882001-02-23 17:55:21 +00005475 def = xmlSearchNs(doc, tree, prefix);
5476 while (def != NULL) {
5477 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005478 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005479 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005480 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005481 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005482 def = xmlSearchNs(doc, tree, prefix);
5483 }
5484
5485 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005486 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005487 */
5488 def = xmlNewNs(tree, ns->href, prefix);
5489 return(def);
5490}
5491
5492/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005493 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005494 * @doc: the document
5495 * @tree: a node defining the subtree to reconciliate
5496 *
5497 * This function checks that all the namespaces declared within the given
5498 * tree are properly declared. This is needed for example after Copy or Cut
5499 * and then paste operations. The subtree may still hold pointers to
5500 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005501 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005502 * the new environment. If not possible the new namespaces are redeclared
5503 * on @tree at the top of the given subtree.
5504 * Returns the number of namespace declarations created or -1 in case of error.
5505 */
5506int
5507xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5508 xmlNsPtr *oldNs = NULL;
5509 xmlNsPtr *newNs = NULL;
5510 int sizeCache = 0;
5511 int nbCache = 0;
5512
5513 xmlNsPtr n;
5514 xmlNodePtr node = tree;
5515 xmlAttrPtr attr;
5516 int ret = 0, i;
5517
5518 while (node != NULL) {
5519 /*
5520 * Reconciliate the node namespace
5521 */
5522 if (node->ns != NULL) {
5523 /*
5524 * initialize the cache if needed
5525 */
5526 if (sizeCache == 0) {
5527 sizeCache = 10;
5528 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5529 sizeof(xmlNsPtr));
5530 if (oldNs == NULL) {
5531 xmlGenericError(xmlGenericErrorContext,
5532 "xmlReconciliateNs : memory pbm\n");
5533 return(-1);
5534 }
5535 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5536 sizeof(xmlNsPtr));
5537 if (newNs == NULL) {
5538 xmlGenericError(xmlGenericErrorContext,
5539 "xmlReconciliateNs : memory pbm\n");
5540 xmlFree(oldNs);
5541 return(-1);
5542 }
5543 }
5544 for (i = 0;i < nbCache;i++) {
5545 if (oldNs[i] == node->ns) {
5546 node->ns = newNs[i];
5547 break;
5548 }
5549 }
5550 if (i == nbCache) {
5551 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005552 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005553 */
5554 n = xmlNewReconciliedNs(doc, tree, node->ns);
5555 if (n != NULL) { /* :-( what if else ??? */
5556 /*
5557 * check if we need to grow the cache buffers.
5558 */
5559 if (sizeCache <= nbCache) {
5560 sizeCache *= 2;
5561 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5562 sizeof(xmlNsPtr));
5563 if (oldNs == NULL) {
5564 xmlGenericError(xmlGenericErrorContext,
5565 "xmlReconciliateNs : memory pbm\n");
5566 xmlFree(newNs);
5567 return(-1);
5568 }
5569 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5570 sizeof(xmlNsPtr));
5571 if (newNs == NULL) {
5572 xmlGenericError(xmlGenericErrorContext,
5573 "xmlReconciliateNs : memory pbm\n");
5574 xmlFree(oldNs);
5575 return(-1);
5576 }
5577 }
5578 newNs[nbCache] = n;
5579 oldNs[nbCache++] = node->ns;
5580 node->ns = n;
5581 }
5582 }
5583 }
5584 /*
5585 * now check for namespace hold by attributes on the node.
5586 */
5587 attr = node->properties;
5588 while (attr != NULL) {
5589 if (attr->ns != NULL) {
5590 /*
5591 * initialize the cache if needed
5592 */
5593 if (sizeCache == 0) {
5594 sizeCache = 10;
5595 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5596 sizeof(xmlNsPtr));
5597 if (oldNs == NULL) {
5598 xmlGenericError(xmlGenericErrorContext,
5599 "xmlReconciliateNs : memory pbm\n");
5600 return(-1);
5601 }
5602 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5603 sizeof(xmlNsPtr));
5604 if (newNs == NULL) {
5605 xmlGenericError(xmlGenericErrorContext,
5606 "xmlReconciliateNs : memory pbm\n");
5607 xmlFree(oldNs);
5608 return(-1);
5609 }
5610 }
5611 for (i = 0;i < nbCache;i++) {
5612 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005613 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005614 break;
5615 }
5616 }
5617 if (i == nbCache) {
5618 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005619 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005620 */
5621 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5622 if (n != NULL) { /* :-( what if else ??? */
5623 /*
5624 * check if we need to grow the cache buffers.
5625 */
5626 if (sizeCache <= nbCache) {
5627 sizeCache *= 2;
5628 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5629 sizeof(xmlNsPtr));
5630 if (oldNs == NULL) {
5631 xmlGenericError(xmlGenericErrorContext,
5632 "xmlReconciliateNs : memory pbm\n");
5633 xmlFree(newNs);
5634 return(-1);
5635 }
5636 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5637 sizeof(xmlNsPtr));
5638 if (newNs == NULL) {
5639 xmlGenericError(xmlGenericErrorContext,
5640 "xmlReconciliateNs : memory pbm\n");
5641 xmlFree(oldNs);
5642 return(-1);
5643 }
5644 }
5645 newNs[nbCache] = n;
5646 oldNs[nbCache++] = attr->ns;
5647 attr->ns = n;
5648 }
5649 }
5650 }
5651 attr = attr->next;
5652 }
5653
5654 /*
5655 * Browse the full subtree, deep first
5656 */
5657 if (node->children != NULL) {
5658 /* deep first */
5659 node = node->children;
5660 } else if ((node != tree) && (node->next != NULL)) {
5661 /* then siblings */
5662 node = node->next;
5663 } else if (node != tree) {
5664 /* go up to parents->next if needed */
5665 while (node != tree) {
5666 if (node->parent != NULL)
5667 node = node->parent;
5668 if ((node != tree) && (node->next != NULL)) {
5669 node = node->next;
5670 break;
5671 }
5672 if (node->parent == NULL) {
5673 node = NULL;
5674 break;
5675 }
5676 }
5677 /* exit condition */
5678 if (node == tree)
5679 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005680 } else
5681 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005682 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005683 if (oldNs != NULL)
5684 xmlFree(oldNs);
5685 if (newNs != NULL)
5686 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005687 return(ret);
5688}
5689
5690/**
5691 * xmlHasProp:
5692 * @node: the node
5693 * @name: the attribute name
5694 *
5695 * Search an attribute associated to a node
5696 * This function also looks in DTD attribute declaration for #FIXED or
5697 * default declaration values unless DTD use has been turned off.
5698 *
5699 * Returns the attribute or the attribute declaration or NULL if
5700 * neither was found.
5701 */
5702xmlAttrPtr
5703xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5704 xmlAttrPtr prop;
5705 xmlDocPtr doc;
5706
5707 if ((node == NULL) || (name == NULL)) return(NULL);
5708 /*
5709 * Check on the properties attached to the node
5710 */
5711 prop = node->properties;
5712 while (prop != NULL) {
5713 if (xmlStrEqual(prop->name, name)) {
5714 return(prop);
5715 }
5716 prop = prop->next;
5717 }
5718 if (!xmlCheckDTD) return(NULL);
5719
5720 /*
5721 * Check if there is a default declaration in the internal
5722 * or external subsets
5723 */
5724 doc = node->doc;
5725 if (doc != NULL) {
5726 xmlAttributePtr attrDecl;
5727 if (doc->intSubset != NULL) {
5728 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5729 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5730 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005731 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5732 /* return attribute declaration only if a default value is given
5733 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005734 return((xmlAttrPtr) attrDecl);
5735 }
5736 }
5737 return(NULL);
5738}
5739
5740/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005741 * xmlHasNsProp:
5742 * @node: the node
5743 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005744 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005745 *
5746 * Search for an attribute associated to a node
5747 * This attribute has to be anchored in the namespace specified.
5748 * This does the entity substitution.
5749 * This function looks in DTD attribute declaration for #FIXED or
5750 * default declaration values unless DTD use has been turned off.
5751 *
5752 * Returns the attribute or the attribute declaration or NULL
5753 * if neither was found.
5754 */
5755xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005756xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005757 xmlAttrPtr prop;
5758 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005759
5760 if (node == NULL)
5761 return(NULL);
5762
5763 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005764 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005765 return(xmlHasProp(node, name));
5766 while (prop != NULL) {
5767 /*
5768 * One need to have
5769 * - same attribute names
5770 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005771 */
5772 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005773 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5774 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005775 }
5776 prop = prop->next;
5777 }
5778 if (!xmlCheckDTD) return(NULL);
5779
5780 /*
5781 * Check if there is a default declaration in the internal
5782 * or external subsets
5783 */
5784 doc = node->doc;
5785 if (doc != NULL) {
5786 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005787 xmlAttributePtr attrDecl = NULL;
5788 xmlNsPtr *nsList, *cur;
5789 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005790
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005791 nsList = xmlGetNsList(node->doc, node);
5792 if (nsList == NULL)
5793 return(NULL);
5794 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5795 ename = xmlStrdup(node->ns->prefix);
5796 ename = xmlStrcat(ename, BAD_CAST ":");
5797 ename = xmlStrcat(ename, node->name);
5798 } else {
5799 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005800 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005801 if (ename == NULL) {
5802 xmlFree(nsList);
5803 return(NULL);
5804 }
5805
5806 cur = nsList;
5807 while (*cur != NULL) {
5808 if (xmlStrEqual((*cur)->href, nameSpace)) {
5809 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5810 name, (*cur)->prefix);
5811 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5812 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5813 name, (*cur)->prefix);
5814 }
5815 cur++;
5816 }
5817 xmlFree(nsList);
5818 xmlFree(ename);
5819 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005820 }
5821 }
5822 return(NULL);
5823}
5824
5825/**
Owen Taylor3473f882001-02-23 17:55:21 +00005826 * xmlGetProp:
5827 * @node: the node
5828 * @name: the attribute name
5829 *
5830 * Search and get the value of an attribute associated to a node
5831 * This does the entity substitution.
5832 * This function looks in DTD attribute declaration for #FIXED or
5833 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00005834 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00005835 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
5836 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00005837 *
5838 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005839 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005840 */
5841xmlChar *
5842xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5843 xmlAttrPtr prop;
5844 xmlDocPtr doc;
5845
5846 if ((node == NULL) || (name == NULL)) return(NULL);
5847 /*
5848 * Check on the properties attached to the node
5849 */
5850 prop = node->properties;
5851 while (prop != NULL) {
5852 if (xmlStrEqual(prop->name, name)) {
5853 xmlChar *ret;
5854
5855 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5856 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5857 return(ret);
5858 }
5859 prop = prop->next;
5860 }
5861 if (!xmlCheckDTD) return(NULL);
5862
5863 /*
5864 * Check if there is a default declaration in the internal
5865 * or external subsets
5866 */
5867 doc = node->doc;
5868 if (doc != NULL) {
5869 xmlAttributePtr attrDecl;
5870 if (doc->intSubset != NULL) {
5871 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5872 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5873 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005874 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5875 /* return attribute declaration only if a default value is given
5876 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005877 return(xmlStrdup(attrDecl->defaultValue));
5878 }
5879 }
5880 return(NULL);
5881}
5882
5883/**
Daniel Veillard71531f32003-02-05 13:19:53 +00005884 * xmlGetNoNsProp:
5885 * @node: the node
5886 * @name: the attribute name
5887 *
5888 * Search and get the value of an attribute associated to a node
5889 * This does the entity substitution.
5890 * This function looks in DTD attribute declaration for #FIXED or
5891 * default declaration values unless DTD use has been turned off.
5892 * This function is similar to xmlGetProp except it will accept only
5893 * an attribute in no namespace.
5894 *
5895 * Returns the attribute value or NULL if not found.
5896 * It's up to the caller to free the memory with xmlFree().
5897 */
5898xmlChar *
5899xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
5900 xmlAttrPtr prop;
5901 xmlDocPtr doc;
5902
5903 if ((node == NULL) || (name == NULL)) return(NULL);
5904 /*
5905 * Check on the properties attached to the node
5906 */
5907 prop = node->properties;
5908 while (prop != NULL) {
5909 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
5910 xmlChar *ret;
5911
5912 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5913 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5914 return(ret);
5915 }
5916 prop = prop->next;
5917 }
5918 if (!xmlCheckDTD) return(NULL);
5919
5920 /*
5921 * Check if there is a default declaration in the internal
5922 * or external subsets
5923 */
5924 doc = node->doc;
5925 if (doc != NULL) {
5926 xmlAttributePtr attrDecl;
5927 if (doc->intSubset != NULL) {
5928 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5929 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5930 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005931 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5932 /* return attribute declaration only if a default value is given
5933 (that includes #FIXED declarations) */
Daniel Veillard71531f32003-02-05 13:19:53 +00005934 return(xmlStrdup(attrDecl->defaultValue));
5935 }
5936 }
5937 return(NULL);
5938}
5939
5940/**
Owen Taylor3473f882001-02-23 17:55:21 +00005941 * xmlGetNsProp:
5942 * @node: the node
5943 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005944 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005945 *
5946 * Search and get the value of an attribute associated to a node
5947 * This attribute has to be anchored in the namespace specified.
5948 * This does the entity substitution.
5949 * This function looks in DTD attribute declaration for #FIXED or
5950 * default declaration values unless DTD use has been turned off.
5951 *
5952 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005953 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005954 */
5955xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00005956xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00005957 xmlAttrPtr prop;
5958 xmlDocPtr doc;
5959 xmlNsPtr ns;
5960
5961 if (node == NULL)
5962 return(NULL);
5963
5964 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005965 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00005966 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00005967 while (prop != NULL) {
5968 /*
5969 * One need to have
5970 * - same attribute names
5971 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005972 */
5973 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00005974 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00005975 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005976 xmlChar *ret;
5977
5978 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5979 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5980 return(ret);
5981 }
5982 prop = prop->next;
5983 }
5984 if (!xmlCheckDTD) return(NULL);
5985
5986 /*
5987 * Check if there is a default declaration in the internal
5988 * or external subsets
5989 */
5990 doc = node->doc;
5991 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005992 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00005993 xmlAttributePtr attrDecl;
5994
Owen Taylor3473f882001-02-23 17:55:21 +00005995 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5996 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5997 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5998
5999 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
6000 /*
6001 * The DTD declaration only allows a prefix search
6002 */
6003 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00006004 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00006005 return(xmlStrdup(attrDecl->defaultValue));
6006 }
6007 }
6008 }
6009 return(NULL);
6010}
6011
6012/**
6013 * xmlSetProp:
6014 * @node: the node
6015 * @name: the attribute name
6016 * @value: the attribute value
6017 *
6018 * Set (or reset) an attribute carried by a node.
6019 * Returns the attribute pointer.
6020 */
6021xmlAttrPtr
6022xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006023 xmlAttrPtr prop;
6024 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00006025
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006026 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00006027 return(NULL);
6028 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006029 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00006030 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006031 if ((xmlStrEqual(prop->name, name)) &&
6032 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006033 xmlNodePtr oldprop = prop->children;
6034
Owen Taylor3473f882001-02-23 17:55:21 +00006035 prop->children = NULL;
6036 prop->last = NULL;
6037 if (value != NULL) {
6038 xmlChar *buffer;
6039 xmlNodePtr tmp;
6040
6041 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6042 prop->children = xmlStringGetNodeList(node->doc, buffer);
6043 prop->last = NULL;
6044 prop->doc = doc;
6045 tmp = prop->children;
6046 while (tmp != NULL) {
6047 tmp->parent = (xmlNodePtr) prop;
6048 tmp->doc = doc;
6049 if (tmp->next == NULL)
6050 prop->last = tmp;
6051 tmp = tmp->next;
6052 }
6053 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00006054 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006055 if (oldprop != NULL)
6056 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00006057 return(prop);
6058 }
6059 prop = prop->next;
6060 }
6061 prop = xmlNewProp(node, name, value);
6062 return(prop);
6063}
6064
6065/**
Daniel Veillard75bea542001-05-11 17:41:21 +00006066 * xmlUnsetProp:
6067 * @node: the node
6068 * @name: the attribute name
6069 *
6070 * Remove an attribute carried by a node.
6071 * Returns 0 if successful, -1 if not found
6072 */
6073int
6074xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Daniel Veillard814a76d2003-01-23 18:24:20 +00006075 xmlAttrPtr prop, prev = NULL;;
Daniel Veillard75bea542001-05-11 17:41:21 +00006076
6077 if ((node == NULL) || (name == NULL))
6078 return(-1);
Daniel Veillard814a76d2003-01-23 18:24:20 +00006079 prop = node->properties;
Daniel Veillard75bea542001-05-11 17:41:21 +00006080 while (prop != NULL) {
6081 if ((xmlStrEqual(prop->name, name)) &&
6082 (prop->ns == NULL)) {
6083 if (prev == NULL)
6084 node->properties = prop->next;
6085 else
6086 prev->next = prop->next;
6087 xmlFreeProp(prop);
6088 return(0);
6089 }
6090 prev = prop;
6091 prop = prop->next;
6092 }
6093 return(-1);
6094}
6095
6096/**
Owen Taylor3473f882001-02-23 17:55:21 +00006097 * xmlSetNsProp:
6098 * @node: the node
6099 * @ns: the namespace definition
6100 * @name: the attribute name
6101 * @value: the attribute value
6102 *
6103 * Set (or reset) an attribute carried by a node.
6104 * The ns structure must be in scope, this is not checked.
6105 *
6106 * Returns the attribute pointer.
6107 */
6108xmlAttrPtr
6109xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
6110 const xmlChar *value) {
6111 xmlAttrPtr prop;
6112
6113 if ((node == NULL) || (name == NULL))
6114 return(NULL);
6115
6116 if (ns == NULL)
6117 return(xmlSetProp(node, name, value));
6118 if (ns->href == NULL)
6119 return(NULL);
6120 prop = node->properties;
6121
6122 while (prop != NULL) {
6123 /*
6124 * One need to have
6125 * - same attribute names
6126 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006127 */
6128 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00006129 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006130 if (prop->children != NULL)
6131 xmlFreeNodeList(prop->children);
6132 prop->children = NULL;
6133 prop->last = NULL;
6134 prop->ns = ns;
6135 if (value != NULL) {
6136 xmlChar *buffer;
6137 xmlNodePtr tmp;
6138
6139 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6140 prop->children = xmlStringGetNodeList(node->doc, buffer);
6141 prop->last = NULL;
6142 tmp = prop->children;
6143 while (tmp != NULL) {
6144 tmp->parent = (xmlNodePtr) prop;
6145 if (tmp->next == NULL)
6146 prop->last = tmp;
6147 tmp = tmp->next;
6148 }
6149 xmlFree(buffer);
6150 }
6151 return(prop);
6152 }
6153 prop = prop->next;
6154 }
6155 prop = xmlNewNsProp(node, ns, name, value);
6156 return(prop);
6157}
6158
6159/**
Daniel Veillard75bea542001-05-11 17:41:21 +00006160 * xmlUnsetNsProp:
6161 * @node: the node
6162 * @ns: the namespace definition
6163 * @name: the attribute name
6164 *
6165 * Remove an attribute carried by a node.
6166 * Returns 0 if successful, -1 if not found
6167 */
6168int
6169xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
6170 xmlAttrPtr prop = node->properties, prev = NULL;;
6171
6172 if ((node == NULL) || (name == NULL))
6173 return(-1);
6174 if (ns == NULL)
6175 return(xmlUnsetProp(node, name));
6176 if (ns->href == NULL)
6177 return(-1);
6178 while (prop != NULL) {
6179 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00006180 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006181 if (prev == NULL)
6182 node->properties = prop->next;
6183 else
6184 prev->next = prop->next;
6185 xmlFreeProp(prop);
6186 return(0);
6187 }
6188 prev = prop;
6189 prop = prop->next;
6190 }
6191 return(-1);
6192}
6193
6194/**
Owen Taylor3473f882001-02-23 17:55:21 +00006195 * xmlNodeIsText:
6196 * @node: the node
6197 *
6198 * Is this node a Text node ?
6199 * Returns 1 yes, 0 no
6200 */
6201int
6202xmlNodeIsText(xmlNodePtr node) {
6203 if (node == NULL) return(0);
6204
6205 if (node->type == XML_TEXT_NODE) return(1);
6206 return(0);
6207}
6208
6209/**
6210 * xmlIsBlankNode:
6211 * @node: the node
6212 *
6213 * Checks whether this node is an empty or whitespace only
6214 * (and possibly ignorable) text-node.
6215 *
6216 * Returns 1 yes, 0 no
6217 */
6218int
6219xmlIsBlankNode(xmlNodePtr node) {
6220 const xmlChar *cur;
6221 if (node == NULL) return(0);
6222
Daniel Veillard7db37732001-07-12 01:20:08 +00006223 if ((node->type != XML_TEXT_NODE) &&
6224 (node->type != XML_CDATA_SECTION_NODE))
6225 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006226 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006227 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006228 while (*cur != 0) {
6229 if (!IS_BLANK(*cur)) return(0);
6230 cur++;
6231 }
6232
6233 return(1);
6234}
6235
6236/**
6237 * xmlTextConcat:
6238 * @node: the node
6239 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006240 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006241 *
6242 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006243 *
6244 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006245 */
6246
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006247int
Owen Taylor3473f882001-02-23 17:55:21 +00006248xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006249 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006250
6251 if ((node->type != XML_TEXT_NODE) &&
6252 (node->type != XML_CDATA_SECTION_NODE)) {
6253#ifdef DEBUG_TREE
6254 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006255 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006256#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006257 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006258 }
Owen Taylor3473f882001-02-23 17:55:21 +00006259 node->content = xmlStrncat(node->content, content, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006260 if (node->content == NULL)
6261 return(-1);
6262 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006263}
6264
6265/************************************************************************
6266 * *
6267 * Output : to a FILE or in memory *
6268 * *
6269 ************************************************************************/
6270
Owen Taylor3473f882001-02-23 17:55:21 +00006271/**
6272 * xmlBufferCreate:
6273 *
6274 * routine to create an XML buffer.
6275 * returns the new structure.
6276 */
6277xmlBufferPtr
6278xmlBufferCreate(void) {
6279 xmlBufferPtr ret;
6280
6281 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6282 if (ret == NULL) {
6283 xmlGenericError(xmlGenericErrorContext,
6284 "xmlBufferCreate : out of memory!\n");
6285 return(NULL);
6286 }
6287 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006288 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006289 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006290 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006291 if (ret->content == NULL) {
6292 xmlGenericError(xmlGenericErrorContext,
6293 "xmlBufferCreate : out of memory!\n");
6294 xmlFree(ret);
6295 return(NULL);
6296 }
6297 ret->content[0] = 0;
6298 return(ret);
6299}
6300
6301/**
6302 * xmlBufferCreateSize:
6303 * @size: initial size of buffer
6304 *
6305 * routine to create an XML buffer.
6306 * returns the new structure.
6307 */
6308xmlBufferPtr
6309xmlBufferCreateSize(size_t size) {
6310 xmlBufferPtr ret;
6311
6312 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6313 if (ret == NULL) {
6314 xmlGenericError(xmlGenericErrorContext,
6315 "xmlBufferCreate : out of memory!\n");
6316 return(NULL);
6317 }
6318 ret->use = 0;
6319 ret->alloc = xmlBufferAllocScheme;
6320 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6321 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006322 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006323 if (ret->content == NULL) {
6324 xmlGenericError(xmlGenericErrorContext,
6325 "xmlBufferCreate : out of memory!\n");
6326 xmlFree(ret);
6327 return(NULL);
6328 }
6329 ret->content[0] = 0;
6330 } else
6331 ret->content = NULL;
6332 return(ret);
6333}
6334
6335/**
Daniel Veillard53350552003-09-18 13:35:51 +00006336 * xmlBufferCreateStatic:
6337 * @mem: the memory area
6338 * @size: the size in byte
6339 *
6340 * routine to create an XML buffer from an immutable memory area,
6341 * The are won't be modified nor copied, and is expected to be
6342 * present until the end of the buffer lifetime.
6343 *
6344 * returns the new structure.
6345 */
6346xmlBufferPtr
6347xmlBufferCreateStatic(void *mem, size_t size) {
6348 xmlBufferPtr ret;
6349
6350 if ((mem == NULL) || (size == 0))
6351 return(NULL);
6352
6353 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6354 if (ret == NULL) {
6355 xmlGenericError(xmlGenericErrorContext,
6356 "xmlBufferCreate : out of memory!\n");
6357 return(NULL);
6358 }
6359 ret->use = size;
6360 ret->size = size;
6361 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6362 ret->content = (xmlChar *) mem;
6363 return(ret);
6364}
6365
6366/**
Owen Taylor3473f882001-02-23 17:55:21 +00006367 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006368 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006369 * @scheme: allocation scheme to use
6370 *
6371 * Sets the allocation scheme for this buffer
6372 */
6373void
6374xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6375 xmlBufferAllocationScheme scheme) {
6376 if (buf == NULL) {
6377#ifdef DEBUG_BUFFER
6378 xmlGenericError(xmlGenericErrorContext,
6379 "xmlBufferSetAllocationScheme: buf == NULL\n");
6380#endif
6381 return;
6382 }
Daniel Veillard53350552003-09-18 13:35:51 +00006383 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006384
6385 buf->alloc = scheme;
6386}
6387
6388/**
6389 * xmlBufferFree:
6390 * @buf: the buffer to free
6391 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006392 * Frees an XML buffer. It frees both the content and the structure which
6393 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006394 */
6395void
6396xmlBufferFree(xmlBufferPtr buf) {
6397 if (buf == NULL) {
6398#ifdef DEBUG_BUFFER
6399 xmlGenericError(xmlGenericErrorContext,
6400 "xmlBufferFree: buf == NULL\n");
6401#endif
6402 return;
6403 }
Daniel Veillard53350552003-09-18 13:35:51 +00006404
6405 if ((buf->content != NULL) &&
6406 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006407 xmlFree(buf->content);
6408 }
Owen Taylor3473f882001-02-23 17:55:21 +00006409 xmlFree(buf);
6410}
6411
6412/**
6413 * xmlBufferEmpty:
6414 * @buf: the buffer
6415 *
6416 * empty a buffer.
6417 */
6418void
6419xmlBufferEmpty(xmlBufferPtr buf) {
6420 if (buf->content == NULL) return;
6421 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006422 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6423 buf->content="";
6424 } else {
6425 memset(buf->content, 0, buf->size);
6426 }
Owen Taylor3473f882001-02-23 17:55:21 +00006427}
6428
6429/**
6430 * xmlBufferShrink:
6431 * @buf: the buffer to dump
6432 * @len: the number of xmlChar to remove
6433 *
6434 * Remove the beginning of an XML buffer.
6435 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006436 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006437 */
6438int
6439xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
6440 if (len == 0) return(0);
6441 if (len > buf->use) return(-1);
6442
6443 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006444 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6445 buf->content += len;
6446 } else {
6447 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6448 buf->content[buf->use] = 0;
6449 }
Owen Taylor3473f882001-02-23 17:55:21 +00006450 return(len);
6451}
6452
6453/**
6454 * xmlBufferGrow:
6455 * @buf: the buffer
6456 * @len: the minimum free size to allocate
6457 *
6458 * Grow the available space of an XML buffer.
6459 *
6460 * Returns the new available space or -1 in case of error
6461 */
6462int
6463xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6464 int size;
6465 xmlChar *newbuf;
6466
Daniel Veillard53350552003-09-18 13:35:51 +00006467 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006468 if (len + buf->use < buf->size) return(0);
6469
6470 size = buf->use + len + 100;
6471
6472 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
6473 if (newbuf == NULL) return(-1);
6474 buf->content = newbuf;
6475 buf->size = size;
6476 return(buf->size - buf->use);
6477}
6478
6479/**
6480 * xmlBufferDump:
6481 * @file: the file output
6482 * @buf: the buffer to dump
6483 *
6484 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006485 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006486 */
6487int
6488xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6489 int ret;
6490
6491 if (buf == NULL) {
6492#ifdef DEBUG_BUFFER
6493 xmlGenericError(xmlGenericErrorContext,
6494 "xmlBufferDump: buf == NULL\n");
6495#endif
6496 return(0);
6497 }
6498 if (buf->content == NULL) {
6499#ifdef DEBUG_BUFFER
6500 xmlGenericError(xmlGenericErrorContext,
6501 "xmlBufferDump: buf->content == NULL\n");
6502#endif
6503 return(0);
6504 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006505 if (file == NULL)
6506 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006507 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6508 return(ret);
6509}
6510
6511/**
6512 * xmlBufferContent:
6513 * @buf: the buffer
6514 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006515 * Function to extract the content of a buffer
6516 *
Owen Taylor3473f882001-02-23 17:55:21 +00006517 * Returns the internal content
6518 */
6519
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006520const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006521xmlBufferContent(const xmlBufferPtr buf)
6522{
6523 if(!buf)
6524 return NULL;
6525
6526 return buf->content;
6527}
6528
6529/**
6530 * xmlBufferLength:
6531 * @buf: the buffer
6532 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006533 * Function to get the length of a buffer
6534 *
Owen Taylor3473f882001-02-23 17:55:21 +00006535 * Returns the length of data in the internal content
6536 */
6537
6538int
6539xmlBufferLength(const xmlBufferPtr buf)
6540{
6541 if(!buf)
6542 return 0;
6543
6544 return buf->use;
6545}
6546
6547/**
6548 * xmlBufferResize:
6549 * @buf: the buffer to resize
6550 * @size: the desired size
6551 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006552 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006553 *
6554 * Returns 0 in case of problems, 1 otherwise
6555 */
6556int
6557xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6558{
6559 unsigned int newSize;
6560 xmlChar* rebuf = NULL;
6561
Daniel Veillard53350552003-09-18 13:35:51 +00006562 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6563
Owen Taylor3473f882001-02-23 17:55:21 +00006564 /*take care of empty case*/
6565 newSize = (buf->size ? buf->size*2 : size);
6566
6567 /* Don't resize if we don't have to */
6568 if (size < buf->size)
6569 return 1;
6570
6571 /* figure out new size */
6572 switch (buf->alloc){
6573 case XML_BUFFER_ALLOC_DOUBLEIT:
6574 while (size > newSize) newSize *= 2;
6575 break;
6576 case XML_BUFFER_ALLOC_EXACT:
6577 newSize = size+10;
6578 break;
6579 default:
6580 newSize = size+10;
6581 break;
6582 }
6583
6584 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006585 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006586 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006587 rebuf = (xmlChar *) xmlRealloc(buf->content,
6588 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006589 } else {
6590 /*
6591 * if we are reallocating a buffer far from being full, it's
6592 * better to make a new allocation and copy only the used range
6593 * and free the old one.
6594 */
6595 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6596 if (rebuf != NULL) {
6597 memcpy(rebuf, buf->content, buf->use);
6598 xmlFree(buf->content);
6599 }
Daniel Veillarde5984082003-08-19 22:21:13 +00006600 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006601 }
Owen Taylor3473f882001-02-23 17:55:21 +00006602 if (rebuf == NULL) {
6603 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006604 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006605 return 0;
6606 }
6607 buf->content = rebuf;
6608 buf->size = newSize;
6609
6610 return 1;
6611}
6612
6613/**
6614 * xmlBufferAdd:
6615 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006616 * @str: the #xmlChar string
6617 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006618 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006619 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006620 * str is recomputed.
6621 */
6622void
6623xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6624 unsigned int needSize;
6625
6626 if (str == NULL) {
6627#ifdef DEBUG_BUFFER
6628 xmlGenericError(xmlGenericErrorContext,
6629 "xmlBufferAdd: str == NULL\n");
6630#endif
6631 return;
6632 }
Daniel Veillard53350552003-09-18 13:35:51 +00006633 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006634 if (len < -1) {
6635#ifdef DEBUG_BUFFER
6636 xmlGenericError(xmlGenericErrorContext,
6637 "xmlBufferAdd: len < 0\n");
6638#endif
6639 return;
6640 }
6641 if (len == 0) return;
6642
6643 if (len < 0)
6644 len = xmlStrlen(str);
6645
6646 if (len <= 0) return;
6647
6648 needSize = buf->use + len + 2;
6649 if (needSize > buf->size){
6650 if (!xmlBufferResize(buf, needSize)){
6651 xmlGenericError(xmlGenericErrorContext,
6652 "xmlBufferAdd : out of memory!\n");
6653 return;
6654 }
6655 }
6656
6657 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6658 buf->use += len;
6659 buf->content[buf->use] = 0;
6660}
6661
6662/**
6663 * xmlBufferAddHead:
6664 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006665 * @str: the #xmlChar string
6666 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006667 *
6668 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006669 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00006670 */
6671void
6672xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6673 unsigned int needSize;
6674
Daniel Veillard53350552003-09-18 13:35:51 +00006675 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006676 if (str == NULL) {
6677#ifdef DEBUG_BUFFER
6678 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006679 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006680#endif
6681 return;
6682 }
6683 if (len < -1) {
6684#ifdef DEBUG_BUFFER
6685 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006686 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006687#endif
6688 return;
6689 }
6690 if (len == 0) return;
6691
6692 if (len < 0)
6693 len = xmlStrlen(str);
6694
6695 if (len <= 0) return;
6696
6697 needSize = buf->use + len + 2;
6698 if (needSize > buf->size){
6699 if (!xmlBufferResize(buf, needSize)){
6700 xmlGenericError(xmlGenericErrorContext,
6701 "xmlBufferAddHead : out of memory!\n");
6702 return;
6703 }
6704 }
6705
6706 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6707 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6708 buf->use += len;
6709 buf->content[buf->use] = 0;
6710}
6711
6712/**
6713 * xmlBufferCat:
6714 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006715 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006716 *
6717 * Append a zero terminated string to an XML buffer.
6718 */
6719void
6720xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillard53350552003-09-18 13:35:51 +00006721 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006722 if (str != NULL)
6723 xmlBufferAdd(buf, str, -1);
6724}
6725
6726/**
6727 * xmlBufferCCat:
6728 * @buf: the buffer to dump
6729 * @str: the C char string
6730 *
6731 * Append a zero terminated C string to an XML buffer.
6732 */
6733void
6734xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6735 const char *cur;
6736
Daniel Veillard53350552003-09-18 13:35:51 +00006737 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006738 if (str == NULL) {
6739#ifdef DEBUG_BUFFER
6740 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006741 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006742#endif
6743 return;
6744 }
6745 for (cur = str;*cur != 0;cur++) {
6746 if (buf->use + 10 >= buf->size) {
6747 if (!xmlBufferResize(buf, buf->use+10)){
6748 xmlGenericError(xmlGenericErrorContext,
6749 "xmlBufferCCat : out of memory!\n");
6750 return;
6751 }
6752 }
6753 buf->content[buf->use++] = *cur;
6754 }
6755 buf->content[buf->use] = 0;
6756}
6757
6758/**
6759 * xmlBufferWriteCHAR:
6760 * @buf: the XML buffer
6761 * @string: the string to add
6762 *
6763 * routine which manages and grows an output buffer. This one adds
6764 * xmlChars at the end of the buffer.
6765 */
6766void
Daniel Veillard53350552003-09-18 13:35:51 +00006767xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
6768 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006769 xmlBufferCat(buf, string);
6770}
6771
6772/**
6773 * xmlBufferWriteChar:
6774 * @buf: the XML buffer output
6775 * @string: the string to add
6776 *
6777 * routine which manage and grows an output buffer. This one add
6778 * C chars at the end of the array.
6779 */
6780void
6781xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillard53350552003-09-18 13:35:51 +00006782 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006783 xmlBufferCCat(buf, string);
6784}
6785
6786
6787/**
6788 * xmlBufferWriteQuotedString:
6789 * @buf: the XML buffer output
6790 * @string: the string to add
6791 *
6792 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00006793 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00006794 * quote or double-quotes internally
6795 */
6796void
6797xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00006798 const xmlChar *cur, *base;
Daniel Veillard53350552003-09-18 13:35:51 +00006799 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00006800 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00006801 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00006802#ifdef DEBUG_BUFFER
6803 xmlGenericError(xmlGenericErrorContext,
6804 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
6805#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00006806 xmlBufferCCat(buf, "\"");
6807 base = cur = string;
6808 while(*cur != 0){
6809 if(*cur == '"'){
6810 if (base != cur)
6811 xmlBufferAdd(buf, base, cur - base);
6812 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6813 cur++;
6814 base = cur;
6815 }
6816 else {
6817 cur++;
6818 }
6819 }
6820 if (base != cur)
6821 xmlBufferAdd(buf, base, cur - base);
6822 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006823 }
Daniel Veillard39057f42003-08-04 01:33:43 +00006824 else{
6825 xmlBufferCCat(buf, "\'");
6826 xmlBufferCat(buf, string);
6827 xmlBufferCCat(buf, "\'");
6828 }
Owen Taylor3473f882001-02-23 17:55:21 +00006829 } else {
6830 xmlBufferCCat(buf, "\"");
6831 xmlBufferCat(buf, string);
6832 xmlBufferCCat(buf, "\"");
6833 }
6834}
6835
6836
6837/************************************************************************
6838 * *
6839 * Dumping XML tree content to a simple buffer *
6840 * *
6841 ************************************************************************/
6842
Owen Taylor3473f882001-02-23 17:55:21 +00006843/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00006844 * xmlAttrSerializeContent:
6845 * @buf: the XML buffer output
6846 * @doc: the document
6847 * @attr: the attribute pointer
6848 *
6849 * Serialize the attribute in the buffer
6850 */
6851static void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006852xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr)
6853{
Daniel Veillarda6d05382002-02-13 13:07:41 +00006854 const xmlChar *cur, *base;
6855 xmlNodePtr children;
6856
6857 children = attr->children;
6858 while (children != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006859 switch (children->type) {
6860 case XML_TEXT_NODE:
6861 base = cur = children->content;
6862 while (*cur != 0) {
6863 if (*cur == '\n') {
6864 if (base != cur)
6865 xmlBufferAdd(buf, base, cur - base);
6866 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
6867 cur++;
6868 base = cur;
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006869 } else if (*cur == '\r') {
6870 if (base != cur)
6871 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006872 xmlBufferAdd(buf, BAD_CAST "&#13;", 5);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006873 cur++;
6874 base = cur;
6875 } else if (*cur == '\t') {
6876 if (base != cur)
6877 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006878 xmlBufferAdd(buf, BAD_CAST "&#9;", 4);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006879 cur++;
6880 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006881#if 0
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006882 } else if (*cur == '\'') {
6883 if (base != cur)
6884 xmlBufferAdd(buf, base, cur - base);
6885 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
6886 cur++;
6887 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006888#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006889 } else if (*cur == '"') {
6890 if (base != cur)
6891 xmlBufferAdd(buf, base, cur - base);
6892 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6893 cur++;
6894 base = cur;
6895 } else if (*cur == '<') {
6896 if (base != cur)
6897 xmlBufferAdd(buf, base, cur - base);
6898 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
6899 cur++;
6900 base = cur;
6901 } else if (*cur == '>') {
6902 if (base != cur)
6903 xmlBufferAdd(buf, base, cur - base);
6904 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
6905 cur++;
6906 base = cur;
6907 } else if (*cur == '&') {
6908 if (base != cur)
6909 xmlBufferAdd(buf, base, cur - base);
6910 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
6911 cur++;
6912 base = cur;
6913 } else if ((*cur >= 0x80) && ((doc == NULL) ||
6914 (doc->encoding ==
6915 NULL))) {
6916 /*
6917 * We assume we have UTF-8 content.
6918 */
6919 char tmp[10];
6920 int val = 0, l = 1;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006921
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006922 if (base != cur)
6923 xmlBufferAdd(buf, base, cur - base);
6924 if (*cur < 0xC0) {
6925 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6d05382002-02-13 13:07:41 +00006926 "xmlAttrSerializeContent : input not UTF-8\n");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006927 if (doc != NULL)
6928 doc->encoding =
6929 xmlStrdup(BAD_CAST "ISO-8859-1");
6930 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6931 tmp[sizeof(tmp) - 1] = 0;
6932 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6933 cur++;
6934 base = cur;
6935 continue;
6936 } else if (*cur < 0xE0) {
6937 val = (cur[0]) & 0x1F;
6938 val <<= 6;
6939 val |= (cur[1]) & 0x3F;
6940 l = 2;
6941 } else if (*cur < 0xF0) {
6942 val = (cur[0]) & 0x0F;
6943 val <<= 6;
6944 val |= (cur[1]) & 0x3F;
6945 val <<= 6;
6946 val |= (cur[2]) & 0x3F;
6947 l = 3;
6948 } else if (*cur < 0xF8) {
6949 val = (cur[0]) & 0x07;
6950 val <<= 6;
6951 val |= (cur[1]) & 0x3F;
6952 val <<= 6;
6953 val |= (cur[2]) & 0x3F;
6954 val <<= 6;
6955 val |= (cur[3]) & 0x3F;
6956 l = 4;
6957 }
6958 if ((l == 1) || (!IS_CHAR(val))) {
6959 xmlGenericError(xmlGenericErrorContext,
6960 "xmlAttrSerializeContent : char out of range\n");
6961 if (doc != NULL)
6962 doc->encoding =
6963 xmlStrdup(BAD_CAST "ISO-8859-1");
6964 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6965 tmp[sizeof(tmp) - 1] = 0;
6966 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6967 cur++;
6968 base = cur;
6969 continue;
6970 }
6971 /*
6972 * We could do multiple things here. Just save
6973 * as a char ref
6974 */
6975 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
6976 tmp[sizeof(tmp) - 1] = 0;
6977 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6978 cur += l;
6979 base = cur;
6980 } else {
6981 cur++;
6982 }
6983 }
6984 if (base != cur)
6985 xmlBufferAdd(buf, base, cur - base);
6986 break;
6987 case XML_ENTITY_REF_NODE:
6988 xmlBufferAdd(buf, BAD_CAST "&", 1);
6989 xmlBufferAdd(buf, children->name,
6990 xmlStrlen(children->name));
6991 xmlBufferAdd(buf, BAD_CAST ";", 1);
6992 break;
6993 default:
6994 /* should not happen unless we have a badly built tree */
6995 break;
6996 }
6997 children = children->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006998 }
6999}
7000
7001/**
7002 * xmlNodeDump:
7003 * @buf: the XML buffer output
7004 * @doc: the document
7005 * @cur: the current node
7006 * @level: the imbrication level for indenting
7007 * @format: is formatting allowed
7008 *
7009 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007010 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007011 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007012 *
7013 * Returns the number of bytes written to the buffer or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00007014 */
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007015int
Owen Taylor3473f882001-02-23 17:55:21 +00007016xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007017 int format)
7018{
7019 unsigned int use;
7020 int ret;
7021 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00007022
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007023 xmlInitParser();
7024
Owen Taylor3473f882001-02-23 17:55:21 +00007025 if (cur == NULL) {
7026#ifdef DEBUG_TREE
7027 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007028 "xmlNodeDump : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007029#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007030 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007031 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007032 if (buf == NULL) {
7033#ifdef DEBUG_TREE
7034 xmlGenericError(xmlGenericErrorContext,
7035 "xmlNodeDump : buf == NULL\n");
7036#endif
7037 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007038 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007039 outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
7040 if (outbuf == NULL) {
7041 xmlGenericError(xmlGenericErrorContext,
7042 "xmlNodeDump: out of memory!\n");
7043 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007044 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007045 memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
7046 outbuf->buffer = buf;
7047 outbuf->encoder = NULL;
7048 outbuf->writecallback = NULL;
7049 outbuf->closecallback = NULL;
7050 outbuf->context = NULL;
7051 outbuf->written = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007052
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007053 use = buf->use;
7054 xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
7055 xmlFree(outbuf);
7056 ret = buf->use - use;
7057 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00007058}
7059
7060/**
7061 * xmlElemDump:
7062 * @f: the FILE * for the output
7063 * @doc: the document
7064 * @cur: the current node
7065 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007066 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00007067 */
7068void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007069xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur)
7070{
7071 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00007072
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007073 xmlInitParser();
7074
Owen Taylor3473f882001-02-23 17:55:21 +00007075 if (cur == NULL) {
7076#ifdef DEBUG_TREE
7077 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007078 "xmlElemDump : cur == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007079#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007080 return;
Owen Taylor3473f882001-02-23 17:55:21 +00007081 }
Owen Taylor3473f882001-02-23 17:55:21 +00007082#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007083 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00007084 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007085 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007086 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007087#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007088
7089 outbuf = xmlOutputBufferCreateFile(f, NULL);
7090 if (outbuf == NULL)
7091 return;
7092 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007093#ifdef LIBXML_HTML_ENABLED
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007094 htmlNodeDumpOutput(outbuf, doc, cur, NULL);
7095#else
7096 xmlGenericError(xmlGenericErrorContext,
7097 "HTML support not compiled in\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007098#endif /* LIBXML_HTML_ENABLED */
7099 } else
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007100 xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL);
7101 xmlOutputBufferClose(outbuf);
Owen Taylor3473f882001-02-23 17:55:21 +00007102}
7103
7104/************************************************************************
7105 * *
7106 * Dumping XML tree content to an I/O output buffer *
7107 * *
7108 ************************************************************************/
7109
Owen Taylor3473f882001-02-23 17:55:21 +00007110static void
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007111xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7112 int level, int format, const char *encoding);
7113static void
Owen Taylor3473f882001-02-23 17:55:21 +00007114xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7115 int level, int format, const char *encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007116static void
7117xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
7118 xmlNodePtr cur, int level, int format, const char *encoding);
7119
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00007120void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
7121
Owen Taylor3473f882001-02-23 17:55:21 +00007122/**
7123 * xmlNsDumpOutput:
7124 * @buf: the XML buffer output
7125 * @cur: a namespace
7126 *
7127 * Dump a local Namespace definition.
7128 * Should be called in the context of attributes dumps.
7129 */
7130static void
7131xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
7132 if (cur == NULL) {
7133#ifdef DEBUG_TREE
7134 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007135 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007136#endif
7137 return;
7138 }
7139 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00007140 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
7141 return;
7142
Owen Taylor3473f882001-02-23 17:55:21 +00007143 /* Within the context of an element attributes */
7144 if (cur->prefix != NULL) {
7145 xmlOutputBufferWriteString(buf, " xmlns:");
7146 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
7147 } else
7148 xmlOutputBufferWriteString(buf, " xmlns");
7149 xmlOutputBufferWriteString(buf, "=");
7150 xmlBufferWriteQuotedString(buf->buffer, cur->href);
7151 }
7152}
7153
7154/**
7155 * xmlNsListDumpOutput:
7156 * @buf: the XML buffer output
7157 * @cur: the first namespace
7158 *
7159 * Dump a list of local Namespace definitions.
7160 * Should be called in the context of attributes dumps.
7161 */
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00007162void
Owen Taylor3473f882001-02-23 17:55:21 +00007163xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
7164 while (cur != NULL) {
7165 xmlNsDumpOutput(buf, cur);
7166 cur = cur->next;
7167 }
7168}
7169
7170/**
7171 * xmlDtdDumpOutput:
7172 * @buf: the XML buffer output
7173 * @doc: the document
7174 * @encoding: an optional encoding string
7175 *
7176 * Dump the XML document DTD, if any.
7177 */
7178static void
7179xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
7180 if (dtd == NULL) {
7181#ifdef DEBUG_TREE
7182 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007183 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007184#endif
7185 return;
7186 }
7187 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
7188 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
7189 if (dtd->ExternalID != NULL) {
7190 xmlOutputBufferWriteString(buf, " PUBLIC ");
7191 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
7192 xmlOutputBufferWriteString(buf, " ");
7193 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
7194 } else if (dtd->SystemID != NULL) {
7195 xmlOutputBufferWriteString(buf, " SYSTEM ");
7196 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
7197 }
7198 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
7199 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
7200 xmlOutputBufferWriteString(buf, ">");
7201 return;
7202 }
7203 xmlOutputBufferWriteString(buf, " [\n");
7204 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
7205 xmlOutputBufferWriteString(buf, "]>");
7206}
7207
7208/**
7209 * xmlAttrDumpOutput:
7210 * @buf: the XML buffer output
7211 * @doc: the document
7212 * @cur: the attribute pointer
7213 * @encoding: an optional encoding string
7214 *
7215 * Dump an XML attribute
7216 */
7217static void
7218xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00007219 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00007220 if (cur == NULL) {
7221#ifdef DEBUG_TREE
7222 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007223 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007224#endif
7225 return;
7226 }
7227 xmlOutputBufferWriteString(buf, " ");
7228 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7229 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7230 xmlOutputBufferWriteString(buf, ":");
7231 }
7232 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00007233 xmlOutputBufferWriteString(buf, "=\"");
7234 xmlAttrSerializeContent(buf->buffer, doc, cur);
7235 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007236}
7237
7238/**
7239 * xmlAttrListDumpOutput:
7240 * @buf: the XML buffer output
7241 * @doc: the document
7242 * @cur: the first attribute pointer
7243 * @encoding: an optional encoding string
7244 *
7245 * Dump a list of XML attributes
7246 */
7247static void
7248xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7249 xmlAttrPtr cur, const char *encoding) {
7250 if (cur == NULL) {
7251#ifdef DEBUG_TREE
7252 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007253 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007254#endif
7255 return;
7256 }
7257 while (cur != NULL) {
7258 xmlAttrDumpOutput(buf, doc, cur, encoding);
7259 cur = cur->next;
7260 }
7261}
7262
7263
7264
7265/**
7266 * xmlNodeListDumpOutput:
7267 * @buf: the XML buffer output
7268 * @doc: the document
7269 * @cur: the first node
7270 * @level: the imbrication level for indenting
7271 * @format: is formatting allowed
7272 * @encoding: an optional encoding string
7273 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007274 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007275 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007276 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007277 */
7278static void
7279xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7280 xmlNodePtr cur, int level, int format, const char *encoding) {
7281 int i;
7282
7283 if (cur == NULL) {
7284#ifdef DEBUG_TREE
7285 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007286 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007287#endif
7288 return;
7289 }
7290 while (cur != NULL) {
7291 if ((format) && (xmlIndentTreeOutput) &&
7292 (cur->type == XML_ELEMENT_NODE))
7293 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007294 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007295 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007296 if (format) {
7297 xmlOutputBufferWriteString(buf, "\n");
7298 }
7299 cur = cur->next;
7300 }
7301}
7302
7303/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007304 * xmlNodeDumpOutputInternal:
Owen Taylor3473f882001-02-23 17:55:21 +00007305 * @buf: the XML buffer output
7306 * @doc: the document
7307 * @cur: the current node
7308 * @level: the imbrication level for indenting
7309 * @format: is formatting allowed
7310 * @encoding: an optional encoding string
7311 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007312 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007313 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007314 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007315 */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007316static void
7317xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
7318 xmlNodePtr cur, int level, int format, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007319 int i;
7320 xmlNodePtr tmp;
7321
7322 if (cur == NULL) {
7323#ifdef DEBUG_TREE
7324 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007325 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007326#endif
7327 return;
7328 }
7329 if (cur->type == XML_XINCLUDE_START)
7330 return;
7331 if (cur->type == XML_XINCLUDE_END)
7332 return;
7333 if (cur->type == XML_DTD_NODE) {
7334 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7335 return;
7336 }
7337 if (cur->type == XML_ELEMENT_DECL) {
7338 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7339 return;
7340 }
7341 if (cur->type == XML_ATTRIBUTE_DECL) {
7342 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7343 return;
7344 }
7345 if (cur->type == XML_ENTITY_DECL) {
7346 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7347 return;
7348 }
7349 if (cur->type == XML_TEXT_NODE) {
7350 if (cur->content != NULL) {
7351 if ((cur->name == xmlStringText) ||
7352 (cur->name != xmlStringTextNoenc)) {
7353 xmlChar *buffer;
7354
Owen Taylor3473f882001-02-23 17:55:21 +00007355 if (encoding == NULL)
7356 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7357 else
7358 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007359 if (buffer != NULL) {
7360 xmlOutputBufferWriteString(buf, (const char *)buffer);
7361 xmlFree(buffer);
7362 }
7363 } else {
7364 /*
7365 * Disable escaping, needed for XSLT
7366 */
Owen Taylor3473f882001-02-23 17:55:21 +00007367 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007368 }
7369 }
7370
7371 return;
7372 }
7373 if (cur->type == XML_PI_NODE) {
7374 if (cur->content != NULL) {
7375 xmlOutputBufferWriteString(buf, "<?");
7376 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7377 if (cur->content != NULL) {
7378 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00007379 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007380 }
7381 xmlOutputBufferWriteString(buf, "?>");
7382 } else {
7383 xmlOutputBufferWriteString(buf, "<?");
7384 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7385 xmlOutputBufferWriteString(buf, "?>");
7386 }
7387 return;
7388 }
7389 if (cur->type == XML_COMMENT_NODE) {
7390 if (cur->content != NULL) {
7391 xmlOutputBufferWriteString(buf, "<!--");
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 }
7395 return;
7396 }
7397 if (cur->type == XML_ENTITY_REF_NODE) {
7398 xmlOutputBufferWriteString(buf, "&");
7399 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7400 xmlOutputBufferWriteString(buf, ";");
7401 return;
7402 }
7403 if (cur->type == XML_CDATA_SECTION_NODE) {
7404 xmlOutputBufferWriteString(buf, "<![CDATA[");
7405 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007406 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007407 xmlOutputBufferWriteString(buf, "]]>");
7408 return;
7409 }
Daniel Veillard7b72ee52003-02-27 23:24:53 +00007410 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillarda1a9d042003-03-18 16:53:17 +00007411 xmlAttrDumpOutput(buf,doc, (xmlAttrPtr) cur,encoding);
Daniel Veillard7b72ee52003-02-27 23:24:53 +00007412 return;
7413 }
Daniel Veillard6aa2f602003-02-10 00:01:56 +00007414 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007415 xmlNsDumpOutput(buf, (xmlNsPtr) cur);
Daniel Veillard6aa2f602003-02-10 00:01:56 +00007416 return;
7417 }
Owen Taylor3473f882001-02-23 17:55:21 +00007418
7419 if (format == 1) {
7420 tmp = cur->children;
7421 while (tmp != NULL) {
7422 if ((tmp->type == XML_TEXT_NODE) ||
7423 (tmp->type == XML_ENTITY_REF_NODE)) {
7424 format = 0;
7425 break;
7426 }
7427 tmp = tmp->next;
7428 }
7429 }
7430 xmlOutputBufferWriteString(buf, "<");
7431 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7432 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7433 xmlOutputBufferWriteString(buf, ":");
7434 }
7435
7436 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7437 if (cur->nsDef)
7438 xmlNsListDumpOutput(buf, cur->nsDef);
7439 if (cur->properties != NULL)
7440 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7441
Daniel Veillard7db37732001-07-12 01:20:08 +00007442 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
7443 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007444 xmlOutputBufferWriteString(buf, "/>");
7445 return;
7446 }
7447 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00007448 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007449 xmlChar *buffer;
7450
Owen Taylor3473f882001-02-23 17:55:21 +00007451 if (encoding == NULL)
7452 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7453 else
7454 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007455 if (buffer != NULL) {
7456 xmlOutputBufferWriteString(buf, (const char *)buffer);
7457 xmlFree(buffer);
7458 }
7459 }
7460 if (cur->children != NULL) {
7461 if (format) xmlOutputBufferWriteString(buf, "\n");
7462 xmlNodeListDumpOutput(buf, doc, cur->children,
7463 (level >= 0?level+1:-1), format, encoding);
7464 if ((xmlIndentTreeOutput) && (format))
7465 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007466 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00007467 }
7468 xmlOutputBufferWriteString(buf, "</");
7469 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7470 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7471 xmlOutputBufferWriteString(buf, ":");
7472 }
7473
7474 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7475 xmlOutputBufferWriteString(buf, ">");
7476}
7477
7478/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007479 * xmlNodeDumpOutput:
7480 * @buf: the XML buffer output
7481 * @doc: the document
7482 * @cur: the current node
7483 * @level: the imbrication level for indenting
7484 * @format: is formatting allowed
7485 * @encoding: an optional encoding string
7486 *
7487 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007488 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007489 * or xmlKeepBlanksDefault(0) was called
7490 */
7491void
7492xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007493 int level, int format, const char *encoding)
7494{
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007495#ifdef LIBXML_HTML_ENABLED
7496 xmlDtdPtr dtd;
7497 int is_xhtml = 0;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007498#endif
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007499
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007500 xmlInitParser();
7501
7502#ifdef LIBXML_HTML_ENABLED
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007503 dtd = xmlGetIntSubset(doc);
7504 if (dtd != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007505 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7506 if (is_xhtml < 0)
7507 is_xhtml = 0;
7508 if ((is_xhtml) && (cur->parent == (xmlNodePtr) doc) &&
7509 (cur->type == XML_ELEMENT_NODE) &&
7510 (xmlStrEqual(cur->name, BAD_CAST "html"))) {
7511 if (encoding != NULL)
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007512 htmlSetMetaEncoding((htmlDocPtr) doc,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007513 (const xmlChar *) encoding);
7514 else
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007515 htmlSetMetaEncoding((htmlDocPtr) doc, BAD_CAST "UTF-8");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007516 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007517 }
7518
7519 if (is_xhtml)
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007520 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007521 else
7522#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007523 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007524}
7525
7526/**
Owen Taylor3473f882001-02-23 17:55:21 +00007527 * xmlDocContentDumpOutput:
7528 * @buf: the XML buffer output
7529 * @cur: the document
7530 * @encoding: an optional encoding string
7531 * @format: should formatting spaces been added
7532 *
7533 * Dump an XML document.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007534 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007535 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007536 */
7537static void
7538xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
7539 const char *encoding, int format) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007540#ifdef LIBXML_HTML_ENABLED
7541 xmlDtdPtr dtd;
7542 int is_xhtml = 0;
7543#endif
7544
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007545 xmlInitParser();
7546
Owen Taylor3473f882001-02-23 17:55:21 +00007547 xmlOutputBufferWriteString(buf, "<?xml version=");
7548 if (cur->version != NULL)
7549 xmlBufferWriteQuotedString(buf->buffer, cur->version);
7550 else
7551 xmlOutputBufferWriteString(buf, "\"1.0\"");
7552 if (encoding == NULL) {
7553 if (cur->encoding != NULL)
7554 encoding = (const char *) cur->encoding;
7555 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
7556 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
7557 }
7558 if (encoding != NULL) {
7559 xmlOutputBufferWriteString(buf, " encoding=");
7560 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
7561 }
7562 switch (cur->standalone) {
7563 case 0:
7564 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
7565 break;
7566 case 1:
7567 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
7568 break;
7569 }
7570 xmlOutputBufferWriteString(buf, "?>\n");
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007571
7572#ifdef LIBXML_HTML_ENABLED
7573 dtd = xmlGetIntSubset(cur);
7574 if (dtd != NULL) {
7575 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7576 if (is_xhtml < 0) is_xhtml = 0;
7577 }
7578 if (is_xhtml) {
7579 if (encoding != NULL)
7580 htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
7581 else
7582 htmlSetMetaEncoding(cur, BAD_CAST "UTF-8");
7583 }
7584#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007585 if (cur->children != NULL) {
7586 xmlNodePtr child = cur->children;
7587
7588 while (child != NULL) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007589#ifdef LIBXML_HTML_ENABLED
7590 if (is_xhtml)
7591 xhtmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
7592 else
7593#endif
7594 xmlNodeDumpOutputInternal(buf, cur, child, 0, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007595 xmlOutputBufferWriteString(buf, "\n");
7596 child = child->next;
7597 }
7598 }
7599}
7600
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007601#ifdef LIBXML_HTML_ENABLED
7602/************************************************************************
7603 * *
7604 * Functions specific to XHTML serialization *
7605 * *
7606 ************************************************************************/
7607
7608#define XHTML_STRICT_PUBLIC_ID BAD_CAST \
7609 "-//W3C//DTD XHTML 1.0 Strict//EN"
7610#define XHTML_STRICT_SYSTEM_ID BAD_CAST \
7611 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
7612#define XHTML_FRAME_PUBLIC_ID BAD_CAST \
7613 "-//W3C//DTD XHTML 1.0 Frameset//EN"
7614#define XHTML_FRAME_SYSTEM_ID BAD_CAST \
7615 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
7616#define XHTML_TRANS_PUBLIC_ID BAD_CAST \
7617 "-//W3C//DTD XHTML 1.0 Transitional//EN"
7618#define XHTML_TRANS_SYSTEM_ID BAD_CAST \
7619 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
7620
7621#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
7622/**
7623 * xmlIsXHTML:
7624 * @systemID: the system identifier
7625 * @publicID: the public identifier
7626 *
7627 * Try to find if the document correspond to an XHTML DTD
7628 *
7629 * Returns 1 if true, 0 if not and -1 in case of error
7630 */
7631int
7632xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) {
7633 if ((systemID == NULL) && (publicID == NULL))
7634 return(-1);
7635 if (publicID != NULL) {
7636 if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1);
7637 if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1);
7638 if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1);
7639 }
7640 if (systemID != NULL) {
7641 if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1);
7642 if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1);
7643 if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1);
7644 }
7645 return(0);
7646}
7647
7648/**
7649 * xhtmlIsEmpty:
7650 * @node: the node
7651 *
7652 * Check if a node is an empty xhtml node
7653 *
7654 * Returns 1 if the node is an empty node, 0 if not and -1 in case of error
7655 */
7656static int
7657xhtmlIsEmpty(xmlNodePtr node) {
7658 if (node == NULL)
7659 return(-1);
7660 if (node->type != XML_ELEMENT_NODE)
7661 return(0);
7662 if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME)))
7663 return(0);
7664 if (node->children != NULL)
7665 return(0);
7666 switch (node->name[0]) {
7667 case 'a':
7668 if (xmlStrEqual(node->name, BAD_CAST "area"))
7669 return(1);
7670 return(0);
7671 case 'b':
7672 if (xmlStrEqual(node->name, BAD_CAST "br"))
7673 return(1);
7674 if (xmlStrEqual(node->name, BAD_CAST "base"))
7675 return(1);
7676 if (xmlStrEqual(node->name, BAD_CAST "basefont"))
7677 return(1);
7678 return(0);
7679 case 'c':
7680 if (xmlStrEqual(node->name, BAD_CAST "col"))
7681 return(1);
7682 return(0);
7683 case 'f':
7684 if (xmlStrEqual(node->name, BAD_CAST "frame"))
7685 return(1);
7686 return(0);
7687 case 'h':
7688 if (xmlStrEqual(node->name, BAD_CAST "hr"))
7689 return(1);
7690 return(0);
7691 case 'i':
7692 if (xmlStrEqual(node->name, BAD_CAST "img"))
7693 return(1);
7694 if (xmlStrEqual(node->name, BAD_CAST "input"))
7695 return(1);
7696 if (xmlStrEqual(node->name, BAD_CAST "isindex"))
7697 return(1);
7698 return(0);
7699 case 'l':
7700 if (xmlStrEqual(node->name, BAD_CAST "link"))
7701 return(1);
7702 return(0);
7703 case 'm':
7704 if (xmlStrEqual(node->name, BAD_CAST "meta"))
7705 return(1);
7706 return(0);
7707 case 'p':
7708 if (xmlStrEqual(node->name, BAD_CAST "param"))
7709 return(1);
7710 return(0);
7711 }
7712 return(0);
7713}
7714
7715/**
7716 * xhtmlAttrListDumpOutput:
7717 * @buf: the XML buffer output
7718 * @doc: the document
7719 * @cur: the first attribute pointer
7720 * @encoding: an optional encoding string
7721 *
7722 * Dump a list of XML attributes
7723 */
7724static void
7725xhtmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7726 xmlAttrPtr cur, const char *encoding) {
7727 xmlAttrPtr xml_lang = NULL;
7728 xmlAttrPtr lang = NULL;
7729 xmlAttrPtr name = NULL;
7730 xmlAttrPtr id = NULL;
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007731 xmlNodePtr parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007732
7733 if (cur == NULL) {
7734#ifdef DEBUG_TREE
7735 xmlGenericError(xmlGenericErrorContext,
7736 "xmlAttrListDumpOutput : property == NULL\n");
7737#endif
7738 return;
7739 }
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007740 parent = cur->parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007741 while (cur != NULL) {
7742 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id")))
7743 id = cur;
7744 else
7745 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name")))
7746 name = cur;
7747 else
7748 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")))
7749 lang = cur;
7750 else
7751 if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) &&
7752 (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml")))
7753 xml_lang = cur;
7754 else if ((cur->ns == NULL) &&
7755 ((cur->children == NULL) ||
7756 (cur->children->content == NULL) ||
7757 (cur->children->content[0] == 0)) &&
7758 (htmlIsBooleanAttr(cur->name))) {
7759 if (cur->children != NULL)
7760 xmlFreeNode(cur->children);
7761 cur->children = xmlNewText(cur->name);
7762 if (cur->children != NULL)
7763 cur->children->parent = (xmlNodePtr) cur;
7764 }
7765 xmlAttrDumpOutput(buf, doc, cur, encoding);
7766 cur = cur->next;
7767 }
7768 /*
7769 * C.8
7770 */
7771 if ((name != NULL) && (id == NULL)) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007772 if ((parent != NULL) && (parent->name != NULL) &&
7773 ((xmlStrEqual(parent->name, BAD_CAST "a")) ||
7774 (xmlStrEqual(parent->name, BAD_CAST "p")) ||
7775 (xmlStrEqual(parent->name, BAD_CAST "div")) ||
7776 (xmlStrEqual(parent->name, BAD_CAST "img")) ||
7777 (xmlStrEqual(parent->name, BAD_CAST "map")) ||
7778 (xmlStrEqual(parent->name, BAD_CAST "applet")) ||
7779 (xmlStrEqual(parent->name, BAD_CAST "form")) ||
7780 (xmlStrEqual(parent->name, BAD_CAST "frame")) ||
7781 (xmlStrEqual(parent->name, BAD_CAST "iframe")))) {
7782 xmlOutputBufferWriteString(buf, " id=\"");
7783 xmlAttrSerializeContent(buf->buffer, doc, name);
7784 xmlOutputBufferWriteString(buf, "\"");
7785 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007786 }
7787 /*
7788 * C.7.
7789 */
7790 if ((lang != NULL) && (xml_lang == NULL)) {
7791 xmlOutputBufferWriteString(buf, " xml:lang=\"");
7792 xmlAttrSerializeContent(buf->buffer, doc, lang);
7793 xmlOutputBufferWriteString(buf, "\"");
7794 } else
7795 if ((xml_lang != NULL) && (lang == NULL)) {
7796 xmlOutputBufferWriteString(buf, " lang=\"");
7797 xmlAttrSerializeContent(buf->buffer, doc, xml_lang);
7798 xmlOutputBufferWriteString(buf, "\"");
7799 }
7800}
7801
7802/**
7803 * xhtmlNodeListDumpOutput:
7804 * @buf: the XML buffer output
7805 * @doc: the XHTML document
7806 * @cur: the first node
7807 * @level: the imbrication level for indenting
7808 * @format: is formatting allowed
7809 * @encoding: an optional encoding string
7810 *
7811 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007812 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007813 * or xmlKeepBlanksDefault(0) was called
7814 */
7815static void
7816xhtmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7817 xmlNodePtr cur, int level, int format, const char *encoding) {
7818 int i;
7819
7820 if (cur == NULL) {
7821#ifdef DEBUG_TREE
7822 xmlGenericError(xmlGenericErrorContext,
7823 "xhtmlNodeListDumpOutput : node == NULL\n");
7824#endif
7825 return;
7826 }
7827 while (cur != NULL) {
7828 if ((format) && (xmlIndentTreeOutput) &&
7829 (cur->type == XML_ELEMENT_NODE))
7830 for (i = 0;i < level;i++)
7831 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7832 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
7833 if (format) {
7834 xmlOutputBufferWriteString(buf, "\n");
7835 }
7836 cur = cur->next;
7837 }
7838}
7839
7840/**
7841 * xhtmlNodeDumpOutput:
7842 * @buf: the XML buffer output
7843 * @doc: the XHTML document
7844 * @cur: the current node
7845 * @level: the imbrication level for indenting
7846 * @format: is formatting allowed
7847 * @encoding: an optional encoding string
7848 *
7849 * Dump an XHTML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007850 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007851 * or xmlKeepBlanksDefault(0) was called
7852 */
7853static void
7854xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7855 int level, int format, const char *encoding) {
7856 int i;
7857 xmlNodePtr tmp;
7858
7859 if (cur == NULL) {
7860#ifdef DEBUG_TREE
7861 xmlGenericError(xmlGenericErrorContext,
7862 "xmlNodeDumpOutput : node == NULL\n");
7863#endif
7864 return;
7865 }
7866 if (cur->type == XML_XINCLUDE_START)
7867 return;
7868 if (cur->type == XML_XINCLUDE_END)
7869 return;
7870 if (cur->type == XML_DTD_NODE) {
7871 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7872 return;
7873 }
7874 if (cur->type == XML_ELEMENT_DECL) {
7875 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7876 return;
7877 }
7878 if (cur->type == XML_ATTRIBUTE_DECL) {
7879 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7880 return;
7881 }
7882 if (cur->type == XML_ENTITY_DECL) {
7883 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7884 return;
7885 }
7886 if (cur->type == XML_TEXT_NODE) {
7887 if (cur->content != NULL) {
7888 if ((cur->name == xmlStringText) ||
7889 (cur->name != xmlStringTextNoenc)) {
7890 xmlChar *buffer;
7891
7892 if (encoding == NULL)
7893 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7894 else
7895 buffer = xmlEncodeSpecialChars(doc, cur->content);
7896 if (buffer != NULL) {
7897 xmlOutputBufferWriteString(buf, (const char *)buffer);
7898 xmlFree(buffer);
7899 }
7900 } else {
7901 /*
7902 * Disable escaping, needed for XSLT
7903 */
7904 xmlOutputBufferWriteString(buf, (const char *) cur->content);
7905 }
7906 }
7907
7908 return;
7909 }
7910 if (cur->type == XML_PI_NODE) {
7911 if (cur->content != NULL) {
7912 xmlOutputBufferWriteString(buf, "<?");
7913 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7914 if (cur->content != NULL) {
7915 xmlOutputBufferWriteString(buf, " ");
7916 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7917 }
7918 xmlOutputBufferWriteString(buf, "?>");
7919 } else {
7920 xmlOutputBufferWriteString(buf, "<?");
7921 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7922 xmlOutputBufferWriteString(buf, "?>");
7923 }
7924 return;
7925 }
7926 if (cur->type == XML_COMMENT_NODE) {
7927 if (cur->content != NULL) {
7928 xmlOutputBufferWriteString(buf, "<!--");
7929 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7930 xmlOutputBufferWriteString(buf, "-->");
7931 }
7932 return;
7933 }
7934 if (cur->type == XML_ENTITY_REF_NODE) {
7935 xmlOutputBufferWriteString(buf, "&");
7936 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7937 xmlOutputBufferWriteString(buf, ";");
7938 return;
7939 }
7940 if (cur->type == XML_CDATA_SECTION_NODE) {
7941 xmlOutputBufferWriteString(buf, "<![CDATA[");
7942 if (cur->content != NULL)
7943 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7944 xmlOutputBufferWriteString(buf, "]]>");
7945 return;
7946 }
7947
7948 if (format == 1) {
7949 tmp = cur->children;
7950 while (tmp != NULL) {
7951 if ((tmp->type == XML_TEXT_NODE) ||
7952 (tmp->type == XML_ENTITY_REF_NODE)) {
7953 format = 0;
7954 break;
7955 }
7956 tmp = tmp->next;
7957 }
7958 }
7959 xmlOutputBufferWriteString(buf, "<");
7960 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7961 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7962 xmlOutputBufferWriteString(buf, ":");
7963 }
7964
7965 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7966 if (cur->nsDef)
7967 xmlNsListDumpOutput(buf, cur->nsDef);
7968 if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
7969 (cur->ns == NULL) && (cur->nsDef == NULL))) {
7970 /*
7971 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
7972 */
7973 xmlOutputBufferWriteString(buf,
7974 " xmlns=\"http://www.w3.org/1999/xhtml\"");
7975 }
7976 if (cur->properties != NULL)
7977 xhtmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7978
7979 if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) {
7980 if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
7981 (xhtmlIsEmpty(cur) == 1)) {
7982 /*
7983 * C.2. Empty Elements
7984 */
7985 xmlOutputBufferWriteString(buf, " />");
7986 } else {
7987 /*
7988 * C.3. Element Minimization and Empty Element Content
7989 */
7990 xmlOutputBufferWriteString(buf, "></");
7991 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7992 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7993 xmlOutputBufferWriteString(buf, ":");
7994 }
7995 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7996 xmlOutputBufferWriteString(buf, ">");
7997 }
7998 return;
7999 }
8000 xmlOutputBufferWriteString(buf, ">");
8001 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
8002 xmlChar *buffer;
8003
8004 if (encoding == NULL)
8005 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
8006 else
8007 buffer = xmlEncodeSpecialChars(doc, cur->content);
8008 if (buffer != NULL) {
8009 xmlOutputBufferWriteString(buf, (const char *)buffer);
8010 xmlFree(buffer);
8011 }
8012 }
8013
8014 /*
8015 * 4.8. Script and Style elements
8016 */
8017 if ((cur->type == XML_ELEMENT_NODE) &&
8018 ((xmlStrEqual(cur->name, BAD_CAST "script")) ||
8019 (xmlStrEqual(cur->name, BAD_CAST "style"))) &&
8020 ((cur->ns == NULL) ||
8021 (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) {
8022 xmlNodePtr child = cur->children;
8023
8024 while (child != NULL) {
8025 if ((child->type == XML_TEXT_NODE) ||
8026 (child->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard64b35282002-12-04 15:10:40 +00008027 /*
8028 * Apparently CDATA escaping for style just break on IE,
8029 * mozilla and galeon, so ...
8030 */
8031 if (xmlStrEqual(cur->name, BAD_CAST "style") &&
8032 (xmlStrchr(child->content, '<') == NULL) &&
8033 (xmlStrchr(child->content, '>') == NULL) &&
8034 (xmlStrchr(child->content, '&') == NULL)) {
8035 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
8036 } else {
8037 xmlOutputBufferWriteString(buf, "<![CDATA[");
8038 if (child->content != NULL)
8039 xmlOutputBufferWriteString(buf,
8040 (const char *)child->content);
8041 xmlOutputBufferWriteString(buf, "]]>");
8042 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00008043 } else {
8044 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
8045 }
8046 child = child->next;
8047 }
8048 } else if (cur->children != NULL) {
8049 if (format) xmlOutputBufferWriteString(buf, "\n");
8050 xhtmlNodeListDumpOutput(buf, doc, cur->children,
8051 (level >= 0?level+1:-1), format, encoding);
8052 if ((xmlIndentTreeOutput) && (format))
8053 for (i = 0;i < level;i++)
8054 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
8055 }
8056 xmlOutputBufferWriteString(buf, "</");
8057 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
8058 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
8059 xmlOutputBufferWriteString(buf, ":");
8060 }
8061
8062 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8063 xmlOutputBufferWriteString(buf, ">");
8064}
8065#endif
8066
Owen Taylor3473f882001-02-23 17:55:21 +00008067/************************************************************************
8068 * *
8069 * Saving functions front-ends *
8070 * *
8071 ************************************************************************/
8072
8073/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00008074 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00008075 * @out_doc: Document to generate XML text from
8076 * @doc_txt_ptr: Memory pointer for allocated XML text
8077 * @doc_txt_len: Length of the generated XML text
8078 * @txt_encoding: Character encoding to use when generating XML text
8079 * @format: should formatting spaces been added
8080 *
8081 * Dump the current DOM tree into memory using the character encoding specified
8082 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008083 * allocated memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00008084 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00008085 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008086 */
8087
8088void
8089xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008090 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008091 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00008092 int dummy = 0;
8093
Owen Taylor3473f882001-02-23 17:55:21 +00008094 xmlOutputBufferPtr out_buff = NULL;
8095 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
8096
8097 if (doc_txt_len == NULL) {
8098 doc_txt_len = &dummy; /* Continue, caller just won't get length */
8099 }
8100
8101 if (doc_txt_ptr == NULL) {
8102 *doc_txt_len = 0;
8103 xmlGenericError(xmlGenericErrorContext,
8104 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
8105 return;
8106 }
8107
8108 *doc_txt_ptr = NULL;
8109 *doc_txt_len = 0;
8110
8111 if (out_doc == NULL) {
8112 /* No document, no output */
8113 xmlGenericError(xmlGenericErrorContext,
8114 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
8115 return;
8116 }
8117
8118 /*
8119 * Validate the encoding value, if provided.
8120 * This logic is copied from xmlSaveFileEnc.
8121 */
8122
8123 if (txt_encoding == NULL)
8124 txt_encoding = (const char *) out_doc->encoding;
8125 if (txt_encoding != NULL) {
Daniel Veillarde1326112003-06-05 09:32:20 +00008126 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00008127 if ( conv_hdlr == NULL ) {
8128 xmlGenericError(xmlGenericErrorContext,
8129 "%s: %s %s '%s'\n",
8130 "xmlDocDumpFormatMemoryEnc",
8131 "Failed to identify encoding handler for",
8132 "character set",
8133 txt_encoding);
8134 return;
8135 }
8136 }
Owen Taylor3473f882001-02-23 17:55:21 +00008137
8138 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
8139 xmlGenericError(xmlGenericErrorContext,
8140 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
8141 return;
8142 }
8143
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008144 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008145 xmlOutputBufferFlush(out_buff);
8146 if (out_buff->conv != NULL) {
8147 *doc_txt_len = out_buff->conv->use;
8148 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
8149 } else {
8150 *doc_txt_len = out_buff->buffer->use;
8151 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
8152 }
8153 (void)xmlOutputBufferClose(out_buff);
8154
8155 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
8156 *doc_txt_len = 0;
8157 xmlGenericError(xmlGenericErrorContext,
8158 "xmlDocDumpFormatMemoryEnc: %s\n",
8159 "Failed to allocate memory for document text representation.");
8160 }
8161
8162 return;
8163}
8164
8165/**
8166 * xmlDocDumpMemory:
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 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008171 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008172 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00008173 */
8174void
8175xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
8176 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
8177}
8178
8179/**
8180 * xmlDocDumpFormatMemory:
8181 * @cur: the document
8182 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00008183 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00008184 * @format: should formatting spaces been added
8185 *
8186 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008187 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008188 * It's up to the caller to free the memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00008189 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00008190 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008191 */
8192void
8193xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
8194 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
8195}
8196
8197/**
8198 * xmlDocDumpMemoryEnc:
8199 * @out_doc: Document to generate XML text from
8200 * @doc_txt_ptr: Memory pointer for allocated XML text
8201 * @doc_txt_len: Length of the generated XML text
8202 * @txt_encoding: Character encoding to use when generating XML text
8203 *
8204 * Dump the current DOM tree into memory using the character encoding specified
8205 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008206 * allocated memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00008207 */
8208
8209void
8210xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
8211 int * doc_txt_len, const char * txt_encoding) {
8212 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008213 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008214}
8215
8216/**
8217 * xmlGetDocCompressMode:
8218 * @doc: the document
8219 *
8220 * get the compression ratio for a document, ZLIB based
8221 * Returns 0 (uncompressed) to 9 (max compression)
8222 */
8223int
8224xmlGetDocCompressMode (xmlDocPtr doc) {
8225 if (doc == NULL) return(-1);
8226 return(doc->compression);
8227}
8228
8229/**
8230 * xmlSetDocCompressMode:
8231 * @doc: the document
8232 * @mode: the compression ratio
8233 *
8234 * set the compression ratio for a document, ZLIB based
8235 * Correct values: 0 (uncompressed) to 9 (max compression)
8236 */
8237void
8238xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
8239 if (doc == NULL) return;
8240 if (mode < 0) doc->compression = 0;
8241 else if (mode > 9) doc->compression = 9;
8242 else doc->compression = mode;
8243}
8244
8245/**
8246 * xmlGetCompressMode:
8247 *
8248 * get the default compression mode used, ZLIB based.
8249 * Returns 0 (uncompressed) to 9 (max compression)
8250 */
8251int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008252xmlGetCompressMode(void)
8253{
8254 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00008255}
8256
8257/**
8258 * xmlSetCompressMode:
8259 * @mode: the compression ratio
8260 *
8261 * set the default compression mode used, ZLIB based
8262 * Correct values: 0 (uncompressed) to 9 (max compression)
8263 */
8264void
8265xmlSetCompressMode(int mode) {
8266 if (mode < 0) xmlCompressMode = 0;
8267 else if (mode > 9) xmlCompressMode = 9;
8268 else xmlCompressMode = mode;
8269}
8270
8271/**
Daniel Veillard9e412302002-06-10 15:59:44 +00008272 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00008273 * @f: the FILE*
8274 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00008275 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00008276 *
8277 * Dump an XML document to an open FILE.
8278 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008279 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008280 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8281 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008282 */
8283int
Daniel Veillard9e412302002-06-10 15:59:44 +00008284xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00008285 xmlOutputBufferPtr buf;
8286 const char * encoding;
8287 xmlCharEncodingHandlerPtr handler = NULL;
8288 int ret;
8289
8290 if (cur == NULL) {
8291#ifdef DEBUG_TREE
8292 xmlGenericError(xmlGenericErrorContext,
8293 "xmlDocDump : document == NULL\n");
8294#endif
8295 return(-1);
8296 }
8297 encoding = (const char *) cur->encoding;
8298
8299 if (encoding != NULL) {
Daniel Veillarde1326112003-06-05 09:32:20 +00008300 handler = xmlFindCharEncodingHandler(encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00008301 if (handler == NULL) {
8302 xmlFree((char *) cur->encoding);
8303 cur->encoding = NULL;
8304 }
8305 }
Owen Taylor3473f882001-02-23 17:55:21 +00008306 buf = xmlOutputBufferCreateFile(f, handler);
8307 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00008308 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008309
8310 ret = xmlOutputBufferClose(buf);
8311 return(ret);
8312}
8313
8314/**
Daniel Veillard9e412302002-06-10 15:59:44 +00008315 * xmlDocDump:
8316 * @f: the FILE*
8317 * @cur: the document
8318 *
8319 * Dump an XML document to an open FILE.
8320 *
8321 * returns: the number of bytes written or -1 in case of failure.
8322 */
8323int
8324xmlDocDump(FILE *f, xmlDocPtr cur) {
8325 return(xmlDocFormatDump (f, cur, 0));
8326}
8327
8328/**
Owen Taylor3473f882001-02-23 17:55:21 +00008329 * xmlSaveFileTo:
8330 * @buf: an output I/O buffer
8331 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00008332 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00008333 *
8334 * Dump an XML document to an I/O buffer.
8335 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008336 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008337 */
8338int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00008339xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00008340 int ret;
8341
8342 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008343 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008344 ret = xmlOutputBufferClose(buf);
8345 return(ret);
8346}
8347
8348/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00008349 * xmlSaveFormatFileTo:
8350 * @buf: an output I/O buffer
8351 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00008352 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00008353 * @format: should formatting spaces been added
8354 *
8355 * Dump an XML document to an I/O buffer.
8356 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008357 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008358 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8359 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardeefd4492001-04-28 16:55:50 +00008360 */
8361int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00008362xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00008363 int ret;
8364
8365 if (buf == NULL) return(0);
8366 xmlDocContentDumpOutput(buf, cur, encoding, format);
8367 ret = xmlOutputBufferClose(buf);
8368 return(ret);
8369}
8370
8371/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00008372 * xmlSaveFormatFileEnc:
Daniel Veillardf012a642001-07-23 19:10:52 +00008373 * @filename: the filename or URL to output
8374 * @cur: the document being saved
8375 * @encoding: the name of the encoding to use or NULL.
8376 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00008377 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00008378 * Dump an XML document to a file or an URL.
8379 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008380 * Returns the number of bytes written or -1 in case of error.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008381 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8382 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008383 */
8384int
Daniel Veillardf012a642001-07-23 19:10:52 +00008385xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
8386 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00008387 xmlOutputBufferPtr buf;
8388 xmlCharEncodingHandlerPtr handler = NULL;
8389 int ret;
8390
Daniel Veillard4dbe77a2003-01-14 00:17:42 +00008391 if (cur == NULL)
8392 return(-1);
8393
Daniel Veillardfb25a512002-01-13 20:32:08 +00008394 if (encoding == NULL)
8395 encoding = (const char *) cur->encoding;
8396
Owen Taylor3473f882001-02-23 17:55:21 +00008397 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00008398
Owen Taylor3473f882001-02-23 17:55:21 +00008399 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00008400 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00008401 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00008402 }
8403
Daniel Veillardf012a642001-07-23 19:10:52 +00008404#ifdef HAVE_ZLIB_H
8405 if (cur->compression < 0) cur->compression = xmlCompressMode;
8406#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008407 /*
8408 * save the content to a temp buffer.
8409 */
Daniel Veillardf012a642001-07-23 19:10:52 +00008410 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00008411 if (buf == NULL) return(-1);
8412
Daniel Veillardf012a642001-07-23 19:10:52 +00008413 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008414
8415 ret = xmlOutputBufferClose(buf);
8416 return(ret);
8417}
8418
Daniel Veillardf012a642001-07-23 19:10:52 +00008419
8420/**
8421 * xmlSaveFileEnc:
8422 * @filename: the filename (or URL)
8423 * @cur: the document
8424 * @encoding: the name of an encoding (or NULL)
8425 *
8426 * Dump an XML document, converting it to the given encoding
8427 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008428 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00008429 */
8430int
8431xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
8432 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
8433}
8434
Owen Taylor3473f882001-02-23 17:55:21 +00008435/**
Daniel Veillard67fee942001-04-26 18:59:03 +00008436 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00008437 * @filename: the filename (or URL)
8438 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00008439 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00008440 *
8441 * Dump an XML document to a file. Will use compression if
8442 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00008443 * used. If @format is set then the document will be indented on output.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008444 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8445 * or xmlKeepBlanksDefault(0) was called
Daniel Veillard67fee942001-04-26 18:59:03 +00008446 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008447 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008448 */
8449int
Daniel Veillard67fee942001-04-26 18:59:03 +00008450xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008451 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00008452}
8453
Daniel Veillard67fee942001-04-26 18:59:03 +00008454/**
8455 * xmlSaveFile:
8456 * @filename: the filename (or URL)
8457 * @cur: the document
8458 *
8459 * Dump an XML document to a file. Will use compression if
8460 * compiled in and enabled. If @filename is "-" the stdout file is
8461 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00008462 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00008463 */
8464int
8465xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008466 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00008467}
8468