blob: abe9cf249f773eb91e9c07fde6fa619cfb5c0bee [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 Veillard56a4cb82001-03-24 17:00:36 +000041xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
42
43/************************************************************************
44 * *
45 * A few static variables and macros *
46 * *
47 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +000048/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +000049const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000050/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +000051const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +000052 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000053/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +000054const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
55
Owen Taylor3473f882001-02-23 17:55:21 +000056static int xmlCompressMode = 0;
57static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000058
Owen Taylor3473f882001-02-23 17:55:21 +000059#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
60 xmlNodePtr ulccur = (n)->children; \
61 if (ulccur == NULL) { \
62 (n)->last = NULL; \
63 } else { \
64 while (ulccur->next != NULL) { \
65 ulccur->parent = (n); \
66 ulccur = ulccur->next; \
67 } \
68 ulccur->parent = (n); \
69 (n)->last = ulccur; \
70}}
71
72/* #define DEBUG_BUFFER */
73/* #define DEBUG_TREE */
74
75/************************************************************************
76 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +000077 * Functions to move to entities.c once the *
78 * API freeze is smoothen and they can be made public. *
79 * *
80 ************************************************************************/
81#include <libxml/hash.h>
82
83/**
84 * xmlGetEntityFromDtd:
85 * @dtd: A pointer to the DTD to search
86 * @name: The entity name
87 *
88 * Do an entity lookup in the DTD entity hash table and
89 * return the corresponding entity, if found.
90 *
91 * Returns A pointer to the entity structure or NULL if not found.
92 */
93static xmlEntityPtr
94xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
95 xmlEntitiesTablePtr table;
96
97 if((dtd != NULL) && (dtd->entities != NULL)) {
98 table = (xmlEntitiesTablePtr) dtd->entities;
99 return((xmlEntityPtr) xmlHashLookup(table, name));
100 /* return(xmlGetEntityFromTable(table, name)); */
101 }
102 return(NULL);
103}
104/**
105 * xmlGetParameterEntityFromDtd:
106 * @dtd: A pointer to the DTD to search
107 * @name: The entity name
108 *
109 * Do an entity lookup in the DTD pararmeter entity hash table and
110 * return the corresponding entity, if found.
111 *
112 * Returns A pointer to the entity structure or NULL if not found.
113 */
114static xmlEntityPtr
115xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
116 xmlEntitiesTablePtr table;
117
118 if ((dtd != NULL) && (dtd->pentities != NULL)) {
119 table = (xmlEntitiesTablePtr) dtd->pentities;
120 return((xmlEntityPtr) xmlHashLookup(table, name));
121 /* return(xmlGetEntityFromTable(table, name)); */
122 }
123 return(NULL);
124}
125
126/************************************************************************
127 * *
Daniel Veillardc00cda82003-04-07 10:22:39 +0000128 * QName handling helper *
129 * *
130 ************************************************************************/
131
132/**
133 * xmlBuildQName:
134 * @ncname: the Name
135 * @prefix: the prefix
136 * @memory: preallocated memory
137 * @len: preallocated memory length
138 *
139 * Builds the QName @prefix:@ncname in @memory if there is enough space
140 * and prefix is not NULL nor empty, otherwise allocate a new string.
141 * If prefix is NULL or empty it returns ncname.
142 *
143 * Returns the new string which must be freed by the caller if different from
144 * @memory and @ncname or NULL in case of error
145 */
146xmlChar *
147xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix,
148 xmlChar *memory, int len) {
149 int lenn, lenp;
150 xmlChar *ret;
151
152 if ((ncname == NULL) || (*ncname == 0)) return(NULL);
153 if ((prefix == NULL) || (*prefix == 0)) return((xmlChar *) ncname);
154
155 lenn = strlen((char *) ncname);
156 lenp = strlen((char *) prefix);
157
158 if ((memory == NULL) || (len < lenn + lenp + 2)) {
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000159 ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000160 if (ret == NULL) return(NULL);
161 } else {
162 ret = memory;
163 }
164 memcpy(&ret[0], prefix, lenp);
165 ret[lenp] = ':';
166 memcpy(&ret[lenp + 1], ncname, lenn);
167 ret[lenn + lenp + 1] = 0;
168 return(ret);
169}
170
171/**
172 * xmlSplitQName2:
173 * @name: the full QName
174 * @prefix: a xmlChar **
175 *
176 * parse an XML qualified name string
177 *
178 * [NS 5] QName ::= (Prefix ':')? LocalPart
179 *
180 * [NS 6] Prefix ::= NCName
181 *
182 * [NS 7] LocalPart ::= NCName
183 *
184 * Returns NULL if not a QName, otherwise the local part, and prefix
185 * is updated to get the Prefix if any.
186 */
187
188xmlChar *
189xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
190 int len = 0;
191 xmlChar *ret = NULL;
192
193 *prefix = NULL;
194
195#ifndef XML_XML_NAMESPACE
196 /* xml: prefix is not really a namespace */
197 if ((name[0] == 'x') && (name[1] == 'm') &&
198 (name[2] == 'l') && (name[3] == ':'))
199 return(NULL);
200#endif
201
202 /* nasty but valid */
203 if (name[0] == ':')
204 return(NULL);
205
206 /*
207 * we are not trying to validate but just to cut, and yes it will
208 * work even if this is as set of UTF-8 encoded chars
209 */
210 while ((name[len] != 0) && (name[len] != ':'))
211 len++;
212
213 if (name[len] == 0)
214 return(NULL);
215
216 *prefix = xmlStrndup(name, len);
217 ret = xmlStrdup(&name[len + 1]);
218
219 return(ret);
220}
221
222/************************************************************************
223 * *
Daniel Veillardd2298792003-02-14 16:54:11 +0000224 * Check Name, NCName and QName strings *
225 * *
226 ************************************************************************/
227
228#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
229
230/**
231 * xmlValidateNCName:
232 * @value: the value to check
233 * @space: allow spaces in front and end of the string
234 *
235 * Check that a value conforms to the lexical space of NCName
236 *
237 * Returns 0 if this validates, a positive error code number otherwise
238 * and -1 in case of internal or API error.
239 */
240int
241xmlValidateNCName(const xmlChar *value, int space) {
242 const xmlChar *cur = value;
243 int c,l;
244
245 /*
246 * First quick algorithm for ASCII range
247 */
248 if (space)
249 while (IS_BLANK(*cur)) cur++;
250 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
251 (*cur == '_'))
252 cur++;
253 else
254 goto try_complex;
255 while (((*cur >= 'a') && (*cur <= 'z')) ||
256 ((*cur >= 'A') && (*cur <= 'Z')) ||
257 ((*cur >= '0') && (*cur <= '9')) ||
258 (*cur == '_') || (*cur == '-') || (*cur == '.'))
259 cur++;
260 if (space)
261 while (IS_BLANK(*cur)) cur++;
262 if (*cur == 0)
263 return(0);
264
265try_complex:
266 /*
267 * Second check for chars outside the ASCII range
268 */
269 cur = value;
270 c = CUR_SCHAR(cur, l);
271 if (space) {
272 while (IS_BLANK(c)) {
273 cur += l;
274 c = CUR_SCHAR(cur, l);
275 }
276 }
277 if ((!xmlIsLetter(c)) && (c != '_'))
278 return(1);
279 cur += l;
280 c = CUR_SCHAR(cur, l);
281 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') ||
282 (c == '-') || (c == '_') || xmlIsCombining(c) ||
283 xmlIsExtender(c)) {
284 cur += l;
285 c = CUR_SCHAR(cur, l);
286 }
287 if (space) {
288 while (IS_BLANK(c)) {
289 cur += l;
290 c = CUR_SCHAR(cur, l);
291 }
292 }
293 if (c != 0)
294 return(1);
295
296 return(0);
297}
298
299/**
300 * xmlValidateQName:
301 * @value: the value to check
302 * @space: allow spaces in front and end of the string
303 *
304 * Check that a value conforms to the lexical space of QName
305 *
306 * Returns 0 if this validates, a positive error code number otherwise
307 * and -1 in case of internal or API error.
308 */
309int
310xmlValidateQName(const xmlChar *value, int space) {
311 const xmlChar *cur = value;
312 int c,l;
313
314 /*
315 * First quick algorithm for ASCII range
316 */
317 if (space)
318 while (IS_BLANK(*cur)) cur++;
319 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
320 (*cur == '_'))
321 cur++;
322 else
323 goto try_complex;
324 while (((*cur >= 'a') && (*cur <= 'z')) ||
325 ((*cur >= 'A') && (*cur <= 'Z')) ||
326 ((*cur >= '0') && (*cur <= '9')) ||
327 (*cur == '_') || (*cur == '-') || (*cur == '.'))
328 cur++;
329 if (*cur == ':') {
330 cur++;
331 if (((*cur >= 'a') && (*cur <= 'z')) ||
332 ((*cur >= 'A') && (*cur <= 'Z')) ||
333 (*cur == '_'))
334 cur++;
335 else
336 goto try_complex;
337 while (((*cur >= 'a') && (*cur <= 'z')) ||
338 ((*cur >= 'A') && (*cur <= 'Z')) ||
339 ((*cur >= '0') && (*cur <= '9')) ||
340 (*cur == '_') || (*cur == '-') || (*cur == '.'))
341 cur++;
342 }
343 if (space)
344 while (IS_BLANK(*cur)) cur++;
345 if (*cur == 0)
346 return(0);
347
348try_complex:
349 /*
350 * Second check for chars outside the ASCII range
351 */
352 cur = value;
353 c = CUR_SCHAR(cur, l);
354 if (space) {
355 while (IS_BLANK(c)) {
356 cur += l;
357 c = CUR_SCHAR(cur, l);
358 }
359 }
360 if ((!xmlIsLetter(c)) && (c != '_'))
361 return(1);
362 cur += l;
363 c = CUR_SCHAR(cur, l);
364 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') ||
365 (c == '-') || (c == '_') || xmlIsCombining(c) ||
366 xmlIsExtender(c)) {
367 cur += l;
368 c = CUR_SCHAR(cur, l);
369 }
370 if (c == ':') {
371 cur += l;
372 c = CUR_SCHAR(cur, l);
373 if ((!xmlIsLetter(c)) && (c != '_'))
374 return(1);
375 cur += l;
376 c = CUR_SCHAR(cur, l);
377 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') ||
378 (c == '-') || (c == '_') || xmlIsCombining(c) ||
379 xmlIsExtender(c)) {
380 cur += l;
381 c = CUR_SCHAR(cur, l);
382 }
383 }
384 if (space) {
385 while (IS_BLANK(c)) {
386 cur += l;
387 c = CUR_SCHAR(cur, l);
388 }
389 }
390 if (c != 0)
391 return(1);
392 return(0);
393}
394
395/**
396 * xmlValidateName:
397 * @value: the value to check
398 * @space: allow spaces in front and end of the string
399 *
400 * Check that a value conforms to the lexical space of Name
401 *
402 * Returns 0 if this validates, a positive error code number otherwise
403 * and -1 in case of internal or API error.
404 */
405int
406xmlValidateName(const xmlChar *value, int space) {
407 const xmlChar *cur = value;
408 int c,l;
409
410 /*
411 * First quick algorithm for ASCII range
412 */
413 if (space)
414 while (IS_BLANK(*cur)) cur++;
415 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
416 (*cur == '_') || (*cur == ':'))
417 cur++;
418 else
419 goto try_complex;
420 while (((*cur >= 'a') && (*cur <= 'z')) ||
421 ((*cur >= 'A') && (*cur <= 'Z')) ||
422 ((*cur >= '0') && (*cur <= '9')) ||
423 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
424 cur++;
425 if (space)
426 while (IS_BLANK(*cur)) cur++;
427 if (*cur == 0)
428 return(0);
429
430try_complex:
431 /*
432 * Second check for chars outside the ASCII range
433 */
434 cur = value;
435 c = CUR_SCHAR(cur, l);
436 if (space) {
437 while (IS_BLANK(c)) {
438 cur += l;
439 c = CUR_SCHAR(cur, l);
440 }
441 }
442 if ((!xmlIsLetter(c)) && (c != '_') && (c != ':'))
443 return(1);
444 cur += l;
445 c = CUR_SCHAR(cur, l);
446 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') || (c == ':') ||
447 (c == '-') || (c == '_') || xmlIsCombining(c) || xmlIsExtender(c)) {
448 cur += l;
449 c = CUR_SCHAR(cur, l);
450 }
451 if (space) {
452 while (IS_BLANK(c)) {
453 cur += l;
454 c = CUR_SCHAR(cur, l);
455 }
456 }
457 if (c != 0)
458 return(1);
459 return(0);
460}
461
Daniel Veillardd4310742003-02-18 21:12:46 +0000462/**
463 * xmlValidateNMToken:
464 * @value: the value to check
465 * @space: allow spaces in front and end of the string
466 *
467 * Check that a value conforms to the lexical space of NMToken
468 *
469 * Returns 0 if this validates, a positive error code number otherwise
470 * and -1 in case of internal or API error.
471 */
472int
473xmlValidateNMToken(const xmlChar *value, int space) {
474 const xmlChar *cur = value;
475 int c,l;
476
477 /*
478 * First quick algorithm for ASCII range
479 */
480 if (space)
481 while (IS_BLANK(*cur)) cur++;
482 if (((*cur >= 'a') && (*cur <= 'z')) ||
483 ((*cur >= 'A') && (*cur <= 'Z')) ||
484 ((*cur >= '0') && (*cur <= '9')) ||
485 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
486 cur++;
487 else
488 goto try_complex;
489 while (((*cur >= 'a') && (*cur <= 'z')) ||
490 ((*cur >= 'A') && (*cur <= 'Z')) ||
491 ((*cur >= '0') && (*cur <= '9')) ||
492 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
493 cur++;
494 if (space)
495 while (IS_BLANK(*cur)) cur++;
496 if (*cur == 0)
497 return(0);
498
499try_complex:
500 /*
501 * Second check for chars outside the ASCII range
502 */
503 cur = value;
504 c = CUR_SCHAR(cur, l);
505 if (space) {
506 while (IS_BLANK(c)) {
507 cur += l;
508 c = CUR_SCHAR(cur, l);
509 }
510 }
511 if (!(xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') || (c == ':') ||
512 (c == '-') || (c == '_') || xmlIsCombining(c) || xmlIsExtender(c)))
513 return(1);
514 cur += l;
515 c = CUR_SCHAR(cur, l);
516 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') || (c == ':') ||
517 (c == '-') || (c == '_') || xmlIsCombining(c) || xmlIsExtender(c)) {
518 cur += l;
519 c = CUR_SCHAR(cur, l);
520 }
521 if (space) {
522 while (IS_BLANK(c)) {
523 cur += l;
524 c = CUR_SCHAR(cur, l);
525 }
526 }
527 if (c != 0)
528 return(1);
529 return(0);
530}
531
Daniel Veillardd2298792003-02-14 16:54:11 +0000532/************************************************************************
533 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000534 * Allocation and deallocation of basic structures *
535 * *
536 ************************************************************************/
537
538/**
539 * xmlSetBufferAllocationScheme:
540 * @scheme: allocation method to use
541 *
542 * Set the buffer allocation method. Types are
543 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
544 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
545 * improves performance
546 */
547void
548xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
549 xmlBufferAllocScheme = scheme;
550}
551
552/**
553 * xmlGetBufferAllocationScheme:
554 *
555 * Types are
556 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
557 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
558 * improves performance
559 *
560 * Returns the current allocation scheme
561 */
562xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000563xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000564 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000565}
566
567/**
568 * xmlNewNs:
569 * @node: the element carrying the namespace
570 * @href: the URI associated
571 * @prefix: the prefix for the namespace
572 *
573 * Creation of a new Namespace. This function will refuse to create
574 * a namespace with a similar prefix than an existing one present on this
575 * node.
576 * We use href==NULL in the case of an element creation where the namespace
577 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000578 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000579 */
580xmlNsPtr
581xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
582 xmlNsPtr cur;
583
584 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
585 return(NULL);
586
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000587 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
588 return(NULL);
589
Owen Taylor3473f882001-02-23 17:55:21 +0000590 /*
591 * Allocate a new Namespace and fill the fields.
592 */
593 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
594 if (cur == NULL) {
595 xmlGenericError(xmlGenericErrorContext,
596 "xmlNewNs : malloc failed\n");
597 return(NULL);
598 }
599 memset(cur, 0, sizeof(xmlNs));
600 cur->type = XML_LOCAL_NAMESPACE;
601
602 if (href != NULL)
603 cur->href = xmlStrdup(href);
604 if (prefix != NULL)
605 cur->prefix = xmlStrdup(prefix);
606
607 /*
608 * Add it at the end to preserve parsing order ...
609 * and checks for existing use of the prefix
610 */
611 if (node != NULL) {
612 if (node->nsDef == NULL) {
613 node->nsDef = cur;
614 } else {
615 xmlNsPtr prev = node->nsDef;
616
617 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
618 (xmlStrEqual(prev->prefix, cur->prefix))) {
619 xmlFreeNs(cur);
620 return(NULL);
621 }
622 while (prev->next != NULL) {
623 prev = prev->next;
624 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
625 (xmlStrEqual(prev->prefix, cur->prefix))) {
626 xmlFreeNs(cur);
627 return(NULL);
628 }
629 }
630 prev->next = cur;
631 }
632 }
633 return(cur);
634}
635
636/**
637 * xmlSetNs:
638 * @node: a node in the document
639 * @ns: a namespace pointer
640 *
641 * Associate a namespace to a node, a posteriori.
642 */
643void
644xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
645 if (node == NULL) {
646#ifdef DEBUG_TREE
647 xmlGenericError(xmlGenericErrorContext,
648 "xmlSetNs: node == NULL\n");
649#endif
650 return;
651 }
652 node->ns = ns;
653}
654
655/**
656 * xmlFreeNs:
657 * @cur: the namespace pointer
658 *
659 * Free up the structures associated to a namespace
660 */
661void
662xmlFreeNs(xmlNsPtr cur) {
663 if (cur == NULL) {
664#ifdef DEBUG_TREE
665 xmlGenericError(xmlGenericErrorContext,
666 "xmlFreeNs : ns == NULL\n");
667#endif
668 return;
669 }
670 if (cur->href != NULL) xmlFree((char *) cur->href);
671 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000672 xmlFree(cur);
673}
674
675/**
676 * xmlFreeNsList:
677 * @cur: the first namespace pointer
678 *
679 * Free up all the structures associated to the chained namespaces.
680 */
681void
682xmlFreeNsList(xmlNsPtr cur) {
683 xmlNsPtr next;
684 if (cur == NULL) {
685#ifdef DEBUG_TREE
686 xmlGenericError(xmlGenericErrorContext,
687 "xmlFreeNsList : ns == NULL\n");
688#endif
689 return;
690 }
691 while (cur != NULL) {
692 next = cur->next;
693 xmlFreeNs(cur);
694 cur = next;
695 }
696}
697
698/**
699 * xmlNewDtd:
700 * @doc: the document pointer
701 * @name: the DTD name
702 * @ExternalID: the external ID
703 * @SystemID: the system ID
704 *
705 * Creation of a new DTD for the external subset. To create an
706 * internal subset, use xmlCreateIntSubset().
707 *
708 * Returns a pointer to the new DTD structure
709 */
710xmlDtdPtr
711xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
712 const xmlChar *ExternalID, const xmlChar *SystemID) {
713 xmlDtdPtr cur;
714
715 if ((doc != NULL) && (doc->extSubset != NULL)) {
716#ifdef DEBUG_TREE
717 xmlGenericError(xmlGenericErrorContext,
718 "xmlNewDtd(%s): document %s already have a DTD %s\n",
719 /* !!! */ (char *) name, doc->name,
720 /* !!! */ (char *)doc->extSubset->name);
721#endif
722 return(NULL);
723 }
724
725 /*
726 * Allocate a new DTD and fill the fields.
727 */
728 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
729 if (cur == NULL) {
730 xmlGenericError(xmlGenericErrorContext,
731 "xmlNewDtd : malloc failed\n");
732 return(NULL);
733 }
734 memset(cur, 0 , sizeof(xmlDtd));
735 cur->type = XML_DTD_NODE;
736
737 if (name != NULL)
738 cur->name = xmlStrdup(name);
739 if (ExternalID != NULL)
740 cur->ExternalID = xmlStrdup(ExternalID);
741 if (SystemID != NULL)
742 cur->SystemID = xmlStrdup(SystemID);
743 if (doc != NULL)
744 doc->extSubset = cur;
745 cur->doc = doc;
746
Daniel Veillard5335dc52003-01-01 20:59:38 +0000747 if (xmlRegisterNodeDefaultValue)
748 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000749 return(cur);
750}
751
752/**
753 * xmlGetIntSubset:
754 * @doc: the document pointer
755 *
756 * Get the internal subset of a document
757 * Returns a pointer to the DTD structure or NULL if not found
758 */
759
760xmlDtdPtr
761xmlGetIntSubset(xmlDocPtr doc) {
762 xmlNodePtr cur;
763
764 if (doc == NULL)
765 return(NULL);
766 cur = doc->children;
767 while (cur != NULL) {
768 if (cur->type == XML_DTD_NODE)
769 return((xmlDtdPtr) cur);
770 cur = cur->next;
771 }
772 return((xmlDtdPtr) doc->intSubset);
773}
774
775/**
776 * xmlCreateIntSubset:
777 * @doc: the document pointer
778 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000779 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000780 * @SystemID: the system ID
781 *
782 * Create the internal subset of a document
783 * Returns a pointer to the new DTD structure
784 */
785xmlDtdPtr
786xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
787 const xmlChar *ExternalID, const xmlChar *SystemID) {
788 xmlDtdPtr cur;
789
790 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
791#ifdef DEBUG_TREE
792 xmlGenericError(xmlGenericErrorContext,
793
794 "xmlCreateIntSubset(): document %s already have an internal subset\n",
795 doc->name);
796#endif
797 return(NULL);
798 }
799
800 /*
801 * Allocate a new DTD and fill the fields.
802 */
803 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
804 if (cur == NULL) {
805 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000806 "xmlCreateIntSubset : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000807 return(NULL);
808 }
809 memset(cur, 0, sizeof(xmlDtd));
810 cur->type = XML_DTD_NODE;
811
812 if (name != NULL)
813 cur->name = xmlStrdup(name);
814 if (ExternalID != NULL)
815 cur->ExternalID = xmlStrdup(ExternalID);
816 if (SystemID != NULL)
817 cur->SystemID = xmlStrdup(SystemID);
818 if (doc != NULL) {
819 doc->intSubset = cur;
820 cur->parent = doc;
821 cur->doc = doc;
822 if (doc->children == NULL) {
823 doc->children = (xmlNodePtr) cur;
824 doc->last = (xmlNodePtr) cur;
825 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000826 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000827 xmlNodePtr prev;
828
Owen Taylor3473f882001-02-23 17:55:21 +0000829 prev = doc->children;
830 prev->prev = (xmlNodePtr) cur;
831 cur->next = prev;
832 doc->children = (xmlNodePtr) cur;
833 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000834 xmlNodePtr next;
835
836 next = doc->children;
837 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
838 next = next->next;
839 if (next == NULL) {
840 cur->prev = doc->last;
841 cur->prev->next = (xmlNodePtr) cur;
842 cur->next = NULL;
843 doc->last = (xmlNodePtr) cur;
844 } else {
845 cur->next = next;
846 cur->prev = next->prev;
847 if (cur->prev == NULL)
848 doc->children = (xmlNodePtr) cur;
849 else
850 cur->prev->next = (xmlNodePtr) cur;
851 next->prev = (xmlNodePtr) cur;
852 }
Owen Taylor3473f882001-02-23 17:55:21 +0000853 }
854 }
855 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000856
857 if (xmlRegisterNodeDefaultValue)
858 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000859 return(cur);
860}
861
862/**
863 * xmlFreeDtd:
864 * @cur: the DTD structure to free up
865 *
866 * Free a DTD structure.
867 */
868void
869xmlFreeDtd(xmlDtdPtr cur) {
870 if (cur == NULL) {
871#ifdef DEBUG_TREE
872 xmlGenericError(xmlGenericErrorContext,
873 "xmlFreeDtd : DTD == NULL\n");
874#endif
875 return;
876 }
Daniel Veillard5335dc52003-01-01 20:59:38 +0000877
878 if (xmlDeregisterNodeDefaultValue)
879 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
880
Owen Taylor3473f882001-02-23 17:55:21 +0000881 if (cur->children != NULL) {
882 xmlNodePtr next, c = cur->children;
883
884 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000885 * Cleanup all the DTD comments they are not in the DTD
Owen Taylor3473f882001-02-23 17:55:21 +0000886 * indexes.
887 */
888 while (c != NULL) {
889 next = c->next;
890 if (c->type == XML_COMMENT_NODE) {
891 xmlUnlinkNode(c);
892 xmlFreeNode(c);
893 }
894 c = next;
895 }
896 }
897 if (cur->name != NULL) xmlFree((char *) cur->name);
898 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
899 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
900 /* TODO !!! */
901 if (cur->notations != NULL)
902 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
903
904 if (cur->elements != NULL)
905 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
906 if (cur->attributes != NULL)
907 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
908 if (cur->entities != NULL)
909 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
910 if (cur->pentities != NULL)
911 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
912
Owen Taylor3473f882001-02-23 17:55:21 +0000913 xmlFree(cur);
914}
915
916/**
917 * xmlNewDoc:
918 * @version: xmlChar string giving the version of XML "1.0"
919 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000920 * Creates a new XML document
921 *
Owen Taylor3473f882001-02-23 17:55:21 +0000922 * Returns a new document
923 */
924xmlDocPtr
925xmlNewDoc(const xmlChar *version) {
926 xmlDocPtr cur;
927
928 if (version == NULL)
929 version = (const xmlChar *) "1.0";
930
931 /*
932 * Allocate a new document and fill the fields.
933 */
934 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
935 if (cur == NULL) {
936 xmlGenericError(xmlGenericErrorContext,
937 "xmlNewDoc : malloc failed\n");
938 return(NULL);
939 }
940 memset(cur, 0, sizeof(xmlDoc));
941 cur->type = XML_DOCUMENT_NODE;
942
943 cur->version = xmlStrdup(version);
944 cur->standalone = -1;
945 cur->compression = -1; /* not initialized */
946 cur->doc = cur;
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000947 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +0000948
949 if (xmlRegisterNodeDefaultValue)
950 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000951 return(cur);
952}
953
954/**
955 * xmlFreeDoc:
956 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +0000957 *
958 * Free up all the structures used by a document, tree included.
959 */
960void
961xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +0000962 xmlDtdPtr extSubset, intSubset;
963
Owen Taylor3473f882001-02-23 17:55:21 +0000964 if (cur == NULL) {
965#ifdef DEBUG_TREE
966 xmlGenericError(xmlGenericErrorContext,
967 "xmlFreeDoc : document == NULL\n");
968#endif
969 return;
970 }
Daniel Veillard5335dc52003-01-01 20:59:38 +0000971
972 if (xmlDeregisterNodeDefaultValue)
973 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
974
Daniel Veillard76d66f42001-05-16 21:05:17 +0000975 /*
976 * Do this before freeing the children list to avoid ID lookups
977 */
978 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
979 cur->ids = NULL;
980 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
981 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000982 extSubset = cur->extSubset;
983 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +0000984 if (intSubset == extSubset)
985 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000986 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000987 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000988 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000989 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000990 }
Daniel Veillarda9142e72001-06-19 11:07:54 +0000991 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000992 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000993 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000994 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000995 }
996
997 if (cur->children != NULL) xmlFreeNodeList(cur->children);
998
Owen Taylor3473f882001-02-23 17:55:21 +0000999 if (cur->version != NULL) xmlFree((char *) cur->version);
1000 if (cur->name != NULL) xmlFree((char *) cur->name);
1001 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00001002 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00001003 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Owen Taylor3473f882001-02-23 17:55:21 +00001004 xmlFree(cur);
1005}
1006
1007/**
1008 * xmlStringLenGetNodeList:
1009 * @doc: the document
1010 * @value: the value of the text
1011 * @len: the length of the string value
1012 *
1013 * Parse the value string and build the node list associated. Should
1014 * produce a flat tree with only TEXTs and ENTITY_REFs.
1015 * Returns a pointer to the first child
1016 */
1017xmlNodePtr
1018xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1019 xmlNodePtr ret = NULL, last = NULL;
1020 xmlNodePtr node;
1021 xmlChar *val;
1022 const xmlChar *cur = value;
1023 const xmlChar *q;
1024 xmlEntityPtr ent;
1025
1026 if (value == NULL) return(NULL);
1027
1028 q = cur;
1029 while ((*cur != 0) && (cur - value < len)) {
1030 if (*cur == '&') {
1031 /*
1032 * Save the current text.
1033 */
1034 if (cur != q) {
1035 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1036 xmlNodeAddContentLen(last, q, cur - q);
1037 } else {
1038 node = xmlNewDocTextLen(doc, q, cur - q);
1039 if (node == NULL) return(ret);
1040 if (last == NULL)
1041 last = ret = node;
1042 else {
1043 last->next = node;
1044 node->prev = last;
1045 last = node;
1046 }
1047 }
1048 }
1049 /*
1050 * Read the entity string
1051 */
1052 cur++;
1053 q = cur;
1054 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
1055 if ((*cur == 0) || (cur - value >= len)) {
1056#ifdef DEBUG_TREE
1057 xmlGenericError(xmlGenericErrorContext,
1058 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
1059#endif
1060 return(ret);
1061 }
1062 if (cur != q) {
1063 /*
1064 * Predefined entities don't generate nodes
1065 */
1066 val = xmlStrndup(q, cur - q);
1067 ent = xmlGetDocEntity(doc, val);
1068 if ((ent != NULL) &&
1069 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1070 if (last == NULL) {
1071 node = xmlNewDocText(doc, ent->content);
1072 last = ret = node;
1073 } else
1074 xmlNodeAddContent(last, ent->content);
1075
1076 } else {
1077 /*
1078 * Create a new REFERENCE_REF node
1079 */
1080 node = xmlNewReference(doc, val);
1081 if (node == NULL) {
1082 if (val != NULL) xmlFree(val);
1083 return(ret);
1084 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001085 else if ((ent != NULL) && (ent->children == NULL)) {
1086 xmlNodePtr tmp;
1087
1088 ent->children =
1089 xmlStringGetNodeList(doc, (const xmlChar*)node->content);
1090 tmp = ent->children;
1091 while (tmp) {
1092 tmp->parent = (xmlNodePtr)ent;
1093 tmp = tmp->next;
1094 }
1095 }
Owen Taylor3473f882001-02-23 17:55:21 +00001096 if (last == NULL)
1097 last = ret = node;
1098 else {
1099 last->next = node;
1100 node->prev = last;
1101 last = node;
1102 }
1103 }
1104 xmlFree(val);
1105 }
1106 cur++;
1107 q = cur;
1108 } else
1109 cur++;
1110 }
1111 if (cur != q) {
1112 /*
1113 * Handle the last piece of text.
1114 */
1115 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1116 xmlNodeAddContentLen(last, q, cur - q);
1117 } else {
1118 node = xmlNewDocTextLen(doc, q, cur - q);
1119 if (node == NULL) return(ret);
1120 if (last == NULL)
1121 last = ret = node;
1122 else {
1123 last->next = node;
1124 node->prev = last;
1125 last = node;
1126 }
1127 }
1128 }
1129 return(ret);
1130}
1131
1132/**
1133 * xmlStringGetNodeList:
1134 * @doc: the document
1135 * @value: the value of the attribute
1136 *
1137 * Parse the value string and build the node list associated. Should
1138 * produce a flat tree with only TEXTs and ENTITY_REFs.
1139 * Returns a pointer to the first child
1140 */
1141xmlNodePtr
1142xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1143 xmlNodePtr ret = NULL, last = NULL;
1144 xmlNodePtr node;
1145 xmlChar *val;
1146 const xmlChar *cur = value;
1147 const xmlChar *q;
1148 xmlEntityPtr ent;
1149
1150 if (value == NULL) return(NULL);
1151
1152 q = cur;
1153 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001154 if (cur[0] == '&') {
1155 int charval = 0;
1156 xmlChar tmp;
1157
Owen Taylor3473f882001-02-23 17:55:21 +00001158 /*
1159 * Save the current text.
1160 */
1161 if (cur != q) {
1162 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1163 xmlNodeAddContentLen(last, q, cur - q);
1164 } else {
1165 node = xmlNewDocTextLen(doc, q, cur - q);
1166 if (node == NULL) return(ret);
1167 if (last == NULL)
1168 last = ret = node;
1169 else {
1170 last->next = node;
1171 node->prev = last;
1172 last = node;
1173 }
1174 }
1175 }
Owen Taylor3473f882001-02-23 17:55:21 +00001176 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001177 if ((cur[1] == '#') && (cur[2] == 'x')) {
1178 cur += 3;
1179 tmp = *cur;
1180 while (tmp != ';') { /* Non input consuming loop */
1181 if ((tmp >= '0') && (tmp <= '9'))
1182 charval = charval * 16 + (tmp - '0');
1183 else if ((tmp >= 'a') && (tmp <= 'f'))
1184 charval = charval * 16 + (tmp - 'a') + 10;
1185 else if ((tmp >= 'A') && (tmp <= 'F'))
1186 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001187 else {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001188 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001189 "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001190 charval = 0;
1191 break;
1192 }
1193 cur++;
1194 tmp = *cur;
1195 }
1196 if (tmp == ';')
1197 cur++;
1198 q = cur;
1199 } else if (cur[1] == '#') {
1200 cur += 2;
1201 tmp = *cur;
1202 while (tmp != ';') { /* Non input consuming loops */
1203 if ((tmp >= '0') && (tmp <= '9'))
1204 charval = charval * 10 + (tmp - '0');
1205 else {
1206 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001207 "xmlStringGetNodeList: invalid decimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001208 charval = 0;
1209 break;
1210 }
1211 cur++;
1212 tmp = *cur;
1213 }
1214 if (tmp == ';')
1215 cur++;
1216 q = cur;
1217 } else {
1218 /*
1219 * Read the entity string
1220 */
1221 cur++;
1222 q = cur;
1223 while ((*cur != 0) && (*cur != ';')) cur++;
1224 if (*cur == 0) {
1225#ifdef DEBUG_TREE
1226 xmlGenericError(xmlGenericErrorContext,
1227 "xmlStringGetNodeList: unterminated entity %30s\n", q);
1228#endif
1229 return(ret);
1230 }
1231 if (cur != q) {
1232 /*
1233 * Predefined entities don't generate nodes
1234 */
1235 val = xmlStrndup(q, cur - q);
1236 ent = xmlGetDocEntity(doc, val);
1237 if ((ent != NULL) &&
1238 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1239 if (last == NULL) {
1240 node = xmlNewDocText(doc, ent->content);
1241 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001242 } else if (last->type != XML_TEXT_NODE) {
1243 node = xmlNewDocText(doc, ent->content);
1244 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001245 } else
1246 xmlNodeAddContent(last, ent->content);
1247
1248 } else {
1249 /*
1250 * Create a new REFERENCE_REF node
1251 */
1252 node = xmlNewReference(doc, val);
1253 if (node == NULL) {
1254 if (val != NULL) xmlFree(val);
1255 return(ret);
1256 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001257 else if ((ent != NULL) && (ent->children == NULL)) {
1258 xmlNodePtr temp;
1259
1260 ent->children = xmlStringGetNodeList(doc,
1261 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001262 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001263 temp = ent->children;
1264 while (temp) {
1265 temp->parent = (xmlNodePtr)ent;
1266 temp = temp->next;
1267 }
1268 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001269 if (last == NULL) {
1270 last = ret = node;
1271 } else {
1272 last = xmlAddNextSibling(last, node);
1273 }
1274 }
1275 xmlFree(val);
1276 }
1277 cur++;
1278 q = cur;
1279 }
1280 if (charval != 0) {
1281 xmlChar buf[10];
1282 int len;
1283
1284 len = xmlCopyCharMultiByte(buf, charval);
1285 buf[len] = 0;
1286 node = xmlNewDocText(doc, buf);
1287 if (node != NULL) {
1288 if (last == NULL) {
1289 last = ret = node;
1290 } else {
1291 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001292 }
1293 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001294
1295 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001296 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001297 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001298 cur++;
1299 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001300 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001301 /*
1302 * Handle the last piece of text.
1303 */
1304 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1305 xmlNodeAddContentLen(last, q, cur - q);
1306 } else {
1307 node = xmlNewDocTextLen(doc, q, cur - q);
1308 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001309 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001310 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001311 } else {
1312 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001313 }
1314 }
1315 }
1316 return(ret);
1317}
1318
1319/**
1320 * xmlNodeListGetString:
1321 * @doc: the document
1322 * @list: a Node list
1323 * @inLine: should we replace entity contents or show their external form
1324 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001325 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001326 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001327 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001328 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001329 */
1330xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001331xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1332{
Owen Taylor3473f882001-02-23 17:55:21 +00001333 xmlNodePtr node = list;
1334 xmlChar *ret = NULL;
1335 xmlEntityPtr ent;
1336
Daniel Veillard7646b182002-04-20 06:41:40 +00001337 if (list == NULL)
1338 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001339
1340 while (node != NULL) {
1341 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001342 (node->type == XML_CDATA_SECTION_NODE)) {
1343 if (inLine) {
1344 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001345 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001346 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001347
Daniel Veillard7646b182002-04-20 06:41:40 +00001348 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1349 if (buffer != NULL) {
1350 ret = xmlStrcat(ret, buffer);
1351 xmlFree(buffer);
1352 }
1353 }
1354 } else if (node->type == XML_ENTITY_REF_NODE) {
1355 if (inLine) {
1356 ent = xmlGetDocEntity(doc, node->name);
1357 if (ent != NULL) {
1358 xmlChar *buffer;
1359
1360 /* an entity content can be any "well balanced chunk",
1361 * i.e. the result of the content [43] production:
1362 * http://www.w3.org/TR/REC-xml#NT-content.
1363 * So it can contain text, CDATA section or nested
1364 * entity reference nodes (among others).
1365 * -> we recursive call xmlNodeListGetString()
1366 * which handles these types */
1367 buffer = xmlNodeListGetString(doc, ent->children, 1);
1368 if (buffer != NULL) {
1369 ret = xmlStrcat(ret, buffer);
1370 xmlFree(buffer);
1371 }
1372 } else {
1373 ret = xmlStrcat(ret, node->content);
1374 }
1375 } else {
1376 xmlChar buf[2];
1377
1378 buf[0] = '&';
1379 buf[1] = 0;
1380 ret = xmlStrncat(ret, buf, 1);
1381 ret = xmlStrcat(ret, node->name);
1382 buf[0] = ';';
1383 buf[1] = 0;
1384 ret = xmlStrncat(ret, buf, 1);
1385 }
1386 }
1387#if 0
1388 else {
1389 xmlGenericError(xmlGenericErrorContext,
1390 "xmlGetNodeListString : invalid node type %d\n",
1391 node->type);
1392 }
1393#endif
1394 node = node->next;
1395 }
1396 return (ret);
1397}
Owen Taylor3473f882001-02-23 17:55:21 +00001398/**
1399 * xmlNodeListGetRawString:
1400 * @doc: the document
1401 * @list: a Node list
1402 * @inLine: should we replace entity contents or show their external form
1403 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001404 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001405 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1406 * this function doesn't do any character encoding handling.
1407 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001408 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001409 */
1410xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001411xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1412{
Owen Taylor3473f882001-02-23 17:55:21 +00001413 xmlNodePtr node = list;
1414 xmlChar *ret = NULL;
1415 xmlEntityPtr ent;
1416
Daniel Veillard7646b182002-04-20 06:41:40 +00001417 if (list == NULL)
1418 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001419
1420 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001421 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001422 (node->type == XML_CDATA_SECTION_NODE)) {
1423 if (inLine) {
1424 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001425 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001426 xmlChar *buffer;
1427
1428 buffer = xmlEncodeSpecialChars(doc, node->content);
1429 if (buffer != NULL) {
1430 ret = xmlStrcat(ret, buffer);
1431 xmlFree(buffer);
1432 }
1433 }
1434 } else if (node->type == XML_ENTITY_REF_NODE) {
1435 if (inLine) {
1436 ent = xmlGetDocEntity(doc, node->name);
1437 if (ent != NULL) {
1438 xmlChar *buffer;
1439
1440 /* an entity content can be any "well balanced chunk",
1441 * i.e. the result of the content [43] production:
1442 * http://www.w3.org/TR/REC-xml#NT-content.
1443 * So it can contain text, CDATA section or nested
1444 * entity reference nodes (among others).
1445 * -> we recursive call xmlNodeListGetRawString()
1446 * which handles these types */
1447 buffer =
1448 xmlNodeListGetRawString(doc, ent->children, 1);
1449 if (buffer != NULL) {
1450 ret = xmlStrcat(ret, buffer);
1451 xmlFree(buffer);
1452 }
1453 } else {
1454 ret = xmlStrcat(ret, node->content);
1455 }
1456 } else {
1457 xmlChar buf[2];
1458
1459 buf[0] = '&';
1460 buf[1] = 0;
1461 ret = xmlStrncat(ret, buf, 1);
1462 ret = xmlStrcat(ret, node->name);
1463 buf[0] = ';';
1464 buf[1] = 0;
1465 ret = xmlStrncat(ret, buf, 1);
1466 }
1467 }
Owen Taylor3473f882001-02-23 17:55:21 +00001468#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001469 else {
1470 xmlGenericError(xmlGenericErrorContext,
1471 "xmlGetNodeListString : invalid node type %d\n",
1472 node->type);
1473 }
Owen Taylor3473f882001-02-23 17:55:21 +00001474#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001475 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001476 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001477 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001478}
1479
1480/**
1481 * xmlNewProp:
1482 * @node: the holding node
1483 * @name: the name of the attribute
1484 * @value: the value of the attribute
1485 *
1486 * Create a new property carried by a node.
1487 * Returns a pointer to the attribute
1488 */
1489xmlAttrPtr
1490xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1491 xmlAttrPtr cur;
1492 xmlDocPtr doc = NULL;
1493
1494 if (name == NULL) {
1495#ifdef DEBUG_TREE
1496 xmlGenericError(xmlGenericErrorContext,
1497 "xmlNewProp : name == NULL\n");
1498#endif
1499 return(NULL);
1500 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00001501 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
1502 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001503
1504 /*
1505 * Allocate a new property and fill the fields.
1506 */
1507 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1508 if (cur == NULL) {
1509 xmlGenericError(xmlGenericErrorContext,
1510 "xmlNewProp : malloc failed\n");
1511 return(NULL);
1512 }
1513 memset(cur, 0, sizeof(xmlAttr));
1514 cur->type = XML_ATTRIBUTE_NODE;
1515
1516 cur->parent = node;
1517 if (node != NULL) {
1518 doc = node->doc;
1519 cur->doc = doc;
1520 }
1521 cur->name = xmlStrdup(name);
1522 if (value != NULL) {
1523 xmlChar *buffer;
1524 xmlNodePtr tmp;
1525
1526 buffer = xmlEncodeEntitiesReentrant(doc, value);
1527 cur->children = xmlStringGetNodeList(doc, buffer);
1528 cur->last = NULL;
1529 tmp = cur->children;
1530 while (tmp != NULL) {
1531 tmp->parent = (xmlNodePtr) cur;
1532 tmp->doc = doc;
1533 if (tmp->next == NULL)
1534 cur->last = tmp;
1535 tmp = tmp->next;
1536 }
1537 xmlFree(buffer);
1538 }
1539
1540 /*
1541 * Add it at the end to preserve parsing order ...
1542 */
1543 if (node != NULL) {
1544 if (node->properties == NULL) {
1545 node->properties = cur;
1546 } else {
1547 xmlAttrPtr prev = node->properties;
1548
1549 while (prev->next != NULL) prev = prev->next;
1550 prev->next = cur;
1551 cur->prev = prev;
1552 }
1553 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001554
1555 if (xmlRegisterNodeDefaultValue)
1556 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001557 return(cur);
1558}
1559
1560/**
1561 * xmlNewNsProp:
1562 * @node: the holding node
1563 * @ns: the namespace
1564 * @name: the name of the attribute
1565 * @value: the value of the attribute
1566 *
1567 * Create a new property tagged with a namespace and carried by a node.
1568 * Returns a pointer to the attribute
1569 */
1570xmlAttrPtr
1571xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1572 const xmlChar *value) {
1573 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001574 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001575
1576 if (name == NULL) {
1577#ifdef DEBUG_TREE
1578 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001579 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001580#endif
1581 return(NULL);
1582 }
1583
1584 /*
1585 * Allocate a new property and fill the fields.
1586 */
1587 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1588 if (cur == NULL) {
1589 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001590 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001591 return(NULL);
1592 }
1593 memset(cur, 0, sizeof(xmlAttr));
1594 cur->type = XML_ATTRIBUTE_NODE;
1595
1596 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001597 if (node != NULL) {
1598 doc = node->doc;
1599 cur->doc = doc;
1600 }
Owen Taylor3473f882001-02-23 17:55:21 +00001601 cur->ns = ns;
1602 cur->name = xmlStrdup(name);
1603 if (value != NULL) {
1604 xmlChar *buffer;
1605 xmlNodePtr tmp;
1606
Daniel Veillarda682b212001-06-07 19:59:42 +00001607 buffer = xmlEncodeEntitiesReentrant(doc, value);
1608 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001609 cur->last = NULL;
1610 tmp = cur->children;
1611 while (tmp != NULL) {
1612 tmp->parent = (xmlNodePtr) cur;
1613 if (tmp->next == NULL)
1614 cur->last = tmp;
1615 tmp = tmp->next;
1616 }
1617 xmlFree(buffer);
1618 }
1619
1620 /*
1621 * Add it at the end to preserve parsing order ...
1622 */
1623 if (node != NULL) {
1624 if (node->properties == NULL) {
1625 node->properties = cur;
1626 } else {
1627 xmlAttrPtr prev = node->properties;
1628
1629 while (prev->next != NULL) prev = prev->next;
1630 prev->next = cur;
1631 cur->prev = prev;
1632 }
1633 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001634
1635 if (xmlRegisterNodeDefaultValue)
1636 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001637 return(cur);
1638}
1639
1640/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001641 * xmlNewNsPropEatName:
1642 * @node: the holding node
1643 * @ns: the namespace
1644 * @name: the name of the attribute
1645 * @value: the value of the attribute
1646 *
1647 * Create a new property tagged with a namespace and carried by a node.
1648 * Returns a pointer to the attribute
1649 */
1650xmlAttrPtr
1651xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1652 const xmlChar *value) {
1653 xmlAttrPtr cur;
1654 xmlDocPtr doc = NULL;
1655
1656 if (name == NULL) {
1657#ifdef DEBUG_TREE
1658 xmlGenericError(xmlGenericErrorContext,
1659 "xmlNewNsPropEatName : name == NULL\n");
1660#endif
1661 return(NULL);
1662 }
1663
1664 /*
1665 * Allocate a new property and fill the fields.
1666 */
1667 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1668 if (cur == NULL) {
1669 xmlGenericError(xmlGenericErrorContext,
1670 "xmlNewNsPropEatName : malloc failed\n");
1671 return(NULL);
1672 }
1673 memset(cur, 0, sizeof(xmlAttr));
1674 cur->type = XML_ATTRIBUTE_NODE;
1675
1676 cur->parent = node;
1677 if (node != NULL) {
1678 doc = node->doc;
1679 cur->doc = doc;
1680 }
1681 cur->ns = ns;
1682 cur->name = name;
1683 if (value != NULL) {
1684 xmlChar *buffer;
1685 xmlNodePtr tmp;
1686
1687 buffer = xmlEncodeEntitiesReentrant(doc, value);
1688 cur->children = xmlStringGetNodeList(doc, buffer);
1689 cur->last = NULL;
1690 tmp = cur->children;
1691 while (tmp != NULL) {
1692 tmp->parent = (xmlNodePtr) cur;
1693 if (tmp->next == NULL)
1694 cur->last = tmp;
1695 tmp = tmp->next;
1696 }
1697 xmlFree(buffer);
1698 }
1699
1700 /*
1701 * Add it at the end to preserve parsing order ...
1702 */
1703 if (node != NULL) {
1704 if (node->properties == NULL) {
1705 node->properties = cur;
1706 } else {
1707 xmlAttrPtr prev = node->properties;
1708
1709 while (prev->next != NULL) prev = prev->next;
1710 prev->next = cur;
1711 cur->prev = prev;
1712 }
1713 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001714
1715 if (xmlRegisterNodeDefaultValue)
1716 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001717 return(cur);
1718}
1719
1720/**
Owen Taylor3473f882001-02-23 17:55:21 +00001721 * xmlNewDocProp:
1722 * @doc: the document
1723 * @name: the name of the attribute
1724 * @value: the value of the attribute
1725 *
1726 * Create a new property carried by a document.
1727 * Returns a pointer to the attribute
1728 */
1729xmlAttrPtr
1730xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1731 xmlAttrPtr cur;
1732
1733 if (name == NULL) {
1734#ifdef DEBUG_TREE
1735 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001736 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001737#endif
1738 return(NULL);
1739 }
1740
1741 /*
1742 * Allocate a new property and fill the fields.
1743 */
1744 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1745 if (cur == NULL) {
1746 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001747 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001748 return(NULL);
1749 }
1750 memset(cur, 0, sizeof(xmlAttr));
1751 cur->type = XML_ATTRIBUTE_NODE;
1752
1753 cur->name = xmlStrdup(name);
1754 cur->doc = doc;
1755 if (value != NULL) {
1756 xmlNodePtr tmp;
1757
1758 cur->children = xmlStringGetNodeList(doc, value);
1759 cur->last = NULL;
1760
1761 tmp = cur->children;
1762 while (tmp != NULL) {
1763 tmp->parent = (xmlNodePtr) cur;
1764 if (tmp->next == NULL)
1765 cur->last = tmp;
1766 tmp = tmp->next;
1767 }
1768 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001769
1770 if (xmlRegisterNodeDefaultValue)
1771 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001772 return(cur);
1773}
1774
1775/**
1776 * xmlFreePropList:
1777 * @cur: the first property in the list
1778 *
1779 * Free a property and all its siblings, all the children are freed too.
1780 */
1781void
1782xmlFreePropList(xmlAttrPtr cur) {
1783 xmlAttrPtr next;
1784 if (cur == NULL) {
1785#ifdef DEBUG_TREE
1786 xmlGenericError(xmlGenericErrorContext,
1787 "xmlFreePropList : property == NULL\n");
1788#endif
1789 return;
1790 }
1791 while (cur != NULL) {
1792 next = cur->next;
1793 xmlFreeProp(cur);
1794 cur = next;
1795 }
1796}
1797
1798/**
1799 * xmlFreeProp:
1800 * @cur: an attribute
1801 *
1802 * Free one attribute, all the content is freed too
1803 */
1804void
1805xmlFreeProp(xmlAttrPtr cur) {
1806 if (cur == NULL) {
1807#ifdef DEBUG_TREE
1808 xmlGenericError(xmlGenericErrorContext,
1809 "xmlFreeProp : property == NULL\n");
1810#endif
1811 return;
1812 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001813
1814 if (xmlDeregisterNodeDefaultValue)
1815 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1816
Owen Taylor3473f882001-02-23 17:55:21 +00001817 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001818 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1819 ((cur->parent->doc->intSubset != NULL) ||
1820 (cur->parent->doc->extSubset != NULL))) {
1821 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1822 xmlRemoveID(cur->parent->doc, cur);
1823 }
Owen Taylor3473f882001-02-23 17:55:21 +00001824 if (cur->name != NULL) xmlFree((char *) cur->name);
1825 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001826 xmlFree(cur);
1827}
1828
1829/**
1830 * xmlRemoveProp:
1831 * @cur: an attribute
1832 *
1833 * Unlink and free one attribute, all the content is freed too
1834 * Note this doesn't work for namespace definition attributes
1835 *
1836 * Returns 0 if success and -1 in case of error.
1837 */
1838int
1839xmlRemoveProp(xmlAttrPtr cur) {
1840 xmlAttrPtr tmp;
1841 if (cur == NULL) {
1842#ifdef DEBUG_TREE
1843 xmlGenericError(xmlGenericErrorContext,
1844 "xmlRemoveProp : cur == NULL\n");
1845#endif
1846 return(-1);
1847 }
1848 if (cur->parent == NULL) {
1849#ifdef DEBUG_TREE
1850 xmlGenericError(xmlGenericErrorContext,
1851 "xmlRemoveProp : cur->parent == NULL\n");
1852#endif
1853 return(-1);
1854 }
1855 tmp = cur->parent->properties;
1856 if (tmp == cur) {
1857 cur->parent->properties = cur->next;
1858 xmlFreeProp(cur);
1859 return(0);
1860 }
1861 while (tmp != NULL) {
1862 if (tmp->next == cur) {
1863 tmp->next = cur->next;
1864 if (tmp->next != NULL)
1865 tmp->next->prev = tmp;
1866 xmlFreeProp(cur);
1867 return(0);
1868 }
1869 tmp = tmp->next;
1870 }
1871#ifdef DEBUG_TREE
1872 xmlGenericError(xmlGenericErrorContext,
1873 "xmlRemoveProp : attribute not owned by its node\n");
1874#endif
1875 return(-1);
1876}
1877
1878/**
1879 * xmlNewPI:
1880 * @name: the processing instruction name
1881 * @content: the PI content
1882 *
1883 * Creation of a processing instruction element.
1884 * Returns a pointer to the new node object.
1885 */
1886xmlNodePtr
1887xmlNewPI(const xmlChar *name, const xmlChar *content) {
1888 xmlNodePtr cur;
1889
1890 if (name == NULL) {
1891#ifdef DEBUG_TREE
1892 xmlGenericError(xmlGenericErrorContext,
1893 "xmlNewPI : name == NULL\n");
1894#endif
1895 return(NULL);
1896 }
1897
1898 /*
1899 * Allocate a new node and fill the fields.
1900 */
1901 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1902 if (cur == NULL) {
1903 xmlGenericError(xmlGenericErrorContext,
1904 "xmlNewPI : malloc failed\n");
1905 return(NULL);
1906 }
1907 memset(cur, 0, sizeof(xmlNode));
1908 cur->type = XML_PI_NODE;
1909
1910 cur->name = xmlStrdup(name);
1911 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001912 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001913 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001914
1915 if (xmlRegisterNodeDefaultValue)
1916 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001917 return(cur);
1918}
1919
1920/**
1921 * xmlNewNode:
1922 * @ns: namespace if any
1923 * @name: the node name
1924 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001925 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001926 *
1927 * Returns a pointer to the new node object.
1928 */
1929xmlNodePtr
1930xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1931 xmlNodePtr cur;
1932
1933 if (name == NULL) {
1934#ifdef DEBUG_TREE
1935 xmlGenericError(xmlGenericErrorContext,
1936 "xmlNewNode : name == NULL\n");
1937#endif
1938 return(NULL);
1939 }
1940
1941 /*
1942 * Allocate a new node and fill the fields.
1943 */
1944 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1945 if (cur == NULL) {
1946 xmlGenericError(xmlGenericErrorContext,
1947 "xmlNewNode : malloc failed\n");
1948 return(NULL);
1949 }
1950 memset(cur, 0, sizeof(xmlNode));
1951 cur->type = XML_ELEMENT_NODE;
1952
1953 cur->name = xmlStrdup(name);
1954 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001955
1956 if (xmlRegisterNodeDefaultValue)
1957 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001958 return(cur);
1959}
1960
1961/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001962 * xmlNewNodeEatName:
1963 * @ns: namespace if any
1964 * @name: the node name
1965 *
1966 * Creation of a new node element. @ns is optional (NULL).
1967 *
1968 * Returns a pointer to the new node object.
1969 */
1970xmlNodePtr
1971xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
1972 xmlNodePtr cur;
1973
1974 if (name == NULL) {
1975#ifdef DEBUG_TREE
1976 xmlGenericError(xmlGenericErrorContext,
1977 "xmlNewNode : name == NULL\n");
1978#endif
1979 return(NULL);
1980 }
1981
1982 /*
1983 * Allocate a new node and fill the fields.
1984 */
1985 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1986 if (cur == NULL) {
1987 xmlGenericError(xmlGenericErrorContext,
1988 "xmlNewNode : malloc failed\n");
1989 return(NULL);
1990 }
1991 memset(cur, 0, sizeof(xmlNode));
1992 cur->type = XML_ELEMENT_NODE;
1993
1994 cur->name = name;
1995 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001996
1997 if (xmlRegisterNodeDefaultValue)
1998 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001999 return(cur);
2000}
2001
2002/**
Owen Taylor3473f882001-02-23 17:55:21 +00002003 * xmlNewDocNode:
2004 * @doc: the document
2005 * @ns: namespace if any
2006 * @name: the node name
2007 * @content: the XML text content if any
2008 *
2009 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002010 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002011 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2012 * references, but XML special chars need to be escaped first by using
2013 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2014 * need entities support.
2015 *
2016 * Returns a pointer to the new node object.
2017 */
2018xmlNodePtr
2019xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2020 const xmlChar *name, const xmlChar *content) {
2021 xmlNodePtr cur;
2022
2023 cur = xmlNewNode(ns, name);
2024 if (cur != NULL) {
2025 cur->doc = doc;
2026 if (content != NULL) {
2027 cur->children = xmlStringGetNodeList(doc, content);
2028 UPDATE_LAST_CHILD_AND_PARENT(cur)
2029 }
2030 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002031
Owen Taylor3473f882001-02-23 17:55:21 +00002032 return(cur);
2033}
2034
Daniel Veillard46de64e2002-05-29 08:21:33 +00002035/**
2036 * xmlNewDocNodeEatName:
2037 * @doc: the document
2038 * @ns: namespace if any
2039 * @name: the node name
2040 * @content: the XML text content if any
2041 *
2042 * Creation of a new node element within a document. @ns and @content
2043 * are optional (NULL).
2044 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2045 * references, but XML special chars need to be escaped first by using
2046 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2047 * need entities support.
2048 *
2049 * Returns a pointer to the new node object.
2050 */
2051xmlNodePtr
2052xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2053 xmlChar *name, const xmlChar *content) {
2054 xmlNodePtr cur;
2055
2056 cur = xmlNewNodeEatName(ns, name);
2057 if (cur != NULL) {
2058 cur->doc = doc;
2059 if (content != NULL) {
2060 cur->children = xmlStringGetNodeList(doc, content);
2061 UPDATE_LAST_CHILD_AND_PARENT(cur)
2062 }
2063 }
2064 return(cur);
2065}
2066
Owen Taylor3473f882001-02-23 17:55:21 +00002067
2068/**
2069 * xmlNewDocRawNode:
2070 * @doc: the document
2071 * @ns: namespace if any
2072 * @name: the node name
2073 * @content: the text content if any
2074 *
2075 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002076 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002077 *
2078 * Returns a pointer to the new node object.
2079 */
2080xmlNodePtr
2081xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2082 const xmlChar *name, const xmlChar *content) {
2083 xmlNodePtr cur;
2084
2085 cur = xmlNewNode(ns, name);
2086 if (cur != NULL) {
2087 cur->doc = doc;
2088 if (content != NULL) {
2089 cur->children = xmlNewDocText(doc, content);
2090 UPDATE_LAST_CHILD_AND_PARENT(cur)
2091 }
2092 }
2093 return(cur);
2094}
2095
2096/**
2097 * xmlNewDocFragment:
2098 * @doc: the document owning the fragment
2099 *
2100 * Creation of a new Fragment node.
2101 * Returns a pointer to the new node object.
2102 */
2103xmlNodePtr
2104xmlNewDocFragment(xmlDocPtr doc) {
2105 xmlNodePtr cur;
2106
2107 /*
2108 * Allocate a new DocumentFragment node and fill the fields.
2109 */
2110 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2111 if (cur == NULL) {
2112 xmlGenericError(xmlGenericErrorContext,
2113 "xmlNewDocFragment : malloc failed\n");
2114 return(NULL);
2115 }
2116 memset(cur, 0, sizeof(xmlNode));
2117 cur->type = XML_DOCUMENT_FRAG_NODE;
2118
2119 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002120
2121 if (xmlRegisterNodeDefaultValue)
2122 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002123 return(cur);
2124}
2125
2126/**
2127 * xmlNewText:
2128 * @content: the text content
2129 *
2130 * Creation of a new text node.
2131 * Returns a pointer to the new node object.
2132 */
2133xmlNodePtr
2134xmlNewText(const xmlChar *content) {
2135 xmlNodePtr cur;
2136
2137 /*
2138 * Allocate a new node and fill the fields.
2139 */
2140 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2141 if (cur == NULL) {
2142 xmlGenericError(xmlGenericErrorContext,
2143 "xmlNewText : malloc failed\n");
2144 return(NULL);
2145 }
2146 memset(cur, 0, sizeof(xmlNode));
2147 cur->type = XML_TEXT_NODE;
2148
2149 cur->name = xmlStringText;
2150 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002151 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002152 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002153
2154 if (xmlRegisterNodeDefaultValue)
2155 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002156 return(cur);
2157}
2158
2159/**
2160 * xmlNewTextChild:
2161 * @parent: the parent node
2162 * @ns: a namespace if any
2163 * @name: the name of the child
2164 * @content: the text content of the child if any.
2165 *
2166 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002167 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002168 * a child TEXT node will be created containing the string content.
2169 *
2170 * Returns a pointer to the new node object.
2171 */
2172xmlNodePtr
2173xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2174 const xmlChar *name, const xmlChar *content) {
2175 xmlNodePtr cur, prev;
2176
2177 if (parent == NULL) {
2178#ifdef DEBUG_TREE
2179 xmlGenericError(xmlGenericErrorContext,
2180 "xmlNewTextChild : parent == NULL\n");
2181#endif
2182 return(NULL);
2183 }
2184
2185 if (name == NULL) {
2186#ifdef DEBUG_TREE
2187 xmlGenericError(xmlGenericErrorContext,
2188 "xmlNewTextChild : name == NULL\n");
2189#endif
2190 return(NULL);
2191 }
2192
2193 /*
2194 * Allocate a new node
2195 */
2196 if (ns == NULL)
2197 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2198 else
2199 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2200 if (cur == NULL) return(NULL);
2201
2202 /*
2203 * add the new element at the end of the children list.
2204 */
2205 cur->type = XML_ELEMENT_NODE;
2206 cur->parent = parent;
2207 cur->doc = parent->doc;
2208 if (parent->children == NULL) {
2209 parent->children = cur;
2210 parent->last = cur;
2211 } else {
2212 prev = parent->last;
2213 prev->next = cur;
2214 cur->prev = prev;
2215 parent->last = cur;
2216 }
2217
2218 return(cur);
2219}
2220
2221/**
2222 * xmlNewCharRef:
2223 * @doc: the document
2224 * @name: the char ref string, starting with # or "&# ... ;"
2225 *
2226 * Creation of a new character reference node.
2227 * Returns a pointer to the new node object.
2228 */
2229xmlNodePtr
2230xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2231 xmlNodePtr cur;
2232
2233 /*
2234 * Allocate a new node and fill the fields.
2235 */
2236 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2237 if (cur == NULL) {
2238 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002239 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002240 return(NULL);
2241 }
2242 memset(cur, 0, sizeof(xmlNode));
2243 cur->type = XML_ENTITY_REF_NODE;
2244
2245 cur->doc = doc;
2246 if (name[0] == '&') {
2247 int len;
2248 name++;
2249 len = xmlStrlen(name);
2250 if (name[len - 1] == ';')
2251 cur->name = xmlStrndup(name, len - 1);
2252 else
2253 cur->name = xmlStrndup(name, len);
2254 } else
2255 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002256
2257 if (xmlRegisterNodeDefaultValue)
2258 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002259 return(cur);
2260}
2261
2262/**
2263 * xmlNewReference:
2264 * @doc: the document
2265 * @name: the reference name, or the reference string with & and ;
2266 *
2267 * Creation of a new reference node.
2268 * Returns a pointer to the new node object.
2269 */
2270xmlNodePtr
2271xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2272 xmlNodePtr cur;
2273 xmlEntityPtr ent;
2274
2275 /*
2276 * Allocate a new node and fill the fields.
2277 */
2278 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2279 if (cur == NULL) {
2280 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002281 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002282 return(NULL);
2283 }
2284 memset(cur, 0, sizeof(xmlNode));
2285 cur->type = XML_ENTITY_REF_NODE;
2286
2287 cur->doc = doc;
2288 if (name[0] == '&') {
2289 int len;
2290 name++;
2291 len = xmlStrlen(name);
2292 if (name[len - 1] == ';')
2293 cur->name = xmlStrndup(name, len - 1);
2294 else
2295 cur->name = xmlStrndup(name, len);
2296 } else
2297 cur->name = xmlStrdup(name);
2298
2299 ent = xmlGetDocEntity(doc, cur->name);
2300 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002301 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002302 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002303 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002304 * updated. Not sure if this is 100% correct.
2305 * -George
2306 */
2307 cur->children = (xmlNodePtr) ent;
2308 cur->last = (xmlNodePtr) ent;
2309 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002310
2311 if (xmlRegisterNodeDefaultValue)
2312 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002313 return(cur);
2314}
2315
2316/**
2317 * xmlNewDocText:
2318 * @doc: the document
2319 * @content: the text content
2320 *
2321 * Creation of a new text node within a document.
2322 * Returns a pointer to the new node object.
2323 */
2324xmlNodePtr
2325xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2326 xmlNodePtr cur;
2327
2328 cur = xmlNewText(content);
2329 if (cur != NULL) cur->doc = doc;
2330 return(cur);
2331}
2332
2333/**
2334 * xmlNewTextLen:
2335 * @content: the text content
2336 * @len: the text len.
2337 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002338 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002339 * Returns a pointer to the new node object.
2340 */
2341xmlNodePtr
2342xmlNewTextLen(const xmlChar *content, int len) {
2343 xmlNodePtr cur;
2344
2345 /*
2346 * Allocate a new node and fill the fields.
2347 */
2348 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2349 if (cur == NULL) {
2350 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002351 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002352 return(NULL);
2353 }
2354 memset(cur, 0, sizeof(xmlNode));
2355 cur->type = XML_TEXT_NODE;
2356
2357 cur->name = xmlStringText;
2358 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002359 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002360 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002361
2362 if (xmlRegisterNodeDefaultValue)
2363 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002364 return(cur);
2365}
2366
2367/**
2368 * xmlNewDocTextLen:
2369 * @doc: the document
2370 * @content: the text content
2371 * @len: the text len.
2372 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002373 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002374 * text node pertain to a given document.
2375 * Returns a pointer to the new node object.
2376 */
2377xmlNodePtr
2378xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2379 xmlNodePtr cur;
2380
2381 cur = xmlNewTextLen(content, len);
2382 if (cur != NULL) cur->doc = doc;
2383 return(cur);
2384}
2385
2386/**
2387 * xmlNewComment:
2388 * @content: the comment content
2389 *
2390 * Creation of a new node containing a comment.
2391 * Returns a pointer to the new node object.
2392 */
2393xmlNodePtr
2394xmlNewComment(const xmlChar *content) {
2395 xmlNodePtr cur;
2396
2397 /*
2398 * Allocate a new node and fill the fields.
2399 */
2400 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2401 if (cur == NULL) {
2402 xmlGenericError(xmlGenericErrorContext,
2403 "xmlNewComment : malloc failed\n");
2404 return(NULL);
2405 }
2406 memset(cur, 0, sizeof(xmlNode));
2407 cur->type = XML_COMMENT_NODE;
2408
2409 cur->name = xmlStringComment;
2410 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002411 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002412 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002413
2414 if (xmlRegisterNodeDefaultValue)
2415 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002416 return(cur);
2417}
2418
2419/**
2420 * xmlNewCDataBlock:
2421 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002422 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002423 * @len: the length of the block
2424 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002425 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002426 * Returns a pointer to the new node object.
2427 */
2428xmlNodePtr
2429xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2430 xmlNodePtr cur;
2431
2432 /*
2433 * Allocate a new node and fill the fields.
2434 */
2435 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2436 if (cur == NULL) {
2437 xmlGenericError(xmlGenericErrorContext,
2438 "xmlNewCDataBlock : malloc failed\n");
2439 return(NULL);
2440 }
2441 memset(cur, 0, sizeof(xmlNode));
2442 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002443 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002444
2445 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002446 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002447 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002448
2449 if (xmlRegisterNodeDefaultValue)
2450 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002451 return(cur);
2452}
2453
2454/**
2455 * xmlNewDocComment:
2456 * @doc: the document
2457 * @content: the comment content
2458 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002459 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002460 * Returns a pointer to the new node object.
2461 */
2462xmlNodePtr
2463xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2464 xmlNodePtr cur;
2465
2466 cur = xmlNewComment(content);
2467 if (cur != NULL) cur->doc = doc;
2468 return(cur);
2469}
2470
2471/**
2472 * xmlSetTreeDoc:
2473 * @tree: the top element
2474 * @doc: the document
2475 *
2476 * update all nodes under the tree to point to the right document
2477 */
2478void
2479xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002480 xmlAttrPtr prop;
2481
Owen Taylor3473f882001-02-23 17:55:21 +00002482 if (tree == NULL)
2483 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002484 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002485 if(tree->type == XML_ELEMENT_NODE) {
2486 prop = tree->properties;
2487 while (prop != NULL) {
2488 prop->doc = doc;
2489 xmlSetListDoc(prop->children, doc);
2490 prop = prop->next;
2491 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002492 }
Owen Taylor3473f882001-02-23 17:55:21 +00002493 if (tree->children != NULL)
2494 xmlSetListDoc(tree->children, doc);
2495 tree->doc = doc;
2496 }
2497}
2498
2499/**
2500 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002501 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002502 * @doc: the document
2503 *
2504 * update all nodes in the list to point to the right document
2505 */
2506void
2507xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2508 xmlNodePtr cur;
2509
2510 if (list == NULL)
2511 return;
2512 cur = list;
2513 while (cur != NULL) {
2514 if (cur->doc != doc)
2515 xmlSetTreeDoc(cur, doc);
2516 cur = cur->next;
2517 }
2518}
2519
2520
2521/**
2522 * xmlNewChild:
2523 * @parent: the parent node
2524 * @ns: a namespace if any
2525 * @name: the name of the child
2526 * @content: the XML content of the child if any.
2527 *
2528 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002529 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002530 * a child list containing the TEXTs and ENTITY_REFs node will be created.
2531 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2532 * references, but XML special chars need to be escaped first by using
2533 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
2534 * support is not needed.
2535 *
2536 * Returns a pointer to the new node object.
2537 */
2538xmlNodePtr
2539xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2540 const xmlChar *name, const xmlChar *content) {
2541 xmlNodePtr cur, prev;
2542
2543 if (parent == NULL) {
2544#ifdef DEBUG_TREE
2545 xmlGenericError(xmlGenericErrorContext,
2546 "xmlNewChild : parent == NULL\n");
2547#endif
2548 return(NULL);
2549 }
2550
2551 if (name == NULL) {
2552#ifdef DEBUG_TREE
2553 xmlGenericError(xmlGenericErrorContext,
2554 "xmlNewChild : name == NULL\n");
2555#endif
2556 return(NULL);
2557 }
2558
2559 /*
2560 * Allocate a new node
2561 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002562 if (parent->type == XML_ELEMENT_NODE) {
2563 if (ns == NULL)
2564 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2565 else
2566 cur = xmlNewDocNode(parent->doc, ns, name, content);
2567 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2568 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2569 if (ns == NULL)
2570 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2571 else
2572 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002573 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2574 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002575 } else {
2576 return(NULL);
2577 }
Owen Taylor3473f882001-02-23 17:55:21 +00002578 if (cur == NULL) return(NULL);
2579
2580 /*
2581 * add the new element at the end of the children list.
2582 */
2583 cur->type = XML_ELEMENT_NODE;
2584 cur->parent = parent;
2585 cur->doc = parent->doc;
2586 if (parent->children == NULL) {
2587 parent->children = cur;
2588 parent->last = cur;
2589 } else {
2590 prev = parent->last;
2591 prev->next = cur;
2592 cur->prev = prev;
2593 parent->last = cur;
2594 }
2595
2596 return(cur);
2597}
2598
2599/**
2600 * xmlAddNextSibling:
2601 * @cur: the child node
2602 * @elem: the new node
2603 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002604 * Add a new node @elem as the next sibling of @cur
2605 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002606 * first unlinked from its existing context.
2607 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002608 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2609 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002610 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002611 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002612 */
2613xmlNodePtr
2614xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2615 if (cur == NULL) {
2616#ifdef DEBUG_TREE
2617 xmlGenericError(xmlGenericErrorContext,
2618 "xmlAddNextSibling : cur == NULL\n");
2619#endif
2620 return(NULL);
2621 }
2622 if (elem == NULL) {
2623#ifdef DEBUG_TREE
2624 xmlGenericError(xmlGenericErrorContext,
2625 "xmlAddNextSibling : elem == NULL\n");
2626#endif
2627 return(NULL);
2628 }
2629
2630 xmlUnlinkNode(elem);
2631
2632 if (elem->type == XML_TEXT_NODE) {
2633 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002634 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002635 xmlFreeNode(elem);
2636 return(cur);
2637 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002638 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2639 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002640 xmlChar *tmp;
2641
2642 tmp = xmlStrdup(elem->content);
2643 tmp = xmlStrcat(tmp, cur->next->content);
2644 xmlNodeSetContent(cur->next, tmp);
2645 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002646 xmlFreeNode(elem);
2647 return(cur->next);
2648 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002649 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2650 /* check if an attribute with the same name exists */
2651 xmlAttrPtr attr;
2652
2653 if (elem->ns == NULL)
2654 attr = xmlHasProp(cur->parent, elem->name);
2655 else
2656 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2657 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2658 /* different instance, destroy it (attributes must be unique) */
2659 xmlFreeProp(attr);
2660 }
Owen Taylor3473f882001-02-23 17:55:21 +00002661 }
2662
2663 if (elem->doc != cur->doc) {
2664 xmlSetTreeDoc(elem, cur->doc);
2665 }
2666 elem->parent = cur->parent;
2667 elem->prev = cur;
2668 elem->next = cur->next;
2669 cur->next = elem;
2670 if (elem->next != NULL)
2671 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002672 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002673 elem->parent->last = elem;
2674 return(elem);
2675}
2676
2677/**
2678 * xmlAddPrevSibling:
2679 * @cur: the child node
2680 * @elem: the new node
2681 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002682 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002683 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002684 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002685 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002686 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2687 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002688 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002689 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002690 */
2691xmlNodePtr
2692xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2693 if (cur == NULL) {
2694#ifdef DEBUG_TREE
2695 xmlGenericError(xmlGenericErrorContext,
2696 "xmlAddPrevSibling : cur == NULL\n");
2697#endif
2698 return(NULL);
2699 }
2700 if (elem == NULL) {
2701#ifdef DEBUG_TREE
2702 xmlGenericError(xmlGenericErrorContext,
2703 "xmlAddPrevSibling : elem == NULL\n");
2704#endif
2705 return(NULL);
2706 }
2707
2708 xmlUnlinkNode(elem);
2709
2710 if (elem->type == XML_TEXT_NODE) {
2711 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002712 xmlChar *tmp;
2713
2714 tmp = xmlStrdup(elem->content);
2715 tmp = xmlStrcat(tmp, cur->content);
2716 xmlNodeSetContent(cur, tmp);
2717 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002718 xmlFreeNode(elem);
2719 return(cur);
2720 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002721 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2722 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002723 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002724 xmlFreeNode(elem);
2725 return(cur->prev);
2726 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002727 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2728 /* check if an attribute with the same name exists */
2729 xmlAttrPtr attr;
2730
2731 if (elem->ns == NULL)
2732 attr = xmlHasProp(cur->parent, elem->name);
2733 else
2734 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2735 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2736 /* different instance, destroy it (attributes must be unique) */
2737 xmlFreeProp(attr);
2738 }
Owen Taylor3473f882001-02-23 17:55:21 +00002739 }
2740
2741 if (elem->doc != cur->doc) {
2742 xmlSetTreeDoc(elem, cur->doc);
2743 }
2744 elem->parent = cur->parent;
2745 elem->next = cur;
2746 elem->prev = cur->prev;
2747 cur->prev = elem;
2748 if (elem->prev != NULL)
2749 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002750 if (elem->parent != NULL) {
2751 if (elem->type == XML_ATTRIBUTE_NODE) {
2752 if (elem->parent->properties == (xmlAttrPtr) cur) {
2753 elem->parent->properties = (xmlAttrPtr) elem;
2754 }
2755 } else {
2756 if (elem->parent->children == cur) {
2757 elem->parent->children = elem;
2758 }
2759 }
2760 }
Owen Taylor3473f882001-02-23 17:55:21 +00002761 return(elem);
2762}
2763
2764/**
2765 * xmlAddSibling:
2766 * @cur: the child node
2767 * @elem: the new node
2768 *
2769 * Add a new element @elem to the list of siblings of @cur
2770 * merging adjacent TEXT nodes (@elem may be freed)
2771 * If the new element was already inserted in a document it is
2772 * first unlinked from its existing context.
2773 *
2774 * Returns the new element or NULL in case of error.
2775 */
2776xmlNodePtr
2777xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2778 xmlNodePtr parent;
2779
2780 if (cur == NULL) {
2781#ifdef DEBUG_TREE
2782 xmlGenericError(xmlGenericErrorContext,
2783 "xmlAddSibling : cur == NULL\n");
2784#endif
2785 return(NULL);
2786 }
2787
2788 if (elem == NULL) {
2789#ifdef DEBUG_TREE
2790 xmlGenericError(xmlGenericErrorContext,
2791 "xmlAddSibling : elem == NULL\n");
2792#endif
2793 return(NULL);
2794 }
2795
2796 /*
2797 * Constant time is we can rely on the ->parent->last to find
2798 * the last sibling.
2799 */
2800 if ((cur->parent != NULL) &&
2801 (cur->parent->children != NULL) &&
2802 (cur->parent->last != NULL) &&
2803 (cur->parent->last->next == NULL)) {
2804 cur = cur->parent->last;
2805 } else {
2806 while (cur->next != NULL) cur = cur->next;
2807 }
2808
2809 xmlUnlinkNode(elem);
2810
2811 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002812 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002813 xmlFreeNode(elem);
2814 return(cur);
2815 }
2816
2817 if (elem->doc != cur->doc) {
2818 xmlSetTreeDoc(elem, cur->doc);
2819 }
2820 parent = cur->parent;
2821 elem->prev = cur;
2822 elem->next = NULL;
2823 elem->parent = parent;
2824 cur->next = elem;
2825 if (parent != NULL)
2826 parent->last = elem;
2827
2828 return(elem);
2829}
2830
2831/**
2832 * xmlAddChildList:
2833 * @parent: the parent node
2834 * @cur: the first node in the list
2835 *
2836 * Add a list of node at the end of the child list of the parent
2837 * merging adjacent TEXT nodes (@cur may be freed)
2838 *
2839 * Returns the last child or NULL in case of error.
2840 */
2841xmlNodePtr
2842xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2843 xmlNodePtr prev;
2844
2845 if (parent == NULL) {
2846#ifdef DEBUG_TREE
2847 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002848 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002849#endif
2850 return(NULL);
2851 }
2852
2853 if (cur == NULL) {
2854#ifdef DEBUG_TREE
2855 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002856 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002857#endif
2858 return(NULL);
2859 }
2860
2861 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2862 (cur->doc != parent->doc)) {
2863#ifdef DEBUG_TREE
2864 xmlGenericError(xmlGenericErrorContext,
2865 "Elements moved to a different document\n");
2866#endif
2867 }
2868
2869 /*
2870 * add the first element at the end of the children list.
2871 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00002872
Owen Taylor3473f882001-02-23 17:55:21 +00002873 if (parent->children == NULL) {
2874 parent->children = cur;
2875 } else {
2876 /*
2877 * If cur and parent->last both are TEXT nodes, then merge them.
2878 */
2879 if ((cur->type == XML_TEXT_NODE) &&
2880 (parent->last->type == XML_TEXT_NODE) &&
2881 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00002882 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002883 /*
2884 * if it's the only child, nothing more to be done.
2885 */
2886 if (cur->next == NULL) {
2887 xmlFreeNode(cur);
2888 return(parent->last);
2889 }
2890 prev = cur;
2891 cur = cur->next;
2892 xmlFreeNode(prev);
2893 }
2894 prev = parent->last;
2895 prev->next = cur;
2896 cur->prev = prev;
2897 }
2898 while (cur->next != NULL) {
2899 cur->parent = parent;
2900 if (cur->doc != parent->doc) {
2901 xmlSetTreeDoc(cur, parent->doc);
2902 }
2903 cur = cur->next;
2904 }
2905 cur->parent = parent;
2906 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2907 parent->last = cur;
2908
2909 return(cur);
2910}
2911
2912/**
2913 * xmlAddChild:
2914 * @parent: the parent node
2915 * @cur: the child node
2916 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002917 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00002918 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002919 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2920 * If there is an attribute with equal name, it is first destroyed.
2921 *
Owen Taylor3473f882001-02-23 17:55:21 +00002922 * Returns the child or NULL in case of error.
2923 */
2924xmlNodePtr
2925xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2926 xmlNodePtr prev;
2927
2928 if (parent == NULL) {
2929#ifdef DEBUG_TREE
2930 xmlGenericError(xmlGenericErrorContext,
2931 "xmlAddChild : parent == NULL\n");
2932#endif
2933 return(NULL);
2934 }
2935
2936 if (cur == NULL) {
2937#ifdef DEBUG_TREE
2938 xmlGenericError(xmlGenericErrorContext,
2939 "xmlAddChild : child == NULL\n");
2940#endif
2941 return(NULL);
2942 }
2943
Owen Taylor3473f882001-02-23 17:55:21 +00002944 /*
2945 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002946 * cur is then freed.
2947 */
2948 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002949 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002950 (parent->content != NULL) &&
2951 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002952 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002953 xmlFreeNode(cur);
2954 return(parent);
2955 }
2956 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002957 (parent->last->name == cur->name) &&
2958 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002959 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002960 xmlFreeNode(cur);
2961 return(parent->last);
2962 }
2963 }
2964
2965 /*
2966 * add the new element at the end of the children list.
2967 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00002968 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00002969 cur->parent = parent;
2970 if (cur->doc != parent->doc) {
2971 xmlSetTreeDoc(cur, parent->doc);
2972 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002973 /* this check prevents a loop on tree-traversions if a developer
2974 * tries to add a node to its parent multiple times
2975 */
2976 if (prev == parent)
2977 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002978
2979 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002980 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002981 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002982 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002983 (parent->content != NULL) &&
2984 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002985 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002986 xmlFreeNode(cur);
2987 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002988 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002989 if (cur->type == XML_ATTRIBUTE_NODE) {
2990 if (parent->properties == NULL) {
2991 parent->properties = (xmlAttrPtr) cur;
2992 } else {
2993 /* check if an attribute with the same name exists */
2994 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00002995
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002996 if (cur->ns == NULL)
2997 lastattr = xmlHasProp(parent, cur->name);
2998 else
2999 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3000 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
3001 /* different instance, destroy it (attributes must be unique) */
3002 xmlFreeProp(lastattr);
3003 }
3004 /* find the end */
3005 lastattr = parent->properties;
3006 while (lastattr->next != NULL) {
3007 lastattr = lastattr->next;
3008 }
3009 lastattr->next = (xmlAttrPtr) cur;
3010 ((xmlAttrPtr) cur)->prev = lastattr;
3011 }
3012 } else {
3013 if (parent->children == NULL) {
3014 parent->children = cur;
3015 parent->last = cur;
3016 } else {
3017 prev = parent->last;
3018 prev->next = cur;
3019 cur->prev = prev;
3020 parent->last = cur;
3021 }
3022 }
Owen Taylor3473f882001-02-23 17:55:21 +00003023 return(cur);
3024}
3025
3026/**
3027 * xmlGetLastChild:
3028 * @parent: the parent node
3029 *
3030 * Search the last child of a node.
3031 * Returns the last child or NULL if none.
3032 */
3033xmlNodePtr
3034xmlGetLastChild(xmlNodePtr parent) {
3035 if (parent == NULL) {
3036#ifdef DEBUG_TREE
3037 xmlGenericError(xmlGenericErrorContext,
3038 "xmlGetLastChild : parent == NULL\n");
3039#endif
3040 return(NULL);
3041 }
3042 return(parent->last);
3043}
3044
3045/**
3046 * xmlFreeNodeList:
3047 * @cur: the first node in the list
3048 *
3049 * Free a node and all its siblings, this is a recursive behaviour, all
3050 * the children are freed too.
3051 */
3052void
3053xmlFreeNodeList(xmlNodePtr cur) {
3054 xmlNodePtr next;
3055 if (cur == NULL) {
3056#ifdef DEBUG_TREE
3057 xmlGenericError(xmlGenericErrorContext,
3058 "xmlFreeNodeList : node == NULL\n");
3059#endif
3060 return;
3061 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00003062 if (cur->type == XML_NAMESPACE_DECL) {
3063 xmlFreeNsList((xmlNsPtr) cur);
3064 return;
3065 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003066 if ((cur->type == XML_DOCUMENT_NODE) ||
3067#ifdef LIBXML_DOCB_ENABLED
3068 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003069#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003070 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003071 xmlFreeDoc((xmlDocPtr) cur);
3072 return;
3073 }
Owen Taylor3473f882001-02-23 17:55:21 +00003074 while (cur != NULL) {
3075 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003076 /* unroll to speed up freeing the document */
3077 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003078
3079 if (xmlDeregisterNodeDefaultValue)
3080 xmlDeregisterNodeDefaultValue(cur);
3081
Daniel Veillard02141ea2001-04-30 11:46:40 +00003082 if ((cur->children != NULL) &&
3083 (cur->type != XML_ENTITY_REF_NODE))
3084 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003085 if (((cur->type == XML_ELEMENT_NODE) ||
3086 (cur->type == XML_XINCLUDE_START) ||
3087 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003088 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003089 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003090 if ((cur->type != XML_ELEMENT_NODE) &&
3091 (cur->type != XML_XINCLUDE_START) &&
3092 (cur->type != XML_XINCLUDE_END) &&
3093 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00003094 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003095 }
3096 if (((cur->type == XML_ELEMENT_NODE) ||
3097 (cur->type == XML_XINCLUDE_START) ||
3098 (cur->type == XML_XINCLUDE_END)) &&
3099 (cur->nsDef != NULL))
3100 xmlFreeNsList(cur->nsDef);
3101
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003102 /*
3103 * When a node is a text node or a comment, it uses a global static
3104 * variable for the name of the node.
3105 *
3106 * The xmlStrEqual comparisons need to be done when (happened with
3107 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003108 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00003109 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003110 * the string addresses compare are not sufficient.
3111 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003112 if ((cur->name != NULL) &&
3113 (cur->name != xmlStringText) &&
3114 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003115 (cur->name != xmlStringComment)) {
3116 if (cur->type == XML_TEXT_NODE) {
3117 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
3118 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
3119 xmlFree((char *) cur->name);
3120 } else if (cur->type == XML_COMMENT_NODE) {
3121 if (!xmlStrEqual(cur->name, xmlStringComment))
3122 xmlFree((char *) cur->name);
3123 } else
3124 xmlFree((char *) cur->name);
3125 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00003126 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003127 xmlFree(cur);
3128 }
Owen Taylor3473f882001-02-23 17:55:21 +00003129 cur = next;
3130 }
3131}
3132
3133/**
3134 * xmlFreeNode:
3135 * @cur: the node
3136 *
3137 * Free a node, this is a recursive behaviour, all the children are freed too.
3138 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3139 */
3140void
3141xmlFreeNode(xmlNodePtr cur) {
3142 if (cur == NULL) {
3143#ifdef DEBUG_TREE
3144 xmlGenericError(xmlGenericErrorContext,
3145 "xmlFreeNode : node == NULL\n");
3146#endif
3147 return;
3148 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003149
Daniel Veillard02141ea2001-04-30 11:46:40 +00003150 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003151 if (cur->type == XML_DTD_NODE) {
3152 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003153 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003154 }
3155 if (cur->type == XML_NAMESPACE_DECL) {
3156 xmlFreeNs((xmlNsPtr) cur);
3157 return;
3158 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003159 if (cur->type == XML_ATTRIBUTE_NODE) {
3160 xmlFreeProp((xmlAttrPtr) cur);
3161 return;
3162 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003163
3164 if (xmlDeregisterNodeDefaultValue)
3165 xmlDeregisterNodeDefaultValue(cur);
3166
Owen Taylor3473f882001-02-23 17:55:21 +00003167 if ((cur->children != NULL) &&
3168 (cur->type != XML_ENTITY_REF_NODE))
3169 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003170 if (((cur->type == XML_ELEMENT_NODE) ||
3171 (cur->type == XML_XINCLUDE_START) ||
3172 (cur->type == XML_XINCLUDE_END)) &&
3173 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003174 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003175 if ((cur->type != XML_ELEMENT_NODE) &&
3176 (cur->content != NULL) &&
3177 (cur->type != XML_ENTITY_REF_NODE) &&
3178 (cur->type != XML_XINCLUDE_END) &&
3179 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003180 xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003181 }
3182
Daniel Veillardacd370f2001-06-09 17:17:51 +00003183 /*
3184 * When a node is a text node or a comment, it uses a global static
3185 * variable for the name of the node.
3186 *
3187 * The xmlStrEqual comparisons need to be done when (happened with
3188 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003189 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00003190 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00003191 * are not sufficient.
3192 */
Owen Taylor3473f882001-02-23 17:55:21 +00003193 if ((cur->name != NULL) &&
3194 (cur->name != xmlStringText) &&
3195 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00003196 (cur->name != xmlStringComment)) {
3197 if (cur->type == XML_TEXT_NODE) {
3198 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
3199 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
3200 xmlFree((char *) cur->name);
3201 } else if (cur->type == XML_COMMENT_NODE) {
3202 if (!xmlStrEqual(cur->name, xmlStringComment))
3203 xmlFree((char *) cur->name);
3204 } else
3205 xmlFree((char *) cur->name);
3206 }
3207
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003208 if (((cur->type == XML_ELEMENT_NODE) ||
3209 (cur->type == XML_XINCLUDE_START) ||
3210 (cur->type == XML_XINCLUDE_END)) &&
3211 (cur->nsDef != NULL))
3212 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003213 xmlFree(cur);
3214}
3215
3216/**
3217 * xmlUnlinkNode:
3218 * @cur: the node
3219 *
3220 * Unlink a node from it's current context, the node is not freed
3221 */
3222void
3223xmlUnlinkNode(xmlNodePtr cur) {
3224 if (cur == NULL) {
3225#ifdef DEBUG_TREE
3226 xmlGenericError(xmlGenericErrorContext,
3227 "xmlUnlinkNode : node == NULL\n");
3228#endif
3229 return;
3230 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003231 if (cur->type == XML_DTD_NODE) {
3232 xmlDocPtr doc;
3233 doc = cur->doc;
3234 if (doc->intSubset == (xmlDtdPtr) cur)
3235 doc->intSubset = NULL;
3236 if (doc->extSubset == (xmlDtdPtr) cur)
3237 doc->extSubset = NULL;
3238 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003239 if (cur->parent != NULL) {
3240 xmlNodePtr parent;
3241 parent = cur->parent;
3242 if (cur->type == XML_ATTRIBUTE_NODE) {
3243 if (parent->properties == (xmlAttrPtr) cur)
3244 parent->properties = ((xmlAttrPtr) cur)->next;
3245 } else {
3246 if (parent->children == cur)
3247 parent->children = cur->next;
3248 if (parent->last == cur)
3249 parent->last = cur->prev;
3250 }
3251 cur->parent = NULL;
3252 }
Owen Taylor3473f882001-02-23 17:55:21 +00003253 if (cur->next != NULL)
3254 cur->next->prev = cur->prev;
3255 if (cur->prev != NULL)
3256 cur->prev->next = cur->next;
3257 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003258}
3259
3260/**
3261 * xmlReplaceNode:
3262 * @old: the old node
3263 * @cur: the node
3264 *
3265 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003266 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003267 * first unlinked from its existing context.
3268 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003269 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003270 */
3271xmlNodePtr
3272xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3273 if (old == NULL) {
3274#ifdef DEBUG_TREE
3275 xmlGenericError(xmlGenericErrorContext,
3276 "xmlReplaceNode : old == NULL\n");
3277#endif
3278 return(NULL);
3279 }
3280 if (cur == NULL) {
3281 xmlUnlinkNode(old);
3282 return(old);
3283 }
3284 if (cur == old) {
3285 return(old);
3286 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003287 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3288#ifdef DEBUG_TREE
3289 xmlGenericError(xmlGenericErrorContext,
3290 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3291#endif
3292 return(old);
3293 }
3294 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3295#ifdef DEBUG_TREE
3296 xmlGenericError(xmlGenericErrorContext,
3297 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3298#endif
3299 return(old);
3300 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003301 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3302#ifdef DEBUG_TREE
3303 xmlGenericError(xmlGenericErrorContext,
3304 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3305#endif
3306 return(old);
3307 }
3308 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3309#ifdef DEBUG_TREE
3310 xmlGenericError(xmlGenericErrorContext,
3311 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3312#endif
3313 return(old);
3314 }
Owen Taylor3473f882001-02-23 17:55:21 +00003315 xmlUnlinkNode(cur);
3316 cur->doc = old->doc;
3317 cur->parent = old->parent;
3318 cur->next = old->next;
3319 if (cur->next != NULL)
3320 cur->next->prev = cur;
3321 cur->prev = old->prev;
3322 if (cur->prev != NULL)
3323 cur->prev->next = cur;
3324 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003325 if (cur->type == XML_ATTRIBUTE_NODE) {
3326 if (cur->parent->properties == (xmlAttrPtr)old)
3327 cur->parent->properties = ((xmlAttrPtr) cur);
3328 } else {
3329 if (cur->parent->children == old)
3330 cur->parent->children = cur;
3331 if (cur->parent->last == old)
3332 cur->parent->last = cur;
3333 }
Owen Taylor3473f882001-02-23 17:55:21 +00003334 }
3335 old->next = old->prev = NULL;
3336 old->parent = NULL;
3337 return(old);
3338}
3339
3340/************************************************************************
3341 * *
3342 * Copy operations *
3343 * *
3344 ************************************************************************/
3345
3346/**
3347 * xmlCopyNamespace:
3348 * @cur: the namespace
3349 *
3350 * Do a copy of the namespace.
3351 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003352 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003353 */
3354xmlNsPtr
3355xmlCopyNamespace(xmlNsPtr cur) {
3356 xmlNsPtr ret;
3357
3358 if (cur == NULL) return(NULL);
3359 switch (cur->type) {
3360 case XML_LOCAL_NAMESPACE:
3361 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3362 break;
3363 default:
3364#ifdef DEBUG_TREE
3365 xmlGenericError(xmlGenericErrorContext,
3366 "xmlCopyNamespace: invalid type %d\n", cur->type);
3367#endif
3368 return(NULL);
3369 }
3370 return(ret);
3371}
3372
3373/**
3374 * xmlCopyNamespaceList:
3375 * @cur: the first namespace
3376 *
3377 * Do a copy of an namespace list.
3378 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003379 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003380 */
3381xmlNsPtr
3382xmlCopyNamespaceList(xmlNsPtr cur) {
3383 xmlNsPtr ret = NULL;
3384 xmlNsPtr p = NULL,q;
3385
3386 while (cur != NULL) {
3387 q = xmlCopyNamespace(cur);
3388 if (p == NULL) {
3389 ret = p = q;
3390 } else {
3391 p->next = q;
3392 p = q;
3393 }
3394 cur = cur->next;
3395 }
3396 return(ret);
3397}
3398
3399static xmlNodePtr
3400xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3401/**
3402 * xmlCopyProp:
3403 * @target: the element where the attribute will be grafted
3404 * @cur: the attribute
3405 *
3406 * Do a copy of the attribute.
3407 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003408 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003409 */
3410xmlAttrPtr
3411xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3412 xmlAttrPtr ret;
3413
3414 if (cur == NULL) return(NULL);
3415 if (target != NULL)
3416 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3417 else if (cur->parent != NULL)
3418 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3419 else if (cur->children != NULL)
3420 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3421 else
3422 ret = xmlNewDocProp(NULL, cur->name, NULL);
3423 if (ret == NULL) return(NULL);
3424 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003425
Owen Taylor3473f882001-02-23 17:55:21 +00003426 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003427 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003428/*
3429 * if (target->doc)
3430 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3431 * else if (cur->doc) / * target may not yet have a doc : KPI * /
3432 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
3433 * else
3434 * ns = NULL;
3435 * ret->ns = ns;
3436 */
3437 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3438 if (ns == NULL) {
3439 /*
3440 * Humm, we are copying an element whose namespace is defined
3441 * out of the new tree scope. Search it in the original tree
3442 * and add it at the top of the new tree
3443 */
3444 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3445 if (ns != NULL) {
3446 xmlNodePtr root = target;
3447 xmlNodePtr pred = NULL;
3448
3449 while (root->parent != NULL) {
3450 pred = root;
3451 root = root->parent;
3452 }
3453 if (root == (xmlNodePtr) target->doc) {
3454 /* correct possibly cycling above the document elt */
3455 root = pred;
3456 }
3457 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3458 }
3459 } else {
3460 /*
3461 * we have to find something appropriate here since
3462 * we cant be sure, that the namespce we found is identified
3463 * by the prefix
3464 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003465 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003466 /* this is the nice case */
3467 ret->ns = ns;
3468 } else {
3469 /*
3470 * we are in trouble: we need a new reconcilied namespace.
3471 * This is expensive
3472 */
3473 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3474 }
3475 }
3476
Owen Taylor3473f882001-02-23 17:55:21 +00003477 } else
3478 ret->ns = NULL;
3479
3480 if (cur->children != NULL) {
3481 xmlNodePtr tmp;
3482
3483 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3484 ret->last = NULL;
3485 tmp = ret->children;
3486 while (tmp != NULL) {
3487 /* tmp->parent = (xmlNodePtr)ret; */
3488 if (tmp->next == NULL)
3489 ret->last = tmp;
3490 tmp = tmp->next;
3491 }
3492 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003493 /*
3494 * Try to handle IDs
3495 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003496 if ((target!= NULL) && (cur!= NULL) &&
3497 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003498 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3499 if (xmlIsID(cur->doc, cur->parent, cur)) {
3500 xmlChar *id;
3501
3502 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3503 if (id != NULL) {
3504 xmlAddID(NULL, target->doc, id, ret);
3505 xmlFree(id);
3506 }
3507 }
3508 }
Owen Taylor3473f882001-02-23 17:55:21 +00003509 return(ret);
3510}
3511
3512/**
3513 * xmlCopyPropList:
3514 * @target: the element where the attributes will be grafted
3515 * @cur: the first attribute
3516 *
3517 * Do a copy of an attribute list.
3518 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003519 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003520 */
3521xmlAttrPtr
3522xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3523 xmlAttrPtr ret = NULL;
3524 xmlAttrPtr p = NULL,q;
3525
3526 while (cur != NULL) {
3527 q = xmlCopyProp(target, cur);
3528 if (p == NULL) {
3529 ret = p = q;
3530 } else {
3531 p->next = q;
3532 q->prev = p;
3533 p = q;
3534 }
3535 cur = cur->next;
3536 }
3537 return(ret);
3538}
3539
3540/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003541 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003542 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003543 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003544 * tricky reason: namespaces. Doing a direct copy of a node
3545 * say RPM:Copyright without changing the namespace pointer to
3546 * something else can produce stale links. One way to do it is
3547 * to keep a reference counter but this doesn't work as soon
3548 * as one move the element or the subtree out of the scope of
3549 * the existing namespace. The actual solution seems to add
3550 * a copy of the namespace at the top of the copied tree if
3551 * not available in the subtree.
3552 * Hence two functions, the public front-end call the inner ones
3553 */
3554
3555static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003556xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003557 int recursive) {
3558 xmlNodePtr ret;
3559
3560 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003561 switch (node->type) {
3562 case XML_TEXT_NODE:
3563 case XML_CDATA_SECTION_NODE:
3564 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003565 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003566 case XML_ENTITY_REF_NODE:
3567 case XML_ENTITY_NODE:
3568 case XML_PI_NODE:
3569 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003570 case XML_XINCLUDE_START:
3571 case XML_XINCLUDE_END:
3572 break;
3573 case XML_ATTRIBUTE_NODE:
3574 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3575 case XML_NAMESPACE_DECL:
3576 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3577
Daniel Veillard39196eb2001-06-19 18:09:42 +00003578 case XML_DOCUMENT_NODE:
3579 case XML_HTML_DOCUMENT_NODE:
3580#ifdef LIBXML_DOCB_ENABLED
3581 case XML_DOCB_DOCUMENT_NODE:
3582#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003583 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00003584 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003585 case XML_NOTATION_NODE:
3586 case XML_DTD_NODE:
3587 case XML_ELEMENT_DECL:
3588 case XML_ATTRIBUTE_DECL:
3589 case XML_ENTITY_DECL:
3590 return(NULL);
3591 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003592
Owen Taylor3473f882001-02-23 17:55:21 +00003593 /*
3594 * Allocate a new node and fill the fields.
3595 */
3596 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3597 if (ret == NULL) {
3598 xmlGenericError(xmlGenericErrorContext,
3599 "xmlStaticCopyNode : malloc failed\n");
3600 return(NULL);
3601 }
3602 memset(ret, 0, sizeof(xmlNode));
3603 ret->type = node->type;
3604
3605 ret->doc = doc;
3606 ret->parent = parent;
3607 if (node->name == xmlStringText)
3608 ret->name = xmlStringText;
3609 else if (node->name == xmlStringTextNoenc)
3610 ret->name = xmlStringTextNoenc;
3611 else if (node->name == xmlStringComment)
3612 ret->name = xmlStringComment;
3613 else if (node->name != NULL)
3614 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003615 if ((node->type != XML_ELEMENT_NODE) &&
3616 (node->content != NULL) &&
3617 (node->type != XML_ENTITY_REF_NODE) &&
3618 (node->type != XML_XINCLUDE_END) &&
3619 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003620 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003621 }else{
3622 if (node->type == XML_ELEMENT_NODE)
3623 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00003624 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003625 if (parent != NULL) {
3626 xmlNodePtr tmp;
3627
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003628 /*
3629 * this is a tricky part for the node register thing:
3630 * in case ret does get coalesced in xmlAddChild
3631 * the deregister-node callback is called; so we register ret now already
3632 */
3633 if (xmlRegisterNodeDefaultValue)
3634 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3635
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003636 tmp = xmlAddChild(parent, ret);
3637 /* node could have coalesced */
3638 if (tmp != ret)
3639 return(tmp);
3640 }
Owen Taylor3473f882001-02-23 17:55:21 +00003641
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003642 if (!recursive)
3643 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003644 if (node->nsDef != NULL)
3645 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3646
3647 if (node->ns != NULL) {
3648 xmlNsPtr ns;
3649
3650 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3651 if (ns == NULL) {
3652 /*
3653 * Humm, we are copying an element whose namespace is defined
3654 * out of the new tree scope. Search it in the original tree
3655 * and add it at the top of the new tree
3656 */
3657 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3658 if (ns != NULL) {
3659 xmlNodePtr root = ret;
3660
3661 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003662 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003663 }
3664 } else {
3665 /*
3666 * reference the existing namespace definition in our own tree.
3667 */
3668 ret->ns = ns;
3669 }
3670 }
3671 if (node->properties != NULL)
3672 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003673 if (node->type == XML_ENTITY_REF_NODE) {
3674 if ((doc == NULL) || (node->doc != doc)) {
3675 /*
3676 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003677 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003678 * we cannot keep the reference. Try to find it in the
3679 * target document.
3680 */
3681 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3682 } else {
3683 ret->children = node->children;
3684 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003685 ret->last = ret->children;
3686 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003687 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003688 UPDATE_LAST_CHILD_AND_PARENT(ret)
3689 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003690
3691out:
3692 /* if parent != NULL we already registered the node above */
3693 if (parent == NULL && xmlRegisterNodeDefaultValue)
3694 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003695 return(ret);
3696}
3697
3698static xmlNodePtr
3699xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3700 xmlNodePtr ret = NULL;
3701 xmlNodePtr p = NULL,q;
3702
3703 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003704 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003705 if (doc == NULL) {
3706 node = node->next;
3707 continue;
3708 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003709 if (doc->intSubset == NULL) {
3710 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3711 q->doc = doc;
3712 q->parent = parent;
3713 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003714 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003715 } else {
3716 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003717 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003718 }
3719 } else
3720 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003721 if (ret == NULL) {
3722 q->prev = NULL;
3723 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003724 } else if (p != q) {
3725 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003726 p->next = q;
3727 q->prev = p;
3728 p = q;
3729 }
3730 node = node->next;
3731 }
3732 return(ret);
3733}
3734
3735/**
3736 * xmlCopyNode:
3737 * @node: the node
3738 * @recursive: if 1 do a recursive copy.
3739 *
3740 * Do a copy of the node.
3741 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003742 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003743 */
3744xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003745xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003746 xmlNodePtr ret;
3747
3748 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3749 return(ret);
3750}
3751
3752/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003753 * xmlDocCopyNode:
3754 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003755 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003756 * @recursive: if 1 do a recursive copy.
3757 *
3758 * Do a copy of the node to a given document.
3759 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003760 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003761 */
3762xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003763xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003764 xmlNodePtr ret;
3765
3766 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3767 return(ret);
3768}
3769
3770/**
Owen Taylor3473f882001-02-23 17:55:21 +00003771 * xmlCopyNodeList:
3772 * @node: the first node in the list.
3773 *
3774 * Do a recursive copy of the node list.
3775 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003776 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003777 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003778xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003779 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3780 return(ret);
3781}
3782
3783/**
Owen Taylor3473f882001-02-23 17:55:21 +00003784 * xmlCopyDtd:
3785 * @dtd: the dtd
3786 *
3787 * Do a copy of the dtd.
3788 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003789 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003790 */
3791xmlDtdPtr
3792xmlCopyDtd(xmlDtdPtr dtd) {
3793 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003794 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003795
3796 if (dtd == NULL) return(NULL);
3797 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3798 if (ret == NULL) return(NULL);
3799 if (dtd->entities != NULL)
3800 ret->entities = (void *) xmlCopyEntitiesTable(
3801 (xmlEntitiesTablePtr) dtd->entities);
3802 if (dtd->notations != NULL)
3803 ret->notations = (void *) xmlCopyNotationTable(
3804 (xmlNotationTablePtr) dtd->notations);
3805 if (dtd->elements != NULL)
3806 ret->elements = (void *) xmlCopyElementTable(
3807 (xmlElementTablePtr) dtd->elements);
3808 if (dtd->attributes != NULL)
3809 ret->attributes = (void *) xmlCopyAttributeTable(
3810 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003811 if (dtd->pentities != NULL)
3812 ret->pentities = (void *) xmlCopyEntitiesTable(
3813 (xmlEntitiesTablePtr) dtd->pentities);
3814
3815 cur = dtd->children;
3816 while (cur != NULL) {
3817 q = NULL;
3818
3819 if (cur->type == XML_ENTITY_DECL) {
3820 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3821 switch (tmp->etype) {
3822 case XML_INTERNAL_GENERAL_ENTITY:
3823 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3824 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3825 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3826 break;
3827 case XML_INTERNAL_PARAMETER_ENTITY:
3828 case XML_EXTERNAL_PARAMETER_ENTITY:
3829 q = (xmlNodePtr)
3830 xmlGetParameterEntityFromDtd(ret, tmp->name);
3831 break;
3832 case XML_INTERNAL_PREDEFINED_ENTITY:
3833 break;
3834 }
3835 } else if (cur->type == XML_ELEMENT_DECL) {
3836 xmlElementPtr tmp = (xmlElementPtr) cur;
3837 q = (xmlNodePtr)
3838 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3839 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3840 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3841 q = (xmlNodePtr)
3842 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3843 } else if (cur->type == XML_COMMENT_NODE) {
3844 q = xmlCopyNode(cur, 0);
3845 }
3846
3847 if (q == NULL) {
3848 cur = cur->next;
3849 continue;
3850 }
3851
3852 if (p == NULL)
3853 ret->children = q;
3854 else
3855 p->next = q;
3856
3857 q->prev = p;
3858 q->parent = (xmlNodePtr) ret;
3859 q->next = NULL;
3860 ret->last = q;
3861 p = q;
3862 cur = cur->next;
3863 }
3864
Owen Taylor3473f882001-02-23 17:55:21 +00003865 return(ret);
3866}
3867
3868/**
3869 * xmlCopyDoc:
3870 * @doc: the document
3871 * @recursive: if 1 do a recursive copy.
3872 *
3873 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003874 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003875 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003876 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003877 */
3878xmlDocPtr
3879xmlCopyDoc(xmlDocPtr doc, int recursive) {
3880 xmlDocPtr ret;
3881
3882 if (doc == NULL) return(NULL);
3883 ret = xmlNewDoc(doc->version);
3884 if (ret == NULL) return(NULL);
3885 if (doc->name != NULL)
3886 ret->name = xmlMemStrdup(doc->name);
3887 if (doc->encoding != NULL)
3888 ret->encoding = xmlStrdup(doc->encoding);
3889 ret->charset = doc->charset;
3890 ret->compression = doc->compression;
3891 ret->standalone = doc->standalone;
3892 if (!recursive) return(ret);
3893
Daniel Veillardb33c2012001-04-25 12:59:04 +00003894 ret->last = NULL;
3895 ret->children = NULL;
3896 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003897 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003898 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003899 ret->intSubset->parent = ret;
3900 }
Owen Taylor3473f882001-02-23 17:55:21 +00003901 if (doc->oldNs != NULL)
3902 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3903 if (doc->children != NULL) {
3904 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003905
3906 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3907 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003908 ret->last = NULL;
3909 tmp = ret->children;
3910 while (tmp != NULL) {
3911 if (tmp->next == NULL)
3912 ret->last = tmp;
3913 tmp = tmp->next;
3914 }
3915 }
3916 return(ret);
3917}
3918
3919/************************************************************************
3920 * *
3921 * Content access functions *
3922 * *
3923 ************************************************************************/
3924
3925/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003926 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003927 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00003928 *
3929 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003930 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003931 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003932 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003933 */
3934long
3935xmlGetLineNo(xmlNodePtr node)
3936{
3937 long result = -1;
3938
3939 if (!node)
3940 return result;
3941 if (node->type == XML_ELEMENT_NODE)
3942 result = (long) node->content;
3943 else if ((node->prev != NULL) &&
3944 ((node->prev->type == XML_ELEMENT_NODE) ||
3945 (node->prev->type == XML_TEXT_NODE)))
3946 result = xmlGetLineNo(node->prev);
3947 else if ((node->parent != NULL) &&
3948 ((node->parent->type == XML_ELEMENT_NODE) ||
3949 (node->parent->type == XML_TEXT_NODE)))
3950 result = xmlGetLineNo(node->parent);
3951
3952 return result;
3953}
3954
3955/**
3956 * xmlGetNodePath:
3957 * @node: a node
3958 *
3959 * Build a structure based Path for the given node
3960 *
3961 * Returns the new path or NULL in case of error. The caller must free
3962 * the returned string
3963 */
3964xmlChar *
3965xmlGetNodePath(xmlNodePtr node)
3966{
3967 xmlNodePtr cur, tmp, next;
3968 xmlChar *buffer = NULL, *temp;
3969 size_t buf_len;
3970 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00003971 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00003972 const char *name;
3973 char nametemp[100];
3974 int occur = 0;
3975
3976 if (node == NULL)
3977 return (NULL);
3978
3979 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00003980 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00003981 if (buffer == NULL)
3982 return (NULL);
Daniel Veillard3c908dc2003-04-19 00:07:51 +00003983 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00003984 if (buf == NULL) {
3985 xmlFree(buffer);
3986 return (NULL);
3987 }
3988
3989 buffer[0] = 0;
3990 cur = node;
3991 do {
3992 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003993 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003994 occur = 0;
3995 if ((cur->type == XML_DOCUMENT_NODE) ||
3996 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3997 if (buffer[0] == '/')
3998 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003999 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004000 next = NULL;
4001 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004002 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004003 name = (const char *) cur->name;
4004 if (cur->ns) {
4005 snprintf(nametemp, sizeof(nametemp) - 1,
4006 "%s:%s", cur->ns->prefix, cur->name);
4007 nametemp[sizeof(nametemp) - 1] = 0;
4008 name = nametemp;
4009 }
4010 next = cur->parent;
4011
4012 /*
4013 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004014 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004015 */
4016 tmp = cur->prev;
4017 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004018 if ((tmp->type == XML_ELEMENT_NODE) &&
4019 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004020 occur++;
4021 tmp = tmp->prev;
4022 }
4023 if (occur == 0) {
4024 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004025 while (tmp != NULL && occur == 0) {
4026 if ((tmp->type == XML_ELEMENT_NODE) &&
4027 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004028 occur++;
4029 tmp = tmp->next;
4030 }
4031 if (occur != 0)
4032 occur = 1;
4033 } else
4034 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004035 } else if (cur->type == XML_COMMENT_NODE) {
4036 sep = "/";
4037 name = "comment()";
4038 next = cur->parent;
4039
4040 /*
4041 * Thumbler index computation
4042 */
4043 tmp = cur->prev;
4044 while (tmp != NULL) {
4045 if (tmp->type == XML_COMMENT_NODE)
4046 occur++;
4047 tmp = tmp->prev;
4048 }
4049 if (occur == 0) {
4050 tmp = cur->next;
4051 while (tmp != NULL && occur == 0) {
4052 if (tmp->type == XML_COMMENT_NODE)
4053 occur++;
4054 tmp = tmp->next;
4055 }
4056 if (occur != 0)
4057 occur = 1;
4058 } else
4059 occur++;
4060 } else if ((cur->type == XML_TEXT_NODE) ||
4061 (cur->type == XML_CDATA_SECTION_NODE)) {
4062 sep = "/";
4063 name = "text()";
4064 next = cur->parent;
4065
4066 /*
4067 * Thumbler index computation
4068 */
4069 tmp = cur->prev;
4070 while (tmp != NULL) {
4071 if ((cur->type == XML_TEXT_NODE) ||
4072 (cur->type == XML_CDATA_SECTION_NODE))
4073 occur++;
4074 tmp = tmp->prev;
4075 }
4076 if (occur == 0) {
4077 tmp = cur->next;
4078 while (tmp != NULL && occur == 0) {
4079 if ((cur->type == XML_TEXT_NODE) ||
4080 (cur->type == XML_CDATA_SECTION_NODE))
4081 occur++;
4082 tmp = tmp->next;
4083 }
4084 if (occur != 0)
4085 occur = 1;
4086 } else
4087 occur++;
4088 } else if (cur->type == XML_PI_NODE) {
4089 sep = "/";
4090 snprintf(nametemp, sizeof(nametemp) - 1,
4091 "processing-instruction('%s')", cur->name);
4092 nametemp[sizeof(nametemp) - 1] = 0;
4093 name = nametemp;
4094
4095 next = cur->parent;
4096
4097 /*
4098 * Thumbler index computation
4099 */
4100 tmp = cur->prev;
4101 while (tmp != NULL) {
4102 if ((tmp->type == XML_PI_NODE) &&
4103 (xmlStrEqual(cur->name, tmp->name)))
4104 occur++;
4105 tmp = tmp->prev;
4106 }
4107 if (occur == 0) {
4108 tmp = cur->next;
4109 while (tmp != NULL && occur == 0) {
4110 if ((tmp->type == XML_PI_NODE) &&
4111 (xmlStrEqual(cur->name, tmp->name)))
4112 occur++;
4113 tmp = tmp->next;
4114 }
4115 if (occur != 0)
4116 occur = 1;
4117 } else
4118 occur++;
4119
Daniel Veillard8faa7832001-11-26 15:58:08 +00004120 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004121 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004122 name = (const char *) (((xmlAttrPtr) cur)->name);
4123 next = ((xmlAttrPtr) cur)->parent;
4124 } else {
4125 next = cur->parent;
4126 }
4127
4128 /*
4129 * Make sure there is enough room
4130 */
4131 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4132 buf_len =
4133 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4134 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4135 if (temp == NULL) {
4136 xmlFree(buf);
4137 xmlFree(buffer);
4138 return (NULL);
4139 }
4140 buffer = temp;
4141 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4142 if (temp == NULL) {
4143 xmlFree(buf);
4144 xmlFree(buffer);
4145 return (NULL);
4146 }
4147 buf = temp;
4148 }
4149 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004150 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004151 sep, name, (char *) buffer);
4152 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004153 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004154 sep, name, occur, (char *) buffer);
4155 snprintf((char *) buffer, buf_len, "%s", buf);
4156 cur = next;
4157 } while (cur != NULL);
4158 xmlFree(buf);
4159 return (buffer);
4160}
4161
4162/**
Owen Taylor3473f882001-02-23 17:55:21 +00004163 * xmlDocGetRootElement:
4164 * @doc: the document
4165 *
4166 * Get the root element of the document (doc->children is a list
4167 * containing possibly comments, PIs, etc ...).
4168 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004169 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004170 */
4171xmlNodePtr
4172xmlDocGetRootElement(xmlDocPtr doc) {
4173 xmlNodePtr ret;
4174
4175 if (doc == NULL) return(NULL);
4176 ret = doc->children;
4177 while (ret != NULL) {
4178 if (ret->type == XML_ELEMENT_NODE)
4179 return(ret);
4180 ret = ret->next;
4181 }
4182 return(ret);
4183}
4184
4185/**
4186 * xmlDocSetRootElement:
4187 * @doc: the document
4188 * @root: the new document root element
4189 *
4190 * Set the root element of the document (doc->children is a list
4191 * containing possibly comments, PIs, etc ...).
4192 *
4193 * Returns the old root element if any was found
4194 */
4195xmlNodePtr
4196xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4197 xmlNodePtr old = NULL;
4198
4199 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004200 if (root == NULL)
4201 return(NULL);
4202 xmlUnlinkNode(root);
4203 root->doc = doc;
4204 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004205 old = doc->children;
4206 while (old != NULL) {
4207 if (old->type == XML_ELEMENT_NODE)
4208 break;
4209 old = old->next;
4210 }
4211 if (old == NULL) {
4212 if (doc->children == NULL) {
4213 doc->children = root;
4214 doc->last = root;
4215 } else {
4216 xmlAddSibling(doc->children, root);
4217 }
4218 } else {
4219 xmlReplaceNode(old, root);
4220 }
4221 return(old);
4222}
4223
4224/**
4225 * xmlNodeSetLang:
4226 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004227 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004228 *
4229 * Set the language of a node, i.e. the values of the xml:lang
4230 * attribute.
4231 */
4232void
4233xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004234 xmlNsPtr ns;
4235
Owen Taylor3473f882001-02-23 17:55:21 +00004236 if (cur == NULL) return;
4237 switch(cur->type) {
4238 case XML_TEXT_NODE:
4239 case XML_CDATA_SECTION_NODE:
4240 case XML_COMMENT_NODE:
4241 case XML_DOCUMENT_NODE:
4242 case XML_DOCUMENT_TYPE_NODE:
4243 case XML_DOCUMENT_FRAG_NODE:
4244 case XML_NOTATION_NODE:
4245 case XML_HTML_DOCUMENT_NODE:
4246 case XML_DTD_NODE:
4247 case XML_ELEMENT_DECL:
4248 case XML_ATTRIBUTE_DECL:
4249 case XML_ENTITY_DECL:
4250 case XML_PI_NODE:
4251 case XML_ENTITY_REF_NODE:
4252 case XML_ENTITY_NODE:
4253 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004254#ifdef LIBXML_DOCB_ENABLED
4255 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004256#endif
4257 case XML_XINCLUDE_START:
4258 case XML_XINCLUDE_END:
4259 return;
4260 case XML_ELEMENT_NODE:
4261 case XML_ATTRIBUTE_NODE:
4262 break;
4263 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004264 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4265 if (ns == NULL)
4266 return;
4267 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004268}
4269
4270/**
4271 * xmlNodeGetLang:
4272 * @cur: the node being checked
4273 *
4274 * Searches the language of a node, i.e. the values of the xml:lang
4275 * attribute or the one carried by the nearest ancestor.
4276 *
4277 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004278 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004279 */
4280xmlChar *
4281xmlNodeGetLang(xmlNodePtr cur) {
4282 xmlChar *lang;
4283
4284 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004285 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004286 if (lang != NULL)
4287 return(lang);
4288 cur = cur->parent;
4289 }
4290 return(NULL);
4291}
4292
4293
4294/**
4295 * xmlNodeSetSpacePreserve:
4296 * @cur: the node being changed
4297 * @val: the xml:space value ("0": default, 1: "preserve")
4298 *
4299 * Set (or reset) the space preserving behaviour of a node, i.e. the
4300 * value of the xml:space attribute.
4301 */
4302void
4303xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004304 xmlNsPtr ns;
4305
Owen Taylor3473f882001-02-23 17:55:21 +00004306 if (cur == NULL) return;
4307 switch(cur->type) {
4308 case XML_TEXT_NODE:
4309 case XML_CDATA_SECTION_NODE:
4310 case XML_COMMENT_NODE:
4311 case XML_DOCUMENT_NODE:
4312 case XML_DOCUMENT_TYPE_NODE:
4313 case XML_DOCUMENT_FRAG_NODE:
4314 case XML_NOTATION_NODE:
4315 case XML_HTML_DOCUMENT_NODE:
4316 case XML_DTD_NODE:
4317 case XML_ELEMENT_DECL:
4318 case XML_ATTRIBUTE_DECL:
4319 case XML_ENTITY_DECL:
4320 case XML_PI_NODE:
4321 case XML_ENTITY_REF_NODE:
4322 case XML_ENTITY_NODE:
4323 case XML_NAMESPACE_DECL:
4324 case XML_XINCLUDE_START:
4325 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004326#ifdef LIBXML_DOCB_ENABLED
4327 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004328#endif
4329 return;
4330 case XML_ELEMENT_NODE:
4331 case XML_ATTRIBUTE_NODE:
4332 break;
4333 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004334 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4335 if (ns == NULL)
4336 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004337 switch (val) {
4338 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004339 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004340 break;
4341 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004342 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004343 break;
4344 }
4345}
4346
4347/**
4348 * xmlNodeGetSpacePreserve:
4349 * @cur: the node being checked
4350 *
4351 * Searches the space preserving behaviour of a node, i.e. the values
4352 * of the xml:space attribute or the one carried by the nearest
4353 * ancestor.
4354 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004355 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004356 */
4357int
4358xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4359 xmlChar *space;
4360
4361 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004362 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004363 if (space != NULL) {
4364 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4365 xmlFree(space);
4366 return(1);
4367 }
4368 if (xmlStrEqual(space, BAD_CAST "default")) {
4369 xmlFree(space);
4370 return(0);
4371 }
4372 xmlFree(space);
4373 }
4374 cur = cur->parent;
4375 }
4376 return(-1);
4377}
4378
4379/**
4380 * xmlNodeSetName:
4381 * @cur: the node being changed
4382 * @name: the new tag name
4383 *
4384 * Set (or reset) the name of a node.
4385 */
4386void
4387xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
4388 if (cur == NULL) return;
4389 if (name == NULL) return;
4390 switch(cur->type) {
4391 case XML_TEXT_NODE:
4392 case XML_CDATA_SECTION_NODE:
4393 case XML_COMMENT_NODE:
4394 case XML_DOCUMENT_TYPE_NODE:
4395 case XML_DOCUMENT_FRAG_NODE:
4396 case XML_NOTATION_NODE:
4397 case XML_HTML_DOCUMENT_NODE:
4398 case XML_NAMESPACE_DECL:
4399 case XML_XINCLUDE_START:
4400 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004401#ifdef LIBXML_DOCB_ENABLED
4402 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004403#endif
4404 return;
4405 case XML_ELEMENT_NODE:
4406 case XML_ATTRIBUTE_NODE:
4407 case XML_PI_NODE:
4408 case XML_ENTITY_REF_NODE:
4409 case XML_ENTITY_NODE:
4410 case XML_DTD_NODE:
4411 case XML_DOCUMENT_NODE:
4412 case XML_ELEMENT_DECL:
4413 case XML_ATTRIBUTE_DECL:
4414 case XML_ENTITY_DECL:
4415 break;
4416 }
4417 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4418 cur->name = xmlStrdup(name);
4419}
4420
4421/**
4422 * xmlNodeSetBase:
4423 * @cur: the node being changed
4424 * @uri: the new base URI
4425 *
4426 * Set (or reset) the base URI of a node, i.e. the value of the
4427 * xml:base attribute.
4428 */
4429void
4430xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004431 xmlNsPtr ns;
4432
Owen Taylor3473f882001-02-23 17:55:21 +00004433 if (cur == NULL) return;
4434 switch(cur->type) {
4435 case XML_TEXT_NODE:
4436 case XML_CDATA_SECTION_NODE:
4437 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004438 case XML_DOCUMENT_TYPE_NODE:
4439 case XML_DOCUMENT_FRAG_NODE:
4440 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004441 case XML_DTD_NODE:
4442 case XML_ELEMENT_DECL:
4443 case XML_ATTRIBUTE_DECL:
4444 case XML_ENTITY_DECL:
4445 case XML_PI_NODE:
4446 case XML_ENTITY_REF_NODE:
4447 case XML_ENTITY_NODE:
4448 case XML_NAMESPACE_DECL:
4449 case XML_XINCLUDE_START:
4450 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004451 return;
4452 case XML_ELEMENT_NODE:
4453 case XML_ATTRIBUTE_NODE:
4454 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004455 case XML_DOCUMENT_NODE:
4456#ifdef LIBXML_DOCB_ENABLED
4457 case XML_DOCB_DOCUMENT_NODE:
4458#endif
4459 case XML_HTML_DOCUMENT_NODE: {
4460 xmlDocPtr doc = (xmlDocPtr) cur;
4461
4462 if (doc->URL != NULL)
4463 xmlFree((xmlChar *) doc->URL);
4464 if (uri == NULL)
4465 doc->URL = NULL;
4466 else
4467 doc->URL = xmlStrdup(uri);
4468 return;
4469 }
Owen Taylor3473f882001-02-23 17:55:21 +00004470 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004471
4472 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4473 if (ns == NULL)
4474 return;
4475 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004476}
4477
4478/**
Owen Taylor3473f882001-02-23 17:55:21 +00004479 * xmlNodeGetBase:
4480 * @doc: the document the node pertains to
4481 * @cur: the node being checked
4482 *
4483 * Searches for the BASE URL. The code should work on both XML
4484 * and HTML document even if base mechanisms are completely different.
4485 * It returns the base as defined in RFC 2396 sections
4486 * 5.1.1. Base URI within Document Content
4487 * and
4488 * 5.1.2. Base URI from the Encapsulating Entity
4489 * However it does not return the document base (5.1.3), use
4490 * xmlDocumentGetBase() for this
4491 *
4492 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004493 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004494 */
4495xmlChar *
4496xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004497 xmlChar *oldbase = NULL;
4498 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004499
4500 if ((cur == NULL) && (doc == NULL))
4501 return(NULL);
4502 if (doc == NULL) doc = cur->doc;
4503 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4504 cur = doc->children;
4505 while ((cur != NULL) && (cur->name != NULL)) {
4506 if (cur->type != XML_ELEMENT_NODE) {
4507 cur = cur->next;
4508 continue;
4509 }
4510 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4511 cur = cur->children;
4512 continue;
4513 }
4514 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4515 cur = cur->children;
4516 continue;
4517 }
4518 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4519 return(xmlGetProp(cur, BAD_CAST "href"));
4520 }
4521 cur = cur->next;
4522 }
4523 return(NULL);
4524 }
4525 while (cur != NULL) {
4526 if (cur->type == XML_ENTITY_DECL) {
4527 xmlEntityPtr ent = (xmlEntityPtr) cur;
4528 return(xmlStrdup(ent->URI));
4529 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004530 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004531 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004532 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004533 if (oldbase != NULL) {
4534 newbase = xmlBuildURI(oldbase, base);
4535 if (newbase != NULL) {
4536 xmlFree(oldbase);
4537 xmlFree(base);
4538 oldbase = newbase;
4539 } else {
4540 xmlFree(oldbase);
4541 xmlFree(base);
4542 return(NULL);
4543 }
4544 } else {
4545 oldbase = base;
4546 }
4547 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4548 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4549 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4550 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004551 }
4552 }
Owen Taylor3473f882001-02-23 17:55:21 +00004553 cur = cur->parent;
4554 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004555 if ((doc != NULL) && (doc->URL != NULL)) {
4556 if (oldbase == NULL)
4557 return(xmlStrdup(doc->URL));
4558 newbase = xmlBuildURI(oldbase, doc->URL);
4559 xmlFree(oldbase);
4560 return(newbase);
4561 }
4562 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004563}
4564
4565/**
4566 * xmlNodeGetContent:
4567 * @cur: the node being read
4568 *
4569 * Read the value of a node, this can be either the text carried
4570 * directly by this node if it's a TEXT node or the aggregate string
4571 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004572 * Entity references are substituted.
4573 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004574 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004575 */
4576xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004577xmlNodeGetContent(xmlNodePtr cur)
4578{
4579 if (cur == NULL)
4580 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004581 switch (cur->type) {
4582 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004583 case XML_ELEMENT_NODE:{
4584 xmlNodePtr tmp = cur;
4585 xmlBufferPtr buffer;
4586 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004587
Daniel Veillard814a76d2003-01-23 18:24:20 +00004588 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004589 if (buffer == NULL)
4590 return (NULL);
4591 while (tmp != NULL) {
4592 switch (tmp->type) {
4593 case XML_CDATA_SECTION_NODE:
4594 case XML_TEXT_NODE:
4595 if (tmp->content != NULL)
4596 xmlBufferCat(buffer, tmp->content);
4597 break;
4598 case XML_ENTITY_REF_NODE:{
4599 /* recursive substitution of entity references */
4600 xmlChar *cont = xmlNodeGetContent(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00004601
Daniel Veillard7646b182002-04-20 06:41:40 +00004602 if (cont) {
4603 xmlBufferCat(buffer,
4604 (const xmlChar *) cont);
4605 xmlFree(cont);
4606 }
4607 break;
4608 }
4609 default:
4610 break;
4611 }
4612 /*
4613 * Skip to next node
4614 */
4615 if (tmp->children != NULL) {
4616 if (tmp->children->type != XML_ENTITY_DECL) {
4617 tmp = tmp->children;
4618 continue;
4619 }
4620 }
4621 if (tmp == cur)
4622 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00004623
Daniel Veillard7646b182002-04-20 06:41:40 +00004624 if (tmp->next != NULL) {
4625 tmp = tmp->next;
4626 continue;
4627 }
4628
4629 do {
4630 tmp = tmp->parent;
4631 if (tmp == NULL)
4632 break;
4633 if (tmp == cur) {
4634 tmp = NULL;
4635 break;
4636 }
4637 if (tmp->next != NULL) {
4638 tmp = tmp->next;
4639 break;
4640 }
4641 } while (tmp != NULL);
4642 }
4643 ret = buffer->content;
4644 buffer->content = NULL;
4645 xmlBufferFree(buffer);
4646 return (ret);
4647 }
4648 case XML_ATTRIBUTE_NODE:{
4649 xmlAttrPtr attr = (xmlAttrPtr) cur;
4650
4651 if (attr->parent != NULL)
4652 return (xmlNodeListGetString
4653 (attr->parent->doc, attr->children, 1));
4654 else
4655 return (xmlNodeListGetString(NULL, attr->children, 1));
4656 break;
4657 }
Owen Taylor3473f882001-02-23 17:55:21 +00004658 case XML_COMMENT_NODE:
4659 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004660 if (cur->content != NULL)
4661 return (xmlStrdup(cur->content));
4662 return (NULL);
4663 case XML_ENTITY_REF_NODE:{
4664 xmlEntityPtr ent;
4665 xmlNodePtr tmp;
4666 xmlBufferPtr buffer;
4667 xmlChar *ret;
4668
4669 /* lookup entity declaration */
4670 ent = xmlGetDocEntity(cur->doc, cur->name);
4671 if (ent == NULL)
4672 return (NULL);
4673
4674 buffer = xmlBufferCreate();
4675 if (buffer == NULL)
4676 return (NULL);
4677
4678 /* an entity content can be any "well balanced chunk",
4679 * i.e. the result of the content [43] production:
4680 * http://www.w3.org/TR/REC-xml#NT-content
4681 * -> we iterate through child nodes and recursive call
4682 * xmlNodeGetContent() which handles all possible node types */
4683 tmp = ent->children;
4684 while (tmp) {
4685 xmlChar *cont = xmlNodeGetContent(tmp);
4686
4687 if (cont) {
4688 xmlBufferCat(buffer, (const xmlChar *) cont);
4689 xmlFree(cont);
4690 }
4691 tmp = tmp->next;
4692 }
4693
4694 ret = buffer->content;
4695 buffer->content = NULL;
4696 xmlBufferFree(buffer);
4697 return (ret);
4698 }
Owen Taylor3473f882001-02-23 17:55:21 +00004699 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004700 case XML_DOCUMENT_TYPE_NODE:
4701 case XML_NOTATION_NODE:
4702 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004703 case XML_XINCLUDE_START:
4704 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00004705 return (NULL);
4706 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004707#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004708 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004709#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00004710 case XML_HTML_DOCUMENT_NODE: {
4711 xmlChar *tmp;
4712 xmlChar *res = NULL;
4713
4714 cur = cur->children;
4715 while (cur!= NULL) {
4716 if ((cur->type == XML_ELEMENT_NODE) ||
4717 (cur->type == XML_TEXT_NODE) ||
4718 (cur->type == XML_CDATA_SECTION_NODE)) {
4719 tmp = xmlNodeGetContent(cur);
4720 if (tmp != NULL) {
4721 if (res == NULL)
4722 res = tmp;
4723 else {
4724 res = xmlStrcat(res, tmp);
4725 xmlFree(tmp);
4726 }
4727 }
4728 }
4729 cur = cur->next;
4730 }
4731 return(res);
4732 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004733 case XML_NAMESPACE_DECL: {
4734 xmlChar *tmp;
4735
4736 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4737 return (tmp);
4738 }
Owen Taylor3473f882001-02-23 17:55:21 +00004739 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004740 /* TODO !!! */
4741 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004742 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004743 /* TODO !!! */
4744 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004745 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004746 /* TODO !!! */
4747 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004748 case XML_CDATA_SECTION_NODE:
4749 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004750 if (cur->content != NULL)
4751 return (xmlStrdup(cur->content));
4752 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004753 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004754 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004755}
Owen Taylor3473f882001-02-23 17:55:21 +00004756/**
4757 * xmlNodeSetContent:
4758 * @cur: the node being modified
4759 * @content: the new value of the content
4760 *
4761 * Replace the content of a node.
4762 */
4763void
4764xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4765 if (cur == NULL) {
4766#ifdef DEBUG_TREE
4767 xmlGenericError(xmlGenericErrorContext,
4768 "xmlNodeSetContent : node == NULL\n");
4769#endif
4770 return;
4771 }
4772 switch (cur->type) {
4773 case XML_DOCUMENT_FRAG_NODE:
4774 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004775 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004776 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4777 cur->children = xmlStringGetNodeList(cur->doc, content);
4778 UPDATE_LAST_CHILD_AND_PARENT(cur)
4779 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004780 case XML_TEXT_NODE:
4781 case XML_CDATA_SECTION_NODE:
4782 case XML_ENTITY_REF_NODE:
4783 case XML_ENTITY_NODE:
4784 case XML_PI_NODE:
4785 case XML_COMMENT_NODE:
4786 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004787 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004788 }
4789 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4790 cur->last = cur->children = NULL;
4791 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004792 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00004793 } else
4794 cur->content = NULL;
4795 break;
4796 case XML_DOCUMENT_NODE:
4797 case XML_HTML_DOCUMENT_NODE:
4798 case XML_DOCUMENT_TYPE_NODE:
4799 case XML_XINCLUDE_START:
4800 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004801#ifdef LIBXML_DOCB_ENABLED
4802 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004803#endif
4804 break;
4805 case XML_NOTATION_NODE:
4806 break;
4807 case XML_DTD_NODE:
4808 break;
4809 case XML_NAMESPACE_DECL:
4810 break;
4811 case XML_ELEMENT_DECL:
4812 /* TODO !!! */
4813 break;
4814 case XML_ATTRIBUTE_DECL:
4815 /* TODO !!! */
4816 break;
4817 case XML_ENTITY_DECL:
4818 /* TODO !!! */
4819 break;
4820 }
4821}
4822
4823/**
4824 * xmlNodeSetContentLen:
4825 * @cur: the node being modified
4826 * @content: the new value of the content
4827 * @len: the size of @content
4828 *
4829 * Replace the content of a node.
4830 */
4831void
4832xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4833 if (cur == NULL) {
4834#ifdef DEBUG_TREE
4835 xmlGenericError(xmlGenericErrorContext,
4836 "xmlNodeSetContentLen : node == NULL\n");
4837#endif
4838 return;
4839 }
4840 switch (cur->type) {
4841 case XML_DOCUMENT_FRAG_NODE:
4842 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004843 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004844 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4845 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
4846 UPDATE_LAST_CHILD_AND_PARENT(cur)
4847 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004848 case XML_TEXT_NODE:
4849 case XML_CDATA_SECTION_NODE:
4850 case XML_ENTITY_REF_NODE:
4851 case XML_ENTITY_NODE:
4852 case XML_PI_NODE:
4853 case XML_COMMENT_NODE:
4854 case XML_NOTATION_NODE:
4855 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004856 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004857 }
4858 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4859 cur->children = cur->last = NULL;
4860 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004861 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004862 } else
4863 cur->content = NULL;
4864 break;
4865 case XML_DOCUMENT_NODE:
4866 case XML_DTD_NODE:
4867 case XML_HTML_DOCUMENT_NODE:
4868 case XML_DOCUMENT_TYPE_NODE:
4869 case XML_NAMESPACE_DECL:
4870 case XML_XINCLUDE_START:
4871 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004872#ifdef LIBXML_DOCB_ENABLED
4873 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004874#endif
4875 break;
4876 case XML_ELEMENT_DECL:
4877 /* TODO !!! */
4878 break;
4879 case XML_ATTRIBUTE_DECL:
4880 /* TODO !!! */
4881 break;
4882 case XML_ENTITY_DECL:
4883 /* TODO !!! */
4884 break;
4885 }
4886}
4887
4888/**
4889 * xmlNodeAddContentLen:
4890 * @cur: the node being modified
4891 * @content: extra content
4892 * @len: the size of @content
4893 *
4894 * Append the extra substring to the node content.
4895 */
4896void
4897xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4898 if (cur == NULL) {
4899#ifdef DEBUG_TREE
4900 xmlGenericError(xmlGenericErrorContext,
4901 "xmlNodeAddContentLen : node == NULL\n");
4902#endif
4903 return;
4904 }
4905 if (len <= 0) return;
4906 switch (cur->type) {
4907 case XML_DOCUMENT_FRAG_NODE:
4908 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004909 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004910
Daniel Veillard7db37732001-07-12 01:20:08 +00004911 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004912 newNode = xmlNewTextLen(content, len);
4913 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004914 tmp = xmlAddChild(cur, newNode);
4915 if (tmp != newNode)
4916 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004917 if ((last != NULL) && (last->next == newNode)) {
4918 xmlTextMerge(last, newNode);
4919 }
4920 }
4921 break;
4922 }
4923 case XML_ATTRIBUTE_NODE:
4924 break;
4925 case XML_TEXT_NODE:
4926 case XML_CDATA_SECTION_NODE:
4927 case XML_ENTITY_REF_NODE:
4928 case XML_ENTITY_NODE:
4929 case XML_PI_NODE:
4930 case XML_COMMENT_NODE:
4931 case XML_NOTATION_NODE:
4932 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004933 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004934 }
4935 case XML_DOCUMENT_NODE:
4936 case XML_DTD_NODE:
4937 case XML_HTML_DOCUMENT_NODE:
4938 case XML_DOCUMENT_TYPE_NODE:
4939 case XML_NAMESPACE_DECL:
4940 case XML_XINCLUDE_START:
4941 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004942#ifdef LIBXML_DOCB_ENABLED
4943 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004944#endif
4945 break;
4946 case XML_ELEMENT_DECL:
4947 case XML_ATTRIBUTE_DECL:
4948 case XML_ENTITY_DECL:
4949 break;
4950 }
4951}
4952
4953/**
4954 * xmlNodeAddContent:
4955 * @cur: the node being modified
4956 * @content: extra content
4957 *
4958 * Append the extra substring to the node content.
4959 */
4960void
4961xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
4962 int len;
4963
4964 if (cur == NULL) {
4965#ifdef DEBUG_TREE
4966 xmlGenericError(xmlGenericErrorContext,
4967 "xmlNodeAddContent : node == NULL\n");
4968#endif
4969 return;
4970 }
4971 if (content == NULL) return;
4972 len = xmlStrlen(content);
4973 xmlNodeAddContentLen(cur, content, len);
4974}
4975
4976/**
4977 * xmlTextMerge:
4978 * @first: the first text node
4979 * @second: the second text node being merged
4980 *
4981 * Merge two text nodes into one
4982 * Returns the first text node augmented
4983 */
4984xmlNodePtr
4985xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
4986 if (first == NULL) return(second);
4987 if (second == NULL) return(first);
4988 if (first->type != XML_TEXT_NODE) return(first);
4989 if (second->type != XML_TEXT_NODE) return(first);
4990 if (second->name != first->name)
4991 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00004992 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004993 xmlUnlinkNode(second);
4994 xmlFreeNode(second);
4995 return(first);
4996}
4997
4998/**
4999 * xmlGetNsList:
5000 * @doc: the document
5001 * @node: the current node
5002 *
5003 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005004 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005005 * that need to be freed by the caller or NULL if no
5006 * namespace if defined
5007 */
5008xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005009xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5010{
Owen Taylor3473f882001-02-23 17:55:21 +00005011 xmlNsPtr cur;
5012 xmlNsPtr *ret = NULL;
5013 int nbns = 0;
5014 int maxns = 10;
5015 int i;
5016
5017 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005018 if (node->type == XML_ELEMENT_NODE) {
5019 cur = node->nsDef;
5020 while (cur != NULL) {
5021 if (ret == NULL) {
5022 ret =
5023 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5024 sizeof(xmlNsPtr));
5025 if (ret == NULL) {
5026 xmlGenericError(xmlGenericErrorContext,
5027 "xmlGetNsList : out of memory!\n");
5028 return (NULL);
5029 }
5030 ret[nbns] = NULL;
5031 }
5032 for (i = 0; i < nbns; i++) {
5033 if ((cur->prefix == ret[i]->prefix) ||
5034 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5035 break;
5036 }
5037 if (i >= nbns) {
5038 if (nbns >= maxns) {
5039 maxns *= 2;
5040 ret = (xmlNsPtr *) xmlRealloc(ret,
5041 (maxns +
5042 1) *
5043 sizeof(xmlNsPtr));
5044 if (ret == NULL) {
5045 xmlGenericError(xmlGenericErrorContext,
5046 "xmlGetNsList : realloc failed!\n");
5047 return (NULL);
5048 }
5049 }
5050 ret[nbns++] = cur;
5051 ret[nbns] = NULL;
5052 }
Owen Taylor3473f882001-02-23 17:55:21 +00005053
Daniel Veillard77044732001-06-29 21:31:07 +00005054 cur = cur->next;
5055 }
5056 }
5057 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005058 }
Daniel Veillard77044732001-06-29 21:31:07 +00005059 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005060}
5061
5062/**
5063 * xmlSearchNs:
5064 * @doc: the document
5065 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005066 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005067 *
5068 * Search a Ns registered under a given name space for a document.
5069 * recurse on the parents until it finds the defined namespace
5070 * or return NULL otherwise.
5071 * @nameSpace can be NULL, this is a search for the default namespace.
5072 * We don't allow to cross entities boundaries. If you don't declare
5073 * the namespace within those you will be in troubles !!! A warning
5074 * is generated to cover this case.
5075 *
5076 * Returns the namespace pointer or NULL.
5077 */
5078xmlNsPtr
5079xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
5080 xmlNsPtr cur;
5081
5082 if (node == NULL) return(NULL);
5083 if ((nameSpace != NULL) &&
5084 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005085 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5086 /*
5087 * The XML-1.0 namespace is normally held on the root
5088 * element. In this case exceptionally create it on the
5089 * node element.
5090 */
5091 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5092 if (cur == NULL) {
5093 xmlGenericError(xmlGenericErrorContext,
5094 "xmlSearchNs : malloc failed\n");
5095 return(NULL);
5096 }
5097 memset(cur, 0, sizeof(xmlNs));
5098 cur->type = XML_LOCAL_NAMESPACE;
5099 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5100 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5101 cur->next = node->nsDef;
5102 node->nsDef = cur;
5103 return(cur);
5104 }
Owen Taylor3473f882001-02-23 17:55:21 +00005105 if (doc->oldNs == NULL) {
5106 /*
5107 * Allocate a new Namespace and fill the fields.
5108 */
5109 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5110 if (doc->oldNs == NULL) {
5111 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005112 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005113 return(NULL);
5114 }
5115 memset(doc->oldNs, 0, sizeof(xmlNs));
5116 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5117
5118 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5119 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5120 }
5121 return(doc->oldNs);
5122 }
5123 while (node != NULL) {
5124 if ((node->type == XML_ENTITY_REF_NODE) ||
5125 (node->type == XML_ENTITY_NODE) ||
5126 (node->type == XML_ENTITY_DECL))
5127 return(NULL);
5128 if (node->type == XML_ELEMENT_NODE) {
5129 cur = node->nsDef;
5130 while (cur != NULL) {
5131 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5132 (cur->href != NULL))
5133 return(cur);
5134 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5135 (cur->href != NULL) &&
5136 (xmlStrEqual(cur->prefix, nameSpace)))
5137 return(cur);
5138 cur = cur->next;
5139 }
5140 }
5141 node = node->parent;
5142 }
5143 return(NULL);
5144}
5145
5146/**
5147 * xmlSearchNsByHref:
5148 * @doc: the document
5149 * @node: the current node
5150 * @href: the namespace value
5151 *
5152 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5153 * the defined namespace or return NULL otherwise.
5154 * Returns the namespace pointer or NULL.
5155 */
5156xmlNsPtr
5157xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
5158 xmlNsPtr cur;
5159 xmlNodePtr orig = node;
5160
5161 if ((node == NULL) || (href == NULL)) return(NULL);
5162 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00005163 /*
5164 * Only the document can hold the XML spec namespace.
5165 */
Daniel Veillardc1a0da32002-08-14 08:32:18 +00005166 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5167 /*
5168 * The XML-1.0 namespace is normally held on the root
5169 * element. In this case exceptionally create it on the
5170 * node element.
5171 */
5172 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5173 if (cur == NULL) {
5174 xmlGenericError(xmlGenericErrorContext,
5175 "xmlSearchNs : malloc failed\n");
5176 return(NULL);
5177 }
5178 memset(cur, 0, sizeof(xmlNs));
5179 cur->type = XML_LOCAL_NAMESPACE;
5180 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5181 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5182 cur->next = node->nsDef;
5183 node->nsDef = cur;
5184 return(cur);
5185 }
Owen Taylor3473f882001-02-23 17:55:21 +00005186 if (doc->oldNs == NULL) {
5187 /*
5188 * Allocate a new Namespace and fill the fields.
5189 */
5190 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5191 if (doc->oldNs == NULL) {
5192 xmlGenericError(xmlGenericErrorContext,
5193 "xmlSearchNsByHref : malloc failed\n");
5194 return(NULL);
5195 }
5196 memset(doc->oldNs, 0, sizeof(xmlNs));
5197 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5198
5199 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5200 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5201 }
5202 return(doc->oldNs);
5203 }
5204 while (node != NULL) {
5205 cur = node->nsDef;
5206 while (cur != NULL) {
5207 if ((cur->href != NULL) && (href != NULL) &&
5208 (xmlStrEqual(cur->href, href))) {
5209 /*
5210 * Check that the prefix is not shadowed between orig and node
5211 */
5212 xmlNodePtr check = orig;
5213 xmlNsPtr tst;
5214
5215 while (check != node) {
5216 tst = check->nsDef;
5217 while (tst != NULL) {
5218 if ((tst->prefix == NULL) && (cur->prefix == NULL))
5219 goto shadowed;
5220 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
5221 (xmlStrEqual(tst->prefix, cur->prefix)))
5222 goto shadowed;
5223 tst = tst->next;
5224 }
5225 check = check->parent;
5226 }
5227 return(cur);
5228 }
5229shadowed:
5230 cur = cur->next;
5231 }
5232 node = node->parent;
5233 }
5234 return(NULL);
5235}
5236
5237/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005238 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005239 * @doc: the document
5240 * @tree: a node expected to hold the new namespace
5241 * @ns: the original namespace
5242 *
5243 * This function tries to locate a namespace definition in a tree
5244 * ancestors, or create a new namespace definition node similar to
5245 * @ns trying to reuse the same prefix. However if the given prefix is
5246 * null (default namespace) or reused within the subtree defined by
5247 * @tree or on one of its ancestors then a new prefix is generated.
5248 * Returns the (new) namespace definition or NULL in case of error
5249 */
5250xmlNsPtr
5251xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5252 xmlNsPtr def;
5253 xmlChar prefix[50];
5254 int counter = 1;
5255
5256 if (tree == NULL) {
5257#ifdef DEBUG_TREE
5258 xmlGenericError(xmlGenericErrorContext,
5259 "xmlNewReconciliedNs : tree == NULL\n");
5260#endif
5261 return(NULL);
5262 }
5263 if (ns == NULL) {
5264#ifdef DEBUG_TREE
5265 xmlGenericError(xmlGenericErrorContext,
5266 "xmlNewReconciliedNs : ns == NULL\n");
5267#endif
5268 return(NULL);
5269 }
5270 /*
5271 * Search an existing namespace definition inherited.
5272 */
5273 def = xmlSearchNsByHref(doc, tree, ns->href);
5274 if (def != NULL)
5275 return(def);
5276
5277 /*
5278 * Find a close prefix which is not already in use.
5279 * Let's strip namespace prefixes longer than 20 chars !
5280 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005281 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005282 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005283 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005284 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005285
Owen Taylor3473f882001-02-23 17:55:21 +00005286 def = xmlSearchNs(doc, tree, prefix);
5287 while (def != NULL) {
5288 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005289 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005290 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005291 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005292 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005293 def = xmlSearchNs(doc, tree, prefix);
5294 }
5295
5296 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005297 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005298 */
5299 def = xmlNewNs(tree, ns->href, prefix);
5300 return(def);
5301}
5302
5303/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005304 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005305 * @doc: the document
5306 * @tree: a node defining the subtree to reconciliate
5307 *
5308 * This function checks that all the namespaces declared within the given
5309 * tree are properly declared. This is needed for example after Copy or Cut
5310 * and then paste operations. The subtree may still hold pointers to
5311 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005312 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005313 * the new environment. If not possible the new namespaces are redeclared
5314 * on @tree at the top of the given subtree.
5315 * Returns the number of namespace declarations created or -1 in case of error.
5316 */
5317int
5318xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5319 xmlNsPtr *oldNs = NULL;
5320 xmlNsPtr *newNs = NULL;
5321 int sizeCache = 0;
5322 int nbCache = 0;
5323
5324 xmlNsPtr n;
5325 xmlNodePtr node = tree;
5326 xmlAttrPtr attr;
5327 int ret = 0, i;
5328
5329 while (node != NULL) {
5330 /*
5331 * Reconciliate the node namespace
5332 */
5333 if (node->ns != NULL) {
5334 /*
5335 * initialize the cache if needed
5336 */
5337 if (sizeCache == 0) {
5338 sizeCache = 10;
5339 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5340 sizeof(xmlNsPtr));
5341 if (oldNs == NULL) {
5342 xmlGenericError(xmlGenericErrorContext,
5343 "xmlReconciliateNs : memory pbm\n");
5344 return(-1);
5345 }
5346 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5347 sizeof(xmlNsPtr));
5348 if (newNs == NULL) {
5349 xmlGenericError(xmlGenericErrorContext,
5350 "xmlReconciliateNs : memory pbm\n");
5351 xmlFree(oldNs);
5352 return(-1);
5353 }
5354 }
5355 for (i = 0;i < nbCache;i++) {
5356 if (oldNs[i] == node->ns) {
5357 node->ns = newNs[i];
5358 break;
5359 }
5360 }
5361 if (i == nbCache) {
5362 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005363 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005364 */
5365 n = xmlNewReconciliedNs(doc, tree, node->ns);
5366 if (n != NULL) { /* :-( what if else ??? */
5367 /*
5368 * check if we need to grow the cache buffers.
5369 */
5370 if (sizeCache <= nbCache) {
5371 sizeCache *= 2;
5372 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5373 sizeof(xmlNsPtr));
5374 if (oldNs == NULL) {
5375 xmlGenericError(xmlGenericErrorContext,
5376 "xmlReconciliateNs : memory pbm\n");
5377 xmlFree(newNs);
5378 return(-1);
5379 }
5380 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5381 sizeof(xmlNsPtr));
5382 if (newNs == NULL) {
5383 xmlGenericError(xmlGenericErrorContext,
5384 "xmlReconciliateNs : memory pbm\n");
5385 xmlFree(oldNs);
5386 return(-1);
5387 }
5388 }
5389 newNs[nbCache] = n;
5390 oldNs[nbCache++] = node->ns;
5391 node->ns = n;
5392 }
5393 }
5394 }
5395 /*
5396 * now check for namespace hold by attributes on the node.
5397 */
5398 attr = node->properties;
5399 while (attr != NULL) {
5400 if (attr->ns != NULL) {
5401 /*
5402 * initialize the cache if needed
5403 */
5404 if (sizeCache == 0) {
5405 sizeCache = 10;
5406 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5407 sizeof(xmlNsPtr));
5408 if (oldNs == NULL) {
5409 xmlGenericError(xmlGenericErrorContext,
5410 "xmlReconciliateNs : memory pbm\n");
5411 return(-1);
5412 }
5413 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5414 sizeof(xmlNsPtr));
5415 if (newNs == NULL) {
5416 xmlGenericError(xmlGenericErrorContext,
5417 "xmlReconciliateNs : memory pbm\n");
5418 xmlFree(oldNs);
5419 return(-1);
5420 }
5421 }
5422 for (i = 0;i < nbCache;i++) {
5423 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005424 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005425 break;
5426 }
5427 }
5428 if (i == nbCache) {
5429 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005430 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005431 */
5432 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5433 if (n != NULL) { /* :-( what if else ??? */
5434 /*
5435 * check if we need to grow the cache buffers.
5436 */
5437 if (sizeCache <= nbCache) {
5438 sizeCache *= 2;
5439 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5440 sizeof(xmlNsPtr));
5441 if (oldNs == NULL) {
5442 xmlGenericError(xmlGenericErrorContext,
5443 "xmlReconciliateNs : memory pbm\n");
5444 xmlFree(newNs);
5445 return(-1);
5446 }
5447 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5448 sizeof(xmlNsPtr));
5449 if (newNs == NULL) {
5450 xmlGenericError(xmlGenericErrorContext,
5451 "xmlReconciliateNs : memory pbm\n");
5452 xmlFree(oldNs);
5453 return(-1);
5454 }
5455 }
5456 newNs[nbCache] = n;
5457 oldNs[nbCache++] = attr->ns;
5458 attr->ns = n;
5459 }
5460 }
5461 }
5462 attr = attr->next;
5463 }
5464
5465 /*
5466 * Browse the full subtree, deep first
5467 */
5468 if (node->children != NULL) {
5469 /* deep first */
5470 node = node->children;
5471 } else if ((node != tree) && (node->next != NULL)) {
5472 /* then siblings */
5473 node = node->next;
5474 } else if (node != tree) {
5475 /* go up to parents->next if needed */
5476 while (node != tree) {
5477 if (node->parent != NULL)
5478 node = node->parent;
5479 if ((node != tree) && (node->next != NULL)) {
5480 node = node->next;
5481 break;
5482 }
5483 if (node->parent == NULL) {
5484 node = NULL;
5485 break;
5486 }
5487 }
5488 /* exit condition */
5489 if (node == tree)
5490 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005491 } else
5492 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005493 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005494 if (oldNs != NULL)
5495 xmlFree(oldNs);
5496 if (newNs != NULL)
5497 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005498 return(ret);
5499}
5500
5501/**
5502 * xmlHasProp:
5503 * @node: the node
5504 * @name: the attribute name
5505 *
5506 * Search an attribute associated to a node
5507 * This function also looks in DTD attribute declaration for #FIXED or
5508 * default declaration values unless DTD use has been turned off.
5509 *
5510 * Returns the attribute or the attribute declaration or NULL if
5511 * neither was found.
5512 */
5513xmlAttrPtr
5514xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5515 xmlAttrPtr prop;
5516 xmlDocPtr doc;
5517
5518 if ((node == NULL) || (name == NULL)) return(NULL);
5519 /*
5520 * Check on the properties attached to the node
5521 */
5522 prop = node->properties;
5523 while (prop != NULL) {
5524 if (xmlStrEqual(prop->name, name)) {
5525 return(prop);
5526 }
5527 prop = prop->next;
5528 }
5529 if (!xmlCheckDTD) return(NULL);
5530
5531 /*
5532 * Check if there is a default declaration in the internal
5533 * or external subsets
5534 */
5535 doc = node->doc;
5536 if (doc != NULL) {
5537 xmlAttributePtr attrDecl;
5538 if (doc->intSubset != NULL) {
5539 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5540 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5541 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5542 if (attrDecl != NULL)
5543 return((xmlAttrPtr) attrDecl);
5544 }
5545 }
5546 return(NULL);
5547}
5548
5549/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005550 * xmlHasNsProp:
5551 * @node: the node
5552 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005553 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005554 *
5555 * Search for an attribute associated to a node
5556 * This attribute has to be anchored in the namespace specified.
5557 * This does the entity substitution.
5558 * This function looks in DTD attribute declaration for #FIXED or
5559 * default declaration values unless DTD use has been turned off.
5560 *
5561 * Returns the attribute or the attribute declaration or NULL
5562 * if neither was found.
5563 */
5564xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005565xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005566 xmlAttrPtr prop;
5567 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005568
5569 if (node == NULL)
5570 return(NULL);
5571
5572 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005573 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005574 return(xmlHasProp(node, name));
5575 while (prop != NULL) {
5576 /*
5577 * One need to have
5578 * - same attribute names
5579 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005580 */
5581 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005582 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5583 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005584 }
5585 prop = prop->next;
5586 }
5587 if (!xmlCheckDTD) return(NULL);
5588
5589 /*
5590 * Check if there is a default declaration in the internal
5591 * or external subsets
5592 */
5593 doc = node->doc;
5594 if (doc != NULL) {
5595 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005596 xmlAttributePtr attrDecl = NULL;
5597 xmlNsPtr *nsList, *cur;
5598 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005599
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005600 nsList = xmlGetNsList(node->doc, node);
5601 if (nsList == NULL)
5602 return(NULL);
5603 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5604 ename = xmlStrdup(node->ns->prefix);
5605 ename = xmlStrcat(ename, BAD_CAST ":");
5606 ename = xmlStrcat(ename, node->name);
5607 } else {
5608 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005609 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005610 if (ename == NULL) {
5611 xmlFree(nsList);
5612 return(NULL);
5613 }
5614
5615 cur = nsList;
5616 while (*cur != NULL) {
5617 if (xmlStrEqual((*cur)->href, nameSpace)) {
5618 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5619 name, (*cur)->prefix);
5620 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5621 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5622 name, (*cur)->prefix);
5623 }
5624 cur++;
5625 }
5626 xmlFree(nsList);
5627 xmlFree(ename);
5628 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005629 }
5630 }
5631 return(NULL);
5632}
5633
5634/**
Owen Taylor3473f882001-02-23 17:55:21 +00005635 * xmlGetProp:
5636 * @node: the node
5637 * @name: the attribute name
5638 *
5639 * Search and get the value of an attribute associated to a node
5640 * This does the entity substitution.
5641 * This function looks in DTD attribute declaration for #FIXED or
5642 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00005643 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00005644 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
5645 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00005646 *
5647 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005648 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005649 */
5650xmlChar *
5651xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5652 xmlAttrPtr prop;
5653 xmlDocPtr doc;
5654
5655 if ((node == NULL) || (name == NULL)) return(NULL);
5656 /*
5657 * Check on the properties attached to the node
5658 */
5659 prop = node->properties;
5660 while (prop != NULL) {
5661 if (xmlStrEqual(prop->name, name)) {
5662 xmlChar *ret;
5663
5664 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5665 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5666 return(ret);
5667 }
5668 prop = prop->next;
5669 }
5670 if (!xmlCheckDTD) return(NULL);
5671
5672 /*
5673 * Check if there is a default declaration in the internal
5674 * or external subsets
5675 */
5676 doc = node->doc;
5677 if (doc != NULL) {
5678 xmlAttributePtr attrDecl;
5679 if (doc->intSubset != NULL) {
5680 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5681 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5682 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5683 if (attrDecl != NULL)
5684 return(xmlStrdup(attrDecl->defaultValue));
5685 }
5686 }
5687 return(NULL);
5688}
5689
5690/**
Daniel Veillard71531f32003-02-05 13:19:53 +00005691 * xmlGetNoNsProp:
5692 * @node: the node
5693 * @name: the attribute name
5694 *
5695 * Search and get the value of an attribute associated to a node
5696 * This does the entity substitution.
5697 * This function looks in DTD attribute declaration for #FIXED or
5698 * default declaration values unless DTD use has been turned off.
5699 * This function is similar to xmlGetProp except it will accept only
5700 * an attribute in no namespace.
5701 *
5702 * Returns the attribute value or NULL if not found.
5703 * It's up to the caller to free the memory with xmlFree().
5704 */
5705xmlChar *
5706xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
5707 xmlAttrPtr prop;
5708 xmlDocPtr doc;
5709
5710 if ((node == NULL) || (name == NULL)) return(NULL);
5711 /*
5712 * Check on the properties attached to the node
5713 */
5714 prop = node->properties;
5715 while (prop != NULL) {
5716 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
5717 xmlChar *ret;
5718
5719 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5720 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5721 return(ret);
5722 }
5723 prop = prop->next;
5724 }
5725 if (!xmlCheckDTD) return(NULL);
5726
5727 /*
5728 * Check if there is a default declaration in the internal
5729 * or external subsets
5730 */
5731 doc = node->doc;
5732 if (doc != NULL) {
5733 xmlAttributePtr attrDecl;
5734 if (doc->intSubset != NULL) {
5735 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5736 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5737 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5738 if (attrDecl != NULL)
5739 return(xmlStrdup(attrDecl->defaultValue));
5740 }
5741 }
5742 return(NULL);
5743}
5744
5745/**
Owen Taylor3473f882001-02-23 17:55:21 +00005746 * xmlGetNsProp:
5747 * @node: the node
5748 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005749 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005750 *
5751 * Search and get the value of an attribute associated to a node
5752 * This attribute has to be anchored in the namespace specified.
5753 * This does the entity substitution.
5754 * This function looks in DTD attribute declaration for #FIXED or
5755 * default declaration values unless DTD use has been turned off.
5756 *
5757 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005758 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005759 */
5760xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00005761xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00005762 xmlAttrPtr prop;
5763 xmlDocPtr doc;
5764 xmlNsPtr ns;
5765
5766 if (node == NULL)
5767 return(NULL);
5768
5769 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005770 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00005771 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00005772 while (prop != NULL) {
5773 /*
5774 * One need to have
5775 * - same attribute names
5776 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005777 */
5778 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00005779 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00005780 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005781 xmlChar *ret;
5782
5783 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5784 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5785 return(ret);
5786 }
5787 prop = prop->next;
5788 }
5789 if (!xmlCheckDTD) return(NULL);
5790
5791 /*
5792 * Check if there is a default declaration in the internal
5793 * or external subsets
5794 */
5795 doc = node->doc;
5796 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005797 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00005798 xmlAttributePtr attrDecl;
5799
Owen Taylor3473f882001-02-23 17:55:21 +00005800 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5801 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5802 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5803
5804 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
5805 /*
5806 * The DTD declaration only allows a prefix search
5807 */
5808 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00005809 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00005810 return(xmlStrdup(attrDecl->defaultValue));
5811 }
5812 }
5813 }
5814 return(NULL);
5815}
5816
5817/**
5818 * xmlSetProp:
5819 * @node: the node
5820 * @name: the attribute name
5821 * @value: the attribute value
5822 *
5823 * Set (or reset) an attribute carried by a node.
5824 * Returns the attribute pointer.
5825 */
5826xmlAttrPtr
5827xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005828 xmlAttrPtr prop;
5829 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00005830
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00005831 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00005832 return(NULL);
5833 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005834 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00005835 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005836 if ((xmlStrEqual(prop->name, name)) &&
5837 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005838 xmlNodePtr oldprop = prop->children;
5839
Owen Taylor3473f882001-02-23 17:55:21 +00005840 prop->children = NULL;
5841 prop->last = NULL;
5842 if (value != NULL) {
5843 xmlChar *buffer;
5844 xmlNodePtr tmp;
5845
5846 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5847 prop->children = xmlStringGetNodeList(node->doc, buffer);
5848 prop->last = NULL;
5849 prop->doc = doc;
5850 tmp = prop->children;
5851 while (tmp != NULL) {
5852 tmp->parent = (xmlNodePtr) prop;
5853 tmp->doc = doc;
5854 if (tmp->next == NULL)
5855 prop->last = tmp;
5856 tmp = tmp->next;
5857 }
5858 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00005859 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005860 if (oldprop != NULL)
5861 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00005862 return(prop);
5863 }
5864 prop = prop->next;
5865 }
5866 prop = xmlNewProp(node, name, value);
5867 return(prop);
5868}
5869
5870/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005871 * xmlUnsetProp:
5872 * @node: the node
5873 * @name: the attribute name
5874 *
5875 * Remove an attribute carried by a node.
5876 * Returns 0 if successful, -1 if not found
5877 */
5878int
5879xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Daniel Veillard814a76d2003-01-23 18:24:20 +00005880 xmlAttrPtr prop, prev = NULL;;
Daniel Veillard75bea542001-05-11 17:41:21 +00005881
5882 if ((node == NULL) || (name == NULL))
5883 return(-1);
Daniel Veillard814a76d2003-01-23 18:24:20 +00005884 prop = node->properties;
Daniel Veillard75bea542001-05-11 17:41:21 +00005885 while (prop != NULL) {
5886 if ((xmlStrEqual(prop->name, name)) &&
5887 (prop->ns == NULL)) {
5888 if (prev == NULL)
5889 node->properties = prop->next;
5890 else
5891 prev->next = prop->next;
5892 xmlFreeProp(prop);
5893 return(0);
5894 }
5895 prev = prop;
5896 prop = prop->next;
5897 }
5898 return(-1);
5899}
5900
5901/**
Owen Taylor3473f882001-02-23 17:55:21 +00005902 * xmlSetNsProp:
5903 * @node: the node
5904 * @ns: the namespace definition
5905 * @name: the attribute name
5906 * @value: the attribute value
5907 *
5908 * Set (or reset) an attribute carried by a node.
5909 * The ns structure must be in scope, this is not checked.
5910 *
5911 * Returns the attribute pointer.
5912 */
5913xmlAttrPtr
5914xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
5915 const xmlChar *value) {
5916 xmlAttrPtr prop;
5917
5918 if ((node == NULL) || (name == NULL))
5919 return(NULL);
5920
5921 if (ns == NULL)
5922 return(xmlSetProp(node, name, value));
5923 if (ns->href == NULL)
5924 return(NULL);
5925 prop = node->properties;
5926
5927 while (prop != NULL) {
5928 /*
5929 * One need to have
5930 * - same attribute names
5931 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005932 */
5933 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00005934 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005935 if (prop->children != NULL)
5936 xmlFreeNodeList(prop->children);
5937 prop->children = NULL;
5938 prop->last = NULL;
5939 prop->ns = ns;
5940 if (value != NULL) {
5941 xmlChar *buffer;
5942 xmlNodePtr tmp;
5943
5944 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5945 prop->children = xmlStringGetNodeList(node->doc, buffer);
5946 prop->last = NULL;
5947 tmp = prop->children;
5948 while (tmp != NULL) {
5949 tmp->parent = (xmlNodePtr) prop;
5950 if (tmp->next == NULL)
5951 prop->last = tmp;
5952 tmp = tmp->next;
5953 }
5954 xmlFree(buffer);
5955 }
5956 return(prop);
5957 }
5958 prop = prop->next;
5959 }
5960 prop = xmlNewNsProp(node, ns, name, value);
5961 return(prop);
5962}
5963
5964/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005965 * xmlUnsetNsProp:
5966 * @node: the node
5967 * @ns: the namespace definition
5968 * @name: the attribute name
5969 *
5970 * Remove an attribute carried by a node.
5971 * Returns 0 if successful, -1 if not found
5972 */
5973int
5974xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
5975 xmlAttrPtr prop = node->properties, prev = NULL;;
5976
5977 if ((node == NULL) || (name == NULL))
5978 return(-1);
5979 if (ns == NULL)
5980 return(xmlUnsetProp(node, name));
5981 if (ns->href == NULL)
5982 return(-1);
5983 while (prop != NULL) {
5984 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00005985 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005986 if (prev == NULL)
5987 node->properties = prop->next;
5988 else
5989 prev->next = prop->next;
5990 xmlFreeProp(prop);
5991 return(0);
5992 }
5993 prev = prop;
5994 prop = prop->next;
5995 }
5996 return(-1);
5997}
5998
5999/**
Owen Taylor3473f882001-02-23 17:55:21 +00006000 * xmlNodeIsText:
6001 * @node: the node
6002 *
6003 * Is this node a Text node ?
6004 * Returns 1 yes, 0 no
6005 */
6006int
6007xmlNodeIsText(xmlNodePtr node) {
6008 if (node == NULL) return(0);
6009
6010 if (node->type == XML_TEXT_NODE) return(1);
6011 return(0);
6012}
6013
6014/**
6015 * xmlIsBlankNode:
6016 * @node: the node
6017 *
6018 * Checks whether this node is an empty or whitespace only
6019 * (and possibly ignorable) text-node.
6020 *
6021 * Returns 1 yes, 0 no
6022 */
6023int
6024xmlIsBlankNode(xmlNodePtr node) {
6025 const xmlChar *cur;
6026 if (node == NULL) return(0);
6027
Daniel Veillard7db37732001-07-12 01:20:08 +00006028 if ((node->type != XML_TEXT_NODE) &&
6029 (node->type != XML_CDATA_SECTION_NODE))
6030 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006031 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006032 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006033 while (*cur != 0) {
6034 if (!IS_BLANK(*cur)) return(0);
6035 cur++;
6036 }
6037
6038 return(1);
6039}
6040
6041/**
6042 * xmlTextConcat:
6043 * @node: the node
6044 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006045 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006046 *
6047 * Concat the given string at the end of the existing node content
6048 */
6049
6050void
6051xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
6052 if (node == NULL) return;
6053
6054 if ((node->type != XML_TEXT_NODE) &&
6055 (node->type != XML_CDATA_SECTION_NODE)) {
6056#ifdef DEBUG_TREE
6057 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006058 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006059#endif
6060 return;
6061 }
Owen Taylor3473f882001-02-23 17:55:21 +00006062 node->content = xmlStrncat(node->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00006063}
6064
6065/************************************************************************
6066 * *
6067 * Output : to a FILE or in memory *
6068 * *
6069 ************************************************************************/
6070
Owen Taylor3473f882001-02-23 17:55:21 +00006071/**
6072 * xmlBufferCreate:
6073 *
6074 * routine to create an XML buffer.
6075 * returns the new structure.
6076 */
6077xmlBufferPtr
6078xmlBufferCreate(void) {
6079 xmlBufferPtr ret;
6080
6081 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6082 if (ret == NULL) {
6083 xmlGenericError(xmlGenericErrorContext,
6084 "xmlBufferCreate : out of memory!\n");
6085 return(NULL);
6086 }
6087 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006088 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006089 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006090 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006091 if (ret->content == NULL) {
6092 xmlGenericError(xmlGenericErrorContext,
6093 "xmlBufferCreate : out of memory!\n");
6094 xmlFree(ret);
6095 return(NULL);
6096 }
6097 ret->content[0] = 0;
6098 return(ret);
6099}
6100
6101/**
6102 * xmlBufferCreateSize:
6103 * @size: initial size of buffer
6104 *
6105 * routine to create an XML buffer.
6106 * returns the new structure.
6107 */
6108xmlBufferPtr
6109xmlBufferCreateSize(size_t size) {
6110 xmlBufferPtr ret;
6111
6112 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6113 if (ret == NULL) {
6114 xmlGenericError(xmlGenericErrorContext,
6115 "xmlBufferCreate : out of memory!\n");
6116 return(NULL);
6117 }
6118 ret->use = 0;
6119 ret->alloc = xmlBufferAllocScheme;
6120 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6121 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006122 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006123 if (ret->content == NULL) {
6124 xmlGenericError(xmlGenericErrorContext,
6125 "xmlBufferCreate : out of memory!\n");
6126 xmlFree(ret);
6127 return(NULL);
6128 }
6129 ret->content[0] = 0;
6130 } else
6131 ret->content = NULL;
6132 return(ret);
6133}
6134
6135/**
6136 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006137 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006138 * @scheme: allocation scheme to use
6139 *
6140 * Sets the allocation scheme for this buffer
6141 */
6142void
6143xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6144 xmlBufferAllocationScheme scheme) {
6145 if (buf == NULL) {
6146#ifdef DEBUG_BUFFER
6147 xmlGenericError(xmlGenericErrorContext,
6148 "xmlBufferSetAllocationScheme: buf == NULL\n");
6149#endif
6150 return;
6151 }
6152
6153 buf->alloc = scheme;
6154}
6155
6156/**
6157 * xmlBufferFree:
6158 * @buf: the buffer to free
6159 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006160 * Frees an XML buffer. It frees both the content and the structure which
6161 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006162 */
6163void
6164xmlBufferFree(xmlBufferPtr buf) {
6165 if (buf == NULL) {
6166#ifdef DEBUG_BUFFER
6167 xmlGenericError(xmlGenericErrorContext,
6168 "xmlBufferFree: buf == NULL\n");
6169#endif
6170 return;
6171 }
Daniel Veillard561b7f82002-03-20 21:55:57 +00006172 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006173 xmlFree(buf->content);
6174 }
Owen Taylor3473f882001-02-23 17:55:21 +00006175 xmlFree(buf);
6176}
6177
6178/**
6179 * xmlBufferEmpty:
6180 * @buf: the buffer
6181 *
6182 * empty a buffer.
6183 */
6184void
6185xmlBufferEmpty(xmlBufferPtr buf) {
6186 if (buf->content == NULL) return;
6187 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006188 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00006189}
6190
6191/**
6192 * xmlBufferShrink:
6193 * @buf: the buffer to dump
6194 * @len: the number of xmlChar to remove
6195 *
6196 * Remove the beginning of an XML buffer.
6197 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006198 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006199 */
6200int
6201xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
6202 if (len == 0) return(0);
6203 if (len > buf->use) return(-1);
6204
6205 buf->use -= len;
6206 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6207
6208 buf->content[buf->use] = 0;
6209 return(len);
6210}
6211
6212/**
6213 * xmlBufferGrow:
6214 * @buf: the buffer
6215 * @len: the minimum free size to allocate
6216 *
6217 * Grow the available space of an XML buffer.
6218 *
6219 * Returns the new available space or -1 in case of error
6220 */
6221int
6222xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6223 int size;
6224 xmlChar *newbuf;
6225
6226 if (len + buf->use < buf->size) return(0);
6227
6228 size = buf->use + len + 100;
6229
6230 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
6231 if (newbuf == NULL) return(-1);
6232 buf->content = newbuf;
6233 buf->size = size;
6234 return(buf->size - buf->use);
6235}
6236
6237/**
6238 * xmlBufferDump:
6239 * @file: the file output
6240 * @buf: the buffer to dump
6241 *
6242 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006243 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006244 */
6245int
6246xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6247 int ret;
6248
6249 if (buf == NULL) {
6250#ifdef DEBUG_BUFFER
6251 xmlGenericError(xmlGenericErrorContext,
6252 "xmlBufferDump: buf == NULL\n");
6253#endif
6254 return(0);
6255 }
6256 if (buf->content == NULL) {
6257#ifdef DEBUG_BUFFER
6258 xmlGenericError(xmlGenericErrorContext,
6259 "xmlBufferDump: buf->content == NULL\n");
6260#endif
6261 return(0);
6262 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006263 if (file == NULL)
6264 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006265 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6266 return(ret);
6267}
6268
6269/**
6270 * xmlBufferContent:
6271 * @buf: the buffer
6272 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006273 * Function to extract the content of a buffer
6274 *
Owen Taylor3473f882001-02-23 17:55:21 +00006275 * Returns the internal content
6276 */
6277
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006278const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006279xmlBufferContent(const xmlBufferPtr buf)
6280{
6281 if(!buf)
6282 return NULL;
6283
6284 return buf->content;
6285}
6286
6287/**
6288 * xmlBufferLength:
6289 * @buf: the buffer
6290 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006291 * Function to get the length of a buffer
6292 *
Owen Taylor3473f882001-02-23 17:55:21 +00006293 * Returns the length of data in the internal content
6294 */
6295
6296int
6297xmlBufferLength(const xmlBufferPtr buf)
6298{
6299 if(!buf)
6300 return 0;
6301
6302 return buf->use;
6303}
6304
6305/**
6306 * xmlBufferResize:
6307 * @buf: the buffer to resize
6308 * @size: the desired size
6309 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006310 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006311 *
6312 * Returns 0 in case of problems, 1 otherwise
6313 */
6314int
6315xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6316{
6317 unsigned int newSize;
6318 xmlChar* rebuf = NULL;
6319
6320 /*take care of empty case*/
6321 newSize = (buf->size ? buf->size*2 : size);
6322
6323 /* Don't resize if we don't have to */
6324 if (size < buf->size)
6325 return 1;
6326
6327 /* figure out new size */
6328 switch (buf->alloc){
6329 case XML_BUFFER_ALLOC_DOUBLEIT:
6330 while (size > newSize) newSize *= 2;
6331 break;
6332 case XML_BUFFER_ALLOC_EXACT:
6333 newSize = size+10;
6334 break;
6335 default:
6336 newSize = size+10;
6337 break;
6338 }
6339
6340 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006341 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006342 else
6343 rebuf = (xmlChar *) xmlRealloc(buf->content,
6344 newSize * sizeof(xmlChar));
6345 if (rebuf == NULL) {
6346 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006347 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006348 return 0;
6349 }
6350 buf->content = rebuf;
6351 buf->size = newSize;
6352
6353 return 1;
6354}
6355
6356/**
6357 * xmlBufferAdd:
6358 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006359 * @str: the #xmlChar string
6360 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006361 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006362 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006363 * str is recomputed.
6364 */
6365void
6366xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6367 unsigned int needSize;
6368
6369 if (str == NULL) {
6370#ifdef DEBUG_BUFFER
6371 xmlGenericError(xmlGenericErrorContext,
6372 "xmlBufferAdd: str == NULL\n");
6373#endif
6374 return;
6375 }
6376 if (len < -1) {
6377#ifdef DEBUG_BUFFER
6378 xmlGenericError(xmlGenericErrorContext,
6379 "xmlBufferAdd: len < 0\n");
6380#endif
6381 return;
6382 }
6383 if (len == 0) return;
6384
6385 if (len < 0)
6386 len = xmlStrlen(str);
6387
6388 if (len <= 0) return;
6389
6390 needSize = buf->use + len + 2;
6391 if (needSize > buf->size){
6392 if (!xmlBufferResize(buf, needSize)){
6393 xmlGenericError(xmlGenericErrorContext,
6394 "xmlBufferAdd : out of memory!\n");
6395 return;
6396 }
6397 }
6398
6399 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6400 buf->use += len;
6401 buf->content[buf->use] = 0;
6402}
6403
6404/**
6405 * xmlBufferAddHead:
6406 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006407 * @str: the #xmlChar string
6408 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006409 *
6410 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006411 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00006412 */
6413void
6414xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6415 unsigned int needSize;
6416
6417 if (str == NULL) {
6418#ifdef DEBUG_BUFFER
6419 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006420 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006421#endif
6422 return;
6423 }
6424 if (len < -1) {
6425#ifdef DEBUG_BUFFER
6426 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006427 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006428#endif
6429 return;
6430 }
6431 if (len == 0) return;
6432
6433 if (len < 0)
6434 len = xmlStrlen(str);
6435
6436 if (len <= 0) return;
6437
6438 needSize = buf->use + len + 2;
6439 if (needSize > buf->size){
6440 if (!xmlBufferResize(buf, needSize)){
6441 xmlGenericError(xmlGenericErrorContext,
6442 "xmlBufferAddHead : out of memory!\n");
6443 return;
6444 }
6445 }
6446
6447 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6448 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6449 buf->use += len;
6450 buf->content[buf->use] = 0;
6451}
6452
6453/**
6454 * xmlBufferCat:
6455 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006456 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006457 *
6458 * Append a zero terminated string to an XML buffer.
6459 */
6460void
6461xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
6462 if (str != NULL)
6463 xmlBufferAdd(buf, str, -1);
6464}
6465
6466/**
6467 * xmlBufferCCat:
6468 * @buf: the buffer to dump
6469 * @str: the C char string
6470 *
6471 * Append a zero terminated C string to an XML buffer.
6472 */
6473void
6474xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6475 const char *cur;
6476
6477 if (str == NULL) {
6478#ifdef DEBUG_BUFFER
6479 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006480 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006481#endif
6482 return;
6483 }
6484 for (cur = str;*cur != 0;cur++) {
6485 if (buf->use + 10 >= buf->size) {
6486 if (!xmlBufferResize(buf, buf->use+10)){
6487 xmlGenericError(xmlGenericErrorContext,
6488 "xmlBufferCCat : out of memory!\n");
6489 return;
6490 }
6491 }
6492 buf->content[buf->use++] = *cur;
6493 }
6494 buf->content[buf->use] = 0;
6495}
6496
6497/**
6498 * xmlBufferWriteCHAR:
6499 * @buf: the XML buffer
6500 * @string: the string to add
6501 *
6502 * routine which manages and grows an output buffer. This one adds
6503 * xmlChars at the end of the buffer.
6504 */
6505void
Owen Taylor3473f882001-02-23 17:55:21 +00006506xmlBufferWriteCHAR
Owen Taylor3473f882001-02-23 17:55:21 +00006507(xmlBufferPtr buf, const xmlChar *string) {
6508 xmlBufferCat(buf, string);
6509}
6510
6511/**
6512 * xmlBufferWriteChar:
6513 * @buf: the XML buffer output
6514 * @string: the string to add
6515 *
6516 * routine which manage and grows an output buffer. This one add
6517 * C chars at the end of the array.
6518 */
6519void
6520xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
6521 xmlBufferCCat(buf, string);
6522}
6523
6524
6525/**
6526 * xmlBufferWriteQuotedString:
6527 * @buf: the XML buffer output
6528 * @string: the string to add
6529 *
6530 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00006531 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00006532 * quote or double-quotes internally
6533 */
6534void
6535xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
6536 if (xmlStrchr(string, '"')) {
6537 if (xmlStrchr(string, '\'')) {
6538#ifdef DEBUG_BUFFER
6539 xmlGenericError(xmlGenericErrorContext,
6540 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
6541#endif
6542 }
6543 xmlBufferCCat(buf, "'");
6544 xmlBufferCat(buf, string);
6545 xmlBufferCCat(buf, "'");
6546 } else {
6547 xmlBufferCCat(buf, "\"");
6548 xmlBufferCat(buf, string);
6549 xmlBufferCCat(buf, "\"");
6550 }
6551}
6552
6553
6554/************************************************************************
6555 * *
6556 * Dumping XML tree content to a simple buffer *
6557 * *
6558 ************************************************************************/
6559
Owen Taylor3473f882001-02-23 17:55:21 +00006560/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00006561 * xmlAttrSerializeContent:
6562 * @buf: the XML buffer output
6563 * @doc: the document
6564 * @attr: the attribute pointer
6565 *
6566 * Serialize the attribute in the buffer
6567 */
6568static void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006569xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr)
6570{
Daniel Veillarda6d05382002-02-13 13:07:41 +00006571 const xmlChar *cur, *base;
6572 xmlNodePtr children;
6573
6574 children = attr->children;
6575 while (children != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006576 switch (children->type) {
6577 case XML_TEXT_NODE:
6578 base = cur = children->content;
6579 while (*cur != 0) {
6580 if (*cur == '\n') {
6581 if (base != cur)
6582 xmlBufferAdd(buf, base, cur - base);
6583 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
6584 cur++;
6585 base = cur;
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006586 } else if (*cur == '\r') {
6587 if (base != cur)
6588 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006589 xmlBufferAdd(buf, BAD_CAST "&#13;", 5);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006590 cur++;
6591 base = cur;
6592 } else if (*cur == '\t') {
6593 if (base != cur)
6594 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006595 xmlBufferAdd(buf, BAD_CAST "&#9;", 4);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006596 cur++;
6597 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006598#if 0
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006599 } else if (*cur == '\'') {
6600 if (base != cur)
6601 xmlBufferAdd(buf, base, cur - base);
6602 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
6603 cur++;
6604 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006605#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006606 } else if (*cur == '"') {
6607 if (base != cur)
6608 xmlBufferAdd(buf, base, cur - base);
6609 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6610 cur++;
6611 base = cur;
6612 } else if (*cur == '<') {
6613 if (base != cur)
6614 xmlBufferAdd(buf, base, cur - base);
6615 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
6616 cur++;
6617 base = cur;
6618 } else if (*cur == '>') {
6619 if (base != cur)
6620 xmlBufferAdd(buf, base, cur - base);
6621 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
6622 cur++;
6623 base = cur;
6624 } else if (*cur == '&') {
6625 if (base != cur)
6626 xmlBufferAdd(buf, base, cur - base);
6627 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
6628 cur++;
6629 base = cur;
6630 } else if ((*cur >= 0x80) && ((doc == NULL) ||
6631 (doc->encoding ==
6632 NULL))) {
6633 /*
6634 * We assume we have UTF-8 content.
6635 */
6636 char tmp[10];
6637 int val = 0, l = 1;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006638
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006639 if (base != cur)
6640 xmlBufferAdd(buf, base, cur - base);
6641 if (*cur < 0xC0) {
6642 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6d05382002-02-13 13:07:41 +00006643 "xmlAttrSerializeContent : input not UTF-8\n");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006644 if (doc != NULL)
6645 doc->encoding =
6646 xmlStrdup(BAD_CAST "ISO-8859-1");
6647 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6648 tmp[sizeof(tmp) - 1] = 0;
6649 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6650 cur++;
6651 base = cur;
6652 continue;
6653 } else if (*cur < 0xE0) {
6654 val = (cur[0]) & 0x1F;
6655 val <<= 6;
6656 val |= (cur[1]) & 0x3F;
6657 l = 2;
6658 } else if (*cur < 0xF0) {
6659 val = (cur[0]) & 0x0F;
6660 val <<= 6;
6661 val |= (cur[1]) & 0x3F;
6662 val <<= 6;
6663 val |= (cur[2]) & 0x3F;
6664 l = 3;
6665 } else if (*cur < 0xF8) {
6666 val = (cur[0]) & 0x07;
6667 val <<= 6;
6668 val |= (cur[1]) & 0x3F;
6669 val <<= 6;
6670 val |= (cur[2]) & 0x3F;
6671 val <<= 6;
6672 val |= (cur[3]) & 0x3F;
6673 l = 4;
6674 }
6675 if ((l == 1) || (!IS_CHAR(val))) {
6676 xmlGenericError(xmlGenericErrorContext,
6677 "xmlAttrSerializeContent : char out of range\n");
6678 if (doc != NULL)
6679 doc->encoding =
6680 xmlStrdup(BAD_CAST "ISO-8859-1");
6681 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6682 tmp[sizeof(tmp) - 1] = 0;
6683 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6684 cur++;
6685 base = cur;
6686 continue;
6687 }
6688 /*
6689 * We could do multiple things here. Just save
6690 * as a char ref
6691 */
6692 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
6693 tmp[sizeof(tmp) - 1] = 0;
6694 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6695 cur += l;
6696 base = cur;
6697 } else {
6698 cur++;
6699 }
6700 }
6701 if (base != cur)
6702 xmlBufferAdd(buf, base, cur - base);
6703 break;
6704 case XML_ENTITY_REF_NODE:
6705 xmlBufferAdd(buf, BAD_CAST "&", 1);
6706 xmlBufferAdd(buf, children->name,
6707 xmlStrlen(children->name));
6708 xmlBufferAdd(buf, BAD_CAST ";", 1);
6709 break;
6710 default:
6711 /* should not happen unless we have a badly built tree */
6712 break;
6713 }
6714 children = children->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006715 }
6716}
6717
6718/**
6719 * xmlNodeDump:
6720 * @buf: the XML buffer output
6721 * @doc: the document
6722 * @cur: the current node
6723 * @level: the imbrication level for indenting
6724 * @format: is formatting allowed
6725 *
6726 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00006727 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006728 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006729 *
6730 * Returns the number of bytes written to the buffer or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00006731 */
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006732int
Owen Taylor3473f882001-02-23 17:55:21 +00006733xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006734 int format)
6735{
6736 unsigned int use;
6737 int ret;
6738 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006739
6740 if (cur == NULL) {
6741#ifdef DEBUG_TREE
6742 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006743 "xmlNodeDump : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006744#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006745 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006746 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006747 if (buf == NULL) {
6748#ifdef DEBUG_TREE
6749 xmlGenericError(xmlGenericErrorContext,
6750 "xmlNodeDump : buf == NULL\n");
6751#endif
6752 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006753 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006754 outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
6755 if (outbuf == NULL) {
6756 xmlGenericError(xmlGenericErrorContext,
6757 "xmlNodeDump: out of memory!\n");
6758 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006759 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006760 memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
6761 outbuf->buffer = buf;
6762 outbuf->encoder = NULL;
6763 outbuf->writecallback = NULL;
6764 outbuf->closecallback = NULL;
6765 outbuf->context = NULL;
6766 outbuf->written = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006767
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006768 use = buf->use;
6769 xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
6770 xmlFree(outbuf);
6771 ret = buf->use - use;
6772 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006773}
6774
6775/**
6776 * xmlElemDump:
6777 * @f: the FILE * for the output
6778 * @doc: the document
6779 * @cur: the current node
6780 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006781 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006782 */
6783void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006784xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur)
6785{
6786 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006787
6788 if (cur == NULL) {
6789#ifdef DEBUG_TREE
6790 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006791 "xmlElemDump : cur == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006792#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006793 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006794 }
Owen Taylor3473f882001-02-23 17:55:21 +00006795#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006796 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006797 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006798 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006799 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006800#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006801
6802 outbuf = xmlOutputBufferCreateFile(f, NULL);
6803 if (outbuf == NULL)
6804 return;
6805 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006806#ifdef LIBXML_HTML_ENABLED
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006807 htmlNodeDumpOutput(outbuf, doc, cur, NULL);
6808#else
6809 xmlGenericError(xmlGenericErrorContext,
6810 "HTML support not compiled in\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006811#endif /* LIBXML_HTML_ENABLED */
6812 } else
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006813 xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL);
6814 xmlOutputBufferClose(outbuf);
Owen Taylor3473f882001-02-23 17:55:21 +00006815}
6816
6817/************************************************************************
6818 * *
6819 * Dumping XML tree content to an I/O output buffer *
6820 * *
6821 ************************************************************************/
6822
Owen Taylor3473f882001-02-23 17:55:21 +00006823static void
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006824xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6825 int level, int format, const char *encoding);
6826static void
Owen Taylor3473f882001-02-23 17:55:21 +00006827xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6828 int level, int format, const char *encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006829static void
6830xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
6831 xmlNodePtr cur, int level, int format, const char *encoding);
6832
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00006833void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
6834
Owen Taylor3473f882001-02-23 17:55:21 +00006835/**
6836 * xmlNsDumpOutput:
6837 * @buf: the XML buffer output
6838 * @cur: a namespace
6839 *
6840 * Dump a local Namespace definition.
6841 * Should be called in the context of attributes dumps.
6842 */
6843static void
6844xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6845 if (cur == NULL) {
6846#ifdef DEBUG_TREE
6847 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006848 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006849#endif
6850 return;
6851 }
6852 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00006853 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
6854 return;
6855
Owen Taylor3473f882001-02-23 17:55:21 +00006856 /* Within the context of an element attributes */
6857 if (cur->prefix != NULL) {
6858 xmlOutputBufferWriteString(buf, " xmlns:");
6859 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6860 } else
6861 xmlOutputBufferWriteString(buf, " xmlns");
6862 xmlOutputBufferWriteString(buf, "=");
6863 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6864 }
6865}
6866
6867/**
6868 * xmlNsListDumpOutput:
6869 * @buf: the XML buffer output
6870 * @cur: the first namespace
6871 *
6872 * Dump a list of local Namespace definitions.
6873 * Should be called in the context of attributes dumps.
6874 */
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00006875void
Owen Taylor3473f882001-02-23 17:55:21 +00006876xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6877 while (cur != NULL) {
6878 xmlNsDumpOutput(buf, cur);
6879 cur = cur->next;
6880 }
6881}
6882
6883/**
6884 * xmlDtdDumpOutput:
6885 * @buf: the XML buffer output
6886 * @doc: the document
6887 * @encoding: an optional encoding string
6888 *
6889 * Dump the XML document DTD, if any.
6890 */
6891static void
6892xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6893 if (dtd == NULL) {
6894#ifdef DEBUG_TREE
6895 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006896 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006897#endif
6898 return;
6899 }
6900 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6901 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6902 if (dtd->ExternalID != NULL) {
6903 xmlOutputBufferWriteString(buf, " PUBLIC ");
6904 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6905 xmlOutputBufferWriteString(buf, " ");
6906 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6907 } else if (dtd->SystemID != NULL) {
6908 xmlOutputBufferWriteString(buf, " SYSTEM ");
6909 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6910 }
6911 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6912 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6913 xmlOutputBufferWriteString(buf, ">");
6914 return;
6915 }
6916 xmlOutputBufferWriteString(buf, " [\n");
6917 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6918 xmlOutputBufferWriteString(buf, "]>");
6919}
6920
6921/**
6922 * xmlAttrDumpOutput:
6923 * @buf: the XML buffer output
6924 * @doc: the document
6925 * @cur: the attribute pointer
6926 * @encoding: an optional encoding string
6927 *
6928 * Dump an XML attribute
6929 */
6930static void
6931xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006932 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006933 if (cur == NULL) {
6934#ifdef DEBUG_TREE
6935 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006936 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006937#endif
6938 return;
6939 }
6940 xmlOutputBufferWriteString(buf, " ");
6941 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6942 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6943 xmlOutputBufferWriteString(buf, ":");
6944 }
6945 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006946 xmlOutputBufferWriteString(buf, "=\"");
6947 xmlAttrSerializeContent(buf->buffer, doc, cur);
6948 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006949}
6950
6951/**
6952 * xmlAttrListDumpOutput:
6953 * @buf: the XML buffer output
6954 * @doc: the document
6955 * @cur: the first attribute pointer
6956 * @encoding: an optional encoding string
6957 *
6958 * Dump a list of XML attributes
6959 */
6960static void
6961xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6962 xmlAttrPtr cur, const char *encoding) {
6963 if (cur == NULL) {
6964#ifdef DEBUG_TREE
6965 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006966 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006967#endif
6968 return;
6969 }
6970 while (cur != NULL) {
6971 xmlAttrDumpOutput(buf, doc, cur, encoding);
6972 cur = cur->next;
6973 }
6974}
6975
6976
6977
6978/**
6979 * xmlNodeListDumpOutput:
6980 * @buf: the XML buffer output
6981 * @doc: the document
6982 * @cur: the first node
6983 * @level: the imbrication level for indenting
6984 * @format: is formatting allowed
6985 * @encoding: an optional encoding string
6986 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006987 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00006988 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006989 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006990 */
6991static void
6992xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6993 xmlNodePtr cur, int level, int format, const char *encoding) {
6994 int i;
6995
6996 if (cur == NULL) {
6997#ifdef DEBUG_TREE
6998 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006999 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007000#endif
7001 return;
7002 }
7003 while (cur != NULL) {
7004 if ((format) && (xmlIndentTreeOutput) &&
7005 (cur->type == XML_ELEMENT_NODE))
7006 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007007 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007008 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007009 if (format) {
7010 xmlOutputBufferWriteString(buf, "\n");
7011 }
7012 cur = cur->next;
7013 }
7014}
7015
7016/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007017 * xmlNodeDumpOutputInternal:
Owen Taylor3473f882001-02-23 17:55:21 +00007018 * @buf: the XML buffer output
7019 * @doc: the document
7020 * @cur: the current node
7021 * @level: the imbrication level for indenting
7022 * @format: is formatting allowed
7023 * @encoding: an optional encoding string
7024 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007025 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007026 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007027 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007028 */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007029static void
7030xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
7031 xmlNodePtr cur, int level, int format, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007032 int i;
7033 xmlNodePtr tmp;
7034
7035 if (cur == NULL) {
7036#ifdef DEBUG_TREE
7037 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007038 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007039#endif
7040 return;
7041 }
7042 if (cur->type == XML_XINCLUDE_START)
7043 return;
7044 if (cur->type == XML_XINCLUDE_END)
7045 return;
7046 if (cur->type == XML_DTD_NODE) {
7047 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7048 return;
7049 }
7050 if (cur->type == XML_ELEMENT_DECL) {
7051 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7052 return;
7053 }
7054 if (cur->type == XML_ATTRIBUTE_DECL) {
7055 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7056 return;
7057 }
7058 if (cur->type == XML_ENTITY_DECL) {
7059 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7060 return;
7061 }
7062 if (cur->type == XML_TEXT_NODE) {
7063 if (cur->content != NULL) {
7064 if ((cur->name == xmlStringText) ||
7065 (cur->name != xmlStringTextNoenc)) {
7066 xmlChar *buffer;
7067
Owen Taylor3473f882001-02-23 17:55:21 +00007068 if (encoding == NULL)
7069 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7070 else
7071 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007072 if (buffer != NULL) {
7073 xmlOutputBufferWriteString(buf, (const char *)buffer);
7074 xmlFree(buffer);
7075 }
7076 } else {
7077 /*
7078 * Disable escaping, needed for XSLT
7079 */
Owen Taylor3473f882001-02-23 17:55:21 +00007080 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007081 }
7082 }
7083
7084 return;
7085 }
7086 if (cur->type == XML_PI_NODE) {
7087 if (cur->content != NULL) {
7088 xmlOutputBufferWriteString(buf, "<?");
7089 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7090 if (cur->content != NULL) {
7091 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00007092 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007093 }
7094 xmlOutputBufferWriteString(buf, "?>");
7095 } else {
7096 xmlOutputBufferWriteString(buf, "<?");
7097 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7098 xmlOutputBufferWriteString(buf, "?>");
7099 }
7100 return;
7101 }
7102 if (cur->type == XML_COMMENT_NODE) {
7103 if (cur->content != NULL) {
7104 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00007105 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007106 xmlOutputBufferWriteString(buf, "-->");
7107 }
7108 return;
7109 }
7110 if (cur->type == XML_ENTITY_REF_NODE) {
7111 xmlOutputBufferWriteString(buf, "&");
7112 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7113 xmlOutputBufferWriteString(buf, ";");
7114 return;
7115 }
7116 if (cur->type == XML_CDATA_SECTION_NODE) {
7117 xmlOutputBufferWriteString(buf, "<![CDATA[");
7118 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007119 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007120 xmlOutputBufferWriteString(buf, "]]>");
7121 return;
7122 }
Daniel Veillard7b72ee52003-02-27 23:24:53 +00007123 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillarda1a9d042003-03-18 16:53:17 +00007124 xmlAttrDumpOutput(buf,doc, (xmlAttrPtr) cur,encoding);
Daniel Veillard7b72ee52003-02-27 23:24:53 +00007125 return;
7126 }
Daniel Veillard6aa2f602003-02-10 00:01:56 +00007127 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007128 xmlNsDumpOutput(buf, (xmlNsPtr) cur);
Daniel Veillard6aa2f602003-02-10 00:01:56 +00007129 return;
7130 }
Owen Taylor3473f882001-02-23 17:55:21 +00007131
7132 if (format == 1) {
7133 tmp = cur->children;
7134 while (tmp != NULL) {
7135 if ((tmp->type == XML_TEXT_NODE) ||
7136 (tmp->type == XML_ENTITY_REF_NODE)) {
7137 format = 0;
7138 break;
7139 }
7140 tmp = tmp->next;
7141 }
7142 }
7143 xmlOutputBufferWriteString(buf, "<");
7144 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7145 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7146 xmlOutputBufferWriteString(buf, ":");
7147 }
7148
7149 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7150 if (cur->nsDef)
7151 xmlNsListDumpOutput(buf, cur->nsDef);
7152 if (cur->properties != NULL)
7153 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7154
Daniel Veillard7db37732001-07-12 01:20:08 +00007155 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
7156 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007157 xmlOutputBufferWriteString(buf, "/>");
7158 return;
7159 }
7160 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00007161 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007162 xmlChar *buffer;
7163
Owen Taylor3473f882001-02-23 17:55:21 +00007164 if (encoding == NULL)
7165 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7166 else
7167 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007168 if (buffer != NULL) {
7169 xmlOutputBufferWriteString(buf, (const char *)buffer);
7170 xmlFree(buffer);
7171 }
7172 }
7173 if (cur->children != NULL) {
7174 if (format) xmlOutputBufferWriteString(buf, "\n");
7175 xmlNodeListDumpOutput(buf, doc, cur->children,
7176 (level >= 0?level+1:-1), format, encoding);
7177 if ((xmlIndentTreeOutput) && (format))
7178 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007179 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00007180 }
7181 xmlOutputBufferWriteString(buf, "</");
7182 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7183 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7184 xmlOutputBufferWriteString(buf, ":");
7185 }
7186
7187 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7188 xmlOutputBufferWriteString(buf, ">");
7189}
7190
7191/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007192 * xmlNodeDumpOutput:
7193 * @buf: the XML buffer output
7194 * @doc: the document
7195 * @cur: the current node
7196 * @level: the imbrication level for indenting
7197 * @format: is formatting allowed
7198 * @encoding: an optional encoding string
7199 *
7200 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007201 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007202 * or xmlKeepBlanksDefault(0) was called
7203 */
7204void
7205xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007206 int level, int format, const char *encoding)
7207{
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007208#ifdef LIBXML_HTML_ENABLED
7209 xmlDtdPtr dtd;
7210 int is_xhtml = 0;
7211
7212 dtd = xmlGetIntSubset(doc);
7213 if (dtd != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007214 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7215 if (is_xhtml < 0)
7216 is_xhtml = 0;
7217 if ((is_xhtml) && (cur->parent == (xmlNodePtr) doc) &&
7218 (cur->type == XML_ELEMENT_NODE) &&
7219 (xmlStrEqual(cur->name, BAD_CAST "html"))) {
7220 if (encoding != NULL)
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007221 htmlSetMetaEncoding((htmlDocPtr) doc,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007222 (const xmlChar *) encoding);
7223 else
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007224 htmlSetMetaEncoding((htmlDocPtr) doc, BAD_CAST "UTF-8");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007225 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007226 }
7227
7228 if (is_xhtml)
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007229 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007230 else
7231#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007232 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007233}
7234
7235/**
Owen Taylor3473f882001-02-23 17:55:21 +00007236 * xmlDocContentDumpOutput:
7237 * @buf: the XML buffer output
7238 * @cur: the document
7239 * @encoding: an optional encoding string
7240 * @format: should formatting spaces been added
7241 *
7242 * Dump an XML document.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007243 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007244 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007245 */
7246static void
7247xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
7248 const char *encoding, int format) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007249#ifdef LIBXML_HTML_ENABLED
7250 xmlDtdPtr dtd;
7251 int is_xhtml = 0;
7252#endif
7253
Owen Taylor3473f882001-02-23 17:55:21 +00007254 xmlOutputBufferWriteString(buf, "<?xml version=");
7255 if (cur->version != NULL)
7256 xmlBufferWriteQuotedString(buf->buffer, cur->version);
7257 else
7258 xmlOutputBufferWriteString(buf, "\"1.0\"");
7259 if (encoding == NULL) {
7260 if (cur->encoding != NULL)
7261 encoding = (const char *) cur->encoding;
7262 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
7263 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
7264 }
7265 if (encoding != NULL) {
7266 xmlOutputBufferWriteString(buf, " encoding=");
7267 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
7268 }
7269 switch (cur->standalone) {
7270 case 0:
7271 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
7272 break;
7273 case 1:
7274 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
7275 break;
7276 }
7277 xmlOutputBufferWriteString(buf, "?>\n");
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007278
7279#ifdef LIBXML_HTML_ENABLED
7280 dtd = xmlGetIntSubset(cur);
7281 if (dtd != NULL) {
7282 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7283 if (is_xhtml < 0) is_xhtml = 0;
7284 }
7285 if (is_xhtml) {
7286 if (encoding != NULL)
7287 htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
7288 else
7289 htmlSetMetaEncoding(cur, BAD_CAST "UTF-8");
7290 }
7291#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007292 if (cur->children != NULL) {
7293 xmlNodePtr child = cur->children;
7294
7295 while (child != NULL) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007296#ifdef LIBXML_HTML_ENABLED
7297 if (is_xhtml)
7298 xhtmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
7299 else
7300#endif
7301 xmlNodeDumpOutputInternal(buf, cur, child, 0, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007302 xmlOutputBufferWriteString(buf, "\n");
7303 child = child->next;
7304 }
7305 }
7306}
7307
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007308#ifdef LIBXML_HTML_ENABLED
7309/************************************************************************
7310 * *
7311 * Functions specific to XHTML serialization *
7312 * *
7313 ************************************************************************/
7314
7315#define XHTML_STRICT_PUBLIC_ID BAD_CAST \
7316 "-//W3C//DTD XHTML 1.0 Strict//EN"
7317#define XHTML_STRICT_SYSTEM_ID BAD_CAST \
7318 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
7319#define XHTML_FRAME_PUBLIC_ID BAD_CAST \
7320 "-//W3C//DTD XHTML 1.0 Frameset//EN"
7321#define XHTML_FRAME_SYSTEM_ID BAD_CAST \
7322 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
7323#define XHTML_TRANS_PUBLIC_ID BAD_CAST \
7324 "-//W3C//DTD XHTML 1.0 Transitional//EN"
7325#define XHTML_TRANS_SYSTEM_ID BAD_CAST \
7326 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
7327
7328#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
7329/**
7330 * xmlIsXHTML:
7331 * @systemID: the system identifier
7332 * @publicID: the public identifier
7333 *
7334 * Try to find if the document correspond to an XHTML DTD
7335 *
7336 * Returns 1 if true, 0 if not and -1 in case of error
7337 */
7338int
7339xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) {
7340 if ((systemID == NULL) && (publicID == NULL))
7341 return(-1);
7342 if (publicID != NULL) {
7343 if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1);
7344 if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1);
7345 if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1);
7346 }
7347 if (systemID != NULL) {
7348 if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1);
7349 if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1);
7350 if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1);
7351 }
7352 return(0);
7353}
7354
7355/**
7356 * xhtmlIsEmpty:
7357 * @node: the node
7358 *
7359 * Check if a node is an empty xhtml node
7360 *
7361 * Returns 1 if the node is an empty node, 0 if not and -1 in case of error
7362 */
7363static int
7364xhtmlIsEmpty(xmlNodePtr node) {
7365 if (node == NULL)
7366 return(-1);
7367 if (node->type != XML_ELEMENT_NODE)
7368 return(0);
7369 if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME)))
7370 return(0);
7371 if (node->children != NULL)
7372 return(0);
7373 switch (node->name[0]) {
7374 case 'a':
7375 if (xmlStrEqual(node->name, BAD_CAST "area"))
7376 return(1);
7377 return(0);
7378 case 'b':
7379 if (xmlStrEqual(node->name, BAD_CAST "br"))
7380 return(1);
7381 if (xmlStrEqual(node->name, BAD_CAST "base"))
7382 return(1);
7383 if (xmlStrEqual(node->name, BAD_CAST "basefont"))
7384 return(1);
7385 return(0);
7386 case 'c':
7387 if (xmlStrEqual(node->name, BAD_CAST "col"))
7388 return(1);
7389 return(0);
7390 case 'f':
7391 if (xmlStrEqual(node->name, BAD_CAST "frame"))
7392 return(1);
7393 return(0);
7394 case 'h':
7395 if (xmlStrEqual(node->name, BAD_CAST "hr"))
7396 return(1);
7397 return(0);
7398 case 'i':
7399 if (xmlStrEqual(node->name, BAD_CAST "img"))
7400 return(1);
7401 if (xmlStrEqual(node->name, BAD_CAST "input"))
7402 return(1);
7403 if (xmlStrEqual(node->name, BAD_CAST "isindex"))
7404 return(1);
7405 return(0);
7406 case 'l':
7407 if (xmlStrEqual(node->name, BAD_CAST "link"))
7408 return(1);
7409 return(0);
7410 case 'm':
7411 if (xmlStrEqual(node->name, BAD_CAST "meta"))
7412 return(1);
7413 return(0);
7414 case 'p':
7415 if (xmlStrEqual(node->name, BAD_CAST "param"))
7416 return(1);
7417 return(0);
7418 }
7419 return(0);
7420}
7421
7422/**
7423 * xhtmlAttrListDumpOutput:
7424 * @buf: the XML buffer output
7425 * @doc: the document
7426 * @cur: the first attribute pointer
7427 * @encoding: an optional encoding string
7428 *
7429 * Dump a list of XML attributes
7430 */
7431static void
7432xhtmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7433 xmlAttrPtr cur, const char *encoding) {
7434 xmlAttrPtr xml_lang = NULL;
7435 xmlAttrPtr lang = NULL;
7436 xmlAttrPtr name = NULL;
7437 xmlAttrPtr id = NULL;
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007438 xmlNodePtr parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007439
7440 if (cur == NULL) {
7441#ifdef DEBUG_TREE
7442 xmlGenericError(xmlGenericErrorContext,
7443 "xmlAttrListDumpOutput : property == NULL\n");
7444#endif
7445 return;
7446 }
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007447 parent = cur->parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007448 while (cur != NULL) {
7449 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id")))
7450 id = cur;
7451 else
7452 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name")))
7453 name = cur;
7454 else
7455 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")))
7456 lang = cur;
7457 else
7458 if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) &&
7459 (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml")))
7460 xml_lang = cur;
7461 else if ((cur->ns == NULL) &&
7462 ((cur->children == NULL) ||
7463 (cur->children->content == NULL) ||
7464 (cur->children->content[0] == 0)) &&
7465 (htmlIsBooleanAttr(cur->name))) {
7466 if (cur->children != NULL)
7467 xmlFreeNode(cur->children);
7468 cur->children = xmlNewText(cur->name);
7469 if (cur->children != NULL)
7470 cur->children->parent = (xmlNodePtr) cur;
7471 }
7472 xmlAttrDumpOutput(buf, doc, cur, encoding);
7473 cur = cur->next;
7474 }
7475 /*
7476 * C.8
7477 */
7478 if ((name != NULL) && (id == NULL)) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007479 if ((parent != NULL) && (parent->name != NULL) &&
7480 ((xmlStrEqual(parent->name, BAD_CAST "a")) ||
7481 (xmlStrEqual(parent->name, BAD_CAST "p")) ||
7482 (xmlStrEqual(parent->name, BAD_CAST "div")) ||
7483 (xmlStrEqual(parent->name, BAD_CAST "img")) ||
7484 (xmlStrEqual(parent->name, BAD_CAST "map")) ||
7485 (xmlStrEqual(parent->name, BAD_CAST "applet")) ||
7486 (xmlStrEqual(parent->name, BAD_CAST "form")) ||
7487 (xmlStrEqual(parent->name, BAD_CAST "frame")) ||
7488 (xmlStrEqual(parent->name, BAD_CAST "iframe")))) {
7489 xmlOutputBufferWriteString(buf, " id=\"");
7490 xmlAttrSerializeContent(buf->buffer, doc, name);
7491 xmlOutputBufferWriteString(buf, "\"");
7492 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007493 }
7494 /*
7495 * C.7.
7496 */
7497 if ((lang != NULL) && (xml_lang == NULL)) {
7498 xmlOutputBufferWriteString(buf, " xml:lang=\"");
7499 xmlAttrSerializeContent(buf->buffer, doc, lang);
7500 xmlOutputBufferWriteString(buf, "\"");
7501 } else
7502 if ((xml_lang != NULL) && (lang == NULL)) {
7503 xmlOutputBufferWriteString(buf, " lang=\"");
7504 xmlAttrSerializeContent(buf->buffer, doc, xml_lang);
7505 xmlOutputBufferWriteString(buf, "\"");
7506 }
7507}
7508
7509/**
7510 * xhtmlNodeListDumpOutput:
7511 * @buf: the XML buffer output
7512 * @doc: the XHTML document
7513 * @cur: the first node
7514 * @level: the imbrication level for indenting
7515 * @format: is formatting allowed
7516 * @encoding: an optional encoding string
7517 *
7518 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007519 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007520 * or xmlKeepBlanksDefault(0) was called
7521 */
7522static void
7523xhtmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7524 xmlNodePtr cur, int level, int format, const char *encoding) {
7525 int i;
7526
7527 if (cur == NULL) {
7528#ifdef DEBUG_TREE
7529 xmlGenericError(xmlGenericErrorContext,
7530 "xhtmlNodeListDumpOutput : node == NULL\n");
7531#endif
7532 return;
7533 }
7534 while (cur != NULL) {
7535 if ((format) && (xmlIndentTreeOutput) &&
7536 (cur->type == XML_ELEMENT_NODE))
7537 for (i = 0;i < level;i++)
7538 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7539 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
7540 if (format) {
7541 xmlOutputBufferWriteString(buf, "\n");
7542 }
7543 cur = cur->next;
7544 }
7545}
7546
7547/**
7548 * xhtmlNodeDumpOutput:
7549 * @buf: the XML buffer output
7550 * @doc: the XHTML document
7551 * @cur: the current node
7552 * @level: the imbrication level for indenting
7553 * @format: is formatting allowed
7554 * @encoding: an optional encoding string
7555 *
7556 * Dump an XHTML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007557 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007558 * or xmlKeepBlanksDefault(0) was called
7559 */
7560static void
7561xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7562 int level, int format, const char *encoding) {
7563 int i;
7564 xmlNodePtr tmp;
7565
7566 if (cur == NULL) {
7567#ifdef DEBUG_TREE
7568 xmlGenericError(xmlGenericErrorContext,
7569 "xmlNodeDumpOutput : node == NULL\n");
7570#endif
7571 return;
7572 }
7573 if (cur->type == XML_XINCLUDE_START)
7574 return;
7575 if (cur->type == XML_XINCLUDE_END)
7576 return;
7577 if (cur->type == XML_DTD_NODE) {
7578 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7579 return;
7580 }
7581 if (cur->type == XML_ELEMENT_DECL) {
7582 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7583 return;
7584 }
7585 if (cur->type == XML_ATTRIBUTE_DECL) {
7586 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7587 return;
7588 }
7589 if (cur->type == XML_ENTITY_DECL) {
7590 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7591 return;
7592 }
7593 if (cur->type == XML_TEXT_NODE) {
7594 if (cur->content != NULL) {
7595 if ((cur->name == xmlStringText) ||
7596 (cur->name != xmlStringTextNoenc)) {
7597 xmlChar *buffer;
7598
7599 if (encoding == NULL)
7600 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7601 else
7602 buffer = xmlEncodeSpecialChars(doc, cur->content);
7603 if (buffer != NULL) {
7604 xmlOutputBufferWriteString(buf, (const char *)buffer);
7605 xmlFree(buffer);
7606 }
7607 } else {
7608 /*
7609 * Disable escaping, needed for XSLT
7610 */
7611 xmlOutputBufferWriteString(buf, (const char *) cur->content);
7612 }
7613 }
7614
7615 return;
7616 }
7617 if (cur->type == XML_PI_NODE) {
7618 if (cur->content != NULL) {
7619 xmlOutputBufferWriteString(buf, "<?");
7620 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7621 if (cur->content != NULL) {
7622 xmlOutputBufferWriteString(buf, " ");
7623 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7624 }
7625 xmlOutputBufferWriteString(buf, "?>");
7626 } else {
7627 xmlOutputBufferWriteString(buf, "<?");
7628 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7629 xmlOutputBufferWriteString(buf, "?>");
7630 }
7631 return;
7632 }
7633 if (cur->type == XML_COMMENT_NODE) {
7634 if (cur->content != NULL) {
7635 xmlOutputBufferWriteString(buf, "<!--");
7636 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7637 xmlOutputBufferWriteString(buf, "-->");
7638 }
7639 return;
7640 }
7641 if (cur->type == XML_ENTITY_REF_NODE) {
7642 xmlOutputBufferWriteString(buf, "&");
7643 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7644 xmlOutputBufferWriteString(buf, ";");
7645 return;
7646 }
7647 if (cur->type == XML_CDATA_SECTION_NODE) {
7648 xmlOutputBufferWriteString(buf, "<![CDATA[");
7649 if (cur->content != NULL)
7650 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7651 xmlOutputBufferWriteString(buf, "]]>");
7652 return;
7653 }
7654
7655 if (format == 1) {
7656 tmp = cur->children;
7657 while (tmp != NULL) {
7658 if ((tmp->type == XML_TEXT_NODE) ||
7659 (tmp->type == XML_ENTITY_REF_NODE)) {
7660 format = 0;
7661 break;
7662 }
7663 tmp = tmp->next;
7664 }
7665 }
7666 xmlOutputBufferWriteString(buf, "<");
7667 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7668 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7669 xmlOutputBufferWriteString(buf, ":");
7670 }
7671
7672 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7673 if (cur->nsDef)
7674 xmlNsListDumpOutput(buf, cur->nsDef);
7675 if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
7676 (cur->ns == NULL) && (cur->nsDef == NULL))) {
7677 /*
7678 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
7679 */
7680 xmlOutputBufferWriteString(buf,
7681 " xmlns=\"http://www.w3.org/1999/xhtml\"");
7682 }
7683 if (cur->properties != NULL)
7684 xhtmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7685
7686 if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) {
7687 if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
7688 (xhtmlIsEmpty(cur) == 1)) {
7689 /*
7690 * C.2. Empty Elements
7691 */
7692 xmlOutputBufferWriteString(buf, " />");
7693 } else {
7694 /*
7695 * C.3. Element Minimization and Empty Element Content
7696 */
7697 xmlOutputBufferWriteString(buf, "></");
7698 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7699 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7700 xmlOutputBufferWriteString(buf, ":");
7701 }
7702 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7703 xmlOutputBufferWriteString(buf, ">");
7704 }
7705 return;
7706 }
7707 xmlOutputBufferWriteString(buf, ">");
7708 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
7709 xmlChar *buffer;
7710
7711 if (encoding == NULL)
7712 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7713 else
7714 buffer = xmlEncodeSpecialChars(doc, cur->content);
7715 if (buffer != NULL) {
7716 xmlOutputBufferWriteString(buf, (const char *)buffer);
7717 xmlFree(buffer);
7718 }
7719 }
7720
7721 /*
7722 * 4.8. Script and Style elements
7723 */
7724 if ((cur->type == XML_ELEMENT_NODE) &&
7725 ((xmlStrEqual(cur->name, BAD_CAST "script")) ||
7726 (xmlStrEqual(cur->name, BAD_CAST "style"))) &&
7727 ((cur->ns == NULL) ||
7728 (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) {
7729 xmlNodePtr child = cur->children;
7730
7731 while (child != NULL) {
7732 if ((child->type == XML_TEXT_NODE) ||
7733 (child->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard64b35282002-12-04 15:10:40 +00007734 /*
7735 * Apparently CDATA escaping for style just break on IE,
7736 * mozilla and galeon, so ...
7737 */
7738 if (xmlStrEqual(cur->name, BAD_CAST "style") &&
7739 (xmlStrchr(child->content, '<') == NULL) &&
7740 (xmlStrchr(child->content, '>') == NULL) &&
7741 (xmlStrchr(child->content, '&') == NULL)) {
7742 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7743 } else {
7744 xmlOutputBufferWriteString(buf, "<![CDATA[");
7745 if (child->content != NULL)
7746 xmlOutputBufferWriteString(buf,
7747 (const char *)child->content);
7748 xmlOutputBufferWriteString(buf, "]]>");
7749 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007750 } else {
7751 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7752 }
7753 child = child->next;
7754 }
7755 } else if (cur->children != NULL) {
7756 if (format) xmlOutputBufferWriteString(buf, "\n");
7757 xhtmlNodeListDumpOutput(buf, doc, cur->children,
7758 (level >= 0?level+1:-1), format, encoding);
7759 if ((xmlIndentTreeOutput) && (format))
7760 for (i = 0;i < level;i++)
7761 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7762 }
7763 xmlOutputBufferWriteString(buf, "</");
7764 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7765 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7766 xmlOutputBufferWriteString(buf, ":");
7767 }
7768
7769 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7770 xmlOutputBufferWriteString(buf, ">");
7771}
7772#endif
7773
Owen Taylor3473f882001-02-23 17:55:21 +00007774/************************************************************************
7775 * *
7776 * Saving functions front-ends *
7777 * *
7778 ************************************************************************/
7779
7780/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00007781 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00007782 * @out_doc: Document to generate XML text from
7783 * @doc_txt_ptr: Memory pointer for allocated XML text
7784 * @doc_txt_len: Length of the generated XML text
7785 * @txt_encoding: Character encoding to use when generating XML text
7786 * @format: should formatting spaces been added
7787 *
7788 * Dump the current DOM tree into memory using the character encoding specified
7789 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007790 * allocated memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00007791 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007792 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007793 */
7794
7795void
7796xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007797 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007798 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007799 int dummy = 0;
7800
7801 xmlCharEncoding doc_charset;
7802 xmlOutputBufferPtr out_buff = NULL;
7803 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
7804
7805 if (doc_txt_len == NULL) {
7806 doc_txt_len = &dummy; /* Continue, caller just won't get length */
7807 }
7808
7809 if (doc_txt_ptr == NULL) {
7810 *doc_txt_len = 0;
7811 xmlGenericError(xmlGenericErrorContext,
7812 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
7813 return;
7814 }
7815
7816 *doc_txt_ptr = NULL;
7817 *doc_txt_len = 0;
7818
7819 if (out_doc == NULL) {
7820 /* No document, no output */
7821 xmlGenericError(xmlGenericErrorContext,
7822 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
7823 return;
7824 }
7825
7826 /*
7827 * Validate the encoding value, if provided.
7828 * This logic is copied from xmlSaveFileEnc.
7829 */
7830
7831 if (txt_encoding == NULL)
7832 txt_encoding = (const char *) out_doc->encoding;
7833 if (txt_encoding != NULL) {
7834 doc_charset = xmlParseCharEncoding(txt_encoding);
7835
7836 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
7837 xmlGenericError(xmlGenericErrorContext,
7838 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
7839 return;
7840
7841 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
7842 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
7843 if ( conv_hdlr == NULL ) {
7844 xmlGenericError(xmlGenericErrorContext,
7845 "%s: %s %s '%s'\n",
7846 "xmlDocDumpFormatMemoryEnc",
7847 "Failed to identify encoding handler for",
7848 "character set",
7849 txt_encoding);
7850 return;
7851 }
7852 }
7853 }
7854
7855 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
7856 xmlGenericError(xmlGenericErrorContext,
7857 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
7858 return;
7859 }
7860
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007861 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007862 xmlOutputBufferFlush(out_buff);
7863 if (out_buff->conv != NULL) {
7864 *doc_txt_len = out_buff->conv->use;
7865 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
7866 } else {
7867 *doc_txt_len = out_buff->buffer->use;
7868 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
7869 }
7870 (void)xmlOutputBufferClose(out_buff);
7871
7872 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
7873 *doc_txt_len = 0;
7874 xmlGenericError(xmlGenericErrorContext,
7875 "xmlDocDumpFormatMemoryEnc: %s\n",
7876 "Failed to allocate memory for document text representation.");
7877 }
7878
7879 return;
7880}
7881
7882/**
7883 * xmlDocDumpMemory:
7884 * @cur: the document
7885 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007886 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007887 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007888 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007889 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007890 */
7891void
7892xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
7893 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
7894}
7895
7896/**
7897 * xmlDocDumpFormatMemory:
7898 * @cur: the document
7899 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007900 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007901 * @format: should formatting spaces been added
7902 *
7903 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007904 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007905 * It's up to the caller to free the memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00007906 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007907 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007908 */
7909void
7910xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
7911 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
7912}
7913
7914/**
7915 * xmlDocDumpMemoryEnc:
7916 * @out_doc: Document to generate XML text from
7917 * @doc_txt_ptr: Memory pointer for allocated XML text
7918 * @doc_txt_len: Length of the generated XML text
7919 * @txt_encoding: Character encoding to use when generating XML text
7920 *
7921 * Dump the current DOM tree into memory using the character encoding specified
7922 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007923 * allocated memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007924 */
7925
7926void
7927xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
7928 int * doc_txt_len, const char * txt_encoding) {
7929 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007930 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007931}
7932
7933/**
7934 * xmlGetDocCompressMode:
7935 * @doc: the document
7936 *
7937 * get the compression ratio for a document, ZLIB based
7938 * Returns 0 (uncompressed) to 9 (max compression)
7939 */
7940int
7941xmlGetDocCompressMode (xmlDocPtr doc) {
7942 if (doc == NULL) return(-1);
7943 return(doc->compression);
7944}
7945
7946/**
7947 * xmlSetDocCompressMode:
7948 * @doc: the document
7949 * @mode: the compression ratio
7950 *
7951 * set the compression ratio for a document, ZLIB based
7952 * Correct values: 0 (uncompressed) to 9 (max compression)
7953 */
7954void
7955xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7956 if (doc == NULL) return;
7957 if (mode < 0) doc->compression = 0;
7958 else if (mode > 9) doc->compression = 9;
7959 else doc->compression = mode;
7960}
7961
7962/**
7963 * xmlGetCompressMode:
7964 *
7965 * get the default compression mode used, ZLIB based.
7966 * Returns 0 (uncompressed) to 9 (max compression)
7967 */
7968int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007969xmlGetCompressMode(void)
7970{
7971 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00007972}
7973
7974/**
7975 * xmlSetCompressMode:
7976 * @mode: the compression ratio
7977 *
7978 * set the default compression mode used, ZLIB based
7979 * Correct values: 0 (uncompressed) to 9 (max compression)
7980 */
7981void
7982xmlSetCompressMode(int mode) {
7983 if (mode < 0) xmlCompressMode = 0;
7984 else if (mode > 9) xmlCompressMode = 9;
7985 else xmlCompressMode = mode;
7986}
7987
7988/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007989 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00007990 * @f: the FILE*
7991 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00007992 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007993 *
7994 * Dump an XML document to an open FILE.
7995 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007996 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007997 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7998 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007999 */
8000int
Daniel Veillard9e412302002-06-10 15:59:44 +00008001xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00008002 xmlOutputBufferPtr buf;
8003 const char * encoding;
8004 xmlCharEncodingHandlerPtr handler = NULL;
8005 int ret;
8006
8007 if (cur == NULL) {
8008#ifdef DEBUG_TREE
8009 xmlGenericError(xmlGenericErrorContext,
8010 "xmlDocDump : document == NULL\n");
8011#endif
8012 return(-1);
8013 }
8014 encoding = (const char *) cur->encoding;
8015
8016 if (encoding != NULL) {
8017 xmlCharEncoding enc;
8018
8019 enc = xmlParseCharEncoding(encoding);
8020
8021 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
8022 xmlGenericError(xmlGenericErrorContext,
8023 "xmlDocDump: document not in UTF8\n");
8024 return(-1);
8025 }
8026 if (enc != XML_CHAR_ENCODING_UTF8) {
8027 handler = xmlFindCharEncodingHandler(encoding);
8028 if (handler == NULL) {
8029 xmlFree((char *) cur->encoding);
8030 cur->encoding = NULL;
8031 }
8032 }
8033 }
8034 buf = xmlOutputBufferCreateFile(f, handler);
8035 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00008036 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008037
8038 ret = xmlOutputBufferClose(buf);
8039 return(ret);
8040}
8041
8042/**
Daniel Veillard9e412302002-06-10 15:59:44 +00008043 * xmlDocDump:
8044 * @f: the FILE*
8045 * @cur: the document
8046 *
8047 * Dump an XML document to an open FILE.
8048 *
8049 * returns: the number of bytes written or -1 in case of failure.
8050 */
8051int
8052xmlDocDump(FILE *f, xmlDocPtr cur) {
8053 return(xmlDocFormatDump (f, cur, 0));
8054}
8055
8056/**
Owen Taylor3473f882001-02-23 17:55:21 +00008057 * xmlSaveFileTo:
8058 * @buf: an output I/O buffer
8059 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00008060 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00008061 *
8062 * Dump an XML document to an I/O buffer.
8063 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008064 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008065 */
8066int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00008067xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00008068 int ret;
8069
8070 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008071 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008072 ret = xmlOutputBufferClose(buf);
8073 return(ret);
8074}
8075
8076/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00008077 * xmlSaveFormatFileTo:
8078 * @buf: an output I/O buffer
8079 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00008080 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00008081 * @format: should formatting spaces been added
8082 *
8083 * Dump an XML document to an I/O buffer.
8084 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008085 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008086 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8087 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardeefd4492001-04-28 16:55:50 +00008088 */
8089int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00008090xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00008091 int ret;
8092
8093 if (buf == NULL) return(0);
8094 xmlDocContentDumpOutput(buf, cur, encoding, format);
8095 ret = xmlOutputBufferClose(buf);
8096 return(ret);
8097}
8098
8099/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00008100 * xmlSaveFormatFileEnc:
Daniel Veillardf012a642001-07-23 19:10:52 +00008101 * @filename: the filename or URL to output
8102 * @cur: the document being saved
8103 * @encoding: the name of the encoding to use or NULL.
8104 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00008105 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00008106 * Dump an XML document to a file or an URL.
8107 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008108 * Returns the number of bytes written or -1 in case of error.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008109 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8110 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008111 */
8112int
Daniel Veillardf012a642001-07-23 19:10:52 +00008113xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
8114 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00008115 xmlOutputBufferPtr buf;
8116 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00008117 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00008118 int ret;
8119
Daniel Veillard4dbe77a2003-01-14 00:17:42 +00008120 if (cur == NULL)
8121 return(-1);
8122
Daniel Veillardfb25a512002-01-13 20:32:08 +00008123 if (encoding == NULL)
8124 encoding = (const char *) cur->encoding;
8125
Owen Taylor3473f882001-02-23 17:55:21 +00008126 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00008127
8128 enc = xmlParseCharEncoding(encoding);
8129 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
8130 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00008131 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00008132 return(-1);
8133 }
8134 if (enc != XML_CHAR_ENCODING_UTF8) {
8135 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00008136 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00008137 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00008138 }
8139 }
8140
Daniel Veillardf012a642001-07-23 19:10:52 +00008141#ifdef HAVE_ZLIB_H
8142 if (cur->compression < 0) cur->compression = xmlCompressMode;
8143#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008144 /*
8145 * save the content to a temp buffer.
8146 */
Daniel Veillardf012a642001-07-23 19:10:52 +00008147 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00008148 if (buf == NULL) return(-1);
8149
Daniel Veillardf012a642001-07-23 19:10:52 +00008150 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008151
8152 ret = xmlOutputBufferClose(buf);
8153 return(ret);
8154}
8155
Daniel Veillardf012a642001-07-23 19:10:52 +00008156
8157/**
8158 * xmlSaveFileEnc:
8159 * @filename: the filename (or URL)
8160 * @cur: the document
8161 * @encoding: the name of an encoding (or NULL)
8162 *
8163 * Dump an XML document, converting it to the given encoding
8164 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008165 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00008166 */
8167int
8168xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
8169 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
8170}
8171
Owen Taylor3473f882001-02-23 17:55:21 +00008172/**
Daniel Veillard67fee942001-04-26 18:59:03 +00008173 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00008174 * @filename: the filename (or URL)
8175 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00008176 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00008177 *
8178 * Dump an XML document to a file. Will use compression if
8179 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00008180 * used. If @format is set then the document will be indented on output.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008181 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8182 * or xmlKeepBlanksDefault(0) was called
Daniel Veillard67fee942001-04-26 18:59:03 +00008183 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008184 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008185 */
8186int
Daniel Veillard67fee942001-04-26 18:59:03 +00008187xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008188 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00008189}
8190
Daniel Veillard67fee942001-04-26 18:59:03 +00008191/**
8192 * xmlSaveFile:
8193 * @filename: the filename (or URL)
8194 * @cur: the document
8195 *
8196 * Dump an XML document to a file. Will use compression if
8197 * compiled in and enabled. If @filename is "-" the stdout file is
8198 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00008199 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00008200 */
8201int
8202xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008203 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00008204}
8205