blob: 4eed575ae1228a6450e1442159be49ebb757fedd [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/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000917 * DICT_FREE:
918 * @str: a string
919 *
920 * Free a string if it is not owned by the "dict" dictionnary in the
921 * current scope
922 */
923#define DICT_FREE(str) \
924 if ((str) && ((!dict) || \
925 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
926 xmlFree((char *)(str));
927
928/**
Owen Taylor3473f882001-02-23 17:55:21 +0000929 * xmlFreeDtd:
930 * @cur: the DTD structure to free up
931 *
932 * Free a DTD structure.
933 */
934void
935xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000936 xmlDictPtr dict = NULL;
937
Owen Taylor3473f882001-02-23 17:55:21 +0000938 if (cur == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000939 return;
940 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000941 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +0000942
Daniel Veillarda880b122003-04-21 21:36:41 +0000943 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000944 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
945
Owen Taylor3473f882001-02-23 17:55:21 +0000946 if (cur->children != NULL) {
947 xmlNodePtr next, c = cur->children;
948
949 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000950 * Cleanup all the DTD comments they are not in the DTD
Owen Taylor3473f882001-02-23 17:55:21 +0000951 * indexes.
952 */
953 while (c != NULL) {
954 next = c->next;
Daniel Veillardd72c7e32003-05-12 21:55:03 +0000955 if ((c->type == XML_COMMENT_NODE) || (c->type == XML_PI_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000956 xmlUnlinkNode(c);
957 xmlFreeNode(c);
958 }
959 c = next;
960 }
961 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000962 DICT_FREE(cur->name)
963 DICT_FREE(cur->SystemID)
964 DICT_FREE(cur->ExternalID)
Owen Taylor3473f882001-02-23 17:55:21 +0000965 /* TODO !!! */
966 if (cur->notations != NULL)
967 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
968
969 if (cur->elements != NULL)
970 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
971 if (cur->attributes != NULL)
972 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
973 if (cur->entities != NULL)
974 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
975 if (cur->pentities != NULL)
976 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
977
Owen Taylor3473f882001-02-23 17:55:21 +0000978 xmlFree(cur);
979}
980
981/**
982 * xmlNewDoc:
983 * @version: xmlChar string giving the version of XML "1.0"
984 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000985 * Creates a new XML document
986 *
Owen Taylor3473f882001-02-23 17:55:21 +0000987 * Returns a new document
988 */
989xmlDocPtr
990xmlNewDoc(const xmlChar *version) {
991 xmlDocPtr cur;
992
993 if (version == NULL)
994 version = (const xmlChar *) "1.0";
995
996 /*
997 * Allocate a new document and fill the fields.
998 */
999 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
1000 if (cur == NULL) {
1001 xmlGenericError(xmlGenericErrorContext,
1002 "xmlNewDoc : malloc failed\n");
1003 return(NULL);
1004 }
1005 memset(cur, 0, sizeof(xmlDoc));
1006 cur->type = XML_DOCUMENT_NODE;
1007
1008 cur->version = xmlStrdup(version);
1009 cur->standalone = -1;
1010 cur->compression = -1; /* not initialized */
1011 cur->doc = cur;
Daniel Veillarda6874ca2003-07-29 16:47:24 +00001012 /*
1013 * The in memory encoding is always UTF8
1014 * This field will never change and would
1015 * be obsolete if not for binary compatibility.
1016 */
Daniel Veillardd2f3ec72001-04-11 07:50:02 +00001017 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001018
Daniel Veillarda880b122003-04-21 21:36:41 +00001019 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001020 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001021 return(cur);
1022}
1023
1024/**
1025 * xmlFreeDoc:
1026 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +00001027 *
1028 * Free up all the structures used by a document, tree included.
1029 */
1030void
1031xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +00001032 xmlDtdPtr extSubset, intSubset;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001033 xmlDictPtr dict = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001034
Owen Taylor3473f882001-02-23 17:55:21 +00001035 if (cur == NULL) {
1036#ifdef DEBUG_TREE
1037 xmlGenericError(xmlGenericErrorContext,
1038 "xmlFreeDoc : document == NULL\n");
1039#endif
1040 return;
1041 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001042 if (cur != NULL) dict = cur->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001043
Daniel Veillarda880b122003-04-21 21:36:41 +00001044 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001045 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1046
Daniel Veillard76d66f42001-05-16 21:05:17 +00001047 /*
1048 * Do this before freeing the children list to avoid ID lookups
1049 */
1050 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1051 cur->ids = NULL;
1052 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1053 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001054 extSubset = cur->extSubset;
1055 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +00001056 if (intSubset == extSubset)
1057 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001058 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001059 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001060 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001061 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001062 }
Daniel Veillarda9142e72001-06-19 11:07:54 +00001063 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001064 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001065 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001066 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001067 }
1068
1069 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001070 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001071
1072 DICT_FREE(cur->version)
1073 DICT_FREE(cur->name)
1074 DICT_FREE(cur->encoding)
1075 DICT_FREE(cur->URL)
Owen Taylor3473f882001-02-23 17:55:21 +00001076 xmlFree(cur);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001077 if (dict) xmlDictFree(dict);
Owen Taylor3473f882001-02-23 17:55:21 +00001078}
1079
1080/**
1081 * xmlStringLenGetNodeList:
1082 * @doc: the document
1083 * @value: the value of the text
1084 * @len: the length of the string value
1085 *
1086 * Parse the value string and build the node list associated. Should
1087 * produce a flat tree with only TEXTs and ENTITY_REFs.
1088 * Returns a pointer to the first child
1089 */
1090xmlNodePtr
1091xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1092 xmlNodePtr ret = NULL, last = NULL;
1093 xmlNodePtr node;
1094 xmlChar *val;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001095 const xmlChar *cur = value, *end = cur + len;
Owen Taylor3473f882001-02-23 17:55:21 +00001096 const xmlChar *q;
1097 xmlEntityPtr ent;
1098
1099 if (value == NULL) return(NULL);
1100
1101 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001102 while ((cur < end) && (*cur != 0)) {
1103 if (cur[0] == '&') {
1104 int charval = 0;
1105 xmlChar tmp;
1106
Owen Taylor3473f882001-02-23 17:55:21 +00001107 /*
1108 * Save the current text.
1109 */
1110 if (cur != q) {
1111 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1112 xmlNodeAddContentLen(last, q, cur - q);
1113 } else {
1114 node = xmlNewDocTextLen(doc, q, cur - q);
1115 if (node == NULL) return(ret);
1116 if (last == NULL)
1117 last = ret = node;
1118 else {
1119 last->next = node;
1120 node->prev = last;
1121 last = node;
1122 }
1123 }
1124 }
Owen Taylor3473f882001-02-23 17:55:21 +00001125 q = cur;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001126 if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
1127 cur += 3;
1128 if (cur < end)
1129 tmp = *cur;
1130 else
1131 tmp = 0;
1132 while (tmp != ';') { /* Non input consuming loop */
1133 if ((tmp >= '0') && (tmp <= '9'))
1134 charval = charval * 16 + (tmp - '0');
1135 else if ((tmp >= 'a') && (tmp <= 'f'))
1136 charval = charval * 16 + (tmp - 'a') + 10;
1137 else if ((tmp >= 'A') && (tmp <= 'F'))
1138 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001139 else {
Daniel Veillard07cb8222003-09-10 10:51:05 +00001140 xmlGenericError(xmlGenericErrorContext,
1141 "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
1142 charval = 0;
1143 break;
1144 }
1145 cur++;
1146 if (cur < end)
1147 tmp = *cur;
1148 else
1149 tmp = 0;
1150 }
1151 if (tmp == ';')
1152 cur++;
1153 q = cur;
1154 } else if ((cur + 1 < end) && (cur[1] == '#')) {
1155 cur += 2;
1156 if (cur < end)
1157 tmp = *cur;
1158 else
1159 tmp = 0;
1160 while (tmp != ';') { /* Non input consuming loops */
1161 if ((tmp >= '0') && (tmp <= '9'))
1162 charval = charval * 10 + (tmp - '0');
1163 else {
1164 xmlGenericError(xmlGenericErrorContext,
1165 "xmlStringGetNodeList: invalid decimal charvalue\n");
1166 charval = 0;
1167 break;
1168 }
1169 cur++;
1170 if (cur < end)
1171 tmp = *cur;
1172 else
1173 tmp = 0;
1174 }
1175 if (tmp == ';')
1176 cur++;
1177 q = cur;
1178 } else {
1179 /*
1180 * Read the entity string
1181 */
1182 cur++;
1183 q = cur;
1184 while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1185 if ((cur >= end) || (*cur == 0)) {
1186#ifdef DEBUG_TREE
1187 xmlGenericError(xmlGenericErrorContext,
1188 "xmlStringGetNodeList: unterminated entity %30s\n", q);
1189#endif
1190 return(ret);
1191 }
1192 if (cur != q) {
1193 /*
1194 * Predefined entities don't generate nodes
1195 */
1196 val = xmlStrndup(q, cur - q);
1197 ent = xmlGetDocEntity(doc, val);
1198 if ((ent != NULL) &&
1199 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1200 if (last == NULL) {
1201 node = xmlNewDocText(doc, ent->content);
1202 last = ret = node;
1203 } else if (last->type != XML_TEXT_NODE) {
1204 node = xmlNewDocText(doc, ent->content);
1205 last = xmlAddNextSibling(last, node);
1206 } else
1207 xmlNodeAddContent(last, ent->content);
1208
1209 } else {
1210 /*
1211 * Create a new REFERENCE_REF node
1212 */
1213 node = xmlNewReference(doc, val);
1214 if (node == NULL) {
1215 if (val != NULL) xmlFree(val);
1216 return(ret);
1217 }
1218 else if ((ent != NULL) && (ent->children == NULL)) {
1219 xmlNodePtr temp;
1220
1221 ent->children = xmlStringGetNodeList(doc,
1222 (const xmlChar*)node->content);
1223 ent->owner = 1;
1224 temp = ent->children;
1225 while (temp) {
1226 temp->parent = (xmlNodePtr)ent;
1227 temp = temp->next;
1228 }
1229 }
1230 if (last == NULL) {
1231 last = ret = node;
1232 } else {
1233 last = xmlAddNextSibling(last, node);
1234 }
1235 }
1236 xmlFree(val);
1237 }
1238 cur++;
1239 q = cur;
1240 }
1241 if (charval != 0) {
1242 xmlChar buf[10];
1243 int l;
1244
1245 l = xmlCopyCharMultiByte(buf, charval);
1246 buf[l] = 0;
1247 node = xmlNewDocText(doc, buf);
1248 if (node != NULL) {
1249 if (last == NULL) {
1250 last = ret = node;
1251 } else {
1252 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001253 }
1254 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001255 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001256 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001257 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001258 cur++;
1259 }
Daniel Veillard07cb8222003-09-10 10:51:05 +00001260 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001261 /*
1262 * Handle the last piece of text.
1263 */
1264 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1265 xmlNodeAddContentLen(last, q, cur - q);
1266 } else {
1267 node = xmlNewDocTextLen(doc, q, cur - q);
1268 if (node == NULL) return(ret);
Daniel Veillard07cb8222003-09-10 10:51:05 +00001269 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001270 last = ret = node;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001271 } else {
1272 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001273 }
1274 }
1275 }
1276 return(ret);
1277}
1278
1279/**
1280 * xmlStringGetNodeList:
1281 * @doc: the document
1282 * @value: the value of the attribute
1283 *
1284 * Parse the value string and build the node list associated. Should
1285 * produce a flat tree with only TEXTs and ENTITY_REFs.
1286 * Returns a pointer to the first child
1287 */
1288xmlNodePtr
1289xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1290 xmlNodePtr ret = NULL, last = NULL;
1291 xmlNodePtr node;
1292 xmlChar *val;
1293 const xmlChar *cur = value;
1294 const xmlChar *q;
1295 xmlEntityPtr ent;
1296
1297 if (value == NULL) return(NULL);
1298
1299 q = cur;
1300 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001301 if (cur[0] == '&') {
1302 int charval = 0;
1303 xmlChar tmp;
1304
Owen Taylor3473f882001-02-23 17:55:21 +00001305 /*
1306 * Save the current text.
1307 */
1308 if (cur != q) {
1309 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1310 xmlNodeAddContentLen(last, q, cur - q);
1311 } else {
1312 node = xmlNewDocTextLen(doc, q, cur - q);
1313 if (node == NULL) return(ret);
1314 if (last == NULL)
1315 last = ret = node;
1316 else {
1317 last->next = node;
1318 node->prev = last;
1319 last = node;
1320 }
1321 }
1322 }
Owen Taylor3473f882001-02-23 17:55:21 +00001323 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001324 if ((cur[1] == '#') && (cur[2] == 'x')) {
1325 cur += 3;
1326 tmp = *cur;
1327 while (tmp != ';') { /* Non input consuming loop */
1328 if ((tmp >= '0') && (tmp <= '9'))
1329 charval = charval * 16 + (tmp - '0');
1330 else if ((tmp >= 'a') && (tmp <= 'f'))
1331 charval = charval * 16 + (tmp - 'a') + 10;
1332 else if ((tmp >= 'A') && (tmp <= 'F'))
1333 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001334 else {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001335 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001336 "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001337 charval = 0;
1338 break;
1339 }
1340 cur++;
1341 tmp = *cur;
1342 }
1343 if (tmp == ';')
1344 cur++;
1345 q = cur;
1346 } else if (cur[1] == '#') {
1347 cur += 2;
1348 tmp = *cur;
1349 while (tmp != ';') { /* Non input consuming loops */
1350 if ((tmp >= '0') && (tmp <= '9'))
1351 charval = charval * 10 + (tmp - '0');
1352 else {
1353 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001354 "xmlStringGetNodeList: invalid decimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001355 charval = 0;
1356 break;
1357 }
1358 cur++;
1359 tmp = *cur;
1360 }
1361 if (tmp == ';')
1362 cur++;
1363 q = cur;
1364 } else {
1365 /*
1366 * Read the entity string
1367 */
1368 cur++;
1369 q = cur;
1370 while ((*cur != 0) && (*cur != ';')) cur++;
1371 if (*cur == 0) {
1372#ifdef DEBUG_TREE
1373 xmlGenericError(xmlGenericErrorContext,
1374 "xmlStringGetNodeList: unterminated entity %30s\n", q);
1375#endif
1376 return(ret);
1377 }
1378 if (cur != q) {
1379 /*
1380 * Predefined entities don't generate nodes
1381 */
1382 val = xmlStrndup(q, cur - q);
1383 ent = xmlGetDocEntity(doc, val);
1384 if ((ent != NULL) &&
1385 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1386 if (last == NULL) {
1387 node = xmlNewDocText(doc, ent->content);
1388 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001389 } else if (last->type != XML_TEXT_NODE) {
1390 node = xmlNewDocText(doc, ent->content);
1391 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001392 } else
1393 xmlNodeAddContent(last, ent->content);
1394
1395 } else {
1396 /*
1397 * Create a new REFERENCE_REF node
1398 */
1399 node = xmlNewReference(doc, val);
1400 if (node == NULL) {
1401 if (val != NULL) xmlFree(val);
1402 return(ret);
1403 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001404 else if ((ent != NULL) && (ent->children == NULL)) {
1405 xmlNodePtr temp;
1406
1407 ent->children = xmlStringGetNodeList(doc,
1408 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001409 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001410 temp = ent->children;
1411 while (temp) {
1412 temp->parent = (xmlNodePtr)ent;
1413 temp = temp->next;
1414 }
1415 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001416 if (last == NULL) {
1417 last = ret = node;
1418 } else {
1419 last = xmlAddNextSibling(last, node);
1420 }
1421 }
1422 xmlFree(val);
1423 }
1424 cur++;
1425 q = cur;
1426 }
1427 if (charval != 0) {
1428 xmlChar buf[10];
1429 int len;
1430
1431 len = xmlCopyCharMultiByte(buf, charval);
1432 buf[len] = 0;
1433 node = xmlNewDocText(doc, buf);
1434 if (node != NULL) {
1435 if (last == NULL) {
1436 last = ret = node;
1437 } else {
1438 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001439 }
1440 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001441
1442 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001443 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001444 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001445 cur++;
1446 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001447 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001448 /*
1449 * Handle the last piece of text.
1450 */
1451 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1452 xmlNodeAddContentLen(last, q, cur - q);
1453 } else {
1454 node = xmlNewDocTextLen(doc, q, cur - q);
1455 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001456 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001457 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001458 } else {
1459 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001460 }
1461 }
1462 }
1463 return(ret);
1464}
1465
1466/**
1467 * xmlNodeListGetString:
1468 * @doc: the document
1469 * @list: a Node list
1470 * @inLine: should we replace entity contents or show their external form
1471 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001472 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001473 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001474 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001475 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001476 */
1477xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001478xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1479{
Owen Taylor3473f882001-02-23 17:55:21 +00001480 xmlNodePtr node = list;
1481 xmlChar *ret = NULL;
1482 xmlEntityPtr ent;
1483
Daniel Veillard7646b182002-04-20 06:41:40 +00001484 if (list == NULL)
1485 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001486
1487 while (node != NULL) {
1488 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001489 (node->type == XML_CDATA_SECTION_NODE)) {
1490 if (inLine) {
1491 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001492 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001493 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001494
Daniel Veillard7646b182002-04-20 06:41:40 +00001495 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1496 if (buffer != NULL) {
1497 ret = xmlStrcat(ret, buffer);
1498 xmlFree(buffer);
1499 }
1500 }
1501 } else if (node->type == XML_ENTITY_REF_NODE) {
1502 if (inLine) {
1503 ent = xmlGetDocEntity(doc, node->name);
1504 if (ent != NULL) {
1505 xmlChar *buffer;
1506
1507 /* an entity content can be any "well balanced chunk",
1508 * i.e. the result of the content [43] production:
1509 * http://www.w3.org/TR/REC-xml#NT-content.
1510 * So it can contain text, CDATA section or nested
1511 * entity reference nodes (among others).
1512 * -> we recursive call xmlNodeListGetString()
1513 * which handles these types */
1514 buffer = xmlNodeListGetString(doc, ent->children, 1);
1515 if (buffer != NULL) {
1516 ret = xmlStrcat(ret, buffer);
1517 xmlFree(buffer);
1518 }
1519 } else {
1520 ret = xmlStrcat(ret, node->content);
1521 }
1522 } else {
1523 xmlChar buf[2];
1524
1525 buf[0] = '&';
1526 buf[1] = 0;
1527 ret = xmlStrncat(ret, buf, 1);
1528 ret = xmlStrcat(ret, node->name);
1529 buf[0] = ';';
1530 buf[1] = 0;
1531 ret = xmlStrncat(ret, buf, 1);
1532 }
1533 }
1534#if 0
1535 else {
1536 xmlGenericError(xmlGenericErrorContext,
1537 "xmlGetNodeListString : invalid node type %d\n",
1538 node->type);
1539 }
1540#endif
1541 node = node->next;
1542 }
1543 return (ret);
1544}
Owen Taylor3473f882001-02-23 17:55:21 +00001545/**
1546 * xmlNodeListGetRawString:
1547 * @doc: the document
1548 * @list: a Node list
1549 * @inLine: should we replace entity contents or show their external form
1550 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001551 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001552 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1553 * this function doesn't do any character encoding handling.
1554 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001555 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001556 */
1557xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001558xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1559{
Owen Taylor3473f882001-02-23 17:55:21 +00001560 xmlNodePtr node = list;
1561 xmlChar *ret = NULL;
1562 xmlEntityPtr ent;
1563
Daniel Veillard7646b182002-04-20 06:41:40 +00001564 if (list == NULL)
1565 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001566
1567 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001568 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001569 (node->type == XML_CDATA_SECTION_NODE)) {
1570 if (inLine) {
1571 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001572 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001573 xmlChar *buffer;
1574
1575 buffer = xmlEncodeSpecialChars(doc, node->content);
1576 if (buffer != NULL) {
1577 ret = xmlStrcat(ret, buffer);
1578 xmlFree(buffer);
1579 }
1580 }
1581 } else if (node->type == XML_ENTITY_REF_NODE) {
1582 if (inLine) {
1583 ent = xmlGetDocEntity(doc, node->name);
1584 if (ent != NULL) {
1585 xmlChar *buffer;
1586
1587 /* an entity content can be any "well balanced chunk",
1588 * i.e. the result of the content [43] production:
1589 * http://www.w3.org/TR/REC-xml#NT-content.
1590 * So it can contain text, CDATA section or nested
1591 * entity reference nodes (among others).
1592 * -> we recursive call xmlNodeListGetRawString()
1593 * which handles these types */
1594 buffer =
1595 xmlNodeListGetRawString(doc, ent->children, 1);
1596 if (buffer != NULL) {
1597 ret = xmlStrcat(ret, buffer);
1598 xmlFree(buffer);
1599 }
1600 } else {
1601 ret = xmlStrcat(ret, node->content);
1602 }
1603 } else {
1604 xmlChar buf[2];
1605
1606 buf[0] = '&';
1607 buf[1] = 0;
1608 ret = xmlStrncat(ret, buf, 1);
1609 ret = xmlStrcat(ret, node->name);
1610 buf[0] = ';';
1611 buf[1] = 0;
1612 ret = xmlStrncat(ret, buf, 1);
1613 }
1614 }
Owen Taylor3473f882001-02-23 17:55:21 +00001615#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001616 else {
1617 xmlGenericError(xmlGenericErrorContext,
1618 "xmlGetNodeListString : invalid node type %d\n",
1619 node->type);
1620 }
Owen Taylor3473f882001-02-23 17:55:21 +00001621#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001622 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001623 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001624 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001625}
1626
1627/**
1628 * xmlNewProp:
1629 * @node: the holding node
1630 * @name: the name of the attribute
1631 * @value: the value of the attribute
1632 *
1633 * Create a new property carried by a node.
1634 * Returns a pointer to the attribute
1635 */
1636xmlAttrPtr
1637xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1638 xmlAttrPtr cur;
1639 xmlDocPtr doc = NULL;
1640
1641 if (name == NULL) {
1642#ifdef DEBUG_TREE
1643 xmlGenericError(xmlGenericErrorContext,
1644 "xmlNewProp : name == NULL\n");
1645#endif
1646 return(NULL);
1647 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00001648 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
1649 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001650
1651 /*
1652 * Allocate a new property and fill the fields.
1653 */
1654 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1655 if (cur == NULL) {
1656 xmlGenericError(xmlGenericErrorContext,
1657 "xmlNewProp : malloc failed\n");
1658 return(NULL);
1659 }
1660 memset(cur, 0, sizeof(xmlAttr));
1661 cur->type = XML_ATTRIBUTE_NODE;
1662
1663 cur->parent = node;
1664 if (node != NULL) {
1665 doc = node->doc;
1666 cur->doc = doc;
1667 }
1668 cur->name = xmlStrdup(name);
1669 if (value != NULL) {
1670 xmlChar *buffer;
1671 xmlNodePtr tmp;
1672
1673 buffer = xmlEncodeEntitiesReentrant(doc, value);
1674 cur->children = xmlStringGetNodeList(doc, buffer);
1675 cur->last = NULL;
1676 tmp = cur->children;
1677 while (tmp != NULL) {
1678 tmp->parent = (xmlNodePtr) cur;
1679 tmp->doc = doc;
1680 if (tmp->next == NULL)
1681 cur->last = tmp;
1682 tmp = tmp->next;
1683 }
1684 xmlFree(buffer);
1685 }
1686
1687 /*
1688 * Add it at the end to preserve parsing order ...
1689 */
1690 if (node != NULL) {
1691 if (node->properties == NULL) {
1692 node->properties = cur;
1693 } else {
1694 xmlAttrPtr prev = node->properties;
1695
1696 while (prev->next != NULL) prev = prev->next;
1697 prev->next = cur;
1698 cur->prev = prev;
1699 }
1700 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001701
Daniel Veillarda880b122003-04-21 21:36:41 +00001702 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001703 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001704 return(cur);
1705}
1706
1707/**
1708 * xmlNewNsProp:
1709 * @node: the holding node
1710 * @ns: the namespace
1711 * @name: the name of the attribute
1712 * @value: the value of the attribute
1713 *
1714 * Create a new property tagged with a namespace and carried by a node.
1715 * Returns a pointer to the attribute
1716 */
1717xmlAttrPtr
1718xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1719 const xmlChar *value) {
1720 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001721 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001722
1723 if (name == NULL) {
1724#ifdef DEBUG_TREE
1725 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001726 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001727#endif
1728 return(NULL);
1729 }
1730
1731 /*
1732 * Allocate a new property and fill the fields.
1733 */
1734 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1735 if (cur == NULL) {
1736 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001737 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001738 return(NULL);
1739 }
1740 memset(cur, 0, sizeof(xmlAttr));
1741 cur->type = XML_ATTRIBUTE_NODE;
1742
1743 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001744 if (node != NULL) {
1745 doc = node->doc;
1746 cur->doc = doc;
1747 }
Owen Taylor3473f882001-02-23 17:55:21 +00001748 cur->ns = ns;
1749 cur->name = xmlStrdup(name);
1750 if (value != NULL) {
1751 xmlChar *buffer;
1752 xmlNodePtr tmp;
1753
Daniel Veillarda682b212001-06-07 19:59:42 +00001754 buffer = xmlEncodeEntitiesReentrant(doc, value);
1755 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001756 cur->last = NULL;
1757 tmp = cur->children;
1758 while (tmp != NULL) {
1759 tmp->parent = (xmlNodePtr) cur;
1760 if (tmp->next == NULL)
1761 cur->last = tmp;
1762 tmp = tmp->next;
1763 }
1764 xmlFree(buffer);
1765 }
1766
1767 /*
1768 * Add it at the end to preserve parsing order ...
1769 */
1770 if (node != NULL) {
1771 if (node->properties == NULL) {
1772 node->properties = cur;
1773 } else {
1774 xmlAttrPtr prev = node->properties;
1775
1776 while (prev->next != NULL) prev = prev->next;
1777 prev->next = cur;
1778 cur->prev = prev;
1779 }
1780 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001781
Daniel Veillarda880b122003-04-21 21:36:41 +00001782 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001783 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001784 return(cur);
1785}
1786
1787/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001788 * xmlNewNsPropEatName:
1789 * @node: the holding node
1790 * @ns: the namespace
1791 * @name: the name of the attribute
1792 * @value: the value of the attribute
1793 *
1794 * Create a new property tagged with a namespace and carried by a node.
1795 * Returns a pointer to the attribute
1796 */
1797xmlAttrPtr
1798xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1799 const xmlChar *value) {
1800 xmlAttrPtr cur;
1801 xmlDocPtr doc = NULL;
1802
1803 if (name == NULL) {
1804#ifdef DEBUG_TREE
1805 xmlGenericError(xmlGenericErrorContext,
1806 "xmlNewNsPropEatName : name == NULL\n");
1807#endif
1808 return(NULL);
1809 }
1810
1811 /*
1812 * Allocate a new property and fill the fields.
1813 */
1814 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1815 if (cur == NULL) {
1816 xmlGenericError(xmlGenericErrorContext,
1817 "xmlNewNsPropEatName : malloc failed\n");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001818 xmlFree(name);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001819 return(NULL);
1820 }
1821 memset(cur, 0, sizeof(xmlAttr));
1822 cur->type = XML_ATTRIBUTE_NODE;
1823
1824 cur->parent = node;
1825 if (node != NULL) {
1826 doc = node->doc;
1827 cur->doc = doc;
1828 }
1829 cur->ns = ns;
1830 cur->name = name;
1831 if (value != NULL) {
1832 xmlChar *buffer;
1833 xmlNodePtr tmp;
1834
1835 buffer = xmlEncodeEntitiesReentrant(doc, value);
1836 cur->children = xmlStringGetNodeList(doc, buffer);
1837 cur->last = NULL;
1838 tmp = cur->children;
1839 while (tmp != NULL) {
1840 tmp->parent = (xmlNodePtr) cur;
1841 if (tmp->next == NULL)
1842 cur->last = tmp;
1843 tmp = tmp->next;
1844 }
1845 xmlFree(buffer);
1846 }
1847
1848 /*
1849 * Add it at the end to preserve parsing order ...
1850 */
1851 if (node != NULL) {
1852 if (node->properties == NULL) {
1853 node->properties = cur;
1854 } else {
1855 xmlAttrPtr prev = node->properties;
1856
1857 while (prev->next != NULL) prev = prev->next;
1858 prev->next = cur;
1859 cur->prev = prev;
1860 }
1861 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001862
Daniel Veillarda880b122003-04-21 21:36:41 +00001863 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001864 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001865 return(cur);
1866}
1867
1868/**
Owen Taylor3473f882001-02-23 17:55:21 +00001869 * xmlNewDocProp:
1870 * @doc: the document
1871 * @name: the name of the attribute
1872 * @value: the value of the attribute
1873 *
1874 * Create a new property carried by a document.
1875 * Returns a pointer to the attribute
1876 */
1877xmlAttrPtr
1878xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1879 xmlAttrPtr cur;
1880
1881 if (name == NULL) {
1882#ifdef DEBUG_TREE
1883 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001884 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001885#endif
1886 return(NULL);
1887 }
1888
1889 /*
1890 * Allocate a new property and fill the fields.
1891 */
1892 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1893 if (cur == NULL) {
1894 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001895 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001896 return(NULL);
1897 }
1898 memset(cur, 0, sizeof(xmlAttr));
1899 cur->type = XML_ATTRIBUTE_NODE;
1900
1901 cur->name = xmlStrdup(name);
1902 cur->doc = doc;
1903 if (value != NULL) {
1904 xmlNodePtr tmp;
1905
1906 cur->children = xmlStringGetNodeList(doc, value);
1907 cur->last = NULL;
1908
1909 tmp = cur->children;
1910 while (tmp != NULL) {
1911 tmp->parent = (xmlNodePtr) cur;
1912 if (tmp->next == NULL)
1913 cur->last = tmp;
1914 tmp = tmp->next;
1915 }
1916 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001917
Daniel Veillarda880b122003-04-21 21:36:41 +00001918 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001919 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001920 return(cur);
1921}
1922
1923/**
1924 * xmlFreePropList:
1925 * @cur: the first property in the list
1926 *
1927 * Free a property and all its siblings, all the children are freed too.
1928 */
1929void
1930xmlFreePropList(xmlAttrPtr cur) {
1931 xmlAttrPtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001932 if (cur == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001933 while (cur != NULL) {
1934 next = cur->next;
1935 xmlFreeProp(cur);
1936 cur = next;
1937 }
1938}
1939
1940/**
1941 * xmlFreeProp:
1942 * @cur: an attribute
1943 *
1944 * Free one attribute, all the content is freed too
1945 */
1946void
1947xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001948 xmlDictPtr dict = NULL;
1949 if (cur == NULL) return;
1950
1951 if (cur->doc != NULL) dict = cur->doc->dict;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001952
Daniel Veillarda880b122003-04-21 21:36:41 +00001953 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001954 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1955
Owen Taylor3473f882001-02-23 17:55:21 +00001956 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001957 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1958 ((cur->parent->doc->intSubset != NULL) ||
1959 (cur->parent->doc->extSubset != NULL))) {
1960 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1961 xmlRemoveID(cur->parent->doc, cur);
1962 }
Owen Taylor3473f882001-02-23 17:55:21 +00001963 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001964 DICT_FREE(cur->name)
Owen Taylor3473f882001-02-23 17:55:21 +00001965 xmlFree(cur);
1966}
1967
1968/**
1969 * xmlRemoveProp:
1970 * @cur: an attribute
1971 *
1972 * Unlink and free one attribute, all the content is freed too
1973 * Note this doesn't work for namespace definition attributes
1974 *
1975 * Returns 0 if success and -1 in case of error.
1976 */
1977int
1978xmlRemoveProp(xmlAttrPtr cur) {
1979 xmlAttrPtr tmp;
1980 if (cur == NULL) {
1981#ifdef DEBUG_TREE
1982 xmlGenericError(xmlGenericErrorContext,
1983 "xmlRemoveProp : cur == NULL\n");
1984#endif
1985 return(-1);
1986 }
1987 if (cur->parent == NULL) {
1988#ifdef DEBUG_TREE
1989 xmlGenericError(xmlGenericErrorContext,
1990 "xmlRemoveProp : cur->parent == NULL\n");
1991#endif
1992 return(-1);
1993 }
1994 tmp = cur->parent->properties;
1995 if (tmp == cur) {
1996 cur->parent->properties = cur->next;
1997 xmlFreeProp(cur);
1998 return(0);
1999 }
2000 while (tmp != NULL) {
2001 if (tmp->next == cur) {
2002 tmp->next = cur->next;
2003 if (tmp->next != NULL)
2004 tmp->next->prev = tmp;
2005 xmlFreeProp(cur);
2006 return(0);
2007 }
2008 tmp = tmp->next;
2009 }
2010#ifdef DEBUG_TREE
2011 xmlGenericError(xmlGenericErrorContext,
2012 "xmlRemoveProp : attribute not owned by its node\n");
2013#endif
2014 return(-1);
2015}
2016
2017/**
2018 * xmlNewPI:
2019 * @name: the processing instruction name
2020 * @content: the PI content
2021 *
2022 * Creation of a processing instruction element.
2023 * Returns a pointer to the new node object.
2024 */
2025xmlNodePtr
2026xmlNewPI(const xmlChar *name, const xmlChar *content) {
2027 xmlNodePtr cur;
2028
2029 if (name == NULL) {
2030#ifdef DEBUG_TREE
2031 xmlGenericError(xmlGenericErrorContext,
2032 "xmlNewPI : name == NULL\n");
2033#endif
2034 return(NULL);
2035 }
2036
2037 /*
2038 * Allocate a new node and fill the fields.
2039 */
2040 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2041 if (cur == NULL) {
2042 xmlGenericError(xmlGenericErrorContext,
2043 "xmlNewPI : malloc failed\n");
2044 return(NULL);
2045 }
2046 memset(cur, 0, sizeof(xmlNode));
2047 cur->type = XML_PI_NODE;
2048
2049 cur->name = xmlStrdup(name);
2050 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002051 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002052 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002053
Daniel Veillarda880b122003-04-21 21:36:41 +00002054 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002055 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002056 return(cur);
2057}
2058
2059/**
2060 * xmlNewNode:
2061 * @ns: namespace if any
2062 * @name: the node name
2063 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002064 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002065 *
2066 * Returns a pointer to the new node object.
2067 */
2068xmlNodePtr
2069xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2070 xmlNodePtr cur;
2071
2072 if (name == NULL) {
2073#ifdef DEBUG_TREE
2074 xmlGenericError(xmlGenericErrorContext,
2075 "xmlNewNode : name == NULL\n");
2076#endif
2077 return(NULL);
2078 }
2079
2080 /*
2081 * Allocate a new node and fill the fields.
2082 */
2083 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2084 if (cur == NULL) {
2085 xmlGenericError(xmlGenericErrorContext,
2086 "xmlNewNode : malloc failed\n");
2087 return(NULL);
2088 }
2089 memset(cur, 0, sizeof(xmlNode));
2090 cur->type = XML_ELEMENT_NODE;
2091
2092 cur->name = xmlStrdup(name);
2093 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002094
Daniel Veillarda880b122003-04-21 21:36:41 +00002095 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002096 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002097 return(cur);
2098}
2099
2100/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00002101 * xmlNewNodeEatName:
2102 * @ns: namespace if any
2103 * @name: the node name
2104 *
2105 * Creation of a new node element. @ns is optional (NULL).
2106 *
2107 * Returns a pointer to the new node object.
2108 */
2109xmlNodePtr
2110xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2111 xmlNodePtr cur;
2112
2113 if (name == NULL) {
2114#ifdef DEBUG_TREE
2115 xmlGenericError(xmlGenericErrorContext,
2116 "xmlNewNode : name == NULL\n");
2117#endif
2118 return(NULL);
2119 }
2120
2121 /*
2122 * Allocate a new node and fill the fields.
2123 */
2124 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2125 if (cur == NULL) {
2126 xmlGenericError(xmlGenericErrorContext,
2127 "xmlNewNode : malloc failed\n");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00002128 xmlFree(name);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002129 return(NULL);
2130 }
2131 memset(cur, 0, sizeof(xmlNode));
2132 cur->type = XML_ELEMENT_NODE;
2133
2134 cur->name = name;
2135 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002136
Daniel Veillarda880b122003-04-21 21:36:41 +00002137 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002138 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002139 return(cur);
2140}
2141
2142/**
Owen Taylor3473f882001-02-23 17:55:21 +00002143 * xmlNewDocNode:
2144 * @doc: the document
2145 * @ns: namespace if any
2146 * @name: the node name
2147 * @content: the XML text content if any
2148 *
2149 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002150 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002151 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2152 * references, but XML special chars need to be escaped first by using
2153 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2154 * need entities support.
2155 *
2156 * Returns a pointer to the new node object.
2157 */
2158xmlNodePtr
2159xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2160 const xmlChar *name, const xmlChar *content) {
2161 xmlNodePtr cur;
2162
2163 cur = xmlNewNode(ns, name);
2164 if (cur != NULL) {
2165 cur->doc = doc;
2166 if (content != NULL) {
2167 cur->children = xmlStringGetNodeList(doc, content);
2168 UPDATE_LAST_CHILD_AND_PARENT(cur)
2169 }
2170 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002171
Owen Taylor3473f882001-02-23 17:55:21 +00002172 return(cur);
2173}
2174
Daniel Veillard46de64e2002-05-29 08:21:33 +00002175/**
2176 * xmlNewDocNodeEatName:
2177 * @doc: the document
2178 * @ns: namespace if any
2179 * @name: the node name
2180 * @content: the XML text content if any
2181 *
2182 * Creation of a new node element within a document. @ns and @content
2183 * are optional (NULL).
2184 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2185 * references, but XML special chars need to be escaped first by using
2186 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2187 * need entities support.
2188 *
2189 * Returns a pointer to the new node object.
2190 */
2191xmlNodePtr
2192xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2193 xmlChar *name, const xmlChar *content) {
2194 xmlNodePtr cur;
2195
2196 cur = xmlNewNodeEatName(ns, name);
2197 if (cur != NULL) {
2198 cur->doc = doc;
2199 if (content != NULL) {
2200 cur->children = xmlStringGetNodeList(doc, content);
2201 UPDATE_LAST_CHILD_AND_PARENT(cur)
2202 }
2203 }
2204 return(cur);
2205}
2206
Owen Taylor3473f882001-02-23 17:55:21 +00002207
2208/**
2209 * xmlNewDocRawNode:
2210 * @doc: the document
2211 * @ns: namespace if any
2212 * @name: the node name
2213 * @content: the text content if any
2214 *
2215 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002216 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002217 *
2218 * Returns a pointer to the new node object.
2219 */
2220xmlNodePtr
2221xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2222 const xmlChar *name, const xmlChar *content) {
2223 xmlNodePtr cur;
2224
2225 cur = xmlNewNode(ns, name);
2226 if (cur != NULL) {
2227 cur->doc = doc;
2228 if (content != NULL) {
2229 cur->children = xmlNewDocText(doc, content);
2230 UPDATE_LAST_CHILD_AND_PARENT(cur)
2231 }
2232 }
2233 return(cur);
2234}
2235
2236/**
2237 * xmlNewDocFragment:
2238 * @doc: the document owning the fragment
2239 *
2240 * Creation of a new Fragment node.
2241 * Returns a pointer to the new node object.
2242 */
2243xmlNodePtr
2244xmlNewDocFragment(xmlDocPtr doc) {
2245 xmlNodePtr cur;
2246
2247 /*
2248 * Allocate a new DocumentFragment node and fill the fields.
2249 */
2250 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2251 if (cur == NULL) {
2252 xmlGenericError(xmlGenericErrorContext,
2253 "xmlNewDocFragment : malloc failed\n");
2254 return(NULL);
2255 }
2256 memset(cur, 0, sizeof(xmlNode));
2257 cur->type = XML_DOCUMENT_FRAG_NODE;
2258
2259 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002260
Daniel Veillarda880b122003-04-21 21:36:41 +00002261 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002262 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002263 return(cur);
2264}
2265
2266/**
2267 * xmlNewText:
2268 * @content: the text content
2269 *
2270 * Creation of a new text node.
2271 * Returns a pointer to the new node object.
2272 */
2273xmlNodePtr
2274xmlNewText(const xmlChar *content) {
2275 xmlNodePtr cur;
2276
2277 /*
2278 * Allocate a new node and fill the fields.
2279 */
2280 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2281 if (cur == NULL) {
2282 xmlGenericError(xmlGenericErrorContext,
2283 "xmlNewText : malloc failed\n");
2284 return(NULL);
2285 }
2286 memset(cur, 0, sizeof(xmlNode));
2287 cur->type = XML_TEXT_NODE;
2288
2289 cur->name = xmlStringText;
2290 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002291 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002292 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002293
Daniel Veillarda880b122003-04-21 21:36:41 +00002294 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002295 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002296 return(cur);
2297}
2298
2299/**
2300 * xmlNewTextChild:
2301 * @parent: the parent node
2302 * @ns: a namespace if any
2303 * @name: the name of the child
2304 * @content: the text content of the child if any.
2305 *
2306 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002307 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002308 * a child TEXT node will be created containing the string content.
2309 *
2310 * Returns a pointer to the new node object.
2311 */
2312xmlNodePtr
2313xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2314 const xmlChar *name, const xmlChar *content) {
2315 xmlNodePtr cur, prev;
2316
2317 if (parent == NULL) {
2318#ifdef DEBUG_TREE
2319 xmlGenericError(xmlGenericErrorContext,
2320 "xmlNewTextChild : parent == NULL\n");
2321#endif
2322 return(NULL);
2323 }
2324
2325 if (name == NULL) {
2326#ifdef DEBUG_TREE
2327 xmlGenericError(xmlGenericErrorContext,
2328 "xmlNewTextChild : name == NULL\n");
2329#endif
2330 return(NULL);
2331 }
2332
2333 /*
2334 * Allocate a new node
2335 */
2336 if (ns == NULL)
2337 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2338 else
2339 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2340 if (cur == NULL) return(NULL);
2341
2342 /*
2343 * add the new element at the end of the children list.
2344 */
2345 cur->type = XML_ELEMENT_NODE;
2346 cur->parent = parent;
2347 cur->doc = parent->doc;
2348 if (parent->children == NULL) {
2349 parent->children = cur;
2350 parent->last = cur;
2351 } else {
2352 prev = parent->last;
2353 prev->next = cur;
2354 cur->prev = prev;
2355 parent->last = cur;
2356 }
2357
2358 return(cur);
2359}
2360
2361/**
2362 * xmlNewCharRef:
2363 * @doc: the document
2364 * @name: the char ref string, starting with # or "&# ... ;"
2365 *
2366 * Creation of a new character reference node.
2367 * Returns a pointer to the new node object.
2368 */
2369xmlNodePtr
2370xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2371 xmlNodePtr cur;
2372
2373 /*
2374 * Allocate a new node and fill the fields.
2375 */
2376 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2377 if (cur == NULL) {
2378 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002379 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002380 return(NULL);
2381 }
2382 memset(cur, 0, sizeof(xmlNode));
2383 cur->type = XML_ENTITY_REF_NODE;
2384
2385 cur->doc = doc;
2386 if (name[0] == '&') {
2387 int len;
2388 name++;
2389 len = xmlStrlen(name);
2390 if (name[len - 1] == ';')
2391 cur->name = xmlStrndup(name, len - 1);
2392 else
2393 cur->name = xmlStrndup(name, len);
2394 } else
2395 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002396
Daniel Veillarda880b122003-04-21 21:36:41 +00002397 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002398 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002399 return(cur);
2400}
2401
2402/**
2403 * xmlNewReference:
2404 * @doc: the document
2405 * @name: the reference name, or the reference string with & and ;
2406 *
2407 * Creation of a new reference node.
2408 * Returns a pointer to the new node object.
2409 */
2410xmlNodePtr
2411xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2412 xmlNodePtr cur;
2413 xmlEntityPtr ent;
2414
2415 /*
2416 * Allocate a new node and fill the fields.
2417 */
2418 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2419 if (cur == NULL) {
2420 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002421 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002422 return(NULL);
2423 }
2424 memset(cur, 0, sizeof(xmlNode));
2425 cur->type = XML_ENTITY_REF_NODE;
2426
2427 cur->doc = doc;
2428 if (name[0] == '&') {
2429 int len;
2430 name++;
2431 len = xmlStrlen(name);
2432 if (name[len - 1] == ';')
2433 cur->name = xmlStrndup(name, len - 1);
2434 else
2435 cur->name = xmlStrndup(name, len);
2436 } else
2437 cur->name = xmlStrdup(name);
2438
2439 ent = xmlGetDocEntity(doc, cur->name);
2440 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002441 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002442 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002443 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002444 * updated. Not sure if this is 100% correct.
2445 * -George
2446 */
2447 cur->children = (xmlNodePtr) ent;
2448 cur->last = (xmlNodePtr) ent;
2449 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002450
Daniel Veillarda880b122003-04-21 21:36:41 +00002451 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002452 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002453 return(cur);
2454}
2455
2456/**
2457 * xmlNewDocText:
2458 * @doc: the document
2459 * @content: the text content
2460 *
2461 * Creation of a new text node within a document.
2462 * Returns a pointer to the new node object.
2463 */
2464xmlNodePtr
2465xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2466 xmlNodePtr cur;
2467
2468 cur = xmlNewText(content);
2469 if (cur != NULL) cur->doc = doc;
2470 return(cur);
2471}
2472
2473/**
2474 * xmlNewTextLen:
2475 * @content: the text content
2476 * @len: the text len.
2477 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002478 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002479 * Returns a pointer to the new node object.
2480 */
2481xmlNodePtr
2482xmlNewTextLen(const xmlChar *content, int len) {
2483 xmlNodePtr cur;
2484
2485 /*
2486 * Allocate a new node and fill the fields.
2487 */
2488 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2489 if (cur == NULL) {
2490 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002491 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002492 return(NULL);
2493 }
2494 memset(cur, 0, sizeof(xmlNode));
2495 cur->type = XML_TEXT_NODE;
2496
2497 cur->name = xmlStringText;
2498 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002499 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002500 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002501
Daniel Veillarda880b122003-04-21 21:36:41 +00002502 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002503 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002504 return(cur);
2505}
2506
2507/**
2508 * xmlNewDocTextLen:
2509 * @doc: the document
2510 * @content: the text content
2511 * @len: the text len.
2512 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002513 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002514 * text node pertain to a given document.
2515 * Returns a pointer to the new node object.
2516 */
2517xmlNodePtr
2518xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2519 xmlNodePtr cur;
2520
2521 cur = xmlNewTextLen(content, len);
2522 if (cur != NULL) cur->doc = doc;
2523 return(cur);
2524}
2525
2526/**
2527 * xmlNewComment:
2528 * @content: the comment content
2529 *
2530 * Creation of a new node containing a comment.
2531 * Returns a pointer to the new node object.
2532 */
2533xmlNodePtr
2534xmlNewComment(const xmlChar *content) {
2535 xmlNodePtr cur;
2536
2537 /*
2538 * Allocate a new node and fill the fields.
2539 */
2540 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2541 if (cur == NULL) {
2542 xmlGenericError(xmlGenericErrorContext,
2543 "xmlNewComment : malloc failed\n");
2544 return(NULL);
2545 }
2546 memset(cur, 0, sizeof(xmlNode));
2547 cur->type = XML_COMMENT_NODE;
2548
2549 cur->name = xmlStringComment;
2550 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002551 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002552 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002553
Daniel Veillarda880b122003-04-21 21:36:41 +00002554 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002555 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002556 return(cur);
2557}
2558
2559/**
2560 * xmlNewCDataBlock:
2561 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002562 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002563 * @len: the length of the block
2564 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002565 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002566 * Returns a pointer to the new node object.
2567 */
2568xmlNodePtr
2569xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2570 xmlNodePtr cur;
2571
2572 /*
2573 * Allocate a new node and fill the fields.
2574 */
2575 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2576 if (cur == NULL) {
2577 xmlGenericError(xmlGenericErrorContext,
2578 "xmlNewCDataBlock : malloc failed\n");
2579 return(NULL);
2580 }
2581 memset(cur, 0, sizeof(xmlNode));
2582 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002583 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002584
2585 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002586 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002587 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002588
Daniel Veillarda880b122003-04-21 21:36:41 +00002589 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002590 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002591 return(cur);
2592}
2593
2594/**
2595 * xmlNewDocComment:
2596 * @doc: the document
2597 * @content: the comment content
2598 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002599 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002600 * Returns a pointer to the new node object.
2601 */
2602xmlNodePtr
2603xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2604 xmlNodePtr cur;
2605
2606 cur = xmlNewComment(content);
2607 if (cur != NULL) cur->doc = doc;
2608 return(cur);
2609}
2610
2611/**
2612 * xmlSetTreeDoc:
2613 * @tree: the top element
2614 * @doc: the document
2615 *
2616 * update all nodes under the tree to point to the right document
2617 */
2618void
2619xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002620 xmlAttrPtr prop;
2621
Owen Taylor3473f882001-02-23 17:55:21 +00002622 if (tree == NULL)
2623 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002624 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002625 if(tree->type == XML_ELEMENT_NODE) {
2626 prop = tree->properties;
2627 while (prop != NULL) {
2628 prop->doc = doc;
2629 xmlSetListDoc(prop->children, doc);
2630 prop = prop->next;
2631 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002632 }
Owen Taylor3473f882001-02-23 17:55:21 +00002633 if (tree->children != NULL)
2634 xmlSetListDoc(tree->children, doc);
2635 tree->doc = doc;
2636 }
2637}
2638
2639/**
2640 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002641 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002642 * @doc: the document
2643 *
2644 * update all nodes in the list to point to the right document
2645 */
2646void
2647xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2648 xmlNodePtr cur;
2649
2650 if (list == NULL)
2651 return;
2652 cur = list;
2653 while (cur != NULL) {
2654 if (cur->doc != doc)
2655 xmlSetTreeDoc(cur, doc);
2656 cur = cur->next;
2657 }
2658}
2659
2660
2661/**
2662 * xmlNewChild:
2663 * @parent: the parent node
2664 * @ns: a namespace if any
2665 * @name: the name of the child
2666 * @content: the XML content of the child if any.
2667 *
2668 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002669 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002670 * a child list containing the TEXTs and ENTITY_REFs node will be created.
2671 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2672 * references, but XML special chars need to be escaped first by using
2673 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
2674 * support is not needed.
2675 *
2676 * Returns a pointer to the new node object.
2677 */
2678xmlNodePtr
2679xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2680 const xmlChar *name, const xmlChar *content) {
2681 xmlNodePtr cur, prev;
2682
2683 if (parent == NULL) {
2684#ifdef DEBUG_TREE
2685 xmlGenericError(xmlGenericErrorContext,
2686 "xmlNewChild : parent == NULL\n");
2687#endif
2688 return(NULL);
2689 }
2690
2691 if (name == NULL) {
2692#ifdef DEBUG_TREE
2693 xmlGenericError(xmlGenericErrorContext,
2694 "xmlNewChild : name == NULL\n");
2695#endif
2696 return(NULL);
2697 }
2698
2699 /*
2700 * Allocate a new node
2701 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002702 if (parent->type == XML_ELEMENT_NODE) {
2703 if (ns == NULL)
2704 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2705 else
2706 cur = xmlNewDocNode(parent->doc, ns, name, content);
2707 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2708 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2709 if (ns == NULL)
2710 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2711 else
2712 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002713 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2714 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002715 } else {
2716 return(NULL);
2717 }
Owen Taylor3473f882001-02-23 17:55:21 +00002718 if (cur == NULL) return(NULL);
2719
2720 /*
2721 * add the new element at the end of the children list.
2722 */
2723 cur->type = XML_ELEMENT_NODE;
2724 cur->parent = parent;
2725 cur->doc = parent->doc;
2726 if (parent->children == NULL) {
2727 parent->children = cur;
2728 parent->last = cur;
2729 } else {
2730 prev = parent->last;
2731 prev->next = cur;
2732 cur->prev = prev;
2733 parent->last = cur;
2734 }
2735
2736 return(cur);
2737}
2738
2739/**
2740 * xmlAddNextSibling:
2741 * @cur: the child node
2742 * @elem: the new node
2743 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002744 * Add a new node @elem as the next sibling of @cur
2745 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002746 * first unlinked from its existing context.
2747 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002748 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2749 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002750 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002751 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002752 */
2753xmlNodePtr
2754xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2755 if (cur == NULL) {
2756#ifdef DEBUG_TREE
2757 xmlGenericError(xmlGenericErrorContext,
2758 "xmlAddNextSibling : cur == NULL\n");
2759#endif
2760 return(NULL);
2761 }
2762 if (elem == NULL) {
2763#ifdef DEBUG_TREE
2764 xmlGenericError(xmlGenericErrorContext,
2765 "xmlAddNextSibling : elem == NULL\n");
2766#endif
2767 return(NULL);
2768 }
2769
2770 xmlUnlinkNode(elem);
2771
2772 if (elem->type == XML_TEXT_NODE) {
2773 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002774 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002775 xmlFreeNode(elem);
2776 return(cur);
2777 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002778 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2779 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002780 xmlChar *tmp;
2781
2782 tmp = xmlStrdup(elem->content);
2783 tmp = xmlStrcat(tmp, cur->next->content);
2784 xmlNodeSetContent(cur->next, tmp);
2785 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002786 xmlFreeNode(elem);
2787 return(cur->next);
2788 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002789 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2790 /* check if an attribute with the same name exists */
2791 xmlAttrPtr attr;
2792
2793 if (elem->ns == NULL)
2794 attr = xmlHasProp(cur->parent, elem->name);
2795 else
2796 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2797 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2798 /* different instance, destroy it (attributes must be unique) */
2799 xmlFreeProp(attr);
2800 }
Owen Taylor3473f882001-02-23 17:55:21 +00002801 }
2802
2803 if (elem->doc != cur->doc) {
2804 xmlSetTreeDoc(elem, cur->doc);
2805 }
2806 elem->parent = cur->parent;
2807 elem->prev = cur;
2808 elem->next = cur->next;
2809 cur->next = elem;
2810 if (elem->next != NULL)
2811 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002812 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002813 elem->parent->last = elem;
2814 return(elem);
2815}
2816
2817/**
2818 * xmlAddPrevSibling:
2819 * @cur: the child node
2820 * @elem: the new node
2821 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002822 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002823 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002824 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002825 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002826 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2827 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002828 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002829 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002830 */
2831xmlNodePtr
2832xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2833 if (cur == NULL) {
2834#ifdef DEBUG_TREE
2835 xmlGenericError(xmlGenericErrorContext,
2836 "xmlAddPrevSibling : cur == NULL\n");
2837#endif
2838 return(NULL);
2839 }
2840 if (elem == NULL) {
2841#ifdef DEBUG_TREE
2842 xmlGenericError(xmlGenericErrorContext,
2843 "xmlAddPrevSibling : elem == NULL\n");
2844#endif
2845 return(NULL);
2846 }
2847
2848 xmlUnlinkNode(elem);
2849
2850 if (elem->type == XML_TEXT_NODE) {
2851 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002852 xmlChar *tmp;
2853
2854 tmp = xmlStrdup(elem->content);
2855 tmp = xmlStrcat(tmp, cur->content);
2856 xmlNodeSetContent(cur, tmp);
2857 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002858 xmlFreeNode(elem);
2859 return(cur);
2860 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002861 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2862 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002863 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002864 xmlFreeNode(elem);
2865 return(cur->prev);
2866 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002867 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2868 /* check if an attribute with the same name exists */
2869 xmlAttrPtr attr;
2870
2871 if (elem->ns == NULL)
2872 attr = xmlHasProp(cur->parent, elem->name);
2873 else
2874 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2875 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2876 /* different instance, destroy it (attributes must be unique) */
2877 xmlFreeProp(attr);
2878 }
Owen Taylor3473f882001-02-23 17:55:21 +00002879 }
2880
2881 if (elem->doc != cur->doc) {
2882 xmlSetTreeDoc(elem, cur->doc);
2883 }
2884 elem->parent = cur->parent;
2885 elem->next = cur;
2886 elem->prev = cur->prev;
2887 cur->prev = elem;
2888 if (elem->prev != NULL)
2889 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002890 if (elem->parent != NULL) {
2891 if (elem->type == XML_ATTRIBUTE_NODE) {
2892 if (elem->parent->properties == (xmlAttrPtr) cur) {
2893 elem->parent->properties = (xmlAttrPtr) elem;
2894 }
2895 } else {
2896 if (elem->parent->children == cur) {
2897 elem->parent->children = elem;
2898 }
2899 }
2900 }
Owen Taylor3473f882001-02-23 17:55:21 +00002901 return(elem);
2902}
2903
2904/**
2905 * xmlAddSibling:
2906 * @cur: the child node
2907 * @elem: the new node
2908 *
2909 * Add a new element @elem to the list of siblings of @cur
2910 * merging adjacent TEXT nodes (@elem may be freed)
2911 * If the new element was already inserted in a document it is
2912 * first unlinked from its existing context.
2913 *
2914 * Returns the new element or NULL in case of error.
2915 */
2916xmlNodePtr
2917xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2918 xmlNodePtr parent;
2919
2920 if (cur == NULL) {
2921#ifdef DEBUG_TREE
2922 xmlGenericError(xmlGenericErrorContext,
2923 "xmlAddSibling : cur == NULL\n");
2924#endif
2925 return(NULL);
2926 }
2927
2928 if (elem == NULL) {
2929#ifdef DEBUG_TREE
2930 xmlGenericError(xmlGenericErrorContext,
2931 "xmlAddSibling : elem == NULL\n");
2932#endif
2933 return(NULL);
2934 }
2935
2936 /*
2937 * Constant time is we can rely on the ->parent->last to find
2938 * the last sibling.
2939 */
2940 if ((cur->parent != NULL) &&
2941 (cur->parent->children != NULL) &&
2942 (cur->parent->last != NULL) &&
2943 (cur->parent->last->next == NULL)) {
2944 cur = cur->parent->last;
2945 } else {
2946 while (cur->next != NULL) cur = cur->next;
2947 }
2948
2949 xmlUnlinkNode(elem);
2950
2951 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002952 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002953 xmlFreeNode(elem);
2954 return(cur);
2955 }
2956
2957 if (elem->doc != cur->doc) {
2958 xmlSetTreeDoc(elem, cur->doc);
2959 }
2960 parent = cur->parent;
2961 elem->prev = cur;
2962 elem->next = NULL;
2963 elem->parent = parent;
2964 cur->next = elem;
2965 if (parent != NULL)
2966 parent->last = elem;
2967
2968 return(elem);
2969}
2970
2971/**
2972 * xmlAddChildList:
2973 * @parent: the parent node
2974 * @cur: the first node in the list
2975 *
2976 * Add a list of node at the end of the child list of the parent
2977 * merging adjacent TEXT nodes (@cur may be freed)
2978 *
2979 * Returns the last child or NULL in case of error.
2980 */
2981xmlNodePtr
2982xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2983 xmlNodePtr prev;
2984
2985 if (parent == NULL) {
2986#ifdef DEBUG_TREE
2987 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002988 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002989#endif
2990 return(NULL);
2991 }
2992
2993 if (cur == NULL) {
2994#ifdef DEBUG_TREE
2995 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002996 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002997#endif
2998 return(NULL);
2999 }
3000
3001 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3002 (cur->doc != parent->doc)) {
3003#ifdef DEBUG_TREE
3004 xmlGenericError(xmlGenericErrorContext,
3005 "Elements moved to a different document\n");
3006#endif
3007 }
3008
3009 /*
3010 * add the first element at the end of the children list.
3011 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003012
Owen Taylor3473f882001-02-23 17:55:21 +00003013 if (parent->children == NULL) {
3014 parent->children = cur;
3015 } else {
3016 /*
3017 * If cur and parent->last both are TEXT nodes, then merge them.
3018 */
3019 if ((cur->type == XML_TEXT_NODE) &&
3020 (parent->last->type == XML_TEXT_NODE) &&
3021 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003022 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003023 /*
3024 * if it's the only child, nothing more to be done.
3025 */
3026 if (cur->next == NULL) {
3027 xmlFreeNode(cur);
3028 return(parent->last);
3029 }
3030 prev = cur;
3031 cur = cur->next;
3032 xmlFreeNode(prev);
3033 }
3034 prev = parent->last;
3035 prev->next = cur;
3036 cur->prev = prev;
3037 }
3038 while (cur->next != NULL) {
3039 cur->parent = parent;
3040 if (cur->doc != parent->doc) {
3041 xmlSetTreeDoc(cur, parent->doc);
3042 }
3043 cur = cur->next;
3044 }
3045 cur->parent = parent;
3046 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
3047 parent->last = cur;
3048
3049 return(cur);
3050}
3051
3052/**
3053 * xmlAddChild:
3054 * @parent: the parent node
3055 * @cur: the child node
3056 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003057 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00003058 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003059 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3060 * If there is an attribute with equal name, it is first destroyed.
3061 *
Owen Taylor3473f882001-02-23 17:55:21 +00003062 * Returns the child or NULL in case of error.
3063 */
3064xmlNodePtr
3065xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3066 xmlNodePtr prev;
3067
3068 if (parent == NULL) {
3069#ifdef DEBUG_TREE
3070 xmlGenericError(xmlGenericErrorContext,
3071 "xmlAddChild : parent == NULL\n");
3072#endif
3073 return(NULL);
3074 }
3075
3076 if (cur == NULL) {
3077#ifdef DEBUG_TREE
3078 xmlGenericError(xmlGenericErrorContext,
3079 "xmlAddChild : child == NULL\n");
3080#endif
3081 return(NULL);
3082 }
3083
Owen Taylor3473f882001-02-23 17:55:21 +00003084 /*
3085 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003086 * cur is then freed.
3087 */
3088 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003089 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003090 (parent->content != NULL) &&
3091 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003092 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003093 xmlFreeNode(cur);
3094 return(parent);
3095 }
3096 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003097 (parent->last->name == cur->name) &&
3098 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003099 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003100 xmlFreeNode(cur);
3101 return(parent->last);
3102 }
3103 }
3104
3105 /*
3106 * add the new element at the end of the children list.
3107 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003108 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003109 cur->parent = parent;
3110 if (cur->doc != parent->doc) {
3111 xmlSetTreeDoc(cur, parent->doc);
3112 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003113 /* this check prevents a loop on tree-traversions if a developer
3114 * tries to add a node to its parent multiple times
3115 */
3116 if (prev == parent)
3117 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003118
3119 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003120 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003121 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003122 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003123 (parent->content != NULL) &&
3124 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003125 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003126 xmlFreeNode(cur);
3127 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003128 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003129 if (cur->type == XML_ATTRIBUTE_NODE) {
3130 if (parent->properties == NULL) {
3131 parent->properties = (xmlAttrPtr) cur;
3132 } else {
3133 /* check if an attribute with the same name exists */
3134 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003135
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003136 if (cur->ns == NULL)
3137 lastattr = xmlHasProp(parent, cur->name);
3138 else
3139 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3140 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
3141 /* different instance, destroy it (attributes must be unique) */
3142 xmlFreeProp(lastattr);
3143 }
3144 /* find the end */
3145 lastattr = parent->properties;
3146 while (lastattr->next != NULL) {
3147 lastattr = lastattr->next;
3148 }
3149 lastattr->next = (xmlAttrPtr) cur;
3150 ((xmlAttrPtr) cur)->prev = lastattr;
3151 }
3152 } else {
3153 if (parent->children == NULL) {
3154 parent->children = cur;
3155 parent->last = cur;
3156 } else {
3157 prev = parent->last;
3158 prev->next = cur;
3159 cur->prev = prev;
3160 parent->last = cur;
3161 }
3162 }
Owen Taylor3473f882001-02-23 17:55:21 +00003163 return(cur);
3164}
3165
3166/**
3167 * xmlGetLastChild:
3168 * @parent: the parent node
3169 *
3170 * Search the last child of a node.
3171 * Returns the last child or NULL if none.
3172 */
3173xmlNodePtr
3174xmlGetLastChild(xmlNodePtr parent) {
3175 if (parent == NULL) {
3176#ifdef DEBUG_TREE
3177 xmlGenericError(xmlGenericErrorContext,
3178 "xmlGetLastChild : parent == NULL\n");
3179#endif
3180 return(NULL);
3181 }
3182 return(parent->last);
3183}
3184
3185/**
3186 * xmlFreeNodeList:
3187 * @cur: the first node in the list
3188 *
3189 * Free a node and all its siblings, this is a recursive behaviour, all
3190 * the children are freed too.
3191 */
3192void
3193xmlFreeNodeList(xmlNodePtr cur) {
3194 xmlNodePtr next;
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003195 xmlDictPtr dict = NULL;
3196
3197 if (cur == NULL) return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003198 if (cur->type == XML_NAMESPACE_DECL) {
3199 xmlFreeNsList((xmlNsPtr) cur);
3200 return;
3201 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003202 if ((cur->type == XML_DOCUMENT_NODE) ||
3203#ifdef LIBXML_DOCB_ENABLED
3204 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003205#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003206 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003207 xmlFreeDoc((xmlDocPtr) cur);
3208 return;
3209 }
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003210 if (cur->doc != NULL) dict = cur->doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +00003211 while (cur != NULL) {
3212 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003213 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003214
Daniel Veillarda880b122003-04-21 21:36:41 +00003215 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003216 xmlDeregisterNodeDefaultValue(cur);
3217
Daniel Veillard02141ea2001-04-30 11:46:40 +00003218 if ((cur->children != NULL) &&
3219 (cur->type != XML_ENTITY_REF_NODE))
3220 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003221 if (((cur->type == XML_ELEMENT_NODE) ||
3222 (cur->type == XML_XINCLUDE_START) ||
3223 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003224 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003225 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003226 if ((cur->type != XML_ELEMENT_NODE) &&
3227 (cur->type != XML_XINCLUDE_START) &&
3228 (cur->type != XML_XINCLUDE_END) &&
3229 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003230 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003231 }
3232 if (((cur->type == XML_ELEMENT_NODE) ||
3233 (cur->type == XML_XINCLUDE_START) ||
3234 (cur->type == XML_XINCLUDE_END)) &&
3235 (cur->nsDef != NULL))
3236 xmlFreeNsList(cur->nsDef);
3237
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003238 /*
3239 * When a node is a text node or a comment, it uses a global static
3240 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003241 * Otherwise the node name might come from the document's
3242 * dictionnary
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003243 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003244 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003245 (cur->type != XML_TEXT_NODE) &&
3246 (cur->type != XML_COMMENT_NODE))
3247 DICT_FREE(cur->name)
Daniel Veillard02141ea2001-04-30 11:46:40 +00003248 xmlFree(cur);
3249 }
Owen Taylor3473f882001-02-23 17:55:21 +00003250 cur = next;
3251 }
3252}
3253
3254/**
3255 * xmlFreeNode:
3256 * @cur: the node
3257 *
3258 * Free a node, this is a recursive behaviour, all the children are freed too.
3259 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3260 */
3261void
3262xmlFreeNode(xmlNodePtr cur) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003263 xmlDictPtr dict = NULL;
3264
3265 if (cur == NULL) return;
Daniel Veillard5335dc52003-01-01 20:59:38 +00003266
Daniel Veillard02141ea2001-04-30 11:46:40 +00003267 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003268 if (cur->type == XML_DTD_NODE) {
3269 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003270 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003271 }
3272 if (cur->type == XML_NAMESPACE_DECL) {
3273 xmlFreeNs((xmlNsPtr) cur);
3274 return;
3275 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003276 if (cur->type == XML_ATTRIBUTE_NODE) {
3277 xmlFreeProp((xmlAttrPtr) cur);
3278 return;
3279 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003280
Daniel Veillarda880b122003-04-21 21:36:41 +00003281 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003282 xmlDeregisterNodeDefaultValue(cur);
3283
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003284 if (cur->doc != NULL) dict = cur->doc->dict;
3285
Owen Taylor3473f882001-02-23 17:55:21 +00003286 if ((cur->children != NULL) &&
3287 (cur->type != XML_ENTITY_REF_NODE))
3288 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003289 if (((cur->type == XML_ELEMENT_NODE) ||
3290 (cur->type == XML_XINCLUDE_START) ||
3291 (cur->type == XML_XINCLUDE_END)) &&
3292 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003293 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003294 if ((cur->type != XML_ELEMENT_NODE) &&
3295 (cur->content != NULL) &&
3296 (cur->type != XML_ENTITY_REF_NODE) &&
3297 (cur->type != XML_XINCLUDE_END) &&
3298 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003299 DICT_FREE(cur->content)
Daniel Veillard7db37732001-07-12 01:20:08 +00003300 }
3301
Daniel Veillardacd370f2001-06-09 17:17:51 +00003302 /*
3303 * When a node is a text node or a comment, it uses a global static
3304 * variable for the name of the node.
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003305 * Otherwise the node name might come from the document's dictionnary
Daniel Veillardacd370f2001-06-09 17:17:51 +00003306 */
Owen Taylor3473f882001-02-23 17:55:21 +00003307 if ((cur->name != NULL) &&
Daniel Veillarde96a2a42003-09-24 21:23:56 +00003308 (cur->type != XML_TEXT_NODE) &&
3309 (cur->type != XML_COMMENT_NODE))
3310 DICT_FREE(cur->name)
Daniel Veillardacd370f2001-06-09 17:17:51 +00003311
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003312 if (((cur->type == XML_ELEMENT_NODE) ||
3313 (cur->type == XML_XINCLUDE_START) ||
3314 (cur->type == XML_XINCLUDE_END)) &&
3315 (cur->nsDef != NULL))
3316 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003317 xmlFree(cur);
3318}
3319
3320/**
3321 * xmlUnlinkNode:
3322 * @cur: the node
3323 *
3324 * Unlink a node from it's current context, the node is not freed
3325 */
3326void
3327xmlUnlinkNode(xmlNodePtr cur) {
3328 if (cur == NULL) {
3329#ifdef DEBUG_TREE
3330 xmlGenericError(xmlGenericErrorContext,
3331 "xmlUnlinkNode : node == NULL\n");
3332#endif
3333 return;
3334 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003335 if (cur->type == XML_DTD_NODE) {
3336 xmlDocPtr doc;
3337 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003338 if (doc != NULL) {
3339 if (doc->intSubset == (xmlDtdPtr) cur)
3340 doc->intSubset = NULL;
3341 if (doc->extSubset == (xmlDtdPtr) cur)
3342 doc->extSubset = NULL;
3343 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003344 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003345 if (cur->parent != NULL) {
3346 xmlNodePtr parent;
3347 parent = cur->parent;
3348 if (cur->type == XML_ATTRIBUTE_NODE) {
3349 if (parent->properties == (xmlAttrPtr) cur)
3350 parent->properties = ((xmlAttrPtr) cur)->next;
3351 } else {
3352 if (parent->children == cur)
3353 parent->children = cur->next;
3354 if (parent->last == cur)
3355 parent->last = cur->prev;
3356 }
3357 cur->parent = NULL;
3358 }
Owen Taylor3473f882001-02-23 17:55:21 +00003359 if (cur->next != NULL)
3360 cur->next->prev = cur->prev;
3361 if (cur->prev != NULL)
3362 cur->prev->next = cur->next;
3363 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003364}
3365
3366/**
3367 * xmlReplaceNode:
3368 * @old: the old node
3369 * @cur: the node
3370 *
3371 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003372 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003373 * first unlinked from its existing context.
3374 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003375 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003376 */
3377xmlNodePtr
3378xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3379 if (old == NULL) {
3380#ifdef DEBUG_TREE
3381 xmlGenericError(xmlGenericErrorContext,
3382 "xmlReplaceNode : old == NULL\n");
3383#endif
3384 return(NULL);
3385 }
3386 if (cur == NULL) {
3387 xmlUnlinkNode(old);
3388 return(old);
3389 }
3390 if (cur == old) {
3391 return(old);
3392 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003393 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3394#ifdef DEBUG_TREE
3395 xmlGenericError(xmlGenericErrorContext,
3396 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3397#endif
3398 return(old);
3399 }
3400 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3401#ifdef DEBUG_TREE
3402 xmlGenericError(xmlGenericErrorContext,
3403 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3404#endif
3405 return(old);
3406 }
Owen Taylor3473f882001-02-23 17:55:21 +00003407 xmlUnlinkNode(cur);
3408 cur->doc = old->doc;
3409 cur->parent = old->parent;
3410 cur->next = old->next;
3411 if (cur->next != NULL)
3412 cur->next->prev = cur;
3413 cur->prev = old->prev;
3414 if (cur->prev != NULL)
3415 cur->prev->next = cur;
3416 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003417 if (cur->type == XML_ATTRIBUTE_NODE) {
3418 if (cur->parent->properties == (xmlAttrPtr)old)
3419 cur->parent->properties = ((xmlAttrPtr) cur);
3420 } else {
3421 if (cur->parent->children == old)
3422 cur->parent->children = cur;
3423 if (cur->parent->last == old)
3424 cur->parent->last = cur;
3425 }
Owen Taylor3473f882001-02-23 17:55:21 +00003426 }
3427 old->next = old->prev = NULL;
3428 old->parent = NULL;
3429 return(old);
3430}
3431
3432/************************************************************************
3433 * *
3434 * Copy operations *
3435 * *
3436 ************************************************************************/
3437
3438/**
3439 * xmlCopyNamespace:
3440 * @cur: the namespace
3441 *
3442 * Do a copy of the namespace.
3443 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003444 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003445 */
3446xmlNsPtr
3447xmlCopyNamespace(xmlNsPtr cur) {
3448 xmlNsPtr ret;
3449
3450 if (cur == NULL) return(NULL);
3451 switch (cur->type) {
3452 case XML_LOCAL_NAMESPACE:
3453 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3454 break;
3455 default:
3456#ifdef DEBUG_TREE
3457 xmlGenericError(xmlGenericErrorContext,
3458 "xmlCopyNamespace: invalid type %d\n", cur->type);
3459#endif
3460 return(NULL);
3461 }
3462 return(ret);
3463}
3464
3465/**
3466 * xmlCopyNamespaceList:
3467 * @cur: the first namespace
3468 *
3469 * Do a copy of an namespace list.
3470 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003471 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003472 */
3473xmlNsPtr
3474xmlCopyNamespaceList(xmlNsPtr cur) {
3475 xmlNsPtr ret = NULL;
3476 xmlNsPtr p = NULL,q;
3477
3478 while (cur != NULL) {
3479 q = xmlCopyNamespace(cur);
3480 if (p == NULL) {
3481 ret = p = q;
3482 } else {
3483 p->next = q;
3484 p = q;
3485 }
3486 cur = cur->next;
3487 }
3488 return(ret);
3489}
3490
3491static xmlNodePtr
3492xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3493/**
3494 * xmlCopyProp:
3495 * @target: the element where the attribute will be grafted
3496 * @cur: the attribute
3497 *
3498 * Do a copy of the attribute.
3499 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003500 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003501 */
3502xmlAttrPtr
3503xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3504 xmlAttrPtr ret;
3505
3506 if (cur == NULL) return(NULL);
3507 if (target != NULL)
3508 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3509 else if (cur->parent != NULL)
3510 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3511 else if (cur->children != NULL)
3512 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3513 else
3514 ret = xmlNewDocProp(NULL, cur->name, NULL);
3515 if (ret == NULL) return(NULL);
3516 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003517
Owen Taylor3473f882001-02-23 17:55:21 +00003518 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003519 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003520/*
3521 * if (target->doc)
3522 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3523 * else if (cur->doc) / * target may not yet have a doc : KPI * /
3524 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
3525 * else
3526 * ns = NULL;
3527 * ret->ns = ns;
3528 */
3529 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3530 if (ns == NULL) {
3531 /*
3532 * Humm, we are copying an element whose namespace is defined
3533 * out of the new tree scope. Search it in the original tree
3534 * and add it at the top of the new tree
3535 */
3536 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3537 if (ns != NULL) {
3538 xmlNodePtr root = target;
3539 xmlNodePtr pred = NULL;
3540
3541 while (root->parent != NULL) {
3542 pred = root;
3543 root = root->parent;
3544 }
3545 if (root == (xmlNodePtr) target->doc) {
3546 /* correct possibly cycling above the document elt */
3547 root = pred;
3548 }
3549 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3550 }
3551 } else {
3552 /*
3553 * we have to find something appropriate here since
3554 * we cant be sure, that the namespce we found is identified
3555 * by the prefix
3556 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003557 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003558 /* this is the nice case */
3559 ret->ns = ns;
3560 } else {
3561 /*
3562 * we are in trouble: we need a new reconcilied namespace.
3563 * This is expensive
3564 */
3565 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3566 }
3567 }
3568
Owen Taylor3473f882001-02-23 17:55:21 +00003569 } else
3570 ret->ns = NULL;
3571
3572 if (cur->children != NULL) {
3573 xmlNodePtr tmp;
3574
3575 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3576 ret->last = NULL;
3577 tmp = ret->children;
3578 while (tmp != NULL) {
3579 /* tmp->parent = (xmlNodePtr)ret; */
3580 if (tmp->next == NULL)
3581 ret->last = tmp;
3582 tmp = tmp->next;
3583 }
3584 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003585 /*
3586 * Try to handle IDs
3587 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003588 if ((target!= NULL) && (cur!= NULL) &&
3589 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003590 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3591 if (xmlIsID(cur->doc, cur->parent, cur)) {
3592 xmlChar *id;
3593
3594 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3595 if (id != NULL) {
3596 xmlAddID(NULL, target->doc, id, ret);
3597 xmlFree(id);
3598 }
3599 }
3600 }
Owen Taylor3473f882001-02-23 17:55:21 +00003601 return(ret);
3602}
3603
3604/**
3605 * xmlCopyPropList:
3606 * @target: the element where the attributes will be grafted
3607 * @cur: the first attribute
3608 *
3609 * Do a copy of an attribute list.
3610 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003611 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003612 */
3613xmlAttrPtr
3614xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3615 xmlAttrPtr ret = NULL;
3616 xmlAttrPtr p = NULL,q;
3617
3618 while (cur != NULL) {
3619 q = xmlCopyProp(target, cur);
3620 if (p == NULL) {
3621 ret = p = q;
3622 } else {
3623 p->next = q;
3624 q->prev = p;
3625 p = q;
3626 }
3627 cur = cur->next;
3628 }
3629 return(ret);
3630}
3631
3632/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003633 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003634 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003635 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003636 * tricky reason: namespaces. Doing a direct copy of a node
3637 * say RPM:Copyright without changing the namespace pointer to
3638 * something else can produce stale links. One way to do it is
3639 * to keep a reference counter but this doesn't work as soon
3640 * as one move the element or the subtree out of the scope of
3641 * the existing namespace. The actual solution seems to add
3642 * a copy of the namespace at the top of the copied tree if
3643 * not available in the subtree.
3644 * Hence two functions, the public front-end call the inner ones
3645 */
3646
3647static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003648xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003649 int recursive) {
3650 xmlNodePtr ret;
3651
3652 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003653 switch (node->type) {
3654 case XML_TEXT_NODE:
3655 case XML_CDATA_SECTION_NODE:
3656 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003657 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003658 case XML_ENTITY_REF_NODE:
3659 case XML_ENTITY_NODE:
3660 case XML_PI_NODE:
3661 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003662 case XML_XINCLUDE_START:
3663 case XML_XINCLUDE_END:
3664 break;
3665 case XML_ATTRIBUTE_NODE:
3666 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3667 case XML_NAMESPACE_DECL:
3668 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3669
Daniel Veillard39196eb2001-06-19 18:09:42 +00003670 case XML_DOCUMENT_NODE:
3671 case XML_HTML_DOCUMENT_NODE:
3672#ifdef LIBXML_DOCB_ENABLED
3673 case XML_DOCB_DOCUMENT_NODE:
3674#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003675 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00003676 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003677 case XML_NOTATION_NODE:
3678 case XML_DTD_NODE:
3679 case XML_ELEMENT_DECL:
3680 case XML_ATTRIBUTE_DECL:
3681 case XML_ENTITY_DECL:
3682 return(NULL);
3683 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003684
Owen Taylor3473f882001-02-23 17:55:21 +00003685 /*
3686 * Allocate a new node and fill the fields.
3687 */
3688 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3689 if (ret == NULL) {
3690 xmlGenericError(xmlGenericErrorContext,
3691 "xmlStaticCopyNode : malloc failed\n");
3692 return(NULL);
3693 }
3694 memset(ret, 0, sizeof(xmlNode));
3695 ret->type = node->type;
3696
3697 ret->doc = doc;
3698 ret->parent = parent;
3699 if (node->name == xmlStringText)
3700 ret->name = xmlStringText;
3701 else if (node->name == xmlStringTextNoenc)
3702 ret->name = xmlStringTextNoenc;
3703 else if (node->name == xmlStringComment)
3704 ret->name = xmlStringComment;
3705 else if (node->name != NULL)
3706 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003707 if ((node->type != XML_ELEMENT_NODE) &&
3708 (node->content != NULL) &&
3709 (node->type != XML_ENTITY_REF_NODE) &&
3710 (node->type != XML_XINCLUDE_END) &&
3711 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003712 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003713 }else{
3714 if (node->type == XML_ELEMENT_NODE)
3715 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00003716 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003717 if (parent != NULL) {
3718 xmlNodePtr tmp;
3719
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003720 /*
3721 * this is a tricky part for the node register thing:
3722 * in case ret does get coalesced in xmlAddChild
3723 * the deregister-node callback is called; so we register ret now already
3724 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003725 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003726 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3727
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003728 tmp = xmlAddChild(parent, ret);
3729 /* node could have coalesced */
3730 if (tmp != ret)
3731 return(tmp);
3732 }
Owen Taylor3473f882001-02-23 17:55:21 +00003733
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003734 if (!recursive)
3735 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003736 if (node->nsDef != NULL)
3737 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3738
3739 if (node->ns != NULL) {
3740 xmlNsPtr ns;
3741
3742 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3743 if (ns == NULL) {
3744 /*
3745 * Humm, we are copying an element whose namespace is defined
3746 * out of the new tree scope. Search it in the original tree
3747 * and add it at the top of the new tree
3748 */
3749 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3750 if (ns != NULL) {
3751 xmlNodePtr root = ret;
3752
3753 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003754 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003755 }
3756 } else {
3757 /*
3758 * reference the existing namespace definition in our own tree.
3759 */
3760 ret->ns = ns;
3761 }
3762 }
3763 if (node->properties != NULL)
3764 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003765 if (node->type == XML_ENTITY_REF_NODE) {
3766 if ((doc == NULL) || (node->doc != doc)) {
3767 /*
3768 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003769 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003770 * we cannot keep the reference. Try to find it in the
3771 * target document.
3772 */
3773 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3774 } else {
3775 ret->children = node->children;
3776 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003777 ret->last = ret->children;
3778 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003779 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003780 UPDATE_LAST_CHILD_AND_PARENT(ret)
3781 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003782
3783out:
3784 /* if parent != NULL we already registered the node above */
3785 if (parent == NULL && xmlRegisterNodeDefaultValue)
3786 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003787 return(ret);
3788}
3789
3790static xmlNodePtr
3791xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3792 xmlNodePtr ret = NULL;
3793 xmlNodePtr p = NULL,q;
3794
3795 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003796 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003797 if (doc == NULL) {
3798 node = node->next;
3799 continue;
3800 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003801 if (doc->intSubset == NULL) {
3802 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3803 q->doc = doc;
3804 q->parent = parent;
3805 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003806 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003807 } else {
3808 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003809 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003810 }
3811 } else
3812 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003813 if (ret == NULL) {
3814 q->prev = NULL;
3815 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003816 } else if (p != q) {
3817 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003818 p->next = q;
3819 q->prev = p;
3820 p = q;
3821 }
3822 node = node->next;
3823 }
3824 return(ret);
3825}
3826
3827/**
3828 * xmlCopyNode:
3829 * @node: the node
3830 * @recursive: if 1 do a recursive copy.
3831 *
3832 * Do a copy of the node.
3833 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003834 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003835 */
3836xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003837xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003838 xmlNodePtr ret;
3839
3840 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3841 return(ret);
3842}
3843
3844/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003845 * xmlDocCopyNode:
3846 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003847 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003848 * @recursive: if 1 do a recursive copy.
3849 *
3850 * Do a copy of the node to a given document.
3851 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003852 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003853 */
3854xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003855xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003856 xmlNodePtr ret;
3857
3858 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3859 return(ret);
3860}
3861
3862/**
Owen Taylor3473f882001-02-23 17:55:21 +00003863 * xmlCopyNodeList:
3864 * @node: the first node in the list.
3865 *
3866 * Do a recursive copy of the node list.
3867 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003868 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003869 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003870xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003871 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3872 return(ret);
3873}
3874
3875/**
Owen Taylor3473f882001-02-23 17:55:21 +00003876 * xmlCopyDtd:
3877 * @dtd: the dtd
3878 *
3879 * Do a copy of the dtd.
3880 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003881 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003882 */
3883xmlDtdPtr
3884xmlCopyDtd(xmlDtdPtr dtd) {
3885 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003886 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003887
3888 if (dtd == NULL) return(NULL);
3889 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3890 if (ret == NULL) return(NULL);
3891 if (dtd->entities != NULL)
3892 ret->entities = (void *) xmlCopyEntitiesTable(
3893 (xmlEntitiesTablePtr) dtd->entities);
3894 if (dtd->notations != NULL)
3895 ret->notations = (void *) xmlCopyNotationTable(
3896 (xmlNotationTablePtr) dtd->notations);
3897 if (dtd->elements != NULL)
3898 ret->elements = (void *) xmlCopyElementTable(
3899 (xmlElementTablePtr) dtd->elements);
3900 if (dtd->attributes != NULL)
3901 ret->attributes = (void *) xmlCopyAttributeTable(
3902 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003903 if (dtd->pentities != NULL)
3904 ret->pentities = (void *) xmlCopyEntitiesTable(
3905 (xmlEntitiesTablePtr) dtd->pentities);
3906
3907 cur = dtd->children;
3908 while (cur != NULL) {
3909 q = NULL;
3910
3911 if (cur->type == XML_ENTITY_DECL) {
3912 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3913 switch (tmp->etype) {
3914 case XML_INTERNAL_GENERAL_ENTITY:
3915 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3916 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3917 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3918 break;
3919 case XML_INTERNAL_PARAMETER_ENTITY:
3920 case XML_EXTERNAL_PARAMETER_ENTITY:
3921 q = (xmlNodePtr)
3922 xmlGetParameterEntityFromDtd(ret, tmp->name);
3923 break;
3924 case XML_INTERNAL_PREDEFINED_ENTITY:
3925 break;
3926 }
3927 } else if (cur->type == XML_ELEMENT_DECL) {
3928 xmlElementPtr tmp = (xmlElementPtr) cur;
3929 q = (xmlNodePtr)
3930 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3931 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3932 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3933 q = (xmlNodePtr)
3934 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3935 } else if (cur->type == XML_COMMENT_NODE) {
3936 q = xmlCopyNode(cur, 0);
3937 }
3938
3939 if (q == NULL) {
3940 cur = cur->next;
3941 continue;
3942 }
3943
3944 if (p == NULL)
3945 ret->children = q;
3946 else
3947 p->next = q;
3948
3949 q->prev = p;
3950 q->parent = (xmlNodePtr) ret;
3951 q->next = NULL;
3952 ret->last = q;
3953 p = q;
3954 cur = cur->next;
3955 }
3956
Owen Taylor3473f882001-02-23 17:55:21 +00003957 return(ret);
3958}
3959
3960/**
3961 * xmlCopyDoc:
3962 * @doc: the document
3963 * @recursive: if 1 do a recursive copy.
3964 *
3965 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003966 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003967 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003968 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003969 */
3970xmlDocPtr
3971xmlCopyDoc(xmlDocPtr doc, int recursive) {
3972 xmlDocPtr ret;
3973
3974 if (doc == NULL) return(NULL);
3975 ret = xmlNewDoc(doc->version);
3976 if (ret == NULL) return(NULL);
3977 if (doc->name != NULL)
3978 ret->name = xmlMemStrdup(doc->name);
3979 if (doc->encoding != NULL)
3980 ret->encoding = xmlStrdup(doc->encoding);
3981 ret->charset = doc->charset;
3982 ret->compression = doc->compression;
3983 ret->standalone = doc->standalone;
3984 if (!recursive) return(ret);
3985
Daniel Veillardb33c2012001-04-25 12:59:04 +00003986 ret->last = NULL;
3987 ret->children = NULL;
3988 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003989 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003990 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003991 ret->intSubset->parent = ret;
3992 }
Owen Taylor3473f882001-02-23 17:55:21 +00003993 if (doc->oldNs != NULL)
3994 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3995 if (doc->children != NULL) {
3996 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003997
3998 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3999 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004000 ret->last = NULL;
4001 tmp = ret->children;
4002 while (tmp != NULL) {
4003 if (tmp->next == NULL)
4004 ret->last = tmp;
4005 tmp = tmp->next;
4006 }
4007 }
4008 return(ret);
4009}
4010
4011/************************************************************************
4012 * *
4013 * Content access functions *
4014 * *
4015 ************************************************************************/
4016
4017/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00004018 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00004019 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00004020 *
4021 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00004022 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00004023 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004024 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00004025 */
4026long
4027xmlGetLineNo(xmlNodePtr node)
4028{
4029 long result = -1;
4030
4031 if (!node)
4032 return result;
4033 if (node->type == XML_ELEMENT_NODE)
4034 result = (long) node->content;
4035 else if ((node->prev != NULL) &&
4036 ((node->prev->type == XML_ELEMENT_NODE) ||
4037 (node->prev->type == XML_TEXT_NODE)))
4038 result = xmlGetLineNo(node->prev);
4039 else if ((node->parent != NULL) &&
4040 ((node->parent->type == XML_ELEMENT_NODE) ||
4041 (node->parent->type == XML_TEXT_NODE)))
4042 result = xmlGetLineNo(node->parent);
4043
4044 return result;
4045}
4046
4047/**
4048 * xmlGetNodePath:
4049 * @node: a node
4050 *
4051 * Build a structure based Path for the given node
4052 *
4053 * Returns the new path or NULL in case of error. The caller must free
4054 * the returned string
4055 */
4056xmlChar *
4057xmlGetNodePath(xmlNodePtr node)
4058{
4059 xmlNodePtr cur, tmp, next;
4060 xmlChar *buffer = NULL, *temp;
4061 size_t buf_len;
4062 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004063 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004064 const char *name;
4065 char nametemp[100];
4066 int occur = 0;
4067
4068 if (node == NULL)
4069 return (NULL);
4070
4071 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004072 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004073 if (buffer == NULL)
4074 return (NULL);
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004075 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004076 if (buf == NULL) {
4077 xmlFree(buffer);
4078 return (NULL);
4079 }
4080
4081 buffer[0] = 0;
4082 cur = node;
4083 do {
4084 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004085 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004086 occur = 0;
4087 if ((cur->type == XML_DOCUMENT_NODE) ||
4088 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4089 if (buffer[0] == '/')
4090 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004091 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004092 next = NULL;
4093 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004094 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004095 name = (const char *) cur->name;
4096 if (cur->ns) {
4097 snprintf(nametemp, sizeof(nametemp) - 1,
4098 "%s:%s", cur->ns->prefix, cur->name);
4099 nametemp[sizeof(nametemp) - 1] = 0;
4100 name = nametemp;
4101 }
4102 next = cur->parent;
4103
4104 /*
4105 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004106 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004107 */
4108 tmp = cur->prev;
4109 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004110 if ((tmp->type == XML_ELEMENT_NODE) &&
4111 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004112 occur++;
4113 tmp = tmp->prev;
4114 }
4115 if (occur == 0) {
4116 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004117 while (tmp != NULL && occur == 0) {
4118 if ((tmp->type == XML_ELEMENT_NODE) &&
4119 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004120 occur++;
4121 tmp = tmp->next;
4122 }
4123 if (occur != 0)
4124 occur = 1;
4125 } else
4126 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004127 } else if (cur->type == XML_COMMENT_NODE) {
4128 sep = "/";
4129 name = "comment()";
4130 next = cur->parent;
4131
4132 /*
4133 * Thumbler index computation
4134 */
4135 tmp = cur->prev;
4136 while (tmp != NULL) {
4137 if (tmp->type == XML_COMMENT_NODE)
4138 occur++;
4139 tmp = tmp->prev;
4140 }
4141 if (occur == 0) {
4142 tmp = cur->next;
4143 while (tmp != NULL && occur == 0) {
4144 if (tmp->type == XML_COMMENT_NODE)
4145 occur++;
4146 tmp = tmp->next;
4147 }
4148 if (occur != 0)
4149 occur = 1;
4150 } else
4151 occur++;
4152 } else if ((cur->type == XML_TEXT_NODE) ||
4153 (cur->type == XML_CDATA_SECTION_NODE)) {
4154 sep = "/";
4155 name = "text()";
4156 next = cur->parent;
4157
4158 /*
4159 * Thumbler index computation
4160 */
4161 tmp = cur->prev;
4162 while (tmp != NULL) {
4163 if ((cur->type == XML_TEXT_NODE) ||
4164 (cur->type == XML_CDATA_SECTION_NODE))
4165 occur++;
4166 tmp = tmp->prev;
4167 }
4168 if (occur == 0) {
4169 tmp = cur->next;
4170 while (tmp != NULL && occur == 0) {
4171 if ((cur->type == XML_TEXT_NODE) ||
4172 (cur->type == XML_CDATA_SECTION_NODE))
4173 occur++;
4174 tmp = tmp->next;
4175 }
4176 if (occur != 0)
4177 occur = 1;
4178 } else
4179 occur++;
4180 } else if (cur->type == XML_PI_NODE) {
4181 sep = "/";
4182 snprintf(nametemp, sizeof(nametemp) - 1,
4183 "processing-instruction('%s')", cur->name);
4184 nametemp[sizeof(nametemp) - 1] = 0;
4185 name = nametemp;
4186
4187 next = cur->parent;
4188
4189 /*
4190 * Thumbler index computation
4191 */
4192 tmp = cur->prev;
4193 while (tmp != NULL) {
4194 if ((tmp->type == XML_PI_NODE) &&
4195 (xmlStrEqual(cur->name, tmp->name)))
4196 occur++;
4197 tmp = tmp->prev;
4198 }
4199 if (occur == 0) {
4200 tmp = cur->next;
4201 while (tmp != NULL && occur == 0) {
4202 if ((tmp->type == XML_PI_NODE) &&
4203 (xmlStrEqual(cur->name, tmp->name)))
4204 occur++;
4205 tmp = tmp->next;
4206 }
4207 if (occur != 0)
4208 occur = 1;
4209 } else
4210 occur++;
4211
Daniel Veillard8faa7832001-11-26 15:58:08 +00004212 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004213 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004214 name = (const char *) (((xmlAttrPtr) cur)->name);
4215 next = ((xmlAttrPtr) cur)->parent;
4216 } else {
4217 next = cur->parent;
4218 }
4219
4220 /*
4221 * Make sure there is enough room
4222 */
4223 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4224 buf_len =
4225 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4226 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4227 if (temp == NULL) {
4228 xmlFree(buf);
4229 xmlFree(buffer);
4230 return (NULL);
4231 }
4232 buffer = temp;
4233 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4234 if (temp == NULL) {
4235 xmlFree(buf);
4236 xmlFree(buffer);
4237 return (NULL);
4238 }
4239 buf = temp;
4240 }
4241 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004242 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004243 sep, name, (char *) buffer);
4244 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004245 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004246 sep, name, occur, (char *) buffer);
4247 snprintf((char *) buffer, buf_len, "%s", buf);
4248 cur = next;
4249 } while (cur != NULL);
4250 xmlFree(buf);
4251 return (buffer);
4252}
4253
4254/**
Owen Taylor3473f882001-02-23 17:55:21 +00004255 * xmlDocGetRootElement:
4256 * @doc: the document
4257 *
4258 * Get the root element of the document (doc->children is a list
4259 * containing possibly comments, PIs, etc ...).
4260 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004261 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004262 */
4263xmlNodePtr
4264xmlDocGetRootElement(xmlDocPtr doc) {
4265 xmlNodePtr ret;
4266
4267 if (doc == NULL) return(NULL);
4268 ret = doc->children;
4269 while (ret != NULL) {
4270 if (ret->type == XML_ELEMENT_NODE)
4271 return(ret);
4272 ret = ret->next;
4273 }
4274 return(ret);
4275}
4276
4277/**
4278 * xmlDocSetRootElement:
4279 * @doc: the document
4280 * @root: the new document root element
4281 *
4282 * Set the root element of the document (doc->children is a list
4283 * containing possibly comments, PIs, etc ...).
4284 *
4285 * Returns the old root element if any was found
4286 */
4287xmlNodePtr
4288xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4289 xmlNodePtr old = NULL;
4290
4291 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004292 if (root == NULL)
4293 return(NULL);
4294 xmlUnlinkNode(root);
4295 root->doc = doc;
4296 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004297 old = doc->children;
4298 while (old != NULL) {
4299 if (old->type == XML_ELEMENT_NODE)
4300 break;
4301 old = old->next;
4302 }
4303 if (old == NULL) {
4304 if (doc->children == NULL) {
4305 doc->children = root;
4306 doc->last = root;
4307 } else {
4308 xmlAddSibling(doc->children, root);
4309 }
4310 } else {
4311 xmlReplaceNode(old, root);
4312 }
4313 return(old);
4314}
4315
4316/**
4317 * xmlNodeSetLang:
4318 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004319 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004320 *
4321 * Set the language of a node, i.e. the values of the xml:lang
4322 * attribute.
4323 */
4324void
4325xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004326 xmlNsPtr ns;
4327
Owen Taylor3473f882001-02-23 17:55:21 +00004328 if (cur == NULL) return;
4329 switch(cur->type) {
4330 case XML_TEXT_NODE:
4331 case XML_CDATA_SECTION_NODE:
4332 case XML_COMMENT_NODE:
4333 case XML_DOCUMENT_NODE:
4334 case XML_DOCUMENT_TYPE_NODE:
4335 case XML_DOCUMENT_FRAG_NODE:
4336 case XML_NOTATION_NODE:
4337 case XML_HTML_DOCUMENT_NODE:
4338 case XML_DTD_NODE:
4339 case XML_ELEMENT_DECL:
4340 case XML_ATTRIBUTE_DECL:
4341 case XML_ENTITY_DECL:
4342 case XML_PI_NODE:
4343 case XML_ENTITY_REF_NODE:
4344 case XML_ENTITY_NODE:
4345 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004346#ifdef LIBXML_DOCB_ENABLED
4347 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004348#endif
4349 case XML_XINCLUDE_START:
4350 case XML_XINCLUDE_END:
4351 return;
4352 case XML_ELEMENT_NODE:
4353 case XML_ATTRIBUTE_NODE:
4354 break;
4355 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004356 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4357 if (ns == NULL)
4358 return;
4359 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004360}
4361
4362/**
4363 * xmlNodeGetLang:
4364 * @cur: the node being checked
4365 *
4366 * Searches the language of a node, i.e. the values of the xml:lang
4367 * attribute or the one carried by the nearest ancestor.
4368 *
4369 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004370 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004371 */
4372xmlChar *
4373xmlNodeGetLang(xmlNodePtr cur) {
4374 xmlChar *lang;
4375
4376 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004377 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004378 if (lang != NULL)
4379 return(lang);
4380 cur = cur->parent;
4381 }
4382 return(NULL);
4383}
4384
4385
4386/**
4387 * xmlNodeSetSpacePreserve:
4388 * @cur: the node being changed
4389 * @val: the xml:space value ("0": default, 1: "preserve")
4390 *
4391 * Set (or reset) the space preserving behaviour of a node, i.e. the
4392 * value of the xml:space attribute.
4393 */
4394void
4395xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004396 xmlNsPtr ns;
4397
Owen Taylor3473f882001-02-23 17:55:21 +00004398 if (cur == NULL) return;
4399 switch(cur->type) {
4400 case XML_TEXT_NODE:
4401 case XML_CDATA_SECTION_NODE:
4402 case XML_COMMENT_NODE:
4403 case XML_DOCUMENT_NODE:
4404 case XML_DOCUMENT_TYPE_NODE:
4405 case XML_DOCUMENT_FRAG_NODE:
4406 case XML_NOTATION_NODE:
4407 case XML_HTML_DOCUMENT_NODE:
4408 case XML_DTD_NODE:
4409 case XML_ELEMENT_DECL:
4410 case XML_ATTRIBUTE_DECL:
4411 case XML_ENTITY_DECL:
4412 case XML_PI_NODE:
4413 case XML_ENTITY_REF_NODE:
4414 case XML_ENTITY_NODE:
4415 case XML_NAMESPACE_DECL:
4416 case XML_XINCLUDE_START:
4417 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004418#ifdef LIBXML_DOCB_ENABLED
4419 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004420#endif
4421 return;
4422 case XML_ELEMENT_NODE:
4423 case XML_ATTRIBUTE_NODE:
4424 break;
4425 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004426 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4427 if (ns == NULL)
4428 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004429 switch (val) {
4430 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004431 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004432 break;
4433 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004434 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004435 break;
4436 }
4437}
4438
4439/**
4440 * xmlNodeGetSpacePreserve:
4441 * @cur: the node being checked
4442 *
4443 * Searches the space preserving behaviour of a node, i.e. the values
4444 * of the xml:space attribute or the one carried by the nearest
4445 * ancestor.
4446 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004447 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004448 */
4449int
4450xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4451 xmlChar *space;
4452
4453 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004454 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004455 if (space != NULL) {
4456 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4457 xmlFree(space);
4458 return(1);
4459 }
4460 if (xmlStrEqual(space, BAD_CAST "default")) {
4461 xmlFree(space);
4462 return(0);
4463 }
4464 xmlFree(space);
4465 }
4466 cur = cur->parent;
4467 }
4468 return(-1);
4469}
4470
4471/**
4472 * xmlNodeSetName:
4473 * @cur: the node being changed
4474 * @name: the new tag name
4475 *
4476 * Set (or reset) the name of a node.
4477 */
4478void
4479xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
4480 if (cur == NULL) return;
4481 if (name == NULL) return;
4482 switch(cur->type) {
4483 case XML_TEXT_NODE:
4484 case XML_CDATA_SECTION_NODE:
4485 case XML_COMMENT_NODE:
4486 case XML_DOCUMENT_TYPE_NODE:
4487 case XML_DOCUMENT_FRAG_NODE:
4488 case XML_NOTATION_NODE:
4489 case XML_HTML_DOCUMENT_NODE:
4490 case XML_NAMESPACE_DECL:
4491 case XML_XINCLUDE_START:
4492 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004493#ifdef LIBXML_DOCB_ENABLED
4494 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004495#endif
4496 return;
4497 case XML_ELEMENT_NODE:
4498 case XML_ATTRIBUTE_NODE:
4499 case XML_PI_NODE:
4500 case XML_ENTITY_REF_NODE:
4501 case XML_ENTITY_NODE:
4502 case XML_DTD_NODE:
4503 case XML_DOCUMENT_NODE:
4504 case XML_ELEMENT_DECL:
4505 case XML_ATTRIBUTE_DECL:
4506 case XML_ENTITY_DECL:
4507 break;
4508 }
4509 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4510 cur->name = xmlStrdup(name);
4511}
4512
4513/**
4514 * xmlNodeSetBase:
4515 * @cur: the node being changed
4516 * @uri: the new base URI
4517 *
4518 * Set (or reset) the base URI of a node, i.e. the value of the
4519 * xml:base attribute.
4520 */
4521void
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00004522xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004523 xmlNsPtr ns;
4524
Owen Taylor3473f882001-02-23 17:55:21 +00004525 if (cur == NULL) return;
4526 switch(cur->type) {
4527 case XML_TEXT_NODE:
4528 case XML_CDATA_SECTION_NODE:
4529 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004530 case XML_DOCUMENT_TYPE_NODE:
4531 case XML_DOCUMENT_FRAG_NODE:
4532 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004533 case XML_DTD_NODE:
4534 case XML_ELEMENT_DECL:
4535 case XML_ATTRIBUTE_DECL:
4536 case XML_ENTITY_DECL:
4537 case XML_PI_NODE:
4538 case XML_ENTITY_REF_NODE:
4539 case XML_ENTITY_NODE:
4540 case XML_NAMESPACE_DECL:
4541 case XML_XINCLUDE_START:
4542 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004543 return;
4544 case XML_ELEMENT_NODE:
4545 case XML_ATTRIBUTE_NODE:
4546 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004547 case XML_DOCUMENT_NODE:
4548#ifdef LIBXML_DOCB_ENABLED
4549 case XML_DOCB_DOCUMENT_NODE:
4550#endif
4551 case XML_HTML_DOCUMENT_NODE: {
4552 xmlDocPtr doc = (xmlDocPtr) cur;
4553
4554 if (doc->URL != NULL)
4555 xmlFree((xmlChar *) doc->URL);
4556 if (uri == NULL)
4557 doc->URL = NULL;
4558 else
4559 doc->URL = xmlStrdup(uri);
4560 return;
4561 }
Owen Taylor3473f882001-02-23 17:55:21 +00004562 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004563
4564 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4565 if (ns == NULL)
4566 return;
4567 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004568}
4569
4570/**
Owen Taylor3473f882001-02-23 17:55:21 +00004571 * xmlNodeGetBase:
4572 * @doc: the document the node pertains to
4573 * @cur: the node being checked
4574 *
4575 * Searches for the BASE URL. The code should work on both XML
4576 * and HTML document even if base mechanisms are completely different.
4577 * It returns the base as defined in RFC 2396 sections
4578 * 5.1.1. Base URI within Document Content
4579 * and
4580 * 5.1.2. Base URI from the Encapsulating Entity
4581 * However it does not return the document base (5.1.3), use
4582 * xmlDocumentGetBase() for this
4583 *
4584 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004585 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004586 */
4587xmlChar *
4588xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004589 xmlChar *oldbase = NULL;
4590 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004591
4592 if ((cur == NULL) && (doc == NULL))
4593 return(NULL);
4594 if (doc == NULL) doc = cur->doc;
4595 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4596 cur = doc->children;
4597 while ((cur != NULL) && (cur->name != NULL)) {
4598 if (cur->type != XML_ELEMENT_NODE) {
4599 cur = cur->next;
4600 continue;
4601 }
4602 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4603 cur = cur->children;
4604 continue;
4605 }
4606 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4607 cur = cur->children;
4608 continue;
4609 }
4610 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4611 return(xmlGetProp(cur, BAD_CAST "href"));
4612 }
4613 cur = cur->next;
4614 }
4615 return(NULL);
4616 }
4617 while (cur != NULL) {
4618 if (cur->type == XML_ENTITY_DECL) {
4619 xmlEntityPtr ent = (xmlEntityPtr) cur;
4620 return(xmlStrdup(ent->URI));
4621 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004622 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004623 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004624 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004625 if (oldbase != NULL) {
4626 newbase = xmlBuildURI(oldbase, base);
4627 if (newbase != NULL) {
4628 xmlFree(oldbase);
4629 xmlFree(base);
4630 oldbase = newbase;
4631 } else {
4632 xmlFree(oldbase);
4633 xmlFree(base);
4634 return(NULL);
4635 }
4636 } else {
4637 oldbase = base;
4638 }
4639 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4640 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4641 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4642 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004643 }
4644 }
Owen Taylor3473f882001-02-23 17:55:21 +00004645 cur = cur->parent;
4646 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004647 if ((doc != NULL) && (doc->URL != NULL)) {
4648 if (oldbase == NULL)
4649 return(xmlStrdup(doc->URL));
4650 newbase = xmlBuildURI(oldbase, doc->URL);
4651 xmlFree(oldbase);
4652 return(newbase);
4653 }
4654 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004655}
4656
4657/**
4658 * xmlNodeGetContent:
4659 * @cur: the node being read
4660 *
4661 * Read the value of a node, this can be either the text carried
4662 * directly by this node if it's a TEXT node or the aggregate string
4663 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004664 * Entity references are substituted.
4665 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004666 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004667 */
4668xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004669xmlNodeGetContent(xmlNodePtr cur)
4670{
4671 if (cur == NULL)
4672 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004673 switch (cur->type) {
4674 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004675 case XML_ELEMENT_NODE:{
4676 xmlNodePtr tmp = cur;
4677 xmlBufferPtr buffer;
4678 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004679
Daniel Veillard814a76d2003-01-23 18:24:20 +00004680 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004681 if (buffer == NULL)
4682 return (NULL);
4683 while (tmp != NULL) {
4684 switch (tmp->type) {
4685 case XML_CDATA_SECTION_NODE:
4686 case XML_TEXT_NODE:
4687 if (tmp->content != NULL)
4688 xmlBufferCat(buffer, tmp->content);
4689 break;
4690 case XML_ENTITY_REF_NODE:{
4691 /* recursive substitution of entity references */
4692 xmlChar *cont = xmlNodeGetContent(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00004693
Daniel Veillard7646b182002-04-20 06:41:40 +00004694 if (cont) {
4695 xmlBufferCat(buffer,
4696 (const xmlChar *) cont);
4697 xmlFree(cont);
4698 }
4699 break;
4700 }
4701 default:
4702 break;
4703 }
4704 /*
4705 * Skip to next node
4706 */
4707 if (tmp->children != NULL) {
4708 if (tmp->children->type != XML_ENTITY_DECL) {
4709 tmp = tmp->children;
4710 continue;
4711 }
4712 }
4713 if (tmp == cur)
4714 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00004715
Daniel Veillard7646b182002-04-20 06:41:40 +00004716 if (tmp->next != NULL) {
4717 tmp = tmp->next;
4718 continue;
4719 }
4720
4721 do {
4722 tmp = tmp->parent;
4723 if (tmp == NULL)
4724 break;
4725 if (tmp == cur) {
4726 tmp = NULL;
4727 break;
4728 }
4729 if (tmp->next != NULL) {
4730 tmp = tmp->next;
4731 break;
4732 }
4733 } while (tmp != NULL);
4734 }
4735 ret = buffer->content;
4736 buffer->content = NULL;
4737 xmlBufferFree(buffer);
4738 return (ret);
4739 }
4740 case XML_ATTRIBUTE_NODE:{
4741 xmlAttrPtr attr = (xmlAttrPtr) cur;
4742
4743 if (attr->parent != NULL)
4744 return (xmlNodeListGetString
4745 (attr->parent->doc, attr->children, 1));
4746 else
4747 return (xmlNodeListGetString(NULL, attr->children, 1));
4748 break;
4749 }
Owen Taylor3473f882001-02-23 17:55:21 +00004750 case XML_COMMENT_NODE:
4751 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004752 if (cur->content != NULL)
4753 return (xmlStrdup(cur->content));
4754 return (NULL);
4755 case XML_ENTITY_REF_NODE:{
4756 xmlEntityPtr ent;
4757 xmlNodePtr tmp;
4758 xmlBufferPtr buffer;
4759 xmlChar *ret;
4760
4761 /* lookup entity declaration */
4762 ent = xmlGetDocEntity(cur->doc, cur->name);
4763 if (ent == NULL)
4764 return (NULL);
4765
4766 buffer = xmlBufferCreate();
4767 if (buffer == NULL)
4768 return (NULL);
4769
4770 /* an entity content can be any "well balanced chunk",
4771 * i.e. the result of the content [43] production:
4772 * http://www.w3.org/TR/REC-xml#NT-content
4773 * -> we iterate through child nodes and recursive call
4774 * xmlNodeGetContent() which handles all possible node types */
4775 tmp = ent->children;
4776 while (tmp) {
4777 xmlChar *cont = xmlNodeGetContent(tmp);
4778
4779 if (cont) {
4780 xmlBufferCat(buffer, (const xmlChar *) cont);
4781 xmlFree(cont);
4782 }
4783 tmp = tmp->next;
4784 }
4785
4786 ret = buffer->content;
4787 buffer->content = NULL;
4788 xmlBufferFree(buffer);
4789 return (ret);
4790 }
Owen Taylor3473f882001-02-23 17:55:21 +00004791 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004792 case XML_DOCUMENT_TYPE_NODE:
4793 case XML_NOTATION_NODE:
4794 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004795 case XML_XINCLUDE_START:
4796 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00004797 return (NULL);
4798 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004799#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004800 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004801#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00004802 case XML_HTML_DOCUMENT_NODE: {
4803 xmlChar *tmp;
4804 xmlChar *res = NULL;
4805
4806 cur = cur->children;
4807 while (cur!= NULL) {
4808 if ((cur->type == XML_ELEMENT_NODE) ||
4809 (cur->type == XML_TEXT_NODE) ||
4810 (cur->type == XML_CDATA_SECTION_NODE)) {
4811 tmp = xmlNodeGetContent(cur);
4812 if (tmp != NULL) {
4813 if (res == NULL)
4814 res = tmp;
4815 else {
4816 res = xmlStrcat(res, tmp);
4817 xmlFree(tmp);
4818 }
4819 }
4820 }
4821 cur = cur->next;
4822 }
4823 return(res);
4824 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004825 case XML_NAMESPACE_DECL: {
4826 xmlChar *tmp;
4827
4828 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4829 return (tmp);
4830 }
Owen Taylor3473f882001-02-23 17:55:21 +00004831 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004832 /* TODO !!! */
4833 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004834 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004835 /* TODO !!! */
4836 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004837 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004838 /* TODO !!! */
4839 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004840 case XML_CDATA_SECTION_NODE:
4841 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004842 if (cur->content != NULL)
4843 return (xmlStrdup(cur->content));
4844 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004845 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004846 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004847}
Owen Taylor3473f882001-02-23 17:55:21 +00004848/**
4849 * xmlNodeSetContent:
4850 * @cur: the node being modified
4851 * @content: the new value of the content
4852 *
4853 * Replace the content of a node.
4854 */
4855void
4856xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4857 if (cur == NULL) {
4858#ifdef DEBUG_TREE
4859 xmlGenericError(xmlGenericErrorContext,
4860 "xmlNodeSetContent : node == NULL\n");
4861#endif
4862 return;
4863 }
4864 switch (cur->type) {
4865 case XML_DOCUMENT_FRAG_NODE:
4866 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004867 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004868 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4869 cur->children = xmlStringGetNodeList(cur->doc, content);
4870 UPDATE_LAST_CHILD_AND_PARENT(cur)
4871 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004872 case XML_TEXT_NODE:
4873 case XML_CDATA_SECTION_NODE:
4874 case XML_ENTITY_REF_NODE:
4875 case XML_ENTITY_NODE:
4876 case XML_PI_NODE:
4877 case XML_COMMENT_NODE:
4878 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004879 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004880 }
4881 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4882 cur->last = cur->children = NULL;
4883 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004884 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00004885 } else
4886 cur->content = NULL;
4887 break;
4888 case XML_DOCUMENT_NODE:
4889 case XML_HTML_DOCUMENT_NODE:
4890 case XML_DOCUMENT_TYPE_NODE:
4891 case XML_XINCLUDE_START:
4892 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004893#ifdef LIBXML_DOCB_ENABLED
4894 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004895#endif
4896 break;
4897 case XML_NOTATION_NODE:
4898 break;
4899 case XML_DTD_NODE:
4900 break;
4901 case XML_NAMESPACE_DECL:
4902 break;
4903 case XML_ELEMENT_DECL:
4904 /* TODO !!! */
4905 break;
4906 case XML_ATTRIBUTE_DECL:
4907 /* TODO !!! */
4908 break;
4909 case XML_ENTITY_DECL:
4910 /* TODO !!! */
4911 break;
4912 }
4913}
4914
4915/**
4916 * xmlNodeSetContentLen:
4917 * @cur: the node being modified
4918 * @content: the new value of the content
4919 * @len: the size of @content
4920 *
4921 * Replace the content of a node.
4922 */
4923void
4924xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4925 if (cur == NULL) {
4926#ifdef DEBUG_TREE
4927 xmlGenericError(xmlGenericErrorContext,
4928 "xmlNodeSetContentLen : node == NULL\n");
4929#endif
4930 return;
4931 }
4932 switch (cur->type) {
4933 case XML_DOCUMENT_FRAG_NODE:
4934 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004935 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004936 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4937 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
4938 UPDATE_LAST_CHILD_AND_PARENT(cur)
4939 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004940 case XML_TEXT_NODE:
4941 case XML_CDATA_SECTION_NODE:
4942 case XML_ENTITY_REF_NODE:
4943 case XML_ENTITY_NODE:
4944 case XML_PI_NODE:
4945 case XML_COMMENT_NODE:
4946 case XML_NOTATION_NODE:
4947 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004948 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004949 }
4950 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4951 cur->children = cur->last = NULL;
4952 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004953 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004954 } else
4955 cur->content = NULL;
4956 break;
4957 case XML_DOCUMENT_NODE:
4958 case XML_DTD_NODE:
4959 case XML_HTML_DOCUMENT_NODE:
4960 case XML_DOCUMENT_TYPE_NODE:
4961 case XML_NAMESPACE_DECL:
4962 case XML_XINCLUDE_START:
4963 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004964#ifdef LIBXML_DOCB_ENABLED
4965 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004966#endif
4967 break;
4968 case XML_ELEMENT_DECL:
4969 /* TODO !!! */
4970 break;
4971 case XML_ATTRIBUTE_DECL:
4972 /* TODO !!! */
4973 break;
4974 case XML_ENTITY_DECL:
4975 /* TODO !!! */
4976 break;
4977 }
4978}
4979
4980/**
4981 * xmlNodeAddContentLen:
4982 * @cur: the node being modified
4983 * @content: extra content
4984 * @len: the size of @content
4985 *
4986 * Append the extra substring to the node content.
4987 */
4988void
4989xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4990 if (cur == NULL) {
4991#ifdef DEBUG_TREE
4992 xmlGenericError(xmlGenericErrorContext,
4993 "xmlNodeAddContentLen : node == NULL\n");
4994#endif
4995 return;
4996 }
4997 if (len <= 0) return;
4998 switch (cur->type) {
4999 case XML_DOCUMENT_FRAG_NODE:
5000 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005001 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005002
Daniel Veillard7db37732001-07-12 01:20:08 +00005003 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00005004 newNode = xmlNewTextLen(content, len);
5005 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00005006 tmp = xmlAddChild(cur, newNode);
5007 if (tmp != newNode)
5008 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005009 if ((last != NULL) && (last->next == newNode)) {
5010 xmlTextMerge(last, newNode);
5011 }
5012 }
5013 break;
5014 }
5015 case XML_ATTRIBUTE_NODE:
5016 break;
5017 case XML_TEXT_NODE:
5018 case XML_CDATA_SECTION_NODE:
5019 case XML_ENTITY_REF_NODE:
5020 case XML_ENTITY_NODE:
5021 case XML_PI_NODE:
5022 case XML_COMMENT_NODE:
5023 case XML_NOTATION_NODE:
5024 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005025 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005026 }
5027 case XML_DOCUMENT_NODE:
5028 case XML_DTD_NODE:
5029 case XML_HTML_DOCUMENT_NODE:
5030 case XML_DOCUMENT_TYPE_NODE:
5031 case XML_NAMESPACE_DECL:
5032 case XML_XINCLUDE_START:
5033 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005034#ifdef LIBXML_DOCB_ENABLED
5035 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005036#endif
5037 break;
5038 case XML_ELEMENT_DECL:
5039 case XML_ATTRIBUTE_DECL:
5040 case XML_ENTITY_DECL:
5041 break;
5042 }
5043}
5044
5045/**
5046 * xmlNodeAddContent:
5047 * @cur: the node being modified
5048 * @content: extra content
5049 *
5050 * Append the extra substring to the node content.
5051 */
5052void
5053xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5054 int len;
5055
5056 if (cur == NULL) {
5057#ifdef DEBUG_TREE
5058 xmlGenericError(xmlGenericErrorContext,
5059 "xmlNodeAddContent : node == NULL\n");
5060#endif
5061 return;
5062 }
5063 if (content == NULL) return;
5064 len = xmlStrlen(content);
5065 xmlNodeAddContentLen(cur, content, len);
5066}
5067
5068/**
5069 * xmlTextMerge:
5070 * @first: the first text node
5071 * @second: the second text node being merged
5072 *
5073 * Merge two text nodes into one
5074 * Returns the first text node augmented
5075 */
5076xmlNodePtr
5077xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5078 if (first == NULL) return(second);
5079 if (second == NULL) return(first);
5080 if (first->type != XML_TEXT_NODE) return(first);
5081 if (second->type != XML_TEXT_NODE) return(first);
5082 if (second->name != first->name)
5083 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005084 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005085 xmlUnlinkNode(second);
5086 xmlFreeNode(second);
5087 return(first);
5088}
5089
5090/**
5091 * xmlGetNsList:
5092 * @doc: the document
5093 * @node: the current node
5094 *
5095 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005096 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005097 * that need to be freed by the caller or NULL if no
5098 * namespace if defined
5099 */
5100xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005101xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5102{
Owen Taylor3473f882001-02-23 17:55:21 +00005103 xmlNsPtr cur;
5104 xmlNsPtr *ret = NULL;
5105 int nbns = 0;
5106 int maxns = 10;
5107 int i;
5108
5109 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005110 if (node->type == XML_ELEMENT_NODE) {
5111 cur = node->nsDef;
5112 while (cur != NULL) {
5113 if (ret == NULL) {
5114 ret =
5115 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5116 sizeof(xmlNsPtr));
5117 if (ret == NULL) {
5118 xmlGenericError(xmlGenericErrorContext,
5119 "xmlGetNsList : out of memory!\n");
5120 return (NULL);
5121 }
5122 ret[nbns] = NULL;
5123 }
5124 for (i = 0; i < nbns; i++) {
5125 if ((cur->prefix == ret[i]->prefix) ||
5126 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5127 break;
5128 }
5129 if (i >= nbns) {
5130 if (nbns >= maxns) {
5131 maxns *= 2;
5132 ret = (xmlNsPtr *) xmlRealloc(ret,
5133 (maxns +
5134 1) *
5135 sizeof(xmlNsPtr));
5136 if (ret == NULL) {
5137 xmlGenericError(xmlGenericErrorContext,
5138 "xmlGetNsList : realloc failed!\n");
5139 return (NULL);
5140 }
5141 }
5142 ret[nbns++] = cur;
5143 ret[nbns] = NULL;
5144 }
Owen Taylor3473f882001-02-23 17:55:21 +00005145
Daniel Veillard77044732001-06-29 21:31:07 +00005146 cur = cur->next;
5147 }
5148 }
5149 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005150 }
Daniel Veillard77044732001-06-29 21:31:07 +00005151 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005152}
5153
5154/**
5155 * xmlSearchNs:
5156 * @doc: the document
5157 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005158 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005159 *
5160 * Search a Ns registered under a given name space for a document.
5161 * recurse on the parents until it finds the defined namespace
5162 * or return NULL otherwise.
5163 * @nameSpace can be NULL, this is a search for the default namespace.
5164 * We don't allow to cross entities boundaries. If you don't declare
5165 * the namespace within those you will be in troubles !!! A warning
5166 * is generated to cover this case.
5167 *
5168 * Returns the namespace pointer or NULL.
5169 */
5170xmlNsPtr
5171xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
5172 xmlNsPtr cur;
5173
5174 if (node == NULL) return(NULL);
5175 if ((nameSpace != NULL) &&
5176 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005177 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5178 /*
5179 * The XML-1.0 namespace is normally held on the root
5180 * element. In this case exceptionally create it on the
5181 * node element.
5182 */
5183 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5184 if (cur == NULL) {
5185 xmlGenericError(xmlGenericErrorContext,
5186 "xmlSearchNs : malloc failed\n");
5187 return(NULL);
5188 }
5189 memset(cur, 0, sizeof(xmlNs));
5190 cur->type = XML_LOCAL_NAMESPACE;
5191 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5192 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5193 cur->next = node->nsDef;
5194 node->nsDef = cur;
5195 return(cur);
5196 }
Owen Taylor3473f882001-02-23 17:55:21 +00005197 if (doc->oldNs == NULL) {
5198 /*
5199 * Allocate a new Namespace and fill the fields.
5200 */
5201 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5202 if (doc->oldNs == NULL) {
5203 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005204 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005205 return(NULL);
5206 }
5207 memset(doc->oldNs, 0, sizeof(xmlNs));
5208 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5209
5210 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5211 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5212 }
5213 return(doc->oldNs);
5214 }
5215 while (node != NULL) {
5216 if ((node->type == XML_ENTITY_REF_NODE) ||
5217 (node->type == XML_ENTITY_NODE) ||
5218 (node->type == XML_ENTITY_DECL))
5219 return(NULL);
5220 if (node->type == XML_ELEMENT_NODE) {
5221 cur = node->nsDef;
5222 while (cur != NULL) {
5223 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5224 (cur->href != NULL))
5225 return(cur);
5226 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5227 (cur->href != NULL) &&
5228 (xmlStrEqual(cur->prefix, nameSpace)))
5229 return(cur);
5230 cur = cur->next;
5231 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005232 cur = node->ns;
5233 if (cur != NULL) {
5234 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5235 (cur->href != NULL))
5236 return(cur);
5237 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5238 (cur->href != NULL) &&
5239 (xmlStrEqual(cur->prefix, nameSpace)))
5240 return(cur);
5241 }
Owen Taylor3473f882001-02-23 17:55:21 +00005242 }
5243 node = node->parent;
5244 }
5245 return(NULL);
5246}
5247
5248/**
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005249 * xmlNsInScope:
5250 * @doc: the document
5251 * @node: the current node
5252 * @ancestor: the ancestor carrying the namespace
5253 * @prefix: the namespace prefix
5254 *
5255 * Verify that the given namespace held on @ancestor is still in scope
5256 * on node.
5257 *
5258 * Returns 1 if true, 0 if false and -1 in case of error.
5259 */
5260static int
Daniel Veillardbdbe0d42003-09-14 19:56:14 +00005261xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5262 xmlNodePtr ancestor, const xmlChar * prefix)
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005263{
5264 xmlNsPtr tst;
5265
5266 while ((node != NULL) && (node != ancestor)) {
5267 if ((node->type == XML_ENTITY_REF_NODE) ||
5268 (node->type == XML_ENTITY_NODE) ||
5269 (node->type == XML_ENTITY_DECL))
5270 return (-1);
5271 if (node->type == XML_ELEMENT_NODE) {
5272 tst = node->nsDef;
5273 while (tst != NULL) {
5274 if ((tst->prefix == NULL)
5275 && (prefix == NULL))
5276 return (0);
5277 if ((tst->prefix != NULL)
5278 && (prefix != NULL)
5279 && (xmlStrEqual(tst->prefix, prefix)))
5280 return (0);
5281 tst = tst->next;
5282 }
5283 }
5284 node = node->parent;
5285 }
5286 if (node != ancestor)
5287 return (-1);
5288 return (1);
5289}
5290
5291
5292/**
Owen Taylor3473f882001-02-23 17:55:21 +00005293 * xmlSearchNsByHref:
5294 * @doc: the document
5295 * @node: the current node
5296 * @href: the namespace value
5297 *
5298 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5299 * the defined namespace or return NULL otherwise.
5300 * Returns the namespace pointer or NULL.
5301 */
5302xmlNsPtr
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005303xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5304{
Owen Taylor3473f882001-02-23 17:55:21 +00005305 xmlNsPtr cur;
5306 xmlNodePtr orig = node;
5307
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005308 if ((node == NULL) || (href == NULL))
5309 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005310 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005311 /*
5312 * Only the document can hold the XML spec namespace.
5313 */
5314 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5315 /*
5316 * The XML-1.0 namespace is normally held on the root
5317 * element. In this case exceptionally create it on the
5318 * node element.
5319 */
5320 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5321 if (cur == NULL) {
5322 xmlGenericError(xmlGenericErrorContext,
5323 "xmlSearchNs : malloc failed\n");
5324 return (NULL);
5325 }
5326 memset(cur, 0, sizeof(xmlNs));
5327 cur->type = XML_LOCAL_NAMESPACE;
5328 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5329 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5330 cur->next = node->nsDef;
5331 node->nsDef = cur;
5332 return (cur);
5333 }
5334 if (doc->oldNs == NULL) {
5335 /*
5336 * Allocate a new Namespace and fill the fields.
5337 */
5338 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5339 if (doc->oldNs == NULL) {
5340 xmlGenericError(xmlGenericErrorContext,
5341 "xmlSearchNsByHref : malloc failed\n");
5342 return (NULL);
5343 }
5344 memset(doc->oldNs, 0, sizeof(xmlNs));
5345 doc->oldNs->type = XML_LOCAL_NAMESPACE;
Owen Taylor3473f882001-02-23 17:55:21 +00005346
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005347 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5348 doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml");
5349 }
5350 return (doc->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005351 }
5352 while (node != NULL) {
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005353 if ((node->type == XML_ENTITY_REF_NODE) ||
5354 (node->type == XML_ENTITY_NODE) ||
5355 (node->type == XML_ENTITY_DECL))
5356 return (NULL);
5357 if (node->type == XML_ELEMENT_NODE) {
5358 cur = node->nsDef;
5359 while (cur != NULL) {
5360 if ((cur->href != NULL) && (href != NULL) &&
5361 (xmlStrEqual(cur->href, href))) {
5362 if (xmlNsInScope(doc, orig, node, cur->href) == 1)
5363 return (cur);
5364 }
5365 cur = cur->next;
5366 }
5367 cur = node->ns;
5368 if (cur != NULL) {
5369 if ((cur->href != NULL) && (href != NULL) &&
5370 (xmlStrEqual(cur->href, href))) {
5371 if (xmlNsInScope(doc, orig, node, cur->href) == 1)
5372 return (cur);
5373 }
5374 }
5375 }
5376 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005377 }
Daniel Veillard2a3fea32003-09-12 09:44:56 +00005378 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005379}
5380
5381/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005382 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005383 * @doc: the document
5384 * @tree: a node expected to hold the new namespace
5385 * @ns: the original namespace
5386 *
5387 * This function tries to locate a namespace definition in a tree
5388 * ancestors, or create a new namespace definition node similar to
5389 * @ns trying to reuse the same prefix. However if the given prefix is
5390 * null (default namespace) or reused within the subtree defined by
5391 * @tree or on one of its ancestors then a new prefix is generated.
5392 * Returns the (new) namespace definition or NULL in case of error
5393 */
5394xmlNsPtr
5395xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5396 xmlNsPtr def;
5397 xmlChar prefix[50];
5398 int counter = 1;
5399
5400 if (tree == NULL) {
5401#ifdef DEBUG_TREE
5402 xmlGenericError(xmlGenericErrorContext,
5403 "xmlNewReconciliedNs : tree == NULL\n");
5404#endif
5405 return(NULL);
5406 }
5407 if (ns == NULL) {
5408#ifdef DEBUG_TREE
5409 xmlGenericError(xmlGenericErrorContext,
5410 "xmlNewReconciliedNs : ns == NULL\n");
5411#endif
5412 return(NULL);
5413 }
5414 /*
5415 * Search an existing namespace definition inherited.
5416 */
5417 def = xmlSearchNsByHref(doc, tree, ns->href);
5418 if (def != NULL)
5419 return(def);
5420
5421 /*
5422 * Find a close prefix which is not already in use.
5423 * Let's strip namespace prefixes longer than 20 chars !
5424 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005425 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005426 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005427 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005428 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005429
Owen Taylor3473f882001-02-23 17:55:21 +00005430 def = xmlSearchNs(doc, tree, prefix);
5431 while (def != NULL) {
5432 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005433 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005434 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005435 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005436 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005437 def = xmlSearchNs(doc, tree, prefix);
5438 }
5439
5440 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005441 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005442 */
5443 def = xmlNewNs(tree, ns->href, prefix);
5444 return(def);
5445}
5446
5447/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005448 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005449 * @doc: the document
5450 * @tree: a node defining the subtree to reconciliate
5451 *
5452 * This function checks that all the namespaces declared within the given
5453 * tree are properly declared. This is needed for example after Copy or Cut
5454 * and then paste operations. The subtree may still hold pointers to
5455 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005456 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005457 * the new environment. If not possible the new namespaces are redeclared
5458 * on @tree at the top of the given subtree.
5459 * Returns the number of namespace declarations created or -1 in case of error.
5460 */
5461int
5462xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5463 xmlNsPtr *oldNs = NULL;
5464 xmlNsPtr *newNs = NULL;
5465 int sizeCache = 0;
5466 int nbCache = 0;
5467
5468 xmlNsPtr n;
5469 xmlNodePtr node = tree;
5470 xmlAttrPtr attr;
5471 int ret = 0, i;
5472
5473 while (node != NULL) {
5474 /*
5475 * Reconciliate the node namespace
5476 */
5477 if (node->ns != NULL) {
5478 /*
5479 * initialize the cache if needed
5480 */
5481 if (sizeCache == 0) {
5482 sizeCache = 10;
5483 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5484 sizeof(xmlNsPtr));
5485 if (oldNs == NULL) {
5486 xmlGenericError(xmlGenericErrorContext,
5487 "xmlReconciliateNs : memory pbm\n");
5488 return(-1);
5489 }
5490 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5491 sizeof(xmlNsPtr));
5492 if (newNs == NULL) {
5493 xmlGenericError(xmlGenericErrorContext,
5494 "xmlReconciliateNs : memory pbm\n");
5495 xmlFree(oldNs);
5496 return(-1);
5497 }
5498 }
5499 for (i = 0;i < nbCache;i++) {
5500 if (oldNs[i] == node->ns) {
5501 node->ns = newNs[i];
5502 break;
5503 }
5504 }
5505 if (i == nbCache) {
5506 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005507 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005508 */
5509 n = xmlNewReconciliedNs(doc, tree, node->ns);
5510 if (n != NULL) { /* :-( what if else ??? */
5511 /*
5512 * check if we need to grow the cache buffers.
5513 */
5514 if (sizeCache <= nbCache) {
5515 sizeCache *= 2;
5516 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5517 sizeof(xmlNsPtr));
5518 if (oldNs == NULL) {
5519 xmlGenericError(xmlGenericErrorContext,
5520 "xmlReconciliateNs : memory pbm\n");
5521 xmlFree(newNs);
5522 return(-1);
5523 }
5524 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5525 sizeof(xmlNsPtr));
5526 if (newNs == NULL) {
5527 xmlGenericError(xmlGenericErrorContext,
5528 "xmlReconciliateNs : memory pbm\n");
5529 xmlFree(oldNs);
5530 return(-1);
5531 }
5532 }
5533 newNs[nbCache] = n;
5534 oldNs[nbCache++] = node->ns;
5535 node->ns = n;
5536 }
5537 }
5538 }
5539 /*
5540 * now check for namespace hold by attributes on the node.
5541 */
5542 attr = node->properties;
5543 while (attr != NULL) {
5544 if (attr->ns != NULL) {
5545 /*
5546 * initialize the cache if needed
5547 */
5548 if (sizeCache == 0) {
5549 sizeCache = 10;
5550 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5551 sizeof(xmlNsPtr));
5552 if (oldNs == NULL) {
5553 xmlGenericError(xmlGenericErrorContext,
5554 "xmlReconciliateNs : memory pbm\n");
5555 return(-1);
5556 }
5557 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5558 sizeof(xmlNsPtr));
5559 if (newNs == NULL) {
5560 xmlGenericError(xmlGenericErrorContext,
5561 "xmlReconciliateNs : memory pbm\n");
5562 xmlFree(oldNs);
5563 return(-1);
5564 }
5565 }
5566 for (i = 0;i < nbCache;i++) {
5567 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005568 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005569 break;
5570 }
5571 }
5572 if (i == nbCache) {
5573 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005574 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005575 */
5576 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5577 if (n != NULL) { /* :-( what if else ??? */
5578 /*
5579 * check if we need to grow the cache buffers.
5580 */
5581 if (sizeCache <= nbCache) {
5582 sizeCache *= 2;
5583 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5584 sizeof(xmlNsPtr));
5585 if (oldNs == NULL) {
5586 xmlGenericError(xmlGenericErrorContext,
5587 "xmlReconciliateNs : memory pbm\n");
5588 xmlFree(newNs);
5589 return(-1);
5590 }
5591 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5592 sizeof(xmlNsPtr));
5593 if (newNs == NULL) {
5594 xmlGenericError(xmlGenericErrorContext,
5595 "xmlReconciliateNs : memory pbm\n");
5596 xmlFree(oldNs);
5597 return(-1);
5598 }
5599 }
5600 newNs[nbCache] = n;
5601 oldNs[nbCache++] = attr->ns;
5602 attr->ns = n;
5603 }
5604 }
5605 }
5606 attr = attr->next;
5607 }
5608
5609 /*
5610 * Browse the full subtree, deep first
5611 */
5612 if (node->children != NULL) {
5613 /* deep first */
5614 node = node->children;
5615 } else if ((node != tree) && (node->next != NULL)) {
5616 /* then siblings */
5617 node = node->next;
5618 } else if (node != tree) {
5619 /* go up to parents->next if needed */
5620 while (node != tree) {
5621 if (node->parent != NULL)
5622 node = node->parent;
5623 if ((node != tree) && (node->next != NULL)) {
5624 node = node->next;
5625 break;
5626 }
5627 if (node->parent == NULL) {
5628 node = NULL;
5629 break;
5630 }
5631 }
5632 /* exit condition */
5633 if (node == tree)
5634 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005635 } else
5636 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005637 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005638 if (oldNs != NULL)
5639 xmlFree(oldNs);
5640 if (newNs != NULL)
5641 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005642 return(ret);
5643}
5644
5645/**
5646 * xmlHasProp:
5647 * @node: the node
5648 * @name: the attribute name
5649 *
5650 * Search an attribute associated to a node
5651 * This function also looks in DTD attribute declaration for #FIXED or
5652 * default declaration values unless DTD use has been turned off.
5653 *
5654 * Returns the attribute or the attribute declaration or NULL if
5655 * neither was found.
5656 */
5657xmlAttrPtr
5658xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5659 xmlAttrPtr prop;
5660 xmlDocPtr doc;
5661
5662 if ((node == NULL) || (name == NULL)) return(NULL);
5663 /*
5664 * Check on the properties attached to the node
5665 */
5666 prop = node->properties;
5667 while (prop != NULL) {
5668 if (xmlStrEqual(prop->name, name)) {
5669 return(prop);
5670 }
5671 prop = prop->next;
5672 }
5673 if (!xmlCheckDTD) return(NULL);
5674
5675 /*
5676 * Check if there is a default declaration in the internal
5677 * or external subsets
5678 */
5679 doc = node->doc;
5680 if (doc != NULL) {
5681 xmlAttributePtr attrDecl;
5682 if (doc->intSubset != NULL) {
5683 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5684 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5685 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005686 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5687 /* return attribute declaration only if a default value is given
5688 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005689 return((xmlAttrPtr) attrDecl);
5690 }
5691 }
5692 return(NULL);
5693}
5694
5695/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005696 * xmlHasNsProp:
5697 * @node: the node
5698 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005699 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005700 *
5701 * Search for an attribute associated to a node
5702 * This attribute has to be anchored in the namespace specified.
5703 * This does the entity substitution.
5704 * This function looks in DTD attribute declaration for #FIXED or
5705 * default declaration values unless DTD use has been turned off.
5706 *
5707 * Returns the attribute or the attribute declaration or NULL
5708 * if neither was found.
5709 */
5710xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005711xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005712 xmlAttrPtr prop;
5713 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005714
5715 if (node == NULL)
5716 return(NULL);
5717
5718 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005719 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005720 return(xmlHasProp(node, name));
5721 while (prop != NULL) {
5722 /*
5723 * One need to have
5724 * - same attribute names
5725 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005726 */
5727 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005728 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5729 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005730 }
5731 prop = prop->next;
5732 }
5733 if (!xmlCheckDTD) return(NULL);
5734
5735 /*
5736 * Check if there is a default declaration in the internal
5737 * or external subsets
5738 */
5739 doc = node->doc;
5740 if (doc != NULL) {
5741 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005742 xmlAttributePtr attrDecl = NULL;
5743 xmlNsPtr *nsList, *cur;
5744 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005745
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005746 nsList = xmlGetNsList(node->doc, node);
5747 if (nsList == NULL)
5748 return(NULL);
5749 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5750 ename = xmlStrdup(node->ns->prefix);
5751 ename = xmlStrcat(ename, BAD_CAST ":");
5752 ename = xmlStrcat(ename, node->name);
5753 } else {
5754 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005755 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005756 if (ename == NULL) {
5757 xmlFree(nsList);
5758 return(NULL);
5759 }
5760
5761 cur = nsList;
5762 while (*cur != NULL) {
5763 if (xmlStrEqual((*cur)->href, nameSpace)) {
5764 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5765 name, (*cur)->prefix);
5766 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5767 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5768 name, (*cur)->prefix);
5769 }
5770 cur++;
5771 }
5772 xmlFree(nsList);
5773 xmlFree(ename);
5774 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005775 }
5776 }
5777 return(NULL);
5778}
5779
5780/**
Owen Taylor3473f882001-02-23 17:55:21 +00005781 * xmlGetProp:
5782 * @node: the node
5783 * @name: the attribute name
5784 *
5785 * Search and get the value of an attribute associated to a node
5786 * This does the entity substitution.
5787 * This function looks in DTD attribute declaration for #FIXED or
5788 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00005789 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00005790 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
5791 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00005792 *
5793 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005794 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005795 */
5796xmlChar *
5797xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5798 xmlAttrPtr prop;
5799 xmlDocPtr doc;
5800
5801 if ((node == NULL) || (name == NULL)) return(NULL);
5802 /*
5803 * Check on the properties attached to the node
5804 */
5805 prop = node->properties;
5806 while (prop != NULL) {
5807 if (xmlStrEqual(prop->name, name)) {
5808 xmlChar *ret;
5809
5810 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5811 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5812 return(ret);
5813 }
5814 prop = prop->next;
5815 }
5816 if (!xmlCheckDTD) return(NULL);
5817
5818 /*
5819 * Check if there is a default declaration in the internal
5820 * or external subsets
5821 */
5822 doc = node->doc;
5823 if (doc != NULL) {
5824 xmlAttributePtr attrDecl;
5825 if (doc->intSubset != NULL) {
5826 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5827 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5828 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005829 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5830 /* return attribute declaration only if a default value is given
5831 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005832 return(xmlStrdup(attrDecl->defaultValue));
5833 }
5834 }
5835 return(NULL);
5836}
5837
5838/**
Daniel Veillard71531f32003-02-05 13:19:53 +00005839 * xmlGetNoNsProp:
5840 * @node: the node
5841 * @name: the attribute name
5842 *
5843 * Search and get the value of an attribute associated to a node
5844 * This does the entity substitution.
5845 * This function looks in DTD attribute declaration for #FIXED or
5846 * default declaration values unless DTD use has been turned off.
5847 * This function is similar to xmlGetProp except it will accept only
5848 * an attribute in no namespace.
5849 *
5850 * Returns the attribute value or NULL if not found.
5851 * It's up to the caller to free the memory with xmlFree().
5852 */
5853xmlChar *
5854xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
5855 xmlAttrPtr prop;
5856 xmlDocPtr doc;
5857
5858 if ((node == NULL) || (name == NULL)) return(NULL);
5859 /*
5860 * Check on the properties attached to the node
5861 */
5862 prop = node->properties;
5863 while (prop != NULL) {
5864 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
5865 xmlChar *ret;
5866
5867 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5868 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5869 return(ret);
5870 }
5871 prop = prop->next;
5872 }
5873 if (!xmlCheckDTD) return(NULL);
5874
5875 /*
5876 * Check if there is a default declaration in the internal
5877 * or external subsets
5878 */
5879 doc = node->doc;
5880 if (doc != NULL) {
5881 xmlAttributePtr attrDecl;
5882 if (doc->intSubset != NULL) {
5883 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5884 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5885 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005886 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5887 /* return attribute declaration only if a default value is given
5888 (that includes #FIXED declarations) */
Daniel Veillard71531f32003-02-05 13:19:53 +00005889 return(xmlStrdup(attrDecl->defaultValue));
5890 }
5891 }
5892 return(NULL);
5893}
5894
5895/**
Owen Taylor3473f882001-02-23 17:55:21 +00005896 * xmlGetNsProp:
5897 * @node: the node
5898 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005899 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005900 *
5901 * Search and get the value of an attribute associated to a node
5902 * This attribute has to be anchored in the namespace specified.
5903 * This does the entity substitution.
5904 * This function looks in DTD attribute declaration for #FIXED or
5905 * default declaration values unless DTD use has been turned off.
5906 *
5907 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005908 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005909 */
5910xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00005911xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00005912 xmlAttrPtr prop;
5913 xmlDocPtr doc;
5914 xmlNsPtr ns;
5915
5916 if (node == NULL)
5917 return(NULL);
5918
5919 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005920 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00005921 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00005922 while (prop != NULL) {
5923 /*
5924 * One need to have
5925 * - same attribute names
5926 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005927 */
5928 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00005929 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00005930 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005931 xmlChar *ret;
5932
5933 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5934 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5935 return(ret);
5936 }
5937 prop = prop->next;
5938 }
5939 if (!xmlCheckDTD) return(NULL);
5940
5941 /*
5942 * Check if there is a default declaration in the internal
5943 * or external subsets
5944 */
5945 doc = node->doc;
5946 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005947 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00005948 xmlAttributePtr attrDecl;
5949
Owen Taylor3473f882001-02-23 17:55:21 +00005950 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5951 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5952 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5953
5954 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
5955 /*
5956 * The DTD declaration only allows a prefix search
5957 */
5958 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00005959 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00005960 return(xmlStrdup(attrDecl->defaultValue));
5961 }
5962 }
5963 }
5964 return(NULL);
5965}
5966
5967/**
5968 * xmlSetProp:
5969 * @node: the node
5970 * @name: the attribute name
5971 * @value: the attribute value
5972 *
5973 * Set (or reset) an attribute carried by a node.
5974 * Returns the attribute pointer.
5975 */
5976xmlAttrPtr
5977xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005978 xmlAttrPtr prop;
5979 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00005980
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00005981 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00005982 return(NULL);
5983 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005984 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00005985 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005986 if ((xmlStrEqual(prop->name, name)) &&
5987 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005988 xmlNodePtr oldprop = prop->children;
5989
Owen Taylor3473f882001-02-23 17:55:21 +00005990 prop->children = NULL;
5991 prop->last = NULL;
5992 if (value != NULL) {
5993 xmlChar *buffer;
5994 xmlNodePtr tmp;
5995
5996 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5997 prop->children = xmlStringGetNodeList(node->doc, buffer);
5998 prop->last = NULL;
5999 prop->doc = doc;
6000 tmp = prop->children;
6001 while (tmp != NULL) {
6002 tmp->parent = (xmlNodePtr) prop;
6003 tmp->doc = doc;
6004 if (tmp->next == NULL)
6005 prop->last = tmp;
6006 tmp = tmp->next;
6007 }
6008 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00006009 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00006010 if (oldprop != NULL)
6011 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00006012 return(prop);
6013 }
6014 prop = prop->next;
6015 }
6016 prop = xmlNewProp(node, name, value);
6017 return(prop);
6018}
6019
6020/**
Daniel Veillard75bea542001-05-11 17:41:21 +00006021 * xmlUnsetProp:
6022 * @node: the node
6023 * @name: the attribute name
6024 *
6025 * Remove an attribute carried by a node.
6026 * Returns 0 if successful, -1 if not found
6027 */
6028int
6029xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Daniel Veillard814a76d2003-01-23 18:24:20 +00006030 xmlAttrPtr prop, prev = NULL;;
Daniel Veillard75bea542001-05-11 17:41:21 +00006031
6032 if ((node == NULL) || (name == NULL))
6033 return(-1);
Daniel Veillard814a76d2003-01-23 18:24:20 +00006034 prop = node->properties;
Daniel Veillard75bea542001-05-11 17:41:21 +00006035 while (prop != NULL) {
6036 if ((xmlStrEqual(prop->name, name)) &&
6037 (prop->ns == NULL)) {
6038 if (prev == NULL)
6039 node->properties = prop->next;
6040 else
6041 prev->next = prop->next;
6042 xmlFreeProp(prop);
6043 return(0);
6044 }
6045 prev = prop;
6046 prop = prop->next;
6047 }
6048 return(-1);
6049}
6050
6051/**
Owen Taylor3473f882001-02-23 17:55:21 +00006052 * xmlSetNsProp:
6053 * @node: the node
6054 * @ns: the namespace definition
6055 * @name: the attribute name
6056 * @value: the attribute value
6057 *
6058 * Set (or reset) an attribute carried by a node.
6059 * The ns structure must be in scope, this is not checked.
6060 *
6061 * Returns the attribute pointer.
6062 */
6063xmlAttrPtr
6064xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
6065 const xmlChar *value) {
6066 xmlAttrPtr prop;
6067
6068 if ((node == NULL) || (name == NULL))
6069 return(NULL);
6070
6071 if (ns == NULL)
6072 return(xmlSetProp(node, name, value));
6073 if (ns->href == NULL)
6074 return(NULL);
6075 prop = node->properties;
6076
6077 while (prop != NULL) {
6078 /*
6079 * One need to have
6080 * - same attribute names
6081 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006082 */
6083 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00006084 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006085 if (prop->children != NULL)
6086 xmlFreeNodeList(prop->children);
6087 prop->children = NULL;
6088 prop->last = NULL;
6089 prop->ns = ns;
6090 if (value != NULL) {
6091 xmlChar *buffer;
6092 xmlNodePtr tmp;
6093
6094 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6095 prop->children = xmlStringGetNodeList(node->doc, buffer);
6096 prop->last = NULL;
6097 tmp = prop->children;
6098 while (tmp != NULL) {
6099 tmp->parent = (xmlNodePtr) prop;
6100 if (tmp->next == NULL)
6101 prop->last = tmp;
6102 tmp = tmp->next;
6103 }
6104 xmlFree(buffer);
6105 }
6106 return(prop);
6107 }
6108 prop = prop->next;
6109 }
6110 prop = xmlNewNsProp(node, ns, name, value);
6111 return(prop);
6112}
6113
6114/**
Daniel Veillard75bea542001-05-11 17:41:21 +00006115 * xmlUnsetNsProp:
6116 * @node: the node
6117 * @ns: the namespace definition
6118 * @name: the attribute name
6119 *
6120 * Remove an attribute carried by a node.
6121 * Returns 0 if successful, -1 if not found
6122 */
6123int
6124xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
6125 xmlAttrPtr prop = node->properties, prev = NULL;;
6126
6127 if ((node == NULL) || (name == NULL))
6128 return(-1);
6129 if (ns == NULL)
6130 return(xmlUnsetProp(node, name));
6131 if (ns->href == NULL)
6132 return(-1);
6133 while (prop != NULL) {
6134 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00006135 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006136 if (prev == NULL)
6137 node->properties = prop->next;
6138 else
6139 prev->next = prop->next;
6140 xmlFreeProp(prop);
6141 return(0);
6142 }
6143 prev = prop;
6144 prop = prop->next;
6145 }
6146 return(-1);
6147}
6148
6149/**
Owen Taylor3473f882001-02-23 17:55:21 +00006150 * xmlNodeIsText:
6151 * @node: the node
6152 *
6153 * Is this node a Text node ?
6154 * Returns 1 yes, 0 no
6155 */
6156int
6157xmlNodeIsText(xmlNodePtr node) {
6158 if (node == NULL) return(0);
6159
6160 if (node->type == XML_TEXT_NODE) return(1);
6161 return(0);
6162}
6163
6164/**
6165 * xmlIsBlankNode:
6166 * @node: the node
6167 *
6168 * Checks whether this node is an empty or whitespace only
6169 * (and possibly ignorable) text-node.
6170 *
6171 * Returns 1 yes, 0 no
6172 */
6173int
6174xmlIsBlankNode(xmlNodePtr node) {
6175 const xmlChar *cur;
6176 if (node == NULL) return(0);
6177
Daniel Veillard7db37732001-07-12 01:20:08 +00006178 if ((node->type != XML_TEXT_NODE) &&
6179 (node->type != XML_CDATA_SECTION_NODE))
6180 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006181 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006182 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006183 while (*cur != 0) {
6184 if (!IS_BLANK(*cur)) return(0);
6185 cur++;
6186 }
6187
6188 return(1);
6189}
6190
6191/**
6192 * xmlTextConcat:
6193 * @node: the node
6194 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006195 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006196 *
6197 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006198 *
6199 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006200 */
6201
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006202int
Owen Taylor3473f882001-02-23 17:55:21 +00006203xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006204 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006205
6206 if ((node->type != XML_TEXT_NODE) &&
6207 (node->type != XML_CDATA_SECTION_NODE)) {
6208#ifdef DEBUG_TREE
6209 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006210 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006211#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006212 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006213 }
Owen Taylor3473f882001-02-23 17:55:21 +00006214 node->content = xmlStrncat(node->content, content, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006215 if (node->content == NULL)
6216 return(-1);
6217 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006218}
6219
6220/************************************************************************
6221 * *
6222 * Output : to a FILE or in memory *
6223 * *
6224 ************************************************************************/
6225
Owen Taylor3473f882001-02-23 17:55:21 +00006226/**
6227 * xmlBufferCreate:
6228 *
6229 * routine to create an XML buffer.
6230 * returns the new structure.
6231 */
6232xmlBufferPtr
6233xmlBufferCreate(void) {
6234 xmlBufferPtr ret;
6235
6236 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6237 if (ret == NULL) {
6238 xmlGenericError(xmlGenericErrorContext,
6239 "xmlBufferCreate : out of memory!\n");
6240 return(NULL);
6241 }
6242 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006243 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006244 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006245 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006246 if (ret->content == NULL) {
6247 xmlGenericError(xmlGenericErrorContext,
6248 "xmlBufferCreate : out of memory!\n");
6249 xmlFree(ret);
6250 return(NULL);
6251 }
6252 ret->content[0] = 0;
6253 return(ret);
6254}
6255
6256/**
6257 * xmlBufferCreateSize:
6258 * @size: initial size of buffer
6259 *
6260 * routine to create an XML buffer.
6261 * returns the new structure.
6262 */
6263xmlBufferPtr
6264xmlBufferCreateSize(size_t size) {
6265 xmlBufferPtr ret;
6266
6267 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6268 if (ret == NULL) {
6269 xmlGenericError(xmlGenericErrorContext,
6270 "xmlBufferCreate : out of memory!\n");
6271 return(NULL);
6272 }
6273 ret->use = 0;
6274 ret->alloc = xmlBufferAllocScheme;
6275 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6276 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006277 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006278 if (ret->content == NULL) {
6279 xmlGenericError(xmlGenericErrorContext,
6280 "xmlBufferCreate : out of memory!\n");
6281 xmlFree(ret);
6282 return(NULL);
6283 }
6284 ret->content[0] = 0;
6285 } else
6286 ret->content = NULL;
6287 return(ret);
6288}
6289
6290/**
Daniel Veillard53350552003-09-18 13:35:51 +00006291 * xmlBufferCreateStatic:
6292 * @mem: the memory area
6293 * @size: the size in byte
6294 *
6295 * routine to create an XML buffer from an immutable memory area,
6296 * The are won't be modified nor copied, and is expected to be
6297 * present until the end of the buffer lifetime.
6298 *
6299 * returns the new structure.
6300 */
6301xmlBufferPtr
6302xmlBufferCreateStatic(void *mem, size_t size) {
6303 xmlBufferPtr ret;
6304
6305 if ((mem == NULL) || (size == 0))
6306 return(NULL);
6307
6308 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6309 if (ret == NULL) {
6310 xmlGenericError(xmlGenericErrorContext,
6311 "xmlBufferCreate : out of memory!\n");
6312 return(NULL);
6313 }
6314 ret->use = size;
6315 ret->size = size;
6316 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6317 ret->content = (xmlChar *) mem;
6318 return(ret);
6319}
6320
6321/**
Owen Taylor3473f882001-02-23 17:55:21 +00006322 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006323 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006324 * @scheme: allocation scheme to use
6325 *
6326 * Sets the allocation scheme for this buffer
6327 */
6328void
6329xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6330 xmlBufferAllocationScheme scheme) {
6331 if (buf == NULL) {
6332#ifdef DEBUG_BUFFER
6333 xmlGenericError(xmlGenericErrorContext,
6334 "xmlBufferSetAllocationScheme: buf == NULL\n");
6335#endif
6336 return;
6337 }
Daniel Veillard53350552003-09-18 13:35:51 +00006338 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006339
6340 buf->alloc = scheme;
6341}
6342
6343/**
6344 * xmlBufferFree:
6345 * @buf: the buffer to free
6346 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006347 * Frees an XML buffer. It frees both the content and the structure which
6348 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006349 */
6350void
6351xmlBufferFree(xmlBufferPtr buf) {
6352 if (buf == NULL) {
6353#ifdef DEBUG_BUFFER
6354 xmlGenericError(xmlGenericErrorContext,
6355 "xmlBufferFree: buf == NULL\n");
6356#endif
6357 return;
6358 }
Daniel Veillard53350552003-09-18 13:35:51 +00006359
6360 if ((buf->content != NULL) &&
6361 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006362 xmlFree(buf->content);
6363 }
Owen Taylor3473f882001-02-23 17:55:21 +00006364 xmlFree(buf);
6365}
6366
6367/**
6368 * xmlBufferEmpty:
6369 * @buf: the buffer
6370 *
6371 * empty a buffer.
6372 */
6373void
6374xmlBufferEmpty(xmlBufferPtr buf) {
6375 if (buf->content == NULL) return;
6376 buf->use = 0;
Daniel Veillard53350552003-09-18 13:35:51 +00006377 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
Daniel Veillard16fa96c2003-09-23 21:50:54 +00006378 buf->content = BAD_CAST "";
Daniel Veillard53350552003-09-18 13:35:51 +00006379 } else {
6380 memset(buf->content, 0, buf->size);
6381 }
Owen Taylor3473f882001-02-23 17:55:21 +00006382}
6383
6384/**
6385 * xmlBufferShrink:
6386 * @buf: the buffer to dump
6387 * @len: the number of xmlChar to remove
6388 *
6389 * Remove the beginning of an XML buffer.
6390 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006391 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006392 */
6393int
6394xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
6395 if (len == 0) return(0);
6396 if (len > buf->use) return(-1);
6397
6398 buf->use -= len;
Daniel Veillard53350552003-09-18 13:35:51 +00006399 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6400 buf->content += len;
6401 } else {
6402 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6403 buf->content[buf->use] = 0;
6404 }
Owen Taylor3473f882001-02-23 17:55:21 +00006405 return(len);
6406}
6407
6408/**
6409 * xmlBufferGrow:
6410 * @buf: the buffer
6411 * @len: the minimum free size to allocate
6412 *
6413 * Grow the available space of an XML buffer.
6414 *
6415 * Returns the new available space or -1 in case of error
6416 */
6417int
6418xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6419 int size;
6420 xmlChar *newbuf;
6421
Daniel Veillard53350552003-09-18 13:35:51 +00006422 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006423 if (len + buf->use < buf->size) return(0);
6424
6425 size = buf->use + len + 100;
6426
6427 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
6428 if (newbuf == NULL) return(-1);
6429 buf->content = newbuf;
6430 buf->size = size;
6431 return(buf->size - buf->use);
6432}
6433
6434/**
6435 * xmlBufferDump:
6436 * @file: the file output
6437 * @buf: the buffer to dump
6438 *
6439 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006440 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006441 */
6442int
6443xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6444 int ret;
6445
6446 if (buf == NULL) {
6447#ifdef DEBUG_BUFFER
6448 xmlGenericError(xmlGenericErrorContext,
6449 "xmlBufferDump: buf == NULL\n");
6450#endif
6451 return(0);
6452 }
6453 if (buf->content == NULL) {
6454#ifdef DEBUG_BUFFER
6455 xmlGenericError(xmlGenericErrorContext,
6456 "xmlBufferDump: buf->content == NULL\n");
6457#endif
6458 return(0);
6459 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006460 if (file == NULL)
6461 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006462 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6463 return(ret);
6464}
6465
6466/**
6467 * xmlBufferContent:
6468 * @buf: the buffer
6469 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006470 * Function to extract the content of a buffer
6471 *
Owen Taylor3473f882001-02-23 17:55:21 +00006472 * Returns the internal content
6473 */
6474
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006475const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006476xmlBufferContent(const xmlBufferPtr buf)
6477{
6478 if(!buf)
6479 return NULL;
6480
6481 return buf->content;
6482}
6483
6484/**
6485 * xmlBufferLength:
6486 * @buf: the buffer
6487 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006488 * Function to get the length of a buffer
6489 *
Owen Taylor3473f882001-02-23 17:55:21 +00006490 * Returns the length of data in the internal content
6491 */
6492
6493int
6494xmlBufferLength(const xmlBufferPtr buf)
6495{
6496 if(!buf)
6497 return 0;
6498
6499 return buf->use;
6500}
6501
6502/**
6503 * xmlBufferResize:
6504 * @buf: the buffer to resize
6505 * @size: the desired size
6506 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006507 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006508 *
6509 * Returns 0 in case of problems, 1 otherwise
6510 */
6511int
6512xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6513{
6514 unsigned int newSize;
6515 xmlChar* rebuf = NULL;
6516
Daniel Veillard53350552003-09-18 13:35:51 +00006517 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6518
Owen Taylor3473f882001-02-23 17:55:21 +00006519 /*take care of empty case*/
6520 newSize = (buf->size ? buf->size*2 : size);
6521
6522 /* Don't resize if we don't have to */
6523 if (size < buf->size)
6524 return 1;
6525
6526 /* figure out new size */
6527 switch (buf->alloc){
6528 case XML_BUFFER_ALLOC_DOUBLEIT:
6529 while (size > newSize) newSize *= 2;
6530 break;
6531 case XML_BUFFER_ALLOC_EXACT:
6532 newSize = size+10;
6533 break;
6534 default:
6535 newSize = size+10;
6536 break;
6537 }
6538
6539 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006540 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006541 else if (buf->size - buf->use < 100) {
Owen Taylor3473f882001-02-23 17:55:21 +00006542 rebuf = (xmlChar *) xmlRealloc(buf->content,
6543 newSize * sizeof(xmlChar));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006544 } else {
6545 /*
6546 * if we are reallocating a buffer far from being full, it's
6547 * better to make a new allocation and copy only the used range
6548 * and free the old one.
6549 */
6550 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6551 if (rebuf != NULL) {
6552 memcpy(rebuf, buf->content, buf->use);
6553 xmlFree(buf->content);
6554 }
Daniel Veillarde5984082003-08-19 22:21:13 +00006555 rebuf[buf->use] = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00006556 }
Owen Taylor3473f882001-02-23 17:55:21 +00006557 if (rebuf == NULL) {
6558 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006559 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006560 return 0;
6561 }
6562 buf->content = rebuf;
6563 buf->size = newSize;
6564
6565 return 1;
6566}
6567
6568/**
6569 * xmlBufferAdd:
6570 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006571 * @str: the #xmlChar string
6572 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006573 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006574 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006575 * str is recomputed.
6576 */
6577void
6578xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6579 unsigned int needSize;
6580
6581 if (str == NULL) {
6582#ifdef DEBUG_BUFFER
6583 xmlGenericError(xmlGenericErrorContext,
6584 "xmlBufferAdd: str == NULL\n");
6585#endif
6586 return;
6587 }
Daniel Veillard53350552003-09-18 13:35:51 +00006588 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006589 if (len < -1) {
6590#ifdef DEBUG_BUFFER
6591 xmlGenericError(xmlGenericErrorContext,
6592 "xmlBufferAdd: len < 0\n");
6593#endif
6594 return;
6595 }
6596 if (len == 0) return;
6597
6598 if (len < 0)
6599 len = xmlStrlen(str);
6600
6601 if (len <= 0) return;
6602
6603 needSize = buf->use + len + 2;
6604 if (needSize > buf->size){
6605 if (!xmlBufferResize(buf, needSize)){
6606 xmlGenericError(xmlGenericErrorContext,
6607 "xmlBufferAdd : out of memory!\n");
6608 return;
6609 }
6610 }
6611
6612 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6613 buf->use += len;
6614 buf->content[buf->use] = 0;
6615}
6616
6617/**
6618 * xmlBufferAddHead:
6619 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006620 * @str: the #xmlChar string
6621 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006622 *
6623 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006624 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00006625 */
6626void
6627xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6628 unsigned int needSize;
6629
Daniel Veillard53350552003-09-18 13:35:51 +00006630 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006631 if (str == NULL) {
6632#ifdef DEBUG_BUFFER
6633 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006634 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006635#endif
6636 return;
6637 }
6638 if (len < -1) {
6639#ifdef DEBUG_BUFFER
6640 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006641 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006642#endif
6643 return;
6644 }
6645 if (len == 0) return;
6646
6647 if (len < 0)
6648 len = xmlStrlen(str);
6649
6650 if (len <= 0) return;
6651
6652 needSize = buf->use + len + 2;
6653 if (needSize > buf->size){
6654 if (!xmlBufferResize(buf, needSize)){
6655 xmlGenericError(xmlGenericErrorContext,
6656 "xmlBufferAddHead : out of memory!\n");
6657 return;
6658 }
6659 }
6660
6661 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6662 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6663 buf->use += len;
6664 buf->content[buf->use] = 0;
6665}
6666
6667/**
6668 * xmlBufferCat:
6669 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006670 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006671 *
6672 * Append a zero terminated string to an XML buffer.
6673 */
6674void
6675xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillard53350552003-09-18 13:35:51 +00006676 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006677 if (str != NULL)
6678 xmlBufferAdd(buf, str, -1);
6679}
6680
6681/**
6682 * xmlBufferCCat:
6683 * @buf: the buffer to dump
6684 * @str: the C char string
6685 *
6686 * Append a zero terminated C string to an XML buffer.
6687 */
6688void
6689xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6690 const char *cur;
6691
Daniel Veillard53350552003-09-18 13:35:51 +00006692 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006693 if (str == NULL) {
6694#ifdef DEBUG_BUFFER
6695 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006696 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006697#endif
6698 return;
6699 }
6700 for (cur = str;*cur != 0;cur++) {
6701 if (buf->use + 10 >= buf->size) {
6702 if (!xmlBufferResize(buf, buf->use+10)){
6703 xmlGenericError(xmlGenericErrorContext,
6704 "xmlBufferCCat : out of memory!\n");
6705 return;
6706 }
6707 }
6708 buf->content[buf->use++] = *cur;
6709 }
6710 buf->content[buf->use] = 0;
6711}
6712
6713/**
6714 * xmlBufferWriteCHAR:
6715 * @buf: the XML buffer
6716 * @string: the string to add
6717 *
6718 * routine which manages and grows an output buffer. This one adds
6719 * xmlChars at the end of the buffer.
6720 */
6721void
Daniel Veillard53350552003-09-18 13:35:51 +00006722xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
6723 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006724 xmlBufferCat(buf, string);
6725}
6726
6727/**
6728 * xmlBufferWriteChar:
6729 * @buf: the XML buffer output
6730 * @string: the string to add
6731 *
6732 * routine which manage and grows an output buffer. This one add
6733 * C chars at the end of the array.
6734 */
6735void
6736xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
Daniel Veillard53350552003-09-18 13:35:51 +00006737 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006738 xmlBufferCCat(buf, string);
6739}
6740
6741
6742/**
6743 * xmlBufferWriteQuotedString:
6744 * @buf: the XML buffer output
6745 * @string: the string to add
6746 *
6747 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00006748 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00006749 * quote or double-quotes internally
6750 */
6751void
6752xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard39057f42003-08-04 01:33:43 +00006753 const xmlChar *cur, *base;
Daniel Veillard53350552003-09-18 13:35:51 +00006754 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
Daniel Veillard39057f42003-08-04 01:33:43 +00006755 if (xmlStrchr(string, '\"')) {
Daniel Veillard20aa0fb2003-08-04 19:43:15 +00006756 if (xmlStrchr(string, '\'')) {
Owen Taylor3473f882001-02-23 17:55:21 +00006757#ifdef DEBUG_BUFFER
6758 xmlGenericError(xmlGenericErrorContext,
6759 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
6760#endif
Daniel Veillard39057f42003-08-04 01:33:43 +00006761 xmlBufferCCat(buf, "\"");
6762 base = cur = string;
6763 while(*cur != 0){
6764 if(*cur == '"'){
6765 if (base != cur)
6766 xmlBufferAdd(buf, base, cur - base);
6767 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6768 cur++;
6769 base = cur;
6770 }
6771 else {
6772 cur++;
6773 }
6774 }
6775 if (base != cur)
6776 xmlBufferAdd(buf, base, cur - base);
6777 xmlBufferCCat(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006778 }
Daniel Veillard39057f42003-08-04 01:33:43 +00006779 else{
6780 xmlBufferCCat(buf, "\'");
6781 xmlBufferCat(buf, string);
6782 xmlBufferCCat(buf, "\'");
6783 }
Owen Taylor3473f882001-02-23 17:55:21 +00006784 } else {
6785 xmlBufferCCat(buf, "\"");
6786 xmlBufferCat(buf, string);
6787 xmlBufferCCat(buf, "\"");
6788 }
6789}
6790
6791
6792/************************************************************************
6793 * *
6794 * Dumping XML tree content to a simple buffer *
6795 * *
6796 ************************************************************************/
6797
Owen Taylor3473f882001-02-23 17:55:21 +00006798/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00006799 * xmlAttrSerializeContent:
6800 * @buf: the XML buffer output
6801 * @doc: the document
6802 * @attr: the attribute pointer
6803 *
6804 * Serialize the attribute in the buffer
6805 */
6806static void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006807xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr)
6808{
Daniel Veillarda6d05382002-02-13 13:07:41 +00006809 const xmlChar *cur, *base;
6810 xmlNodePtr children;
6811
6812 children = attr->children;
6813 while (children != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006814 switch (children->type) {
6815 case XML_TEXT_NODE:
6816 base = cur = children->content;
6817 while (*cur != 0) {
6818 if (*cur == '\n') {
6819 if (base != cur)
6820 xmlBufferAdd(buf, base, cur - base);
6821 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
6822 cur++;
6823 base = cur;
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006824 } else if (*cur == '\r') {
6825 if (base != cur)
6826 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006827 xmlBufferAdd(buf, BAD_CAST "&#13;", 5);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006828 cur++;
6829 base = cur;
6830 } else if (*cur == '\t') {
6831 if (base != cur)
6832 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006833 xmlBufferAdd(buf, BAD_CAST "&#9;", 4);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006834 cur++;
6835 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006836#if 0
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006837 } else if (*cur == '\'') {
6838 if (base != cur)
6839 xmlBufferAdd(buf, base, cur - base);
6840 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
6841 cur++;
6842 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006843#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006844 } else if (*cur == '"') {
6845 if (base != cur)
6846 xmlBufferAdd(buf, base, cur - base);
6847 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6848 cur++;
6849 base = cur;
6850 } else if (*cur == '<') {
6851 if (base != cur)
6852 xmlBufferAdd(buf, base, cur - base);
6853 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
6854 cur++;
6855 base = cur;
6856 } else if (*cur == '>') {
6857 if (base != cur)
6858 xmlBufferAdd(buf, base, cur - base);
6859 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
6860 cur++;
6861 base = cur;
6862 } else if (*cur == '&') {
6863 if (base != cur)
6864 xmlBufferAdd(buf, base, cur - base);
6865 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
6866 cur++;
6867 base = cur;
6868 } else if ((*cur >= 0x80) && ((doc == NULL) ||
6869 (doc->encoding ==
6870 NULL))) {
6871 /*
6872 * We assume we have UTF-8 content.
6873 */
6874 char tmp[10];
6875 int val = 0, l = 1;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006876
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006877 if (base != cur)
6878 xmlBufferAdd(buf, base, cur - base);
6879 if (*cur < 0xC0) {
6880 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6d05382002-02-13 13:07:41 +00006881 "xmlAttrSerializeContent : input not UTF-8\n");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006882 if (doc != NULL)
6883 doc->encoding =
6884 xmlStrdup(BAD_CAST "ISO-8859-1");
6885 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6886 tmp[sizeof(tmp) - 1] = 0;
6887 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6888 cur++;
6889 base = cur;
6890 continue;
6891 } else if (*cur < 0xE0) {
6892 val = (cur[0]) & 0x1F;
6893 val <<= 6;
6894 val |= (cur[1]) & 0x3F;
6895 l = 2;
6896 } else if (*cur < 0xF0) {
6897 val = (cur[0]) & 0x0F;
6898 val <<= 6;
6899 val |= (cur[1]) & 0x3F;
6900 val <<= 6;
6901 val |= (cur[2]) & 0x3F;
6902 l = 3;
6903 } else if (*cur < 0xF8) {
6904 val = (cur[0]) & 0x07;
6905 val <<= 6;
6906 val |= (cur[1]) & 0x3F;
6907 val <<= 6;
6908 val |= (cur[2]) & 0x3F;
6909 val <<= 6;
6910 val |= (cur[3]) & 0x3F;
6911 l = 4;
6912 }
6913 if ((l == 1) || (!IS_CHAR(val))) {
6914 xmlGenericError(xmlGenericErrorContext,
6915 "xmlAttrSerializeContent : char out of range\n");
6916 if (doc != NULL)
6917 doc->encoding =
6918 xmlStrdup(BAD_CAST "ISO-8859-1");
6919 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6920 tmp[sizeof(tmp) - 1] = 0;
6921 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6922 cur++;
6923 base = cur;
6924 continue;
6925 }
6926 /*
6927 * We could do multiple things here. Just save
6928 * as a char ref
6929 */
6930 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
6931 tmp[sizeof(tmp) - 1] = 0;
6932 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6933 cur += l;
6934 base = cur;
6935 } else {
6936 cur++;
6937 }
6938 }
6939 if (base != cur)
6940 xmlBufferAdd(buf, base, cur - base);
6941 break;
6942 case XML_ENTITY_REF_NODE:
6943 xmlBufferAdd(buf, BAD_CAST "&", 1);
6944 xmlBufferAdd(buf, children->name,
6945 xmlStrlen(children->name));
6946 xmlBufferAdd(buf, BAD_CAST ";", 1);
6947 break;
6948 default:
6949 /* should not happen unless we have a badly built tree */
6950 break;
6951 }
6952 children = children->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006953 }
6954}
6955
6956/**
6957 * xmlNodeDump:
6958 * @buf: the XML buffer output
6959 * @doc: the document
6960 * @cur: the current node
6961 * @level: the imbrication level for indenting
6962 * @format: is formatting allowed
6963 *
6964 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00006965 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006966 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006967 *
6968 * Returns the number of bytes written to the buffer or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00006969 */
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006970int
Owen Taylor3473f882001-02-23 17:55:21 +00006971xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006972 int format)
6973{
6974 unsigned int use;
6975 int ret;
6976 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006977
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00006978 xmlInitParser();
6979
Owen Taylor3473f882001-02-23 17:55:21 +00006980 if (cur == NULL) {
6981#ifdef DEBUG_TREE
6982 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006983 "xmlNodeDump : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006984#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006985 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006986 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006987 if (buf == NULL) {
6988#ifdef DEBUG_TREE
6989 xmlGenericError(xmlGenericErrorContext,
6990 "xmlNodeDump : buf == NULL\n");
6991#endif
6992 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006993 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006994 outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
6995 if (outbuf == NULL) {
6996 xmlGenericError(xmlGenericErrorContext,
6997 "xmlNodeDump: out of memory!\n");
6998 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006999 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007000 memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
7001 outbuf->buffer = buf;
7002 outbuf->encoder = NULL;
7003 outbuf->writecallback = NULL;
7004 outbuf->closecallback = NULL;
7005 outbuf->context = NULL;
7006 outbuf->written = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007007
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007008 use = buf->use;
7009 xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
7010 xmlFree(outbuf);
7011 ret = buf->use - use;
7012 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00007013}
7014
7015/**
7016 * xmlElemDump:
7017 * @f: the FILE * for the output
7018 * @doc: the document
7019 * @cur: the current node
7020 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007021 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00007022 */
7023void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007024xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur)
7025{
7026 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00007027
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007028 xmlInitParser();
7029
Owen Taylor3473f882001-02-23 17:55:21 +00007030 if (cur == NULL) {
7031#ifdef DEBUG_TREE
7032 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007033 "xmlElemDump : cur == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007034#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007035 return;
Owen Taylor3473f882001-02-23 17:55:21 +00007036 }
Owen Taylor3473f882001-02-23 17:55:21 +00007037#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007038 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00007039 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007040 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007041 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007042#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007043
7044 outbuf = xmlOutputBufferCreateFile(f, NULL);
7045 if (outbuf == NULL)
7046 return;
7047 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007048#ifdef LIBXML_HTML_ENABLED
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007049 htmlNodeDumpOutput(outbuf, doc, cur, NULL);
7050#else
7051 xmlGenericError(xmlGenericErrorContext,
7052 "HTML support not compiled in\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007053#endif /* LIBXML_HTML_ENABLED */
7054 } else
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007055 xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL);
7056 xmlOutputBufferClose(outbuf);
Owen Taylor3473f882001-02-23 17:55:21 +00007057}
7058
7059/************************************************************************
7060 * *
7061 * Dumping XML tree content to an I/O output buffer *
7062 * *
7063 ************************************************************************/
7064
Owen Taylor3473f882001-02-23 17:55:21 +00007065static void
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007066xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7067 int level, int format, const char *encoding);
7068static void
Owen Taylor3473f882001-02-23 17:55:21 +00007069xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7070 int level, int format, const char *encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007071static void
7072xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
7073 xmlNodePtr cur, int level, int format, const char *encoding);
7074
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00007075void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
7076
Owen Taylor3473f882001-02-23 17:55:21 +00007077/**
7078 * xmlNsDumpOutput:
7079 * @buf: the XML buffer output
7080 * @cur: a namespace
7081 *
7082 * Dump a local Namespace definition.
7083 * Should be called in the context of attributes dumps.
7084 */
7085static void
7086xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
7087 if (cur == NULL) {
7088#ifdef DEBUG_TREE
7089 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007090 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007091#endif
7092 return;
7093 }
7094 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00007095 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
7096 return;
7097
Owen Taylor3473f882001-02-23 17:55:21 +00007098 /* Within the context of an element attributes */
7099 if (cur->prefix != NULL) {
7100 xmlOutputBufferWriteString(buf, " xmlns:");
7101 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
7102 } else
7103 xmlOutputBufferWriteString(buf, " xmlns");
7104 xmlOutputBufferWriteString(buf, "=");
7105 xmlBufferWriteQuotedString(buf->buffer, cur->href);
7106 }
7107}
7108
7109/**
7110 * xmlNsListDumpOutput:
7111 * @buf: the XML buffer output
7112 * @cur: the first namespace
7113 *
7114 * Dump a list of local Namespace definitions.
7115 * Should be called in the context of attributes dumps.
7116 */
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00007117void
Owen Taylor3473f882001-02-23 17:55:21 +00007118xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
7119 while (cur != NULL) {
7120 xmlNsDumpOutput(buf, cur);
7121 cur = cur->next;
7122 }
7123}
7124
7125/**
7126 * xmlDtdDumpOutput:
7127 * @buf: the XML buffer output
7128 * @doc: the document
7129 * @encoding: an optional encoding string
7130 *
7131 * Dump the XML document DTD, if any.
7132 */
7133static void
7134xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
7135 if (dtd == NULL) {
7136#ifdef DEBUG_TREE
7137 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007138 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007139#endif
7140 return;
7141 }
7142 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
7143 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
7144 if (dtd->ExternalID != NULL) {
7145 xmlOutputBufferWriteString(buf, " PUBLIC ");
7146 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
7147 xmlOutputBufferWriteString(buf, " ");
7148 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
7149 } else if (dtd->SystemID != NULL) {
7150 xmlOutputBufferWriteString(buf, " SYSTEM ");
7151 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
7152 }
7153 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
7154 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
7155 xmlOutputBufferWriteString(buf, ">");
7156 return;
7157 }
7158 xmlOutputBufferWriteString(buf, " [\n");
7159 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
7160 xmlOutputBufferWriteString(buf, "]>");
7161}
7162
7163/**
7164 * xmlAttrDumpOutput:
7165 * @buf: the XML buffer output
7166 * @doc: the document
7167 * @cur: the attribute pointer
7168 * @encoding: an optional encoding string
7169 *
7170 * Dump an XML attribute
7171 */
7172static void
7173xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00007174 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00007175 if (cur == NULL) {
7176#ifdef DEBUG_TREE
7177 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007178 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007179#endif
7180 return;
7181 }
7182 xmlOutputBufferWriteString(buf, " ");
7183 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7184 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7185 xmlOutputBufferWriteString(buf, ":");
7186 }
7187 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00007188 xmlOutputBufferWriteString(buf, "=\"");
7189 xmlAttrSerializeContent(buf->buffer, doc, cur);
7190 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007191}
7192
7193/**
7194 * xmlAttrListDumpOutput:
7195 * @buf: the XML buffer output
7196 * @doc: the document
7197 * @cur: the first attribute pointer
7198 * @encoding: an optional encoding string
7199 *
7200 * Dump a list of XML attributes
7201 */
7202static void
7203xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7204 xmlAttrPtr cur, const char *encoding) {
7205 if (cur == NULL) {
7206#ifdef DEBUG_TREE
7207 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007208 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007209#endif
7210 return;
7211 }
7212 while (cur != NULL) {
7213 xmlAttrDumpOutput(buf, doc, cur, encoding);
7214 cur = cur->next;
7215 }
7216}
7217
7218
7219
7220/**
7221 * xmlNodeListDumpOutput:
7222 * @buf: the XML buffer output
7223 * @doc: the document
7224 * @cur: the first node
7225 * @level: the imbrication level for indenting
7226 * @format: is formatting allowed
7227 * @encoding: an optional encoding string
7228 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007229 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007230 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007231 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007232 */
7233static void
7234xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7235 xmlNodePtr cur, int level, int format, const char *encoding) {
7236 int i;
7237
7238 if (cur == NULL) {
7239#ifdef DEBUG_TREE
7240 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007241 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007242#endif
7243 return;
7244 }
7245 while (cur != NULL) {
7246 if ((format) && (xmlIndentTreeOutput) &&
7247 (cur->type == XML_ELEMENT_NODE))
7248 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007249 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007250 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007251 if (format) {
7252 xmlOutputBufferWriteString(buf, "\n");
7253 }
7254 cur = cur->next;
7255 }
7256}
7257
7258/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007259 * xmlNodeDumpOutputInternal:
Owen Taylor3473f882001-02-23 17:55:21 +00007260 * @buf: the XML buffer output
7261 * @doc: the document
7262 * @cur: the current node
7263 * @level: the imbrication level for indenting
7264 * @format: is formatting allowed
7265 * @encoding: an optional encoding string
7266 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007267 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007268 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007269 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007270 */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007271static void
7272xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
7273 xmlNodePtr cur, int level, int format, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007274 int i;
7275 xmlNodePtr tmp;
7276
7277 if (cur == NULL) {
7278#ifdef DEBUG_TREE
7279 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007280 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007281#endif
7282 return;
7283 }
7284 if (cur->type == XML_XINCLUDE_START)
7285 return;
7286 if (cur->type == XML_XINCLUDE_END)
7287 return;
7288 if (cur->type == XML_DTD_NODE) {
7289 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7290 return;
7291 }
7292 if (cur->type == XML_ELEMENT_DECL) {
7293 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7294 return;
7295 }
7296 if (cur->type == XML_ATTRIBUTE_DECL) {
7297 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7298 return;
7299 }
7300 if (cur->type == XML_ENTITY_DECL) {
7301 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7302 return;
7303 }
7304 if (cur->type == XML_TEXT_NODE) {
7305 if (cur->content != NULL) {
7306 if ((cur->name == xmlStringText) ||
7307 (cur->name != xmlStringTextNoenc)) {
7308 xmlChar *buffer;
7309
Owen Taylor3473f882001-02-23 17:55:21 +00007310 if (encoding == NULL)
7311 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7312 else
7313 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007314 if (buffer != NULL) {
7315 xmlOutputBufferWriteString(buf, (const char *)buffer);
7316 xmlFree(buffer);
7317 }
7318 } else {
7319 /*
7320 * Disable escaping, needed for XSLT
7321 */
Owen Taylor3473f882001-02-23 17:55:21 +00007322 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007323 }
7324 }
7325
7326 return;
7327 }
7328 if (cur->type == XML_PI_NODE) {
7329 if (cur->content != NULL) {
7330 xmlOutputBufferWriteString(buf, "<?");
7331 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7332 if (cur->content != NULL) {
7333 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00007334 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007335 }
7336 xmlOutputBufferWriteString(buf, "?>");
7337 } else {
7338 xmlOutputBufferWriteString(buf, "<?");
7339 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7340 xmlOutputBufferWriteString(buf, "?>");
7341 }
7342 return;
7343 }
7344 if (cur->type == XML_COMMENT_NODE) {
7345 if (cur->content != NULL) {
7346 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00007347 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007348 xmlOutputBufferWriteString(buf, "-->");
7349 }
7350 return;
7351 }
7352 if (cur->type == XML_ENTITY_REF_NODE) {
7353 xmlOutputBufferWriteString(buf, "&");
7354 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7355 xmlOutputBufferWriteString(buf, ";");
7356 return;
7357 }
7358 if (cur->type == XML_CDATA_SECTION_NODE) {
7359 xmlOutputBufferWriteString(buf, "<![CDATA[");
7360 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007361 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007362 xmlOutputBufferWriteString(buf, "]]>");
7363 return;
7364 }
Daniel Veillard7b72ee52003-02-27 23:24:53 +00007365 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillarda1a9d042003-03-18 16:53:17 +00007366 xmlAttrDumpOutput(buf,doc, (xmlAttrPtr) cur,encoding);
Daniel Veillard7b72ee52003-02-27 23:24:53 +00007367 return;
7368 }
Daniel Veillard6aa2f602003-02-10 00:01:56 +00007369 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007370 xmlNsDumpOutput(buf, (xmlNsPtr) cur);
Daniel Veillard6aa2f602003-02-10 00:01:56 +00007371 return;
7372 }
Owen Taylor3473f882001-02-23 17:55:21 +00007373
7374 if (format == 1) {
7375 tmp = cur->children;
7376 while (tmp != NULL) {
7377 if ((tmp->type == XML_TEXT_NODE) ||
7378 (tmp->type == XML_ENTITY_REF_NODE)) {
7379 format = 0;
7380 break;
7381 }
7382 tmp = tmp->next;
7383 }
7384 }
7385 xmlOutputBufferWriteString(buf, "<");
7386 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7387 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7388 xmlOutputBufferWriteString(buf, ":");
7389 }
7390
7391 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7392 if (cur->nsDef)
7393 xmlNsListDumpOutput(buf, cur->nsDef);
7394 if (cur->properties != NULL)
7395 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7396
Daniel Veillard7db37732001-07-12 01:20:08 +00007397 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
7398 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007399 xmlOutputBufferWriteString(buf, "/>");
7400 return;
7401 }
7402 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00007403 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007404 xmlChar *buffer;
7405
Owen Taylor3473f882001-02-23 17:55:21 +00007406 if (encoding == NULL)
7407 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7408 else
7409 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007410 if (buffer != NULL) {
7411 xmlOutputBufferWriteString(buf, (const char *)buffer);
7412 xmlFree(buffer);
7413 }
7414 }
7415 if (cur->children != NULL) {
7416 if (format) xmlOutputBufferWriteString(buf, "\n");
7417 xmlNodeListDumpOutput(buf, doc, cur->children,
7418 (level >= 0?level+1:-1), format, encoding);
7419 if ((xmlIndentTreeOutput) && (format))
7420 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007421 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00007422 }
7423 xmlOutputBufferWriteString(buf, "</");
7424 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7425 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7426 xmlOutputBufferWriteString(buf, ":");
7427 }
7428
7429 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7430 xmlOutputBufferWriteString(buf, ">");
7431}
7432
7433/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007434 * xmlNodeDumpOutput:
7435 * @buf: the XML buffer output
7436 * @doc: the document
7437 * @cur: the current node
7438 * @level: the imbrication level for indenting
7439 * @format: is formatting allowed
7440 * @encoding: an optional encoding string
7441 *
7442 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007443 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007444 * or xmlKeepBlanksDefault(0) was called
7445 */
7446void
7447xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007448 int level, int format, const char *encoding)
7449{
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007450#ifdef LIBXML_HTML_ENABLED
7451 xmlDtdPtr dtd;
7452 int is_xhtml = 0;
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007453#endif
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007454
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007455 xmlInitParser();
7456
7457#ifdef LIBXML_HTML_ENABLED
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007458 dtd = xmlGetIntSubset(doc);
7459 if (dtd != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007460 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7461 if (is_xhtml < 0)
7462 is_xhtml = 0;
7463 if ((is_xhtml) && (cur->parent == (xmlNodePtr) doc) &&
7464 (cur->type == XML_ELEMENT_NODE) &&
7465 (xmlStrEqual(cur->name, BAD_CAST "html"))) {
7466 if (encoding != NULL)
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007467 htmlSetMetaEncoding((htmlDocPtr) doc,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007468 (const xmlChar *) encoding);
7469 else
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007470 htmlSetMetaEncoding((htmlDocPtr) doc, BAD_CAST "UTF-8");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007471 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007472 }
7473
7474 if (is_xhtml)
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007475 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007476 else
7477#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007478 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007479}
7480
7481/**
Owen Taylor3473f882001-02-23 17:55:21 +00007482 * xmlDocContentDumpOutput:
7483 * @buf: the XML buffer output
7484 * @cur: the document
7485 * @encoding: an optional encoding string
7486 * @format: should formatting spaces been added
7487 *
7488 * Dump an XML document.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007489 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007490 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007491 */
7492static void
7493xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
7494 const char *encoding, int format) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007495#ifdef LIBXML_HTML_ENABLED
7496 xmlDtdPtr dtd;
7497 int is_xhtml = 0;
7498#endif
7499
Daniel Veillard70bcb0e2003-08-08 14:00:28 +00007500 xmlInitParser();
7501
Owen Taylor3473f882001-02-23 17:55:21 +00007502 xmlOutputBufferWriteString(buf, "<?xml version=");
7503 if (cur->version != NULL)
7504 xmlBufferWriteQuotedString(buf->buffer, cur->version);
7505 else
7506 xmlOutputBufferWriteString(buf, "\"1.0\"");
7507 if (encoding == NULL) {
7508 if (cur->encoding != NULL)
7509 encoding = (const char *) cur->encoding;
7510 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
7511 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
7512 }
7513 if (encoding != NULL) {
7514 xmlOutputBufferWriteString(buf, " encoding=");
7515 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
7516 }
7517 switch (cur->standalone) {
7518 case 0:
7519 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
7520 break;
7521 case 1:
7522 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
7523 break;
7524 }
7525 xmlOutputBufferWriteString(buf, "?>\n");
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007526
7527#ifdef LIBXML_HTML_ENABLED
7528 dtd = xmlGetIntSubset(cur);
7529 if (dtd != NULL) {
7530 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7531 if (is_xhtml < 0) is_xhtml = 0;
7532 }
7533 if (is_xhtml) {
7534 if (encoding != NULL)
7535 htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
7536 else
7537 htmlSetMetaEncoding(cur, BAD_CAST "UTF-8");
7538 }
7539#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007540 if (cur->children != NULL) {
7541 xmlNodePtr child = cur->children;
7542
7543 while (child != NULL) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007544#ifdef LIBXML_HTML_ENABLED
7545 if (is_xhtml)
7546 xhtmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
7547 else
7548#endif
7549 xmlNodeDumpOutputInternal(buf, cur, child, 0, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007550 xmlOutputBufferWriteString(buf, "\n");
7551 child = child->next;
7552 }
7553 }
7554}
7555
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007556#ifdef LIBXML_HTML_ENABLED
7557/************************************************************************
7558 * *
7559 * Functions specific to XHTML serialization *
7560 * *
7561 ************************************************************************/
7562
7563#define XHTML_STRICT_PUBLIC_ID BAD_CAST \
7564 "-//W3C//DTD XHTML 1.0 Strict//EN"
7565#define XHTML_STRICT_SYSTEM_ID BAD_CAST \
7566 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
7567#define XHTML_FRAME_PUBLIC_ID BAD_CAST \
7568 "-//W3C//DTD XHTML 1.0 Frameset//EN"
7569#define XHTML_FRAME_SYSTEM_ID BAD_CAST \
7570 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
7571#define XHTML_TRANS_PUBLIC_ID BAD_CAST \
7572 "-//W3C//DTD XHTML 1.0 Transitional//EN"
7573#define XHTML_TRANS_SYSTEM_ID BAD_CAST \
7574 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
7575
7576#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
7577/**
7578 * xmlIsXHTML:
7579 * @systemID: the system identifier
7580 * @publicID: the public identifier
7581 *
7582 * Try to find if the document correspond to an XHTML DTD
7583 *
7584 * Returns 1 if true, 0 if not and -1 in case of error
7585 */
7586int
7587xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) {
7588 if ((systemID == NULL) && (publicID == NULL))
7589 return(-1);
7590 if (publicID != NULL) {
7591 if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1);
7592 if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1);
7593 if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1);
7594 }
7595 if (systemID != NULL) {
7596 if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1);
7597 if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1);
7598 if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1);
7599 }
7600 return(0);
7601}
7602
7603/**
7604 * xhtmlIsEmpty:
7605 * @node: the node
7606 *
7607 * Check if a node is an empty xhtml node
7608 *
7609 * Returns 1 if the node is an empty node, 0 if not and -1 in case of error
7610 */
7611static int
7612xhtmlIsEmpty(xmlNodePtr node) {
7613 if (node == NULL)
7614 return(-1);
7615 if (node->type != XML_ELEMENT_NODE)
7616 return(0);
7617 if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME)))
7618 return(0);
7619 if (node->children != NULL)
7620 return(0);
7621 switch (node->name[0]) {
7622 case 'a':
7623 if (xmlStrEqual(node->name, BAD_CAST "area"))
7624 return(1);
7625 return(0);
7626 case 'b':
7627 if (xmlStrEqual(node->name, BAD_CAST "br"))
7628 return(1);
7629 if (xmlStrEqual(node->name, BAD_CAST "base"))
7630 return(1);
7631 if (xmlStrEqual(node->name, BAD_CAST "basefont"))
7632 return(1);
7633 return(0);
7634 case 'c':
7635 if (xmlStrEqual(node->name, BAD_CAST "col"))
7636 return(1);
7637 return(0);
7638 case 'f':
7639 if (xmlStrEqual(node->name, BAD_CAST "frame"))
7640 return(1);
7641 return(0);
7642 case 'h':
7643 if (xmlStrEqual(node->name, BAD_CAST "hr"))
7644 return(1);
7645 return(0);
7646 case 'i':
7647 if (xmlStrEqual(node->name, BAD_CAST "img"))
7648 return(1);
7649 if (xmlStrEqual(node->name, BAD_CAST "input"))
7650 return(1);
7651 if (xmlStrEqual(node->name, BAD_CAST "isindex"))
7652 return(1);
7653 return(0);
7654 case 'l':
7655 if (xmlStrEqual(node->name, BAD_CAST "link"))
7656 return(1);
7657 return(0);
7658 case 'm':
7659 if (xmlStrEqual(node->name, BAD_CAST "meta"))
7660 return(1);
7661 return(0);
7662 case 'p':
7663 if (xmlStrEqual(node->name, BAD_CAST "param"))
7664 return(1);
7665 return(0);
7666 }
7667 return(0);
7668}
7669
7670/**
7671 * xhtmlAttrListDumpOutput:
7672 * @buf: the XML buffer output
7673 * @doc: the document
7674 * @cur: the first attribute pointer
7675 * @encoding: an optional encoding string
7676 *
7677 * Dump a list of XML attributes
7678 */
7679static void
7680xhtmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7681 xmlAttrPtr cur, const char *encoding) {
7682 xmlAttrPtr xml_lang = NULL;
7683 xmlAttrPtr lang = NULL;
7684 xmlAttrPtr name = NULL;
7685 xmlAttrPtr id = NULL;
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007686 xmlNodePtr parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007687
7688 if (cur == NULL) {
7689#ifdef DEBUG_TREE
7690 xmlGenericError(xmlGenericErrorContext,
7691 "xmlAttrListDumpOutput : property == NULL\n");
7692#endif
7693 return;
7694 }
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007695 parent = cur->parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007696 while (cur != NULL) {
7697 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id")))
7698 id = cur;
7699 else
7700 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name")))
7701 name = cur;
7702 else
7703 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")))
7704 lang = cur;
7705 else
7706 if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) &&
7707 (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml")))
7708 xml_lang = cur;
7709 else if ((cur->ns == NULL) &&
7710 ((cur->children == NULL) ||
7711 (cur->children->content == NULL) ||
7712 (cur->children->content[0] == 0)) &&
7713 (htmlIsBooleanAttr(cur->name))) {
7714 if (cur->children != NULL)
7715 xmlFreeNode(cur->children);
7716 cur->children = xmlNewText(cur->name);
7717 if (cur->children != NULL)
7718 cur->children->parent = (xmlNodePtr) cur;
7719 }
7720 xmlAttrDumpOutput(buf, doc, cur, encoding);
7721 cur = cur->next;
7722 }
7723 /*
7724 * C.8
7725 */
7726 if ((name != NULL) && (id == NULL)) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007727 if ((parent != NULL) && (parent->name != NULL) &&
7728 ((xmlStrEqual(parent->name, BAD_CAST "a")) ||
7729 (xmlStrEqual(parent->name, BAD_CAST "p")) ||
7730 (xmlStrEqual(parent->name, BAD_CAST "div")) ||
7731 (xmlStrEqual(parent->name, BAD_CAST "img")) ||
7732 (xmlStrEqual(parent->name, BAD_CAST "map")) ||
7733 (xmlStrEqual(parent->name, BAD_CAST "applet")) ||
7734 (xmlStrEqual(parent->name, BAD_CAST "form")) ||
7735 (xmlStrEqual(parent->name, BAD_CAST "frame")) ||
7736 (xmlStrEqual(parent->name, BAD_CAST "iframe")))) {
7737 xmlOutputBufferWriteString(buf, " id=\"");
7738 xmlAttrSerializeContent(buf->buffer, doc, name);
7739 xmlOutputBufferWriteString(buf, "\"");
7740 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007741 }
7742 /*
7743 * C.7.
7744 */
7745 if ((lang != NULL) && (xml_lang == NULL)) {
7746 xmlOutputBufferWriteString(buf, " xml:lang=\"");
7747 xmlAttrSerializeContent(buf->buffer, doc, lang);
7748 xmlOutputBufferWriteString(buf, "\"");
7749 } else
7750 if ((xml_lang != NULL) && (lang == NULL)) {
7751 xmlOutputBufferWriteString(buf, " lang=\"");
7752 xmlAttrSerializeContent(buf->buffer, doc, xml_lang);
7753 xmlOutputBufferWriteString(buf, "\"");
7754 }
7755}
7756
7757/**
7758 * xhtmlNodeListDumpOutput:
7759 * @buf: the XML buffer output
7760 * @doc: the XHTML document
7761 * @cur: the first node
7762 * @level: the imbrication level for indenting
7763 * @format: is formatting allowed
7764 * @encoding: an optional encoding string
7765 *
7766 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007767 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007768 * or xmlKeepBlanksDefault(0) was called
7769 */
7770static void
7771xhtmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7772 xmlNodePtr cur, int level, int format, const char *encoding) {
7773 int i;
7774
7775 if (cur == NULL) {
7776#ifdef DEBUG_TREE
7777 xmlGenericError(xmlGenericErrorContext,
7778 "xhtmlNodeListDumpOutput : node == NULL\n");
7779#endif
7780 return;
7781 }
7782 while (cur != NULL) {
7783 if ((format) && (xmlIndentTreeOutput) &&
7784 (cur->type == XML_ELEMENT_NODE))
7785 for (i = 0;i < level;i++)
7786 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7787 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
7788 if (format) {
7789 xmlOutputBufferWriteString(buf, "\n");
7790 }
7791 cur = cur->next;
7792 }
7793}
7794
7795/**
7796 * xhtmlNodeDumpOutput:
7797 * @buf: the XML buffer output
7798 * @doc: the XHTML document
7799 * @cur: the current node
7800 * @level: the imbrication level for indenting
7801 * @format: is formatting allowed
7802 * @encoding: an optional encoding string
7803 *
7804 * Dump an XHTML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007805 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007806 * or xmlKeepBlanksDefault(0) was called
7807 */
7808static void
7809xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7810 int level, int format, const char *encoding) {
7811 int i;
7812 xmlNodePtr tmp;
7813
7814 if (cur == NULL) {
7815#ifdef DEBUG_TREE
7816 xmlGenericError(xmlGenericErrorContext,
7817 "xmlNodeDumpOutput : node == NULL\n");
7818#endif
7819 return;
7820 }
7821 if (cur->type == XML_XINCLUDE_START)
7822 return;
7823 if (cur->type == XML_XINCLUDE_END)
7824 return;
7825 if (cur->type == XML_DTD_NODE) {
7826 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7827 return;
7828 }
7829 if (cur->type == XML_ELEMENT_DECL) {
7830 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7831 return;
7832 }
7833 if (cur->type == XML_ATTRIBUTE_DECL) {
7834 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7835 return;
7836 }
7837 if (cur->type == XML_ENTITY_DECL) {
7838 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7839 return;
7840 }
7841 if (cur->type == XML_TEXT_NODE) {
7842 if (cur->content != NULL) {
7843 if ((cur->name == xmlStringText) ||
7844 (cur->name != xmlStringTextNoenc)) {
7845 xmlChar *buffer;
7846
7847 if (encoding == NULL)
7848 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7849 else
7850 buffer = xmlEncodeSpecialChars(doc, cur->content);
7851 if (buffer != NULL) {
7852 xmlOutputBufferWriteString(buf, (const char *)buffer);
7853 xmlFree(buffer);
7854 }
7855 } else {
7856 /*
7857 * Disable escaping, needed for XSLT
7858 */
7859 xmlOutputBufferWriteString(buf, (const char *) cur->content);
7860 }
7861 }
7862
7863 return;
7864 }
7865 if (cur->type == XML_PI_NODE) {
7866 if (cur->content != NULL) {
7867 xmlOutputBufferWriteString(buf, "<?");
7868 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7869 if (cur->content != NULL) {
7870 xmlOutputBufferWriteString(buf, " ");
7871 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7872 }
7873 xmlOutputBufferWriteString(buf, "?>");
7874 } else {
7875 xmlOutputBufferWriteString(buf, "<?");
7876 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7877 xmlOutputBufferWriteString(buf, "?>");
7878 }
7879 return;
7880 }
7881 if (cur->type == XML_COMMENT_NODE) {
7882 if (cur->content != NULL) {
7883 xmlOutputBufferWriteString(buf, "<!--");
7884 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7885 xmlOutputBufferWriteString(buf, "-->");
7886 }
7887 return;
7888 }
7889 if (cur->type == XML_ENTITY_REF_NODE) {
7890 xmlOutputBufferWriteString(buf, "&");
7891 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7892 xmlOutputBufferWriteString(buf, ";");
7893 return;
7894 }
7895 if (cur->type == XML_CDATA_SECTION_NODE) {
7896 xmlOutputBufferWriteString(buf, "<![CDATA[");
7897 if (cur->content != NULL)
7898 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7899 xmlOutputBufferWriteString(buf, "]]>");
7900 return;
7901 }
7902
7903 if (format == 1) {
7904 tmp = cur->children;
7905 while (tmp != NULL) {
7906 if ((tmp->type == XML_TEXT_NODE) ||
7907 (tmp->type == XML_ENTITY_REF_NODE)) {
7908 format = 0;
7909 break;
7910 }
7911 tmp = tmp->next;
7912 }
7913 }
7914 xmlOutputBufferWriteString(buf, "<");
7915 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7916 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7917 xmlOutputBufferWriteString(buf, ":");
7918 }
7919
7920 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7921 if (cur->nsDef)
7922 xmlNsListDumpOutput(buf, cur->nsDef);
7923 if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
7924 (cur->ns == NULL) && (cur->nsDef == NULL))) {
7925 /*
7926 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
7927 */
7928 xmlOutputBufferWriteString(buf,
7929 " xmlns=\"http://www.w3.org/1999/xhtml\"");
7930 }
7931 if (cur->properties != NULL)
7932 xhtmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7933
7934 if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) {
7935 if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
7936 (xhtmlIsEmpty(cur) == 1)) {
7937 /*
7938 * C.2. Empty Elements
7939 */
7940 xmlOutputBufferWriteString(buf, " />");
7941 } else {
7942 /*
7943 * C.3. Element Minimization and Empty Element Content
7944 */
7945 xmlOutputBufferWriteString(buf, "></");
7946 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7947 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7948 xmlOutputBufferWriteString(buf, ":");
7949 }
7950 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7951 xmlOutputBufferWriteString(buf, ">");
7952 }
7953 return;
7954 }
7955 xmlOutputBufferWriteString(buf, ">");
7956 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
7957 xmlChar *buffer;
7958
7959 if (encoding == NULL)
7960 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7961 else
7962 buffer = xmlEncodeSpecialChars(doc, cur->content);
7963 if (buffer != NULL) {
7964 xmlOutputBufferWriteString(buf, (const char *)buffer);
7965 xmlFree(buffer);
7966 }
7967 }
7968
7969 /*
7970 * 4.8. Script and Style elements
7971 */
7972 if ((cur->type == XML_ELEMENT_NODE) &&
7973 ((xmlStrEqual(cur->name, BAD_CAST "script")) ||
7974 (xmlStrEqual(cur->name, BAD_CAST "style"))) &&
7975 ((cur->ns == NULL) ||
7976 (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) {
7977 xmlNodePtr child = cur->children;
7978
7979 while (child != NULL) {
7980 if ((child->type == XML_TEXT_NODE) ||
7981 (child->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard64b35282002-12-04 15:10:40 +00007982 /*
7983 * Apparently CDATA escaping for style just break on IE,
7984 * mozilla and galeon, so ...
7985 */
7986 if (xmlStrEqual(cur->name, BAD_CAST "style") &&
7987 (xmlStrchr(child->content, '<') == NULL) &&
7988 (xmlStrchr(child->content, '>') == NULL) &&
7989 (xmlStrchr(child->content, '&') == NULL)) {
7990 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7991 } else {
7992 xmlOutputBufferWriteString(buf, "<![CDATA[");
7993 if (child->content != NULL)
7994 xmlOutputBufferWriteString(buf,
7995 (const char *)child->content);
7996 xmlOutputBufferWriteString(buf, "]]>");
7997 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007998 } else {
7999 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
8000 }
8001 child = child->next;
8002 }
8003 } else if (cur->children != NULL) {
8004 if (format) xmlOutputBufferWriteString(buf, "\n");
8005 xhtmlNodeListDumpOutput(buf, doc, cur->children,
8006 (level >= 0?level+1:-1), format, encoding);
8007 if ((xmlIndentTreeOutput) && (format))
8008 for (i = 0;i < level;i++)
8009 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
8010 }
8011 xmlOutputBufferWriteString(buf, "</");
8012 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
8013 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
8014 xmlOutputBufferWriteString(buf, ":");
8015 }
8016
8017 xmlOutputBufferWriteString(buf, (const char *)cur->name);
8018 xmlOutputBufferWriteString(buf, ">");
8019}
8020#endif
8021
Owen Taylor3473f882001-02-23 17:55:21 +00008022/************************************************************************
8023 * *
8024 * Saving functions front-ends *
8025 * *
8026 ************************************************************************/
8027
8028/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00008029 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00008030 * @out_doc: Document to generate XML text from
8031 * @doc_txt_ptr: Memory pointer for allocated XML text
8032 * @doc_txt_len: Length of the generated XML text
8033 * @txt_encoding: Character encoding to use when generating XML text
8034 * @format: should formatting spaces been added
8035 *
8036 * Dump the current DOM tree into memory using the character encoding specified
8037 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008038 * allocated memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00008039 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00008040 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008041 */
8042
8043void
8044xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008045 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008046 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00008047 int dummy = 0;
8048
Owen Taylor3473f882001-02-23 17:55:21 +00008049 xmlOutputBufferPtr out_buff = NULL;
8050 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
8051
8052 if (doc_txt_len == NULL) {
8053 doc_txt_len = &dummy; /* Continue, caller just won't get length */
8054 }
8055
8056 if (doc_txt_ptr == NULL) {
8057 *doc_txt_len = 0;
8058 xmlGenericError(xmlGenericErrorContext,
8059 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
8060 return;
8061 }
8062
8063 *doc_txt_ptr = NULL;
8064 *doc_txt_len = 0;
8065
8066 if (out_doc == NULL) {
8067 /* No document, no output */
8068 xmlGenericError(xmlGenericErrorContext,
8069 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
8070 return;
8071 }
8072
8073 /*
8074 * Validate the encoding value, if provided.
8075 * This logic is copied from xmlSaveFileEnc.
8076 */
8077
8078 if (txt_encoding == NULL)
8079 txt_encoding = (const char *) out_doc->encoding;
8080 if (txt_encoding != NULL) {
Daniel Veillarde1326112003-06-05 09:32:20 +00008081 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00008082 if ( conv_hdlr == NULL ) {
8083 xmlGenericError(xmlGenericErrorContext,
8084 "%s: %s %s '%s'\n",
8085 "xmlDocDumpFormatMemoryEnc",
8086 "Failed to identify encoding handler for",
8087 "character set",
8088 txt_encoding);
8089 return;
8090 }
8091 }
Owen Taylor3473f882001-02-23 17:55:21 +00008092
8093 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
8094 xmlGenericError(xmlGenericErrorContext,
8095 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
8096 return;
8097 }
8098
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008099 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008100 xmlOutputBufferFlush(out_buff);
8101 if (out_buff->conv != NULL) {
8102 *doc_txt_len = out_buff->conv->use;
8103 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
8104 } else {
8105 *doc_txt_len = out_buff->buffer->use;
8106 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
8107 }
8108 (void)xmlOutputBufferClose(out_buff);
8109
8110 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
8111 *doc_txt_len = 0;
8112 xmlGenericError(xmlGenericErrorContext,
8113 "xmlDocDumpFormatMemoryEnc: %s\n",
8114 "Failed to allocate memory for document text representation.");
8115 }
8116
8117 return;
8118}
8119
8120/**
8121 * xmlDocDumpMemory:
8122 * @cur: the document
8123 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00008124 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00008125 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008126 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008127 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00008128 */
8129void
8130xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
8131 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
8132}
8133
8134/**
8135 * xmlDocDumpFormatMemory:
8136 * @cur: the document
8137 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00008138 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00008139 * @format: should formatting spaces been added
8140 *
8141 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008142 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008143 * It's up to the caller to free the memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00008144 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00008145 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008146 */
8147void
8148xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
8149 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
8150}
8151
8152/**
8153 * xmlDocDumpMemoryEnc:
8154 * @out_doc: Document to generate XML text from
8155 * @doc_txt_ptr: Memory pointer for allocated XML text
8156 * @doc_txt_len: Length of the generated XML text
8157 * @txt_encoding: Character encoding to use when generating XML text
8158 *
8159 * Dump the current DOM tree into memory using the character encoding specified
8160 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00008161 * allocated memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00008162 */
8163
8164void
8165xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
8166 int * doc_txt_len, const char * txt_encoding) {
8167 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008168 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008169}
8170
8171/**
8172 * xmlGetDocCompressMode:
8173 * @doc: the document
8174 *
8175 * get the compression ratio for a document, ZLIB based
8176 * Returns 0 (uncompressed) to 9 (max compression)
8177 */
8178int
8179xmlGetDocCompressMode (xmlDocPtr doc) {
8180 if (doc == NULL) return(-1);
8181 return(doc->compression);
8182}
8183
8184/**
8185 * xmlSetDocCompressMode:
8186 * @doc: the document
8187 * @mode: the compression ratio
8188 *
8189 * set the compression ratio for a document, ZLIB based
8190 * Correct values: 0 (uncompressed) to 9 (max compression)
8191 */
8192void
8193xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
8194 if (doc == NULL) return;
8195 if (mode < 0) doc->compression = 0;
8196 else if (mode > 9) doc->compression = 9;
8197 else doc->compression = mode;
8198}
8199
8200/**
8201 * xmlGetCompressMode:
8202 *
8203 * get the default compression mode used, ZLIB based.
8204 * Returns 0 (uncompressed) to 9 (max compression)
8205 */
8206int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008207xmlGetCompressMode(void)
8208{
8209 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00008210}
8211
8212/**
8213 * xmlSetCompressMode:
8214 * @mode: the compression ratio
8215 *
8216 * set the default compression mode used, ZLIB based
8217 * Correct values: 0 (uncompressed) to 9 (max compression)
8218 */
8219void
8220xmlSetCompressMode(int mode) {
8221 if (mode < 0) xmlCompressMode = 0;
8222 else if (mode > 9) xmlCompressMode = 9;
8223 else xmlCompressMode = mode;
8224}
8225
8226/**
Daniel Veillard9e412302002-06-10 15:59:44 +00008227 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00008228 * @f: the FILE*
8229 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00008230 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00008231 *
8232 * Dump an XML document to an open FILE.
8233 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008234 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008235 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8236 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008237 */
8238int
Daniel Veillard9e412302002-06-10 15:59:44 +00008239xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00008240 xmlOutputBufferPtr buf;
8241 const char * encoding;
8242 xmlCharEncodingHandlerPtr handler = NULL;
8243 int ret;
8244
8245 if (cur == NULL) {
8246#ifdef DEBUG_TREE
8247 xmlGenericError(xmlGenericErrorContext,
8248 "xmlDocDump : document == NULL\n");
8249#endif
8250 return(-1);
8251 }
8252 encoding = (const char *) cur->encoding;
8253
8254 if (encoding != NULL) {
Daniel Veillarde1326112003-06-05 09:32:20 +00008255 handler = xmlFindCharEncodingHandler(encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00008256 if (handler == NULL) {
8257 xmlFree((char *) cur->encoding);
8258 cur->encoding = NULL;
8259 }
8260 }
Owen Taylor3473f882001-02-23 17:55:21 +00008261 buf = xmlOutputBufferCreateFile(f, handler);
8262 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00008263 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008264
8265 ret = xmlOutputBufferClose(buf);
8266 return(ret);
8267}
8268
8269/**
Daniel Veillard9e412302002-06-10 15:59:44 +00008270 * xmlDocDump:
8271 * @f: the FILE*
8272 * @cur: the document
8273 *
8274 * Dump an XML document to an open FILE.
8275 *
8276 * returns: the number of bytes written or -1 in case of failure.
8277 */
8278int
8279xmlDocDump(FILE *f, xmlDocPtr cur) {
8280 return(xmlDocFormatDump (f, cur, 0));
8281}
8282
8283/**
Owen Taylor3473f882001-02-23 17:55:21 +00008284 * xmlSaveFileTo:
8285 * @buf: an output I/O buffer
8286 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00008287 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00008288 *
8289 * Dump an XML document to an I/O buffer.
8290 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008291 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008292 */
8293int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00008294xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00008295 int ret;
8296
8297 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008298 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008299 ret = xmlOutputBufferClose(buf);
8300 return(ret);
8301}
8302
8303/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00008304 * xmlSaveFormatFileTo:
8305 * @buf: an output I/O buffer
8306 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00008307 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00008308 * @format: should formatting spaces been added
8309 *
8310 * Dump an XML document to an I/O buffer.
8311 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008312 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008313 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8314 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardeefd4492001-04-28 16:55:50 +00008315 */
8316int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00008317xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00008318 int ret;
8319
8320 if (buf == NULL) return(0);
8321 xmlDocContentDumpOutput(buf, cur, encoding, format);
8322 ret = xmlOutputBufferClose(buf);
8323 return(ret);
8324}
8325
8326/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00008327 * xmlSaveFormatFileEnc:
Daniel Veillardf012a642001-07-23 19:10:52 +00008328 * @filename: the filename or URL to output
8329 * @cur: the document being saved
8330 * @encoding: the name of the encoding to use or NULL.
8331 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00008332 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00008333 * Dump an XML document to a file or an URL.
8334 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008335 * Returns the number of bytes written or -1 in case of error.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008336 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8337 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008338 */
8339int
Daniel Veillardf012a642001-07-23 19:10:52 +00008340xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
8341 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00008342 xmlOutputBufferPtr buf;
8343 xmlCharEncodingHandlerPtr handler = NULL;
8344 int ret;
8345
Daniel Veillard4dbe77a2003-01-14 00:17:42 +00008346 if (cur == NULL)
8347 return(-1);
8348
Daniel Veillardfb25a512002-01-13 20:32:08 +00008349 if (encoding == NULL)
8350 encoding = (const char *) cur->encoding;
8351
Owen Taylor3473f882001-02-23 17:55:21 +00008352 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00008353
Owen Taylor3473f882001-02-23 17:55:21 +00008354 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00008355 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00008356 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00008357 }
8358
Daniel Veillardf012a642001-07-23 19:10:52 +00008359#ifdef HAVE_ZLIB_H
8360 if (cur->compression < 0) cur->compression = xmlCompressMode;
8361#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008362 /*
8363 * save the content to a temp buffer.
8364 */
Daniel Veillardf012a642001-07-23 19:10:52 +00008365 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00008366 if (buf == NULL) return(-1);
8367
Daniel Veillardf012a642001-07-23 19:10:52 +00008368 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008369
8370 ret = xmlOutputBufferClose(buf);
8371 return(ret);
8372}
8373
Daniel Veillardf012a642001-07-23 19:10:52 +00008374
8375/**
8376 * xmlSaveFileEnc:
8377 * @filename: the filename (or URL)
8378 * @cur: the document
8379 * @encoding: the name of an encoding (or NULL)
8380 *
8381 * Dump an XML document, converting it to the given encoding
8382 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008383 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00008384 */
8385int
8386xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
8387 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
8388}
8389
Owen Taylor3473f882001-02-23 17:55:21 +00008390/**
Daniel Veillard67fee942001-04-26 18:59:03 +00008391 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00008392 * @filename: the filename (or URL)
8393 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00008394 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00008395 *
8396 * Dump an XML document to a file. Will use compression if
8397 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00008398 * used. If @format is set then the document will be indented on output.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008399 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8400 * or xmlKeepBlanksDefault(0) was called
Daniel Veillard67fee942001-04-26 18:59:03 +00008401 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008402 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008403 */
8404int
Daniel Veillard67fee942001-04-26 18:59:03 +00008405xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008406 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00008407}
8408
Daniel Veillard67fee942001-04-26 18:59:03 +00008409/**
8410 * xmlSaveFile:
8411 * @filename: the filename (or URL)
8412 * @cur: the document
8413 *
8414 * Dump an XML document to a file. Will use compression if
8415 * compiled in and enabled. If @filename is "-" the stdout file is
8416 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00008417 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00008418 */
8419int
8420xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008421 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00008422}
8423