blob: c38d0b5829c7624156b7de1608641e346fdf803e [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002 * tree.c : implementation of access function for an XML tree.
Owen Taylor3473f882001-02-23 17:55:21 +00003 *
Daniel Veillardd5c2f922002-11-21 14:10:52 +00004 * References:
5 * XHTML 1.0 W3C REC: http://www.w3.org/TR/2002/REC-xhtml1-20020801/
6 *
Owen Taylor3473f882001-02-23 17:55:21 +00007 * See Copyright for the status of this software.
8 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00009 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000010 *
Owen Taylor3473f882001-02-23 17:55:21 +000011 */
12
Daniel Veillard34ce8be2002-03-18 19:37:11 +000013#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000014#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000015
Owen Taylor3473f882001-02-23 17:55:21 +000016#include <string.h> /* for memset() only ! */
17
18#ifdef HAVE_CTYPE_H
19#include <ctype.h>
20#endif
21#ifdef HAVE_STDLIB_H
22#include <stdlib.h>
23#endif
24#ifdef HAVE_ZLIB_H
25#include <zlib.h>
26#endif
27
28#include <libxml/xmlmemory.h>
29#include <libxml/tree.h>
30#include <libxml/parser.h>
Daniel Veillardb8c9be92001-07-09 16:01:19 +000031#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000032#include <libxml/entities.h>
33#include <libxml/valid.h>
34#include <libxml/xmlerror.h>
Daniel Veillardbdb9ba72001-04-11 11:28:06 +000035#include <libxml/parserInternals.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000036#include <libxml/globals.h>
Daniel Veillardd5c2f922002-11-21 14:10:52 +000037#ifdef LIBXML_HTML_ENABLED
38#include <libxml/HTMLtree.h>
39#endif
Owen Taylor3473f882001-02-23 17:55:21 +000040
Daniel Veillarda880b122003-04-21 21:36:41 +000041int __xmlRegisterCallbacks = 0;
42
Daniel Veillard56a4cb82001-03-24 17:00:36 +000043xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
44
45/************************************************************************
46 * *
47 * A few static variables and macros *
48 * *
49 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +000050/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +000051const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000052/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +000053const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +000054 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000055/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +000056const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
57
Owen Taylor3473f882001-02-23 17:55:21 +000058static int xmlCompressMode = 0;
59static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000060
Owen Taylor3473f882001-02-23 17:55:21 +000061#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
62 xmlNodePtr ulccur = (n)->children; \
63 if (ulccur == NULL) { \
64 (n)->last = NULL; \
65 } else { \
66 while (ulccur->next != NULL) { \
67 ulccur->parent = (n); \
68 ulccur = ulccur->next; \
69 } \
70 ulccur->parent = (n); \
71 (n)->last = ulccur; \
72}}
73
74/* #define DEBUG_BUFFER */
75/* #define DEBUG_TREE */
76
77/************************************************************************
78 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +000079 * Functions to move to entities.c once the *
80 * API freeze is smoothen and they can be made public. *
81 * *
82 ************************************************************************/
83#include <libxml/hash.h>
84
85/**
86 * xmlGetEntityFromDtd:
87 * @dtd: A pointer to the DTD to search
88 * @name: The entity name
89 *
90 * Do an entity lookup in the DTD entity hash table and
91 * return the corresponding entity, if found.
92 *
93 * Returns A pointer to the entity structure or NULL if not found.
94 */
95static xmlEntityPtr
96xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
97 xmlEntitiesTablePtr table;
98
99 if((dtd != NULL) && (dtd->entities != NULL)) {
100 table = (xmlEntitiesTablePtr) dtd->entities;
101 return((xmlEntityPtr) xmlHashLookup(table, name));
102 /* return(xmlGetEntityFromTable(table, name)); */
103 }
104 return(NULL);
105}
106/**
107 * xmlGetParameterEntityFromDtd:
108 * @dtd: A pointer to the DTD to search
109 * @name: The entity name
110 *
111 * Do an entity lookup in the DTD pararmeter entity hash table and
112 * return the corresponding entity, if found.
113 *
114 * Returns A pointer to the entity structure or NULL if not found.
115 */
116static xmlEntityPtr
117xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
118 xmlEntitiesTablePtr table;
119
120 if ((dtd != NULL) && (dtd->pentities != NULL)) {
121 table = (xmlEntitiesTablePtr) dtd->pentities;
122 return((xmlEntityPtr) xmlHashLookup(table, name));
123 /* return(xmlGetEntityFromTable(table, name)); */
124 }
125 return(NULL);
126}
127
128/************************************************************************
129 * *
Daniel Veillardc00cda82003-04-07 10:22:39 +0000130 * QName handling helper *
131 * *
132 ************************************************************************/
133
134/**
135 * xmlBuildQName:
136 * @ncname: the Name
137 * @prefix: the prefix
138 * @memory: preallocated memory
139 * @len: preallocated memory length
140 *
141 * Builds the QName @prefix:@ncname in @memory if there is enough space
142 * and prefix is not NULL nor empty, otherwise allocate a new string.
143 * If prefix is NULL or empty it returns ncname.
144 *
145 * Returns the new string which must be freed by the caller if different from
146 * @memory and @ncname or NULL in case of error
147 */
148xmlChar *
149xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix,
150 xmlChar *memory, int len) {
151 int lenn, lenp;
152 xmlChar *ret;
153
154 if ((ncname == NULL) || (*ncname == 0)) return(NULL);
155 if ((prefix == NULL) || (*prefix == 0)) return((xmlChar *) ncname);
156
157 lenn = strlen((char *) ncname);
158 lenp = strlen((char *) prefix);
159
160 if ((memory == NULL) || (len < lenn + lenp + 2)) {
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000161 ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000162 if (ret == NULL) return(NULL);
163 } else {
164 ret = memory;
165 }
166 memcpy(&ret[0], prefix, lenp);
167 ret[lenp] = ':';
168 memcpy(&ret[lenp + 1], ncname, lenn);
169 ret[lenn + lenp + 1] = 0;
170 return(ret);
171}
172
173/**
174 * xmlSplitQName2:
175 * @name: the full QName
176 * @prefix: a xmlChar **
177 *
178 * parse an XML qualified name string
179 *
180 * [NS 5] QName ::= (Prefix ':')? LocalPart
181 *
182 * [NS 6] Prefix ::= NCName
183 *
184 * [NS 7] LocalPart ::= NCName
185 *
186 * Returns NULL if not a QName, otherwise the local part, and prefix
187 * is updated to get the Prefix if any.
188 */
189
190xmlChar *
191xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
192 int len = 0;
193 xmlChar *ret = NULL;
194
195 *prefix = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000196 if (name == NULL) return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000197
198#ifndef XML_XML_NAMESPACE
199 /* xml: prefix is not really a namespace */
200 if ((name[0] == 'x') && (name[1] == 'm') &&
201 (name[2] == 'l') && (name[3] == ':'))
202 return(NULL);
203#endif
204
205 /* nasty but valid */
206 if (name[0] == ':')
207 return(NULL);
208
209 /*
210 * we are not trying to validate but just to cut, and yes it will
211 * work even if this is as set of UTF-8 encoded chars
212 */
213 while ((name[len] != 0) && (name[len] != ':'))
214 len++;
215
216 if (name[len] == 0)
217 return(NULL);
218
219 *prefix = xmlStrndup(name, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000220 if (*prefix == NULL) {
221 xmlGenericError(xmlGenericErrorContext,
222 "xmlSplitQName2 : out of memory!\n");
223 return(NULL);
224 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000225 ret = xmlStrdup(&name[len + 1]);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000226 if (ret == NULL) {
227 xmlGenericError(xmlGenericErrorContext,
228 "xmlSplitQName2 : out of memory!\n");
229 if (*prefix != NULL) {
230 xmlFree(*prefix);
231 *prefix = NULL;
232 }
233 return(NULL);
234 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000235
236 return(ret);
237}
238
239/************************************************************************
240 * *
Daniel Veillardd2298792003-02-14 16:54:11 +0000241 * Check Name, NCName and QName strings *
242 * *
243 ************************************************************************/
244
245#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
246
247/**
248 * xmlValidateNCName:
249 * @value: the value to check
250 * @space: allow spaces in front and end of the string
251 *
252 * Check that a value conforms to the lexical space of NCName
253 *
254 * Returns 0 if this validates, a positive error code number otherwise
255 * and -1 in case of internal or API error.
256 */
257int
258xmlValidateNCName(const xmlChar *value, int space) {
259 const xmlChar *cur = value;
260 int c,l;
261
262 /*
263 * First quick algorithm for ASCII range
264 */
265 if (space)
266 while (IS_BLANK(*cur)) cur++;
267 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
268 (*cur == '_'))
269 cur++;
270 else
271 goto try_complex;
272 while (((*cur >= 'a') && (*cur <= 'z')) ||
273 ((*cur >= 'A') && (*cur <= 'Z')) ||
274 ((*cur >= '0') && (*cur <= '9')) ||
275 (*cur == '_') || (*cur == '-') || (*cur == '.'))
276 cur++;
277 if (space)
278 while (IS_BLANK(*cur)) cur++;
279 if (*cur == 0)
280 return(0);
281
282try_complex:
283 /*
284 * Second check for chars outside the ASCII range
285 */
286 cur = value;
287 c = CUR_SCHAR(cur, l);
288 if (space) {
289 while (IS_BLANK(c)) {
290 cur += l;
291 c = CUR_SCHAR(cur, l);
292 }
293 }
294 if ((!xmlIsLetter(c)) && (c != '_'))
295 return(1);
296 cur += l;
297 c = CUR_SCHAR(cur, l);
298 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') ||
299 (c == '-') || (c == '_') || xmlIsCombining(c) ||
300 xmlIsExtender(c)) {
301 cur += l;
302 c = CUR_SCHAR(cur, l);
303 }
304 if (space) {
305 while (IS_BLANK(c)) {
306 cur += l;
307 c = CUR_SCHAR(cur, l);
308 }
309 }
310 if (c != 0)
311 return(1);
312
313 return(0);
314}
315
316/**
317 * xmlValidateQName:
318 * @value: the value to check
319 * @space: allow spaces in front and end of the string
320 *
321 * Check that a value conforms to the lexical space of QName
322 *
323 * Returns 0 if this validates, a positive error code number otherwise
324 * and -1 in case of internal or API error.
325 */
326int
327xmlValidateQName(const xmlChar *value, int space) {
328 const xmlChar *cur = value;
329 int c,l;
330
331 /*
332 * First quick algorithm for ASCII range
333 */
334 if (space)
335 while (IS_BLANK(*cur)) cur++;
336 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
337 (*cur == '_'))
338 cur++;
339 else
340 goto try_complex;
341 while (((*cur >= 'a') && (*cur <= 'z')) ||
342 ((*cur >= 'A') && (*cur <= 'Z')) ||
343 ((*cur >= '0') && (*cur <= '9')) ||
344 (*cur == '_') || (*cur == '-') || (*cur == '.'))
345 cur++;
346 if (*cur == ':') {
347 cur++;
348 if (((*cur >= 'a') && (*cur <= 'z')) ||
349 ((*cur >= 'A') && (*cur <= 'Z')) ||
350 (*cur == '_'))
351 cur++;
352 else
353 goto try_complex;
354 while (((*cur >= 'a') && (*cur <= 'z')) ||
355 ((*cur >= 'A') && (*cur <= 'Z')) ||
356 ((*cur >= '0') && (*cur <= '9')) ||
357 (*cur == '_') || (*cur == '-') || (*cur == '.'))
358 cur++;
359 }
360 if (space)
361 while (IS_BLANK(*cur)) cur++;
362 if (*cur == 0)
363 return(0);
364
365try_complex:
366 /*
367 * Second check for chars outside the ASCII range
368 */
369 cur = value;
370 c = CUR_SCHAR(cur, l);
371 if (space) {
372 while (IS_BLANK(c)) {
373 cur += l;
374 c = CUR_SCHAR(cur, l);
375 }
376 }
377 if ((!xmlIsLetter(c)) && (c != '_'))
378 return(1);
379 cur += l;
380 c = CUR_SCHAR(cur, l);
381 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') ||
382 (c == '-') || (c == '_') || xmlIsCombining(c) ||
383 xmlIsExtender(c)) {
384 cur += l;
385 c = CUR_SCHAR(cur, l);
386 }
387 if (c == ':') {
388 cur += l;
389 c = CUR_SCHAR(cur, l);
390 if ((!xmlIsLetter(c)) && (c != '_'))
391 return(1);
392 cur += l;
393 c = CUR_SCHAR(cur, l);
394 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') ||
395 (c == '-') || (c == '_') || xmlIsCombining(c) ||
396 xmlIsExtender(c)) {
397 cur += l;
398 c = CUR_SCHAR(cur, l);
399 }
400 }
401 if (space) {
402 while (IS_BLANK(c)) {
403 cur += l;
404 c = CUR_SCHAR(cur, l);
405 }
406 }
407 if (c != 0)
408 return(1);
409 return(0);
410}
411
412/**
413 * xmlValidateName:
414 * @value: the value to check
415 * @space: allow spaces in front and end of the string
416 *
417 * Check that a value conforms to the lexical space of Name
418 *
419 * Returns 0 if this validates, a positive error code number otherwise
420 * and -1 in case of internal or API error.
421 */
422int
423xmlValidateName(const xmlChar *value, int space) {
424 const xmlChar *cur = value;
425 int c,l;
426
427 /*
428 * First quick algorithm for ASCII range
429 */
430 if (space)
431 while (IS_BLANK(*cur)) cur++;
432 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
433 (*cur == '_') || (*cur == ':'))
434 cur++;
435 else
436 goto try_complex;
437 while (((*cur >= 'a') && (*cur <= 'z')) ||
438 ((*cur >= 'A') && (*cur <= 'Z')) ||
439 ((*cur >= '0') && (*cur <= '9')) ||
440 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
441 cur++;
442 if (space)
443 while (IS_BLANK(*cur)) cur++;
444 if (*cur == 0)
445 return(0);
446
447try_complex:
448 /*
449 * Second check for chars outside the ASCII range
450 */
451 cur = value;
452 c = CUR_SCHAR(cur, l);
453 if (space) {
454 while (IS_BLANK(c)) {
455 cur += l;
456 c = CUR_SCHAR(cur, l);
457 }
458 }
459 if ((!xmlIsLetter(c)) && (c != '_') && (c != ':'))
460 return(1);
461 cur += l;
462 c = CUR_SCHAR(cur, l);
463 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') || (c == ':') ||
464 (c == '-') || (c == '_') || xmlIsCombining(c) || xmlIsExtender(c)) {
465 cur += l;
466 c = CUR_SCHAR(cur, l);
467 }
468 if (space) {
469 while (IS_BLANK(c)) {
470 cur += l;
471 c = CUR_SCHAR(cur, l);
472 }
473 }
474 if (c != 0)
475 return(1);
476 return(0);
477}
478
Daniel Veillardd4310742003-02-18 21:12:46 +0000479/**
480 * xmlValidateNMToken:
481 * @value: the value to check
482 * @space: allow spaces in front and end of the string
483 *
484 * Check that a value conforms to the lexical space of NMToken
485 *
486 * Returns 0 if this validates, a positive error code number otherwise
487 * and -1 in case of internal or API error.
488 */
489int
490xmlValidateNMToken(const xmlChar *value, int space) {
491 const xmlChar *cur = value;
492 int c,l;
493
494 /*
495 * First quick algorithm for ASCII range
496 */
497 if (space)
498 while (IS_BLANK(*cur)) cur++;
499 if (((*cur >= 'a') && (*cur <= 'z')) ||
500 ((*cur >= 'A') && (*cur <= 'Z')) ||
501 ((*cur >= '0') && (*cur <= '9')) ||
502 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
503 cur++;
504 else
505 goto try_complex;
506 while (((*cur >= 'a') && (*cur <= 'z')) ||
507 ((*cur >= 'A') && (*cur <= 'Z')) ||
508 ((*cur >= '0') && (*cur <= '9')) ||
509 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
510 cur++;
511 if (space)
512 while (IS_BLANK(*cur)) cur++;
513 if (*cur == 0)
514 return(0);
515
516try_complex:
517 /*
518 * Second check for chars outside the ASCII range
519 */
520 cur = value;
521 c = CUR_SCHAR(cur, l);
522 if (space) {
523 while (IS_BLANK(c)) {
524 cur += l;
525 c = CUR_SCHAR(cur, l);
526 }
527 }
528 if (!(xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') || (c == ':') ||
529 (c == '-') || (c == '_') || xmlIsCombining(c) || xmlIsExtender(c)))
530 return(1);
531 cur += l;
532 c = CUR_SCHAR(cur, l);
533 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') || (c == ':') ||
534 (c == '-') || (c == '_') || xmlIsCombining(c) || xmlIsExtender(c)) {
535 cur += l;
536 c = CUR_SCHAR(cur, l);
537 }
538 if (space) {
539 while (IS_BLANK(c)) {
540 cur += l;
541 c = CUR_SCHAR(cur, l);
542 }
543 }
544 if (c != 0)
545 return(1);
546 return(0);
547}
548
Daniel Veillardd2298792003-02-14 16:54:11 +0000549/************************************************************************
550 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000551 * Allocation and deallocation of basic structures *
552 * *
553 ************************************************************************/
554
555/**
556 * xmlSetBufferAllocationScheme:
557 * @scheme: allocation method to use
558 *
559 * Set the buffer allocation method. Types are
560 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
561 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
562 * improves performance
563 */
564void
565xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
566 xmlBufferAllocScheme = scheme;
567}
568
569/**
570 * xmlGetBufferAllocationScheme:
571 *
572 * Types are
573 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
574 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
575 * improves performance
576 *
577 * Returns the current allocation scheme
578 */
579xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000580xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000581 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000582}
583
584/**
585 * xmlNewNs:
586 * @node: the element carrying the namespace
587 * @href: the URI associated
588 * @prefix: the prefix for the namespace
589 *
590 * Creation of a new Namespace. This function will refuse to create
591 * a namespace with a similar prefix than an existing one present on this
592 * node.
593 * We use href==NULL in the case of an element creation where the namespace
594 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000595 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000596 */
597xmlNsPtr
598xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
599 xmlNsPtr cur;
600
601 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
602 return(NULL);
603
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000604 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
605 return(NULL);
606
Owen Taylor3473f882001-02-23 17:55:21 +0000607 /*
608 * Allocate a new Namespace and fill the fields.
609 */
610 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
611 if (cur == NULL) {
612 xmlGenericError(xmlGenericErrorContext,
613 "xmlNewNs : malloc failed\n");
614 return(NULL);
615 }
616 memset(cur, 0, sizeof(xmlNs));
617 cur->type = XML_LOCAL_NAMESPACE;
618
619 if (href != NULL)
620 cur->href = xmlStrdup(href);
621 if (prefix != NULL)
622 cur->prefix = xmlStrdup(prefix);
623
624 /*
625 * Add it at the end to preserve parsing order ...
626 * and checks for existing use of the prefix
627 */
628 if (node != NULL) {
629 if (node->nsDef == NULL) {
630 node->nsDef = cur;
631 } else {
632 xmlNsPtr prev = node->nsDef;
633
634 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
635 (xmlStrEqual(prev->prefix, cur->prefix))) {
636 xmlFreeNs(cur);
637 return(NULL);
638 }
639 while (prev->next != NULL) {
640 prev = prev->next;
641 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
642 (xmlStrEqual(prev->prefix, cur->prefix))) {
643 xmlFreeNs(cur);
644 return(NULL);
645 }
646 }
647 prev->next = cur;
648 }
649 }
650 return(cur);
651}
652
653/**
654 * xmlSetNs:
655 * @node: a node in the document
656 * @ns: a namespace pointer
657 *
658 * Associate a namespace to a node, a posteriori.
659 */
660void
661xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
662 if (node == NULL) {
663#ifdef DEBUG_TREE
664 xmlGenericError(xmlGenericErrorContext,
665 "xmlSetNs: node == NULL\n");
666#endif
667 return;
668 }
669 node->ns = ns;
670}
671
672/**
673 * xmlFreeNs:
674 * @cur: the namespace pointer
675 *
676 * Free up the structures associated to a namespace
677 */
678void
679xmlFreeNs(xmlNsPtr cur) {
680 if (cur == NULL) {
681#ifdef DEBUG_TREE
682 xmlGenericError(xmlGenericErrorContext,
683 "xmlFreeNs : ns == NULL\n");
684#endif
685 return;
686 }
687 if (cur->href != NULL) xmlFree((char *) cur->href);
688 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000689 xmlFree(cur);
690}
691
692/**
693 * xmlFreeNsList:
694 * @cur: the first namespace pointer
695 *
696 * Free up all the structures associated to the chained namespaces.
697 */
698void
699xmlFreeNsList(xmlNsPtr cur) {
700 xmlNsPtr next;
701 if (cur == NULL) {
702#ifdef DEBUG_TREE
703 xmlGenericError(xmlGenericErrorContext,
704 "xmlFreeNsList : ns == NULL\n");
705#endif
706 return;
707 }
708 while (cur != NULL) {
709 next = cur->next;
710 xmlFreeNs(cur);
711 cur = next;
712 }
713}
714
715/**
716 * xmlNewDtd:
717 * @doc: the document pointer
718 * @name: the DTD name
719 * @ExternalID: the external ID
720 * @SystemID: the system ID
721 *
722 * Creation of a new DTD for the external subset. To create an
723 * internal subset, use xmlCreateIntSubset().
724 *
725 * Returns a pointer to the new DTD structure
726 */
727xmlDtdPtr
728xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
729 const xmlChar *ExternalID, const xmlChar *SystemID) {
730 xmlDtdPtr cur;
731
732 if ((doc != NULL) && (doc->extSubset != NULL)) {
733#ifdef DEBUG_TREE
734 xmlGenericError(xmlGenericErrorContext,
735 "xmlNewDtd(%s): document %s already have a DTD %s\n",
736 /* !!! */ (char *) name, doc->name,
737 /* !!! */ (char *)doc->extSubset->name);
738#endif
739 return(NULL);
740 }
741
742 /*
743 * Allocate a new DTD and fill the fields.
744 */
745 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
746 if (cur == NULL) {
747 xmlGenericError(xmlGenericErrorContext,
748 "xmlNewDtd : malloc failed\n");
749 return(NULL);
750 }
751 memset(cur, 0 , sizeof(xmlDtd));
752 cur->type = XML_DTD_NODE;
753
754 if (name != NULL)
755 cur->name = xmlStrdup(name);
756 if (ExternalID != NULL)
757 cur->ExternalID = xmlStrdup(ExternalID);
758 if (SystemID != NULL)
759 cur->SystemID = xmlStrdup(SystemID);
760 if (doc != NULL)
761 doc->extSubset = cur;
762 cur->doc = doc;
763
Daniel Veillarda880b122003-04-21 21:36:41 +0000764 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000765 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000766 return(cur);
767}
768
769/**
770 * xmlGetIntSubset:
771 * @doc: the document pointer
772 *
773 * Get the internal subset of a document
774 * Returns a pointer to the DTD structure or NULL if not found
775 */
776
777xmlDtdPtr
778xmlGetIntSubset(xmlDocPtr doc) {
779 xmlNodePtr cur;
780
781 if (doc == NULL)
782 return(NULL);
783 cur = doc->children;
784 while (cur != NULL) {
785 if (cur->type == XML_DTD_NODE)
786 return((xmlDtdPtr) cur);
787 cur = cur->next;
788 }
789 return((xmlDtdPtr) doc->intSubset);
790}
791
792/**
793 * xmlCreateIntSubset:
794 * @doc: the document pointer
795 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000796 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000797 * @SystemID: the system ID
798 *
799 * Create the internal subset of a document
800 * Returns a pointer to the new DTD structure
801 */
802xmlDtdPtr
803xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
804 const xmlChar *ExternalID, const xmlChar *SystemID) {
805 xmlDtdPtr cur;
806
807 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
808#ifdef DEBUG_TREE
809 xmlGenericError(xmlGenericErrorContext,
810
811 "xmlCreateIntSubset(): document %s already have an internal subset\n",
812 doc->name);
813#endif
814 return(NULL);
815 }
816
817 /*
818 * Allocate a new DTD and fill the fields.
819 */
820 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
821 if (cur == NULL) {
822 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000823 "xmlCreateIntSubset : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000824 return(NULL);
825 }
826 memset(cur, 0, sizeof(xmlDtd));
827 cur->type = XML_DTD_NODE;
828
829 if (name != NULL)
830 cur->name = xmlStrdup(name);
831 if (ExternalID != NULL)
832 cur->ExternalID = xmlStrdup(ExternalID);
833 if (SystemID != NULL)
834 cur->SystemID = xmlStrdup(SystemID);
835 if (doc != NULL) {
836 doc->intSubset = cur;
837 cur->parent = doc;
838 cur->doc = doc;
839 if (doc->children == NULL) {
840 doc->children = (xmlNodePtr) cur;
841 doc->last = (xmlNodePtr) cur;
842 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000843 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000844 xmlNodePtr prev;
845
Owen Taylor3473f882001-02-23 17:55:21 +0000846 prev = doc->children;
847 prev->prev = (xmlNodePtr) cur;
848 cur->next = prev;
849 doc->children = (xmlNodePtr) cur;
850 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000851 xmlNodePtr next;
852
853 next = doc->children;
854 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
855 next = next->next;
856 if (next == NULL) {
857 cur->prev = doc->last;
858 cur->prev->next = (xmlNodePtr) cur;
859 cur->next = NULL;
860 doc->last = (xmlNodePtr) cur;
861 } else {
862 cur->next = next;
863 cur->prev = next->prev;
864 if (cur->prev == NULL)
865 doc->children = (xmlNodePtr) cur;
866 else
867 cur->prev->next = (xmlNodePtr) cur;
868 next->prev = (xmlNodePtr) cur;
869 }
Owen Taylor3473f882001-02-23 17:55:21 +0000870 }
871 }
872 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000873
Daniel Veillarda880b122003-04-21 21:36:41 +0000874 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000875 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000876 return(cur);
877}
878
879/**
880 * xmlFreeDtd:
881 * @cur: the DTD structure to free up
882 *
883 * Free a DTD structure.
884 */
885void
886xmlFreeDtd(xmlDtdPtr cur) {
887 if (cur == NULL) {
888#ifdef DEBUG_TREE
889 xmlGenericError(xmlGenericErrorContext,
890 "xmlFreeDtd : DTD == NULL\n");
891#endif
892 return;
893 }
Daniel Veillard5335dc52003-01-01 20:59:38 +0000894
Daniel Veillarda880b122003-04-21 21:36:41 +0000895 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000896 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
897
Owen Taylor3473f882001-02-23 17:55:21 +0000898 if (cur->children != NULL) {
899 xmlNodePtr next, c = cur->children;
900
901 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000902 * Cleanup all the DTD comments they are not in the DTD
Owen Taylor3473f882001-02-23 17:55:21 +0000903 * indexes.
904 */
905 while (c != NULL) {
906 next = c->next;
Daniel Veillardd72c7e32003-05-12 21:55:03 +0000907 if ((c->type == XML_COMMENT_NODE) || (c->type == XML_PI_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000908 xmlUnlinkNode(c);
909 xmlFreeNode(c);
910 }
911 c = next;
912 }
913 }
914 if (cur->name != NULL) xmlFree((char *) cur->name);
915 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
916 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
917 /* TODO !!! */
918 if (cur->notations != NULL)
919 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
920
921 if (cur->elements != NULL)
922 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
923 if (cur->attributes != NULL)
924 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
925 if (cur->entities != NULL)
926 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
927 if (cur->pentities != NULL)
928 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
929
Owen Taylor3473f882001-02-23 17:55:21 +0000930 xmlFree(cur);
931}
932
933/**
934 * xmlNewDoc:
935 * @version: xmlChar string giving the version of XML "1.0"
936 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000937 * Creates a new XML document
938 *
Owen Taylor3473f882001-02-23 17:55:21 +0000939 * Returns a new document
940 */
941xmlDocPtr
942xmlNewDoc(const xmlChar *version) {
943 xmlDocPtr cur;
944
945 if (version == NULL)
946 version = (const xmlChar *) "1.0";
947
948 /*
949 * Allocate a new document and fill the fields.
950 */
951 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
952 if (cur == NULL) {
953 xmlGenericError(xmlGenericErrorContext,
954 "xmlNewDoc : malloc failed\n");
955 return(NULL);
956 }
957 memset(cur, 0, sizeof(xmlDoc));
958 cur->type = XML_DOCUMENT_NODE;
959
960 cur->version = xmlStrdup(version);
961 cur->standalone = -1;
962 cur->compression = -1; /* not initialized */
963 cur->doc = cur;
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000964 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +0000965
Daniel Veillarda880b122003-04-21 21:36:41 +0000966 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000967 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000968 return(cur);
969}
970
971/**
972 * xmlFreeDoc:
973 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +0000974 *
975 * Free up all the structures used by a document, tree included.
976 */
977void
978xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +0000979 xmlDtdPtr extSubset, intSubset;
980
Owen Taylor3473f882001-02-23 17:55:21 +0000981 if (cur == NULL) {
982#ifdef DEBUG_TREE
983 xmlGenericError(xmlGenericErrorContext,
984 "xmlFreeDoc : document == NULL\n");
985#endif
986 return;
987 }
Daniel Veillard5335dc52003-01-01 20:59:38 +0000988
Daniel Veillarda880b122003-04-21 21:36:41 +0000989 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000990 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
991
Daniel Veillard76d66f42001-05-16 21:05:17 +0000992 /*
993 * Do this before freeing the children list to avoid ID lookups
994 */
995 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
996 cur->ids = NULL;
997 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
998 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000999 extSubset = cur->extSubset;
1000 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +00001001 if (intSubset == extSubset)
1002 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001003 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001004 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001005 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001006 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001007 }
Daniel Veillarda9142e72001-06-19 11:07:54 +00001008 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001009 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001010 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001011 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001012 }
1013
1014 if (cur->children != NULL) xmlFreeNodeList(cur->children);
1015
Owen Taylor3473f882001-02-23 17:55:21 +00001016 if (cur->version != NULL) xmlFree((char *) cur->version);
1017 if (cur->name != NULL) xmlFree((char *) cur->name);
1018 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00001019 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00001020 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Owen Taylor3473f882001-02-23 17:55:21 +00001021 xmlFree(cur);
1022}
1023
1024/**
1025 * xmlStringLenGetNodeList:
1026 * @doc: the document
1027 * @value: the value of the text
1028 * @len: the length of the string value
1029 *
1030 * Parse the value string and build the node list associated. Should
1031 * produce a flat tree with only TEXTs and ENTITY_REFs.
1032 * Returns a pointer to the first child
1033 */
1034xmlNodePtr
1035xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1036 xmlNodePtr ret = NULL, last = NULL;
1037 xmlNodePtr node;
1038 xmlChar *val;
1039 const xmlChar *cur = value;
1040 const xmlChar *q;
1041 xmlEntityPtr ent;
1042
1043 if (value == NULL) return(NULL);
1044
1045 q = cur;
1046 while ((*cur != 0) && (cur - value < len)) {
1047 if (*cur == '&') {
1048 /*
1049 * Save the current text.
1050 */
1051 if (cur != q) {
1052 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1053 xmlNodeAddContentLen(last, q, cur - q);
1054 } else {
1055 node = xmlNewDocTextLen(doc, q, cur - q);
1056 if (node == NULL) return(ret);
1057 if (last == NULL)
1058 last = ret = node;
1059 else {
1060 last->next = node;
1061 node->prev = last;
1062 last = node;
1063 }
1064 }
1065 }
1066 /*
1067 * Read the entity string
1068 */
1069 cur++;
1070 q = cur;
1071 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
1072 if ((*cur == 0) || (cur - value >= len)) {
1073#ifdef DEBUG_TREE
1074 xmlGenericError(xmlGenericErrorContext,
1075 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
1076#endif
1077 return(ret);
1078 }
1079 if (cur != q) {
1080 /*
1081 * Predefined entities don't generate nodes
1082 */
1083 val = xmlStrndup(q, cur - q);
1084 ent = xmlGetDocEntity(doc, val);
1085 if ((ent != NULL) &&
1086 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1087 if (last == NULL) {
1088 node = xmlNewDocText(doc, ent->content);
1089 last = ret = node;
1090 } else
1091 xmlNodeAddContent(last, ent->content);
1092
1093 } else {
1094 /*
1095 * Create a new REFERENCE_REF node
1096 */
1097 node = xmlNewReference(doc, val);
1098 if (node == NULL) {
1099 if (val != NULL) xmlFree(val);
1100 return(ret);
1101 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001102 else if ((ent != NULL) && (ent->children == NULL)) {
1103 xmlNodePtr tmp;
1104
1105 ent->children =
1106 xmlStringGetNodeList(doc, (const xmlChar*)node->content);
1107 tmp = ent->children;
1108 while (tmp) {
1109 tmp->parent = (xmlNodePtr)ent;
1110 tmp = tmp->next;
1111 }
1112 }
Owen Taylor3473f882001-02-23 17:55:21 +00001113 if (last == NULL)
1114 last = ret = node;
1115 else {
1116 last->next = node;
1117 node->prev = last;
1118 last = node;
1119 }
1120 }
1121 xmlFree(val);
1122 }
1123 cur++;
1124 q = cur;
1125 } else
1126 cur++;
1127 }
1128 if (cur != q) {
1129 /*
1130 * Handle the last piece of text.
1131 */
1132 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1133 xmlNodeAddContentLen(last, q, cur - q);
1134 } else {
1135 node = xmlNewDocTextLen(doc, q, cur - q);
1136 if (node == NULL) return(ret);
1137 if (last == NULL)
1138 last = ret = node;
1139 else {
1140 last->next = node;
1141 node->prev = last;
1142 last = node;
1143 }
1144 }
1145 }
1146 return(ret);
1147}
1148
1149/**
1150 * xmlStringGetNodeList:
1151 * @doc: the document
1152 * @value: the value of the attribute
1153 *
1154 * Parse the value string and build the node list associated. Should
1155 * produce a flat tree with only TEXTs and ENTITY_REFs.
1156 * Returns a pointer to the first child
1157 */
1158xmlNodePtr
1159xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1160 xmlNodePtr ret = NULL, last = NULL;
1161 xmlNodePtr node;
1162 xmlChar *val;
1163 const xmlChar *cur = value;
1164 const xmlChar *q;
1165 xmlEntityPtr ent;
1166
1167 if (value == NULL) return(NULL);
1168
1169 q = cur;
1170 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001171 if (cur[0] == '&') {
1172 int charval = 0;
1173 xmlChar tmp;
1174
Owen Taylor3473f882001-02-23 17:55:21 +00001175 /*
1176 * Save the current text.
1177 */
1178 if (cur != q) {
1179 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1180 xmlNodeAddContentLen(last, q, cur - q);
1181 } else {
1182 node = xmlNewDocTextLen(doc, q, cur - q);
1183 if (node == NULL) return(ret);
1184 if (last == NULL)
1185 last = ret = node;
1186 else {
1187 last->next = node;
1188 node->prev = last;
1189 last = node;
1190 }
1191 }
1192 }
Owen Taylor3473f882001-02-23 17:55:21 +00001193 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001194 if ((cur[1] == '#') && (cur[2] == 'x')) {
1195 cur += 3;
1196 tmp = *cur;
1197 while (tmp != ';') { /* Non input consuming loop */
1198 if ((tmp >= '0') && (tmp <= '9'))
1199 charval = charval * 16 + (tmp - '0');
1200 else if ((tmp >= 'a') && (tmp <= 'f'))
1201 charval = charval * 16 + (tmp - 'a') + 10;
1202 else if ((tmp >= 'A') && (tmp <= 'F'))
1203 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001204 else {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001205 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001206 "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001207 charval = 0;
1208 break;
1209 }
1210 cur++;
1211 tmp = *cur;
1212 }
1213 if (tmp == ';')
1214 cur++;
1215 q = cur;
1216 } else if (cur[1] == '#') {
1217 cur += 2;
1218 tmp = *cur;
1219 while (tmp != ';') { /* Non input consuming loops */
1220 if ((tmp >= '0') && (tmp <= '9'))
1221 charval = charval * 10 + (tmp - '0');
1222 else {
1223 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001224 "xmlStringGetNodeList: invalid decimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001225 charval = 0;
1226 break;
1227 }
1228 cur++;
1229 tmp = *cur;
1230 }
1231 if (tmp == ';')
1232 cur++;
1233 q = cur;
1234 } else {
1235 /*
1236 * Read the entity string
1237 */
1238 cur++;
1239 q = cur;
1240 while ((*cur != 0) && (*cur != ';')) cur++;
1241 if (*cur == 0) {
1242#ifdef DEBUG_TREE
1243 xmlGenericError(xmlGenericErrorContext,
1244 "xmlStringGetNodeList: unterminated entity %30s\n", q);
1245#endif
1246 return(ret);
1247 }
1248 if (cur != q) {
1249 /*
1250 * Predefined entities don't generate nodes
1251 */
1252 val = xmlStrndup(q, cur - q);
1253 ent = xmlGetDocEntity(doc, val);
1254 if ((ent != NULL) &&
1255 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1256 if (last == NULL) {
1257 node = xmlNewDocText(doc, ent->content);
1258 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001259 } else if (last->type != XML_TEXT_NODE) {
1260 node = xmlNewDocText(doc, ent->content);
1261 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001262 } else
1263 xmlNodeAddContent(last, ent->content);
1264
1265 } else {
1266 /*
1267 * Create a new REFERENCE_REF node
1268 */
1269 node = xmlNewReference(doc, val);
1270 if (node == NULL) {
1271 if (val != NULL) xmlFree(val);
1272 return(ret);
1273 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001274 else if ((ent != NULL) && (ent->children == NULL)) {
1275 xmlNodePtr temp;
1276
1277 ent->children = xmlStringGetNodeList(doc,
1278 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001279 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001280 temp = ent->children;
1281 while (temp) {
1282 temp->parent = (xmlNodePtr)ent;
1283 temp = temp->next;
1284 }
1285 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001286 if (last == NULL) {
1287 last = ret = node;
1288 } else {
1289 last = xmlAddNextSibling(last, node);
1290 }
1291 }
1292 xmlFree(val);
1293 }
1294 cur++;
1295 q = cur;
1296 }
1297 if (charval != 0) {
1298 xmlChar buf[10];
1299 int len;
1300
1301 len = xmlCopyCharMultiByte(buf, charval);
1302 buf[len] = 0;
1303 node = xmlNewDocText(doc, buf);
1304 if (node != NULL) {
1305 if (last == NULL) {
1306 last = ret = node;
1307 } else {
1308 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001309 }
1310 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001311
1312 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001313 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001314 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001315 cur++;
1316 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001317 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001318 /*
1319 * Handle the last piece of text.
1320 */
1321 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1322 xmlNodeAddContentLen(last, q, cur - q);
1323 } else {
1324 node = xmlNewDocTextLen(doc, q, cur - q);
1325 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001326 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001327 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001328 } else {
1329 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001330 }
1331 }
1332 }
1333 return(ret);
1334}
1335
1336/**
1337 * xmlNodeListGetString:
1338 * @doc: the document
1339 * @list: a Node list
1340 * @inLine: should we replace entity contents or show their external form
1341 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001342 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001343 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001344 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001345 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001346 */
1347xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001348xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1349{
Owen Taylor3473f882001-02-23 17:55:21 +00001350 xmlNodePtr node = list;
1351 xmlChar *ret = NULL;
1352 xmlEntityPtr ent;
1353
Daniel Veillard7646b182002-04-20 06:41:40 +00001354 if (list == NULL)
1355 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001356
1357 while (node != NULL) {
1358 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001359 (node->type == XML_CDATA_SECTION_NODE)) {
1360 if (inLine) {
1361 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001362 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001363 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001364
Daniel Veillard7646b182002-04-20 06:41:40 +00001365 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1366 if (buffer != NULL) {
1367 ret = xmlStrcat(ret, buffer);
1368 xmlFree(buffer);
1369 }
1370 }
1371 } else if (node->type == XML_ENTITY_REF_NODE) {
1372 if (inLine) {
1373 ent = xmlGetDocEntity(doc, node->name);
1374 if (ent != NULL) {
1375 xmlChar *buffer;
1376
1377 /* an entity content can be any "well balanced chunk",
1378 * i.e. the result of the content [43] production:
1379 * http://www.w3.org/TR/REC-xml#NT-content.
1380 * So it can contain text, CDATA section or nested
1381 * entity reference nodes (among others).
1382 * -> we recursive call xmlNodeListGetString()
1383 * which handles these types */
1384 buffer = xmlNodeListGetString(doc, ent->children, 1);
1385 if (buffer != NULL) {
1386 ret = xmlStrcat(ret, buffer);
1387 xmlFree(buffer);
1388 }
1389 } else {
1390 ret = xmlStrcat(ret, node->content);
1391 }
1392 } else {
1393 xmlChar buf[2];
1394
1395 buf[0] = '&';
1396 buf[1] = 0;
1397 ret = xmlStrncat(ret, buf, 1);
1398 ret = xmlStrcat(ret, node->name);
1399 buf[0] = ';';
1400 buf[1] = 0;
1401 ret = xmlStrncat(ret, buf, 1);
1402 }
1403 }
1404#if 0
1405 else {
1406 xmlGenericError(xmlGenericErrorContext,
1407 "xmlGetNodeListString : invalid node type %d\n",
1408 node->type);
1409 }
1410#endif
1411 node = node->next;
1412 }
1413 return (ret);
1414}
Owen Taylor3473f882001-02-23 17:55:21 +00001415/**
1416 * xmlNodeListGetRawString:
1417 * @doc: the document
1418 * @list: a Node list
1419 * @inLine: should we replace entity contents or show their external form
1420 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001421 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001422 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1423 * this function doesn't do any character encoding handling.
1424 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001425 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001426 */
1427xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001428xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1429{
Owen Taylor3473f882001-02-23 17:55:21 +00001430 xmlNodePtr node = list;
1431 xmlChar *ret = NULL;
1432 xmlEntityPtr ent;
1433
Daniel Veillard7646b182002-04-20 06:41:40 +00001434 if (list == NULL)
1435 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001436
1437 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001438 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001439 (node->type == XML_CDATA_SECTION_NODE)) {
1440 if (inLine) {
1441 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001442 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001443 xmlChar *buffer;
1444
1445 buffer = xmlEncodeSpecialChars(doc, node->content);
1446 if (buffer != NULL) {
1447 ret = xmlStrcat(ret, buffer);
1448 xmlFree(buffer);
1449 }
1450 }
1451 } else if (node->type == XML_ENTITY_REF_NODE) {
1452 if (inLine) {
1453 ent = xmlGetDocEntity(doc, node->name);
1454 if (ent != NULL) {
1455 xmlChar *buffer;
1456
1457 /* an entity content can be any "well balanced chunk",
1458 * i.e. the result of the content [43] production:
1459 * http://www.w3.org/TR/REC-xml#NT-content.
1460 * So it can contain text, CDATA section or nested
1461 * entity reference nodes (among others).
1462 * -> we recursive call xmlNodeListGetRawString()
1463 * which handles these types */
1464 buffer =
1465 xmlNodeListGetRawString(doc, ent->children, 1);
1466 if (buffer != NULL) {
1467 ret = xmlStrcat(ret, buffer);
1468 xmlFree(buffer);
1469 }
1470 } else {
1471 ret = xmlStrcat(ret, node->content);
1472 }
1473 } else {
1474 xmlChar buf[2];
1475
1476 buf[0] = '&';
1477 buf[1] = 0;
1478 ret = xmlStrncat(ret, buf, 1);
1479 ret = xmlStrcat(ret, node->name);
1480 buf[0] = ';';
1481 buf[1] = 0;
1482 ret = xmlStrncat(ret, buf, 1);
1483 }
1484 }
Owen Taylor3473f882001-02-23 17:55:21 +00001485#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001486 else {
1487 xmlGenericError(xmlGenericErrorContext,
1488 "xmlGetNodeListString : invalid node type %d\n",
1489 node->type);
1490 }
Owen Taylor3473f882001-02-23 17:55:21 +00001491#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001492 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001493 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001494 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001495}
1496
1497/**
1498 * xmlNewProp:
1499 * @node: the holding node
1500 * @name: the name of the attribute
1501 * @value: the value of the attribute
1502 *
1503 * Create a new property carried by a node.
1504 * Returns a pointer to the attribute
1505 */
1506xmlAttrPtr
1507xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1508 xmlAttrPtr cur;
1509 xmlDocPtr doc = NULL;
1510
1511 if (name == NULL) {
1512#ifdef DEBUG_TREE
1513 xmlGenericError(xmlGenericErrorContext,
1514 "xmlNewProp : name == NULL\n");
1515#endif
1516 return(NULL);
1517 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00001518 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
1519 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001520
1521 /*
1522 * Allocate a new property and fill the fields.
1523 */
1524 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1525 if (cur == NULL) {
1526 xmlGenericError(xmlGenericErrorContext,
1527 "xmlNewProp : malloc failed\n");
1528 return(NULL);
1529 }
1530 memset(cur, 0, sizeof(xmlAttr));
1531 cur->type = XML_ATTRIBUTE_NODE;
1532
1533 cur->parent = node;
1534 if (node != NULL) {
1535 doc = node->doc;
1536 cur->doc = doc;
1537 }
1538 cur->name = xmlStrdup(name);
1539 if (value != NULL) {
1540 xmlChar *buffer;
1541 xmlNodePtr tmp;
1542
1543 buffer = xmlEncodeEntitiesReentrant(doc, value);
1544 cur->children = xmlStringGetNodeList(doc, buffer);
1545 cur->last = NULL;
1546 tmp = cur->children;
1547 while (tmp != NULL) {
1548 tmp->parent = (xmlNodePtr) cur;
1549 tmp->doc = doc;
1550 if (tmp->next == NULL)
1551 cur->last = tmp;
1552 tmp = tmp->next;
1553 }
1554 xmlFree(buffer);
1555 }
1556
1557 /*
1558 * Add it at the end to preserve parsing order ...
1559 */
1560 if (node != NULL) {
1561 if (node->properties == NULL) {
1562 node->properties = cur;
1563 } else {
1564 xmlAttrPtr prev = node->properties;
1565
1566 while (prev->next != NULL) prev = prev->next;
1567 prev->next = cur;
1568 cur->prev = prev;
1569 }
1570 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001571
Daniel Veillarda880b122003-04-21 21:36:41 +00001572 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001573 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001574 return(cur);
1575}
1576
1577/**
1578 * xmlNewNsProp:
1579 * @node: the holding node
1580 * @ns: the namespace
1581 * @name: the name of the attribute
1582 * @value: the value of the attribute
1583 *
1584 * Create a new property tagged with a namespace and carried by a node.
1585 * Returns a pointer to the attribute
1586 */
1587xmlAttrPtr
1588xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1589 const xmlChar *value) {
1590 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001591 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001592
1593 if (name == NULL) {
1594#ifdef DEBUG_TREE
1595 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001596 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001597#endif
1598 return(NULL);
1599 }
1600
1601 /*
1602 * Allocate a new property and fill the fields.
1603 */
1604 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1605 if (cur == NULL) {
1606 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001607 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001608 return(NULL);
1609 }
1610 memset(cur, 0, sizeof(xmlAttr));
1611 cur->type = XML_ATTRIBUTE_NODE;
1612
1613 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001614 if (node != NULL) {
1615 doc = node->doc;
1616 cur->doc = doc;
1617 }
Owen Taylor3473f882001-02-23 17:55:21 +00001618 cur->ns = ns;
1619 cur->name = xmlStrdup(name);
1620 if (value != NULL) {
1621 xmlChar *buffer;
1622 xmlNodePtr tmp;
1623
Daniel Veillarda682b212001-06-07 19:59:42 +00001624 buffer = xmlEncodeEntitiesReentrant(doc, value);
1625 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001626 cur->last = NULL;
1627 tmp = cur->children;
1628 while (tmp != NULL) {
1629 tmp->parent = (xmlNodePtr) cur;
1630 if (tmp->next == NULL)
1631 cur->last = tmp;
1632 tmp = tmp->next;
1633 }
1634 xmlFree(buffer);
1635 }
1636
1637 /*
1638 * Add it at the end to preserve parsing order ...
1639 */
1640 if (node != NULL) {
1641 if (node->properties == NULL) {
1642 node->properties = cur;
1643 } else {
1644 xmlAttrPtr prev = node->properties;
1645
1646 while (prev->next != NULL) prev = prev->next;
1647 prev->next = cur;
1648 cur->prev = prev;
1649 }
1650 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001651
Daniel Veillarda880b122003-04-21 21:36:41 +00001652 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001653 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001654 return(cur);
1655}
1656
1657/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001658 * xmlNewNsPropEatName:
1659 * @node: the holding node
1660 * @ns: the namespace
1661 * @name: the name of the attribute
1662 * @value: the value of the attribute
1663 *
1664 * Create a new property tagged with a namespace and carried by a node.
1665 * Returns a pointer to the attribute
1666 */
1667xmlAttrPtr
1668xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1669 const xmlChar *value) {
1670 xmlAttrPtr cur;
1671 xmlDocPtr doc = NULL;
1672
1673 if (name == NULL) {
1674#ifdef DEBUG_TREE
1675 xmlGenericError(xmlGenericErrorContext,
1676 "xmlNewNsPropEatName : name == NULL\n");
1677#endif
1678 return(NULL);
1679 }
1680
1681 /*
1682 * Allocate a new property and fill the fields.
1683 */
1684 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1685 if (cur == NULL) {
1686 xmlGenericError(xmlGenericErrorContext,
1687 "xmlNewNsPropEatName : malloc failed\n");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001688 xmlFree(name);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001689 return(NULL);
1690 }
1691 memset(cur, 0, sizeof(xmlAttr));
1692 cur->type = XML_ATTRIBUTE_NODE;
1693
1694 cur->parent = node;
1695 if (node != NULL) {
1696 doc = node->doc;
1697 cur->doc = doc;
1698 }
1699 cur->ns = ns;
1700 cur->name = name;
1701 if (value != NULL) {
1702 xmlChar *buffer;
1703 xmlNodePtr tmp;
1704
1705 buffer = xmlEncodeEntitiesReentrant(doc, value);
1706 cur->children = xmlStringGetNodeList(doc, buffer);
1707 cur->last = NULL;
1708 tmp = cur->children;
1709 while (tmp != NULL) {
1710 tmp->parent = (xmlNodePtr) cur;
1711 if (tmp->next == NULL)
1712 cur->last = tmp;
1713 tmp = tmp->next;
1714 }
1715 xmlFree(buffer);
1716 }
1717
1718 /*
1719 * Add it at the end to preserve parsing order ...
1720 */
1721 if (node != NULL) {
1722 if (node->properties == NULL) {
1723 node->properties = cur;
1724 } else {
1725 xmlAttrPtr prev = node->properties;
1726
1727 while (prev->next != NULL) prev = prev->next;
1728 prev->next = cur;
1729 cur->prev = prev;
1730 }
1731 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001732
Daniel Veillarda880b122003-04-21 21:36:41 +00001733 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001734 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001735 return(cur);
1736}
1737
1738/**
Owen Taylor3473f882001-02-23 17:55:21 +00001739 * xmlNewDocProp:
1740 * @doc: the document
1741 * @name: the name of the attribute
1742 * @value: the value of the attribute
1743 *
1744 * Create a new property carried by a document.
1745 * Returns a pointer to the attribute
1746 */
1747xmlAttrPtr
1748xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1749 xmlAttrPtr cur;
1750
1751 if (name == NULL) {
1752#ifdef DEBUG_TREE
1753 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001754 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001755#endif
1756 return(NULL);
1757 }
1758
1759 /*
1760 * Allocate a new property and fill the fields.
1761 */
1762 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1763 if (cur == NULL) {
1764 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001765 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001766 return(NULL);
1767 }
1768 memset(cur, 0, sizeof(xmlAttr));
1769 cur->type = XML_ATTRIBUTE_NODE;
1770
1771 cur->name = xmlStrdup(name);
1772 cur->doc = doc;
1773 if (value != NULL) {
1774 xmlNodePtr tmp;
1775
1776 cur->children = xmlStringGetNodeList(doc, value);
1777 cur->last = NULL;
1778
1779 tmp = cur->children;
1780 while (tmp != NULL) {
1781 tmp->parent = (xmlNodePtr) cur;
1782 if (tmp->next == NULL)
1783 cur->last = tmp;
1784 tmp = tmp->next;
1785 }
1786 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001787
Daniel Veillarda880b122003-04-21 21:36:41 +00001788 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001789 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001790 return(cur);
1791}
1792
1793/**
1794 * xmlFreePropList:
1795 * @cur: the first property in the list
1796 *
1797 * Free a property and all its siblings, all the children are freed too.
1798 */
1799void
1800xmlFreePropList(xmlAttrPtr cur) {
1801 xmlAttrPtr next;
1802 if (cur == NULL) {
1803#ifdef DEBUG_TREE
1804 xmlGenericError(xmlGenericErrorContext,
1805 "xmlFreePropList : property == NULL\n");
1806#endif
1807 return;
1808 }
1809 while (cur != NULL) {
1810 next = cur->next;
1811 xmlFreeProp(cur);
1812 cur = next;
1813 }
1814}
1815
1816/**
1817 * xmlFreeProp:
1818 * @cur: an attribute
1819 *
1820 * Free one attribute, all the content is freed too
1821 */
1822void
1823xmlFreeProp(xmlAttrPtr cur) {
1824 if (cur == NULL) {
1825#ifdef DEBUG_TREE
1826 xmlGenericError(xmlGenericErrorContext,
1827 "xmlFreeProp : property == NULL\n");
1828#endif
1829 return;
1830 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001831
Daniel Veillarda880b122003-04-21 21:36:41 +00001832 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001833 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1834
Owen Taylor3473f882001-02-23 17:55:21 +00001835 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001836 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1837 ((cur->parent->doc->intSubset != NULL) ||
1838 (cur->parent->doc->extSubset != NULL))) {
1839 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1840 xmlRemoveID(cur->parent->doc, cur);
1841 }
Owen Taylor3473f882001-02-23 17:55:21 +00001842 if (cur->name != NULL) xmlFree((char *) cur->name);
1843 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001844 xmlFree(cur);
1845}
1846
1847/**
1848 * xmlRemoveProp:
1849 * @cur: an attribute
1850 *
1851 * Unlink and free one attribute, all the content is freed too
1852 * Note this doesn't work for namespace definition attributes
1853 *
1854 * Returns 0 if success and -1 in case of error.
1855 */
1856int
1857xmlRemoveProp(xmlAttrPtr cur) {
1858 xmlAttrPtr tmp;
1859 if (cur == NULL) {
1860#ifdef DEBUG_TREE
1861 xmlGenericError(xmlGenericErrorContext,
1862 "xmlRemoveProp : cur == NULL\n");
1863#endif
1864 return(-1);
1865 }
1866 if (cur->parent == NULL) {
1867#ifdef DEBUG_TREE
1868 xmlGenericError(xmlGenericErrorContext,
1869 "xmlRemoveProp : cur->parent == NULL\n");
1870#endif
1871 return(-1);
1872 }
1873 tmp = cur->parent->properties;
1874 if (tmp == cur) {
1875 cur->parent->properties = cur->next;
1876 xmlFreeProp(cur);
1877 return(0);
1878 }
1879 while (tmp != NULL) {
1880 if (tmp->next == cur) {
1881 tmp->next = cur->next;
1882 if (tmp->next != NULL)
1883 tmp->next->prev = tmp;
1884 xmlFreeProp(cur);
1885 return(0);
1886 }
1887 tmp = tmp->next;
1888 }
1889#ifdef DEBUG_TREE
1890 xmlGenericError(xmlGenericErrorContext,
1891 "xmlRemoveProp : attribute not owned by its node\n");
1892#endif
1893 return(-1);
1894}
1895
1896/**
1897 * xmlNewPI:
1898 * @name: the processing instruction name
1899 * @content: the PI content
1900 *
1901 * Creation of a processing instruction element.
1902 * Returns a pointer to the new node object.
1903 */
1904xmlNodePtr
1905xmlNewPI(const xmlChar *name, const xmlChar *content) {
1906 xmlNodePtr cur;
1907
1908 if (name == NULL) {
1909#ifdef DEBUG_TREE
1910 xmlGenericError(xmlGenericErrorContext,
1911 "xmlNewPI : name == NULL\n");
1912#endif
1913 return(NULL);
1914 }
1915
1916 /*
1917 * Allocate a new node and fill the fields.
1918 */
1919 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1920 if (cur == NULL) {
1921 xmlGenericError(xmlGenericErrorContext,
1922 "xmlNewPI : malloc failed\n");
1923 return(NULL);
1924 }
1925 memset(cur, 0, sizeof(xmlNode));
1926 cur->type = XML_PI_NODE;
1927
1928 cur->name = xmlStrdup(name);
1929 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001930 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001931 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001932
Daniel Veillarda880b122003-04-21 21:36:41 +00001933 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001934 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001935 return(cur);
1936}
1937
1938/**
1939 * xmlNewNode:
1940 * @ns: namespace if any
1941 * @name: the node name
1942 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001943 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001944 *
1945 * Returns a pointer to the new node object.
1946 */
1947xmlNodePtr
1948xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1949 xmlNodePtr cur;
1950
1951 if (name == NULL) {
1952#ifdef DEBUG_TREE
1953 xmlGenericError(xmlGenericErrorContext,
1954 "xmlNewNode : name == NULL\n");
1955#endif
1956 return(NULL);
1957 }
1958
1959 /*
1960 * Allocate a new node and fill the fields.
1961 */
1962 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1963 if (cur == NULL) {
1964 xmlGenericError(xmlGenericErrorContext,
1965 "xmlNewNode : malloc failed\n");
1966 return(NULL);
1967 }
1968 memset(cur, 0, sizeof(xmlNode));
1969 cur->type = XML_ELEMENT_NODE;
1970
1971 cur->name = xmlStrdup(name);
1972 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001973
Daniel Veillarda880b122003-04-21 21:36:41 +00001974 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001975 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001976 return(cur);
1977}
1978
1979/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001980 * xmlNewNodeEatName:
1981 * @ns: namespace if any
1982 * @name: the node name
1983 *
1984 * Creation of a new node element. @ns is optional (NULL).
1985 *
1986 * Returns a pointer to the new node object.
1987 */
1988xmlNodePtr
1989xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
1990 xmlNodePtr cur;
1991
1992 if (name == NULL) {
1993#ifdef DEBUG_TREE
1994 xmlGenericError(xmlGenericErrorContext,
1995 "xmlNewNode : name == NULL\n");
1996#endif
1997 return(NULL);
1998 }
1999
2000 /*
2001 * Allocate a new node and fill the fields.
2002 */
2003 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2004 if (cur == NULL) {
2005 xmlGenericError(xmlGenericErrorContext,
2006 "xmlNewNode : malloc failed\n");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00002007 xmlFree(name);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002008 return(NULL);
2009 }
2010 memset(cur, 0, sizeof(xmlNode));
2011 cur->type = XML_ELEMENT_NODE;
2012
2013 cur->name = name;
2014 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002015
Daniel Veillarda880b122003-04-21 21:36:41 +00002016 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002017 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002018 return(cur);
2019}
2020
2021/**
Owen Taylor3473f882001-02-23 17:55:21 +00002022 * xmlNewDocNode:
2023 * @doc: the document
2024 * @ns: namespace if any
2025 * @name: the node name
2026 * @content: the XML text content if any
2027 *
2028 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002029 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002030 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2031 * references, but XML special chars need to be escaped first by using
2032 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2033 * need entities support.
2034 *
2035 * Returns a pointer to the new node object.
2036 */
2037xmlNodePtr
2038xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2039 const xmlChar *name, const xmlChar *content) {
2040 xmlNodePtr cur;
2041
2042 cur = xmlNewNode(ns, name);
2043 if (cur != NULL) {
2044 cur->doc = doc;
2045 if (content != NULL) {
2046 cur->children = xmlStringGetNodeList(doc, content);
2047 UPDATE_LAST_CHILD_AND_PARENT(cur)
2048 }
2049 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002050
Owen Taylor3473f882001-02-23 17:55:21 +00002051 return(cur);
2052}
2053
Daniel Veillard46de64e2002-05-29 08:21:33 +00002054/**
2055 * xmlNewDocNodeEatName:
2056 * @doc: the document
2057 * @ns: namespace if any
2058 * @name: the node name
2059 * @content: the XML text content if any
2060 *
2061 * Creation of a new node element within a document. @ns and @content
2062 * are optional (NULL).
2063 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2064 * references, but XML special chars need to be escaped first by using
2065 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2066 * need entities support.
2067 *
2068 * Returns a pointer to the new node object.
2069 */
2070xmlNodePtr
2071xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2072 xmlChar *name, const xmlChar *content) {
2073 xmlNodePtr cur;
2074
2075 cur = xmlNewNodeEatName(ns, name);
2076 if (cur != NULL) {
2077 cur->doc = doc;
2078 if (content != NULL) {
2079 cur->children = xmlStringGetNodeList(doc, content);
2080 UPDATE_LAST_CHILD_AND_PARENT(cur)
2081 }
2082 }
2083 return(cur);
2084}
2085
Owen Taylor3473f882001-02-23 17:55:21 +00002086
2087/**
2088 * xmlNewDocRawNode:
2089 * @doc: the document
2090 * @ns: namespace if any
2091 * @name: the node name
2092 * @content: the text content if any
2093 *
2094 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002095 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002096 *
2097 * Returns a pointer to the new node object.
2098 */
2099xmlNodePtr
2100xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2101 const xmlChar *name, const xmlChar *content) {
2102 xmlNodePtr cur;
2103
2104 cur = xmlNewNode(ns, name);
2105 if (cur != NULL) {
2106 cur->doc = doc;
2107 if (content != NULL) {
2108 cur->children = xmlNewDocText(doc, content);
2109 UPDATE_LAST_CHILD_AND_PARENT(cur)
2110 }
2111 }
2112 return(cur);
2113}
2114
2115/**
2116 * xmlNewDocFragment:
2117 * @doc: the document owning the fragment
2118 *
2119 * Creation of a new Fragment node.
2120 * Returns a pointer to the new node object.
2121 */
2122xmlNodePtr
2123xmlNewDocFragment(xmlDocPtr doc) {
2124 xmlNodePtr cur;
2125
2126 /*
2127 * Allocate a new DocumentFragment node and fill the fields.
2128 */
2129 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2130 if (cur == NULL) {
2131 xmlGenericError(xmlGenericErrorContext,
2132 "xmlNewDocFragment : malloc failed\n");
2133 return(NULL);
2134 }
2135 memset(cur, 0, sizeof(xmlNode));
2136 cur->type = XML_DOCUMENT_FRAG_NODE;
2137
2138 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002139
Daniel Veillarda880b122003-04-21 21:36:41 +00002140 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002141 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002142 return(cur);
2143}
2144
2145/**
2146 * xmlNewText:
2147 * @content: the text content
2148 *
2149 * Creation of a new text node.
2150 * Returns a pointer to the new node object.
2151 */
2152xmlNodePtr
2153xmlNewText(const xmlChar *content) {
2154 xmlNodePtr cur;
2155
2156 /*
2157 * Allocate a new node and fill the fields.
2158 */
2159 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2160 if (cur == NULL) {
2161 xmlGenericError(xmlGenericErrorContext,
2162 "xmlNewText : malloc failed\n");
2163 return(NULL);
2164 }
2165 memset(cur, 0, sizeof(xmlNode));
2166 cur->type = XML_TEXT_NODE;
2167
2168 cur->name = xmlStringText;
2169 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002170 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002171 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002172
Daniel Veillarda880b122003-04-21 21:36:41 +00002173 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002174 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002175 return(cur);
2176}
2177
2178/**
2179 * xmlNewTextChild:
2180 * @parent: the parent node
2181 * @ns: a namespace if any
2182 * @name: the name of the child
2183 * @content: the text content of the child if any.
2184 *
2185 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002186 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002187 * a child TEXT node will be created containing the string content.
2188 *
2189 * Returns a pointer to the new node object.
2190 */
2191xmlNodePtr
2192xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2193 const xmlChar *name, const xmlChar *content) {
2194 xmlNodePtr cur, prev;
2195
2196 if (parent == NULL) {
2197#ifdef DEBUG_TREE
2198 xmlGenericError(xmlGenericErrorContext,
2199 "xmlNewTextChild : parent == NULL\n");
2200#endif
2201 return(NULL);
2202 }
2203
2204 if (name == NULL) {
2205#ifdef DEBUG_TREE
2206 xmlGenericError(xmlGenericErrorContext,
2207 "xmlNewTextChild : name == NULL\n");
2208#endif
2209 return(NULL);
2210 }
2211
2212 /*
2213 * Allocate a new node
2214 */
2215 if (ns == NULL)
2216 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2217 else
2218 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2219 if (cur == NULL) return(NULL);
2220
2221 /*
2222 * add the new element at the end of the children list.
2223 */
2224 cur->type = XML_ELEMENT_NODE;
2225 cur->parent = parent;
2226 cur->doc = parent->doc;
2227 if (parent->children == NULL) {
2228 parent->children = cur;
2229 parent->last = cur;
2230 } else {
2231 prev = parent->last;
2232 prev->next = cur;
2233 cur->prev = prev;
2234 parent->last = cur;
2235 }
2236
2237 return(cur);
2238}
2239
2240/**
2241 * xmlNewCharRef:
2242 * @doc: the document
2243 * @name: the char ref string, starting with # or "&# ... ;"
2244 *
2245 * Creation of a new character reference node.
2246 * Returns a pointer to the new node object.
2247 */
2248xmlNodePtr
2249xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2250 xmlNodePtr cur;
2251
2252 /*
2253 * Allocate a new node and fill the fields.
2254 */
2255 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2256 if (cur == NULL) {
2257 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002258 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002259 return(NULL);
2260 }
2261 memset(cur, 0, sizeof(xmlNode));
2262 cur->type = XML_ENTITY_REF_NODE;
2263
2264 cur->doc = doc;
2265 if (name[0] == '&') {
2266 int len;
2267 name++;
2268 len = xmlStrlen(name);
2269 if (name[len - 1] == ';')
2270 cur->name = xmlStrndup(name, len - 1);
2271 else
2272 cur->name = xmlStrndup(name, len);
2273 } else
2274 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002275
Daniel Veillarda880b122003-04-21 21:36:41 +00002276 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002277 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002278 return(cur);
2279}
2280
2281/**
2282 * xmlNewReference:
2283 * @doc: the document
2284 * @name: the reference name, or the reference string with & and ;
2285 *
2286 * Creation of a new reference node.
2287 * Returns a pointer to the new node object.
2288 */
2289xmlNodePtr
2290xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2291 xmlNodePtr cur;
2292 xmlEntityPtr ent;
2293
2294 /*
2295 * Allocate a new node and fill the fields.
2296 */
2297 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2298 if (cur == NULL) {
2299 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002300 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002301 return(NULL);
2302 }
2303 memset(cur, 0, sizeof(xmlNode));
2304 cur->type = XML_ENTITY_REF_NODE;
2305
2306 cur->doc = doc;
2307 if (name[0] == '&') {
2308 int len;
2309 name++;
2310 len = xmlStrlen(name);
2311 if (name[len - 1] == ';')
2312 cur->name = xmlStrndup(name, len - 1);
2313 else
2314 cur->name = xmlStrndup(name, len);
2315 } else
2316 cur->name = xmlStrdup(name);
2317
2318 ent = xmlGetDocEntity(doc, cur->name);
2319 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002320 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002321 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002322 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002323 * updated. Not sure if this is 100% correct.
2324 * -George
2325 */
2326 cur->children = (xmlNodePtr) ent;
2327 cur->last = (xmlNodePtr) ent;
2328 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002329
Daniel Veillarda880b122003-04-21 21:36:41 +00002330 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002331 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002332 return(cur);
2333}
2334
2335/**
2336 * xmlNewDocText:
2337 * @doc: the document
2338 * @content: the text content
2339 *
2340 * Creation of a new text node within a document.
2341 * Returns a pointer to the new node object.
2342 */
2343xmlNodePtr
2344xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2345 xmlNodePtr cur;
2346
2347 cur = xmlNewText(content);
2348 if (cur != NULL) cur->doc = doc;
2349 return(cur);
2350}
2351
2352/**
2353 * xmlNewTextLen:
2354 * @content: the text content
2355 * @len: the text len.
2356 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002357 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002358 * Returns a pointer to the new node object.
2359 */
2360xmlNodePtr
2361xmlNewTextLen(const xmlChar *content, int len) {
2362 xmlNodePtr cur;
2363
2364 /*
2365 * Allocate a new node and fill the fields.
2366 */
2367 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2368 if (cur == NULL) {
2369 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002370 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002371 return(NULL);
2372 }
2373 memset(cur, 0, sizeof(xmlNode));
2374 cur->type = XML_TEXT_NODE;
2375
2376 cur->name = xmlStringText;
2377 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002378 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002379 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002380
Daniel Veillarda880b122003-04-21 21:36:41 +00002381 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002382 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002383 return(cur);
2384}
2385
2386/**
2387 * xmlNewDocTextLen:
2388 * @doc: the document
2389 * @content: the text content
2390 * @len: the text len.
2391 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002392 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002393 * text node pertain to a given document.
2394 * Returns a pointer to the new node object.
2395 */
2396xmlNodePtr
2397xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2398 xmlNodePtr cur;
2399
2400 cur = xmlNewTextLen(content, len);
2401 if (cur != NULL) cur->doc = doc;
2402 return(cur);
2403}
2404
2405/**
2406 * xmlNewComment:
2407 * @content: the comment content
2408 *
2409 * Creation of a new node containing a comment.
2410 * Returns a pointer to the new node object.
2411 */
2412xmlNodePtr
2413xmlNewComment(const xmlChar *content) {
2414 xmlNodePtr cur;
2415
2416 /*
2417 * Allocate a new node and fill the fields.
2418 */
2419 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2420 if (cur == NULL) {
2421 xmlGenericError(xmlGenericErrorContext,
2422 "xmlNewComment : malloc failed\n");
2423 return(NULL);
2424 }
2425 memset(cur, 0, sizeof(xmlNode));
2426 cur->type = XML_COMMENT_NODE;
2427
2428 cur->name = xmlStringComment;
2429 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002430 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002431 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002432
Daniel Veillarda880b122003-04-21 21:36:41 +00002433 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002434 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002435 return(cur);
2436}
2437
2438/**
2439 * xmlNewCDataBlock:
2440 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002441 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002442 * @len: the length of the block
2443 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002444 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002445 * Returns a pointer to the new node object.
2446 */
2447xmlNodePtr
2448xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2449 xmlNodePtr cur;
2450
2451 /*
2452 * Allocate a new node and fill the fields.
2453 */
2454 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2455 if (cur == NULL) {
2456 xmlGenericError(xmlGenericErrorContext,
2457 "xmlNewCDataBlock : malloc failed\n");
2458 return(NULL);
2459 }
2460 memset(cur, 0, sizeof(xmlNode));
2461 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002462 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002463
2464 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002465 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002466 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002467
Daniel Veillarda880b122003-04-21 21:36:41 +00002468 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002469 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002470 return(cur);
2471}
2472
2473/**
2474 * xmlNewDocComment:
2475 * @doc: the document
2476 * @content: the comment content
2477 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002478 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002479 * Returns a pointer to the new node object.
2480 */
2481xmlNodePtr
2482xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2483 xmlNodePtr cur;
2484
2485 cur = xmlNewComment(content);
2486 if (cur != NULL) cur->doc = doc;
2487 return(cur);
2488}
2489
2490/**
2491 * xmlSetTreeDoc:
2492 * @tree: the top element
2493 * @doc: the document
2494 *
2495 * update all nodes under the tree to point to the right document
2496 */
2497void
2498xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002499 xmlAttrPtr prop;
2500
Owen Taylor3473f882001-02-23 17:55:21 +00002501 if (tree == NULL)
2502 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002503 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002504 if(tree->type == XML_ELEMENT_NODE) {
2505 prop = tree->properties;
2506 while (prop != NULL) {
2507 prop->doc = doc;
2508 xmlSetListDoc(prop->children, doc);
2509 prop = prop->next;
2510 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002511 }
Owen Taylor3473f882001-02-23 17:55:21 +00002512 if (tree->children != NULL)
2513 xmlSetListDoc(tree->children, doc);
2514 tree->doc = doc;
2515 }
2516}
2517
2518/**
2519 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002520 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002521 * @doc: the document
2522 *
2523 * update all nodes in the list to point to the right document
2524 */
2525void
2526xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2527 xmlNodePtr cur;
2528
2529 if (list == NULL)
2530 return;
2531 cur = list;
2532 while (cur != NULL) {
2533 if (cur->doc != doc)
2534 xmlSetTreeDoc(cur, doc);
2535 cur = cur->next;
2536 }
2537}
2538
2539
2540/**
2541 * xmlNewChild:
2542 * @parent: the parent node
2543 * @ns: a namespace if any
2544 * @name: the name of the child
2545 * @content: the XML content of the child if any.
2546 *
2547 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002548 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002549 * a child list containing the TEXTs and ENTITY_REFs node will be created.
2550 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2551 * references, but XML special chars need to be escaped first by using
2552 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
2553 * support is not needed.
2554 *
2555 * Returns a pointer to the new node object.
2556 */
2557xmlNodePtr
2558xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2559 const xmlChar *name, const xmlChar *content) {
2560 xmlNodePtr cur, prev;
2561
2562 if (parent == NULL) {
2563#ifdef DEBUG_TREE
2564 xmlGenericError(xmlGenericErrorContext,
2565 "xmlNewChild : parent == NULL\n");
2566#endif
2567 return(NULL);
2568 }
2569
2570 if (name == NULL) {
2571#ifdef DEBUG_TREE
2572 xmlGenericError(xmlGenericErrorContext,
2573 "xmlNewChild : name == NULL\n");
2574#endif
2575 return(NULL);
2576 }
2577
2578 /*
2579 * Allocate a new node
2580 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002581 if (parent->type == XML_ELEMENT_NODE) {
2582 if (ns == NULL)
2583 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2584 else
2585 cur = xmlNewDocNode(parent->doc, ns, name, content);
2586 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2587 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2588 if (ns == NULL)
2589 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2590 else
2591 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002592 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2593 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002594 } else {
2595 return(NULL);
2596 }
Owen Taylor3473f882001-02-23 17:55:21 +00002597 if (cur == NULL) return(NULL);
2598
2599 /*
2600 * add the new element at the end of the children list.
2601 */
2602 cur->type = XML_ELEMENT_NODE;
2603 cur->parent = parent;
2604 cur->doc = parent->doc;
2605 if (parent->children == NULL) {
2606 parent->children = cur;
2607 parent->last = cur;
2608 } else {
2609 prev = parent->last;
2610 prev->next = cur;
2611 cur->prev = prev;
2612 parent->last = cur;
2613 }
2614
2615 return(cur);
2616}
2617
2618/**
2619 * xmlAddNextSibling:
2620 * @cur: the child node
2621 * @elem: the new node
2622 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002623 * Add a new node @elem as the next sibling of @cur
2624 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002625 * first unlinked from its existing context.
2626 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002627 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2628 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002629 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002630 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002631 */
2632xmlNodePtr
2633xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2634 if (cur == NULL) {
2635#ifdef DEBUG_TREE
2636 xmlGenericError(xmlGenericErrorContext,
2637 "xmlAddNextSibling : cur == NULL\n");
2638#endif
2639 return(NULL);
2640 }
2641 if (elem == NULL) {
2642#ifdef DEBUG_TREE
2643 xmlGenericError(xmlGenericErrorContext,
2644 "xmlAddNextSibling : elem == NULL\n");
2645#endif
2646 return(NULL);
2647 }
2648
2649 xmlUnlinkNode(elem);
2650
2651 if (elem->type == XML_TEXT_NODE) {
2652 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002653 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002654 xmlFreeNode(elem);
2655 return(cur);
2656 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002657 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2658 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002659 xmlChar *tmp;
2660
2661 tmp = xmlStrdup(elem->content);
2662 tmp = xmlStrcat(tmp, cur->next->content);
2663 xmlNodeSetContent(cur->next, tmp);
2664 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002665 xmlFreeNode(elem);
2666 return(cur->next);
2667 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002668 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2669 /* check if an attribute with the same name exists */
2670 xmlAttrPtr attr;
2671
2672 if (elem->ns == NULL)
2673 attr = xmlHasProp(cur->parent, elem->name);
2674 else
2675 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2676 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2677 /* different instance, destroy it (attributes must be unique) */
2678 xmlFreeProp(attr);
2679 }
Owen Taylor3473f882001-02-23 17:55:21 +00002680 }
2681
2682 if (elem->doc != cur->doc) {
2683 xmlSetTreeDoc(elem, cur->doc);
2684 }
2685 elem->parent = cur->parent;
2686 elem->prev = cur;
2687 elem->next = cur->next;
2688 cur->next = elem;
2689 if (elem->next != NULL)
2690 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002691 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002692 elem->parent->last = elem;
2693 return(elem);
2694}
2695
2696/**
2697 * xmlAddPrevSibling:
2698 * @cur: the child node
2699 * @elem: the new node
2700 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002701 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002702 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002703 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002704 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002705 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2706 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002707 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002708 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002709 */
2710xmlNodePtr
2711xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2712 if (cur == NULL) {
2713#ifdef DEBUG_TREE
2714 xmlGenericError(xmlGenericErrorContext,
2715 "xmlAddPrevSibling : cur == NULL\n");
2716#endif
2717 return(NULL);
2718 }
2719 if (elem == NULL) {
2720#ifdef DEBUG_TREE
2721 xmlGenericError(xmlGenericErrorContext,
2722 "xmlAddPrevSibling : elem == NULL\n");
2723#endif
2724 return(NULL);
2725 }
2726
2727 xmlUnlinkNode(elem);
2728
2729 if (elem->type == XML_TEXT_NODE) {
2730 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002731 xmlChar *tmp;
2732
2733 tmp = xmlStrdup(elem->content);
2734 tmp = xmlStrcat(tmp, cur->content);
2735 xmlNodeSetContent(cur, tmp);
2736 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002737 xmlFreeNode(elem);
2738 return(cur);
2739 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002740 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2741 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002742 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002743 xmlFreeNode(elem);
2744 return(cur->prev);
2745 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002746 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2747 /* check if an attribute with the same name exists */
2748 xmlAttrPtr attr;
2749
2750 if (elem->ns == NULL)
2751 attr = xmlHasProp(cur->parent, elem->name);
2752 else
2753 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2754 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2755 /* different instance, destroy it (attributes must be unique) */
2756 xmlFreeProp(attr);
2757 }
Owen Taylor3473f882001-02-23 17:55:21 +00002758 }
2759
2760 if (elem->doc != cur->doc) {
2761 xmlSetTreeDoc(elem, cur->doc);
2762 }
2763 elem->parent = cur->parent;
2764 elem->next = cur;
2765 elem->prev = cur->prev;
2766 cur->prev = elem;
2767 if (elem->prev != NULL)
2768 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002769 if (elem->parent != NULL) {
2770 if (elem->type == XML_ATTRIBUTE_NODE) {
2771 if (elem->parent->properties == (xmlAttrPtr) cur) {
2772 elem->parent->properties = (xmlAttrPtr) elem;
2773 }
2774 } else {
2775 if (elem->parent->children == cur) {
2776 elem->parent->children = elem;
2777 }
2778 }
2779 }
Owen Taylor3473f882001-02-23 17:55:21 +00002780 return(elem);
2781}
2782
2783/**
2784 * xmlAddSibling:
2785 * @cur: the child node
2786 * @elem: the new node
2787 *
2788 * Add a new element @elem to the list of siblings of @cur
2789 * merging adjacent TEXT nodes (@elem may be freed)
2790 * If the new element was already inserted in a document it is
2791 * first unlinked from its existing context.
2792 *
2793 * Returns the new element or NULL in case of error.
2794 */
2795xmlNodePtr
2796xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2797 xmlNodePtr parent;
2798
2799 if (cur == NULL) {
2800#ifdef DEBUG_TREE
2801 xmlGenericError(xmlGenericErrorContext,
2802 "xmlAddSibling : cur == NULL\n");
2803#endif
2804 return(NULL);
2805 }
2806
2807 if (elem == NULL) {
2808#ifdef DEBUG_TREE
2809 xmlGenericError(xmlGenericErrorContext,
2810 "xmlAddSibling : elem == NULL\n");
2811#endif
2812 return(NULL);
2813 }
2814
2815 /*
2816 * Constant time is we can rely on the ->parent->last to find
2817 * the last sibling.
2818 */
2819 if ((cur->parent != NULL) &&
2820 (cur->parent->children != NULL) &&
2821 (cur->parent->last != NULL) &&
2822 (cur->parent->last->next == NULL)) {
2823 cur = cur->parent->last;
2824 } else {
2825 while (cur->next != NULL) cur = cur->next;
2826 }
2827
2828 xmlUnlinkNode(elem);
2829
2830 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002831 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002832 xmlFreeNode(elem);
2833 return(cur);
2834 }
2835
2836 if (elem->doc != cur->doc) {
2837 xmlSetTreeDoc(elem, cur->doc);
2838 }
2839 parent = cur->parent;
2840 elem->prev = cur;
2841 elem->next = NULL;
2842 elem->parent = parent;
2843 cur->next = elem;
2844 if (parent != NULL)
2845 parent->last = elem;
2846
2847 return(elem);
2848}
2849
2850/**
2851 * xmlAddChildList:
2852 * @parent: the parent node
2853 * @cur: the first node in the list
2854 *
2855 * Add a list of node at the end of the child list of the parent
2856 * merging adjacent TEXT nodes (@cur may be freed)
2857 *
2858 * Returns the last child or NULL in case of error.
2859 */
2860xmlNodePtr
2861xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2862 xmlNodePtr prev;
2863
2864 if (parent == NULL) {
2865#ifdef DEBUG_TREE
2866 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002867 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002868#endif
2869 return(NULL);
2870 }
2871
2872 if (cur == NULL) {
2873#ifdef DEBUG_TREE
2874 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002875 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002876#endif
2877 return(NULL);
2878 }
2879
2880 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2881 (cur->doc != parent->doc)) {
2882#ifdef DEBUG_TREE
2883 xmlGenericError(xmlGenericErrorContext,
2884 "Elements moved to a different document\n");
2885#endif
2886 }
2887
2888 /*
2889 * add the first element at the end of the children list.
2890 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00002891
Owen Taylor3473f882001-02-23 17:55:21 +00002892 if (parent->children == NULL) {
2893 parent->children = cur;
2894 } else {
2895 /*
2896 * If cur and parent->last both are TEXT nodes, then merge them.
2897 */
2898 if ((cur->type == XML_TEXT_NODE) &&
2899 (parent->last->type == XML_TEXT_NODE) &&
2900 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00002901 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002902 /*
2903 * if it's the only child, nothing more to be done.
2904 */
2905 if (cur->next == NULL) {
2906 xmlFreeNode(cur);
2907 return(parent->last);
2908 }
2909 prev = cur;
2910 cur = cur->next;
2911 xmlFreeNode(prev);
2912 }
2913 prev = parent->last;
2914 prev->next = cur;
2915 cur->prev = prev;
2916 }
2917 while (cur->next != NULL) {
2918 cur->parent = parent;
2919 if (cur->doc != parent->doc) {
2920 xmlSetTreeDoc(cur, parent->doc);
2921 }
2922 cur = cur->next;
2923 }
2924 cur->parent = parent;
2925 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2926 parent->last = cur;
2927
2928 return(cur);
2929}
2930
2931/**
2932 * xmlAddChild:
2933 * @parent: the parent node
2934 * @cur: the child node
2935 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002936 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00002937 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002938 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2939 * If there is an attribute with equal name, it is first destroyed.
2940 *
Owen Taylor3473f882001-02-23 17:55:21 +00002941 * Returns the child or NULL in case of error.
2942 */
2943xmlNodePtr
2944xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2945 xmlNodePtr prev;
2946
2947 if (parent == NULL) {
2948#ifdef DEBUG_TREE
2949 xmlGenericError(xmlGenericErrorContext,
2950 "xmlAddChild : parent == NULL\n");
2951#endif
2952 return(NULL);
2953 }
2954
2955 if (cur == NULL) {
2956#ifdef DEBUG_TREE
2957 xmlGenericError(xmlGenericErrorContext,
2958 "xmlAddChild : child == NULL\n");
2959#endif
2960 return(NULL);
2961 }
2962
Owen Taylor3473f882001-02-23 17:55:21 +00002963 /*
2964 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002965 * cur is then freed.
2966 */
2967 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002968 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002969 (parent->content != NULL) &&
2970 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002971 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002972 xmlFreeNode(cur);
2973 return(parent);
2974 }
2975 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002976 (parent->last->name == cur->name) &&
2977 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002978 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002979 xmlFreeNode(cur);
2980 return(parent->last);
2981 }
2982 }
2983
2984 /*
2985 * add the new element at the end of the children list.
2986 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00002987 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00002988 cur->parent = parent;
2989 if (cur->doc != parent->doc) {
2990 xmlSetTreeDoc(cur, parent->doc);
2991 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002992 /* this check prevents a loop on tree-traversions if a developer
2993 * tries to add a node to its parent multiple times
2994 */
2995 if (prev == parent)
2996 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002997
2998 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002999 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003000 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003001 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003002 (parent->content != NULL) &&
3003 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003004 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003005 xmlFreeNode(cur);
3006 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003007 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003008 if (cur->type == XML_ATTRIBUTE_NODE) {
3009 if (parent->properties == NULL) {
3010 parent->properties = (xmlAttrPtr) cur;
3011 } else {
3012 /* check if an attribute with the same name exists */
3013 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003014
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003015 if (cur->ns == NULL)
3016 lastattr = xmlHasProp(parent, cur->name);
3017 else
3018 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3019 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
3020 /* different instance, destroy it (attributes must be unique) */
3021 xmlFreeProp(lastattr);
3022 }
3023 /* find the end */
3024 lastattr = parent->properties;
3025 while (lastattr->next != NULL) {
3026 lastattr = lastattr->next;
3027 }
3028 lastattr->next = (xmlAttrPtr) cur;
3029 ((xmlAttrPtr) cur)->prev = lastattr;
3030 }
3031 } else {
3032 if (parent->children == NULL) {
3033 parent->children = cur;
3034 parent->last = cur;
3035 } else {
3036 prev = parent->last;
3037 prev->next = cur;
3038 cur->prev = prev;
3039 parent->last = cur;
3040 }
3041 }
Owen Taylor3473f882001-02-23 17:55:21 +00003042 return(cur);
3043}
3044
3045/**
3046 * xmlGetLastChild:
3047 * @parent: the parent node
3048 *
3049 * Search the last child of a node.
3050 * Returns the last child or NULL if none.
3051 */
3052xmlNodePtr
3053xmlGetLastChild(xmlNodePtr parent) {
3054 if (parent == NULL) {
3055#ifdef DEBUG_TREE
3056 xmlGenericError(xmlGenericErrorContext,
3057 "xmlGetLastChild : parent == NULL\n");
3058#endif
3059 return(NULL);
3060 }
3061 return(parent->last);
3062}
3063
3064/**
3065 * xmlFreeNodeList:
3066 * @cur: the first node in the list
3067 *
3068 * Free a node and all its siblings, this is a recursive behaviour, all
3069 * the children are freed too.
3070 */
3071void
3072xmlFreeNodeList(xmlNodePtr cur) {
3073 xmlNodePtr next;
3074 if (cur == NULL) {
3075#ifdef DEBUG_TREE
3076 xmlGenericError(xmlGenericErrorContext,
3077 "xmlFreeNodeList : node == NULL\n");
3078#endif
3079 return;
3080 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00003081 if (cur->type == XML_NAMESPACE_DECL) {
3082 xmlFreeNsList((xmlNsPtr) cur);
3083 return;
3084 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003085 if ((cur->type == XML_DOCUMENT_NODE) ||
3086#ifdef LIBXML_DOCB_ENABLED
3087 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003088#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003089 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003090 xmlFreeDoc((xmlDocPtr) cur);
3091 return;
3092 }
Owen Taylor3473f882001-02-23 17:55:21 +00003093 while (cur != NULL) {
3094 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003095 /* unroll to speed up freeing the document */
3096 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003097
Daniel Veillarda880b122003-04-21 21:36:41 +00003098 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003099 xmlDeregisterNodeDefaultValue(cur);
3100
Daniel Veillard02141ea2001-04-30 11:46:40 +00003101 if ((cur->children != NULL) &&
3102 (cur->type != XML_ENTITY_REF_NODE))
3103 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003104 if (((cur->type == XML_ELEMENT_NODE) ||
3105 (cur->type == XML_XINCLUDE_START) ||
3106 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003107 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003108 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003109 if ((cur->type != XML_ELEMENT_NODE) &&
3110 (cur->type != XML_XINCLUDE_START) &&
3111 (cur->type != XML_XINCLUDE_END) &&
3112 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00003113 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003114 }
3115 if (((cur->type == XML_ELEMENT_NODE) ||
3116 (cur->type == XML_XINCLUDE_START) ||
3117 (cur->type == XML_XINCLUDE_END)) &&
3118 (cur->nsDef != NULL))
3119 xmlFreeNsList(cur->nsDef);
3120
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003121 /*
3122 * When a node is a text node or a comment, it uses a global static
3123 * variable for the name of the node.
3124 *
3125 * The xmlStrEqual comparisons need to be done when (happened with
3126 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003127 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00003128 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003129 * the string addresses compare are not sufficient.
3130 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003131 if ((cur->name != NULL) &&
3132 (cur->name != xmlStringText) &&
3133 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003134 (cur->name != xmlStringComment)) {
3135 if (cur->type == XML_TEXT_NODE) {
3136 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
3137 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
3138 xmlFree((char *) cur->name);
3139 } else if (cur->type == XML_COMMENT_NODE) {
3140 if (!xmlStrEqual(cur->name, xmlStringComment))
3141 xmlFree((char *) cur->name);
3142 } else
3143 xmlFree((char *) cur->name);
3144 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00003145 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003146 xmlFree(cur);
3147 }
Owen Taylor3473f882001-02-23 17:55:21 +00003148 cur = next;
3149 }
3150}
3151
3152/**
3153 * xmlFreeNode:
3154 * @cur: the node
3155 *
3156 * Free a node, this is a recursive behaviour, all the children are freed too.
3157 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3158 */
3159void
3160xmlFreeNode(xmlNodePtr cur) {
3161 if (cur == NULL) {
3162#ifdef DEBUG_TREE
3163 xmlGenericError(xmlGenericErrorContext,
3164 "xmlFreeNode : node == NULL\n");
3165#endif
3166 return;
3167 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003168
Daniel Veillard02141ea2001-04-30 11:46:40 +00003169 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003170 if (cur->type == XML_DTD_NODE) {
3171 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003172 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003173 }
3174 if (cur->type == XML_NAMESPACE_DECL) {
3175 xmlFreeNs((xmlNsPtr) cur);
3176 return;
3177 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003178 if (cur->type == XML_ATTRIBUTE_NODE) {
3179 xmlFreeProp((xmlAttrPtr) cur);
3180 return;
3181 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003182
Daniel Veillarda880b122003-04-21 21:36:41 +00003183 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003184 xmlDeregisterNodeDefaultValue(cur);
3185
Owen Taylor3473f882001-02-23 17:55:21 +00003186 if ((cur->children != NULL) &&
3187 (cur->type != XML_ENTITY_REF_NODE))
3188 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003189 if (((cur->type == XML_ELEMENT_NODE) ||
3190 (cur->type == XML_XINCLUDE_START) ||
3191 (cur->type == XML_XINCLUDE_END)) &&
3192 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003193 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003194 if ((cur->type != XML_ELEMENT_NODE) &&
3195 (cur->content != NULL) &&
3196 (cur->type != XML_ENTITY_REF_NODE) &&
3197 (cur->type != XML_XINCLUDE_END) &&
3198 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003199 xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003200 }
3201
Daniel Veillardacd370f2001-06-09 17:17:51 +00003202 /*
3203 * When a node is a text node or a comment, it uses a global static
3204 * variable for the name of the node.
3205 *
3206 * The xmlStrEqual comparisons need to be done when (happened with
3207 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003208 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00003209 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00003210 * are not sufficient.
3211 */
Owen Taylor3473f882001-02-23 17:55:21 +00003212 if ((cur->name != NULL) &&
3213 (cur->name != xmlStringText) &&
3214 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00003215 (cur->name != xmlStringComment)) {
3216 if (cur->type == XML_TEXT_NODE) {
3217 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
3218 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
3219 xmlFree((char *) cur->name);
3220 } else if (cur->type == XML_COMMENT_NODE) {
3221 if (!xmlStrEqual(cur->name, xmlStringComment))
3222 xmlFree((char *) cur->name);
3223 } else
3224 xmlFree((char *) cur->name);
3225 }
3226
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003227 if (((cur->type == XML_ELEMENT_NODE) ||
3228 (cur->type == XML_XINCLUDE_START) ||
3229 (cur->type == XML_XINCLUDE_END)) &&
3230 (cur->nsDef != NULL))
3231 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003232 xmlFree(cur);
3233}
3234
3235/**
3236 * xmlUnlinkNode:
3237 * @cur: the node
3238 *
3239 * Unlink a node from it's current context, the node is not freed
3240 */
3241void
3242xmlUnlinkNode(xmlNodePtr cur) {
3243 if (cur == NULL) {
3244#ifdef DEBUG_TREE
3245 xmlGenericError(xmlGenericErrorContext,
3246 "xmlUnlinkNode : node == NULL\n");
3247#endif
3248 return;
3249 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003250 if (cur->type == XML_DTD_NODE) {
3251 xmlDocPtr doc;
3252 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003253 if (doc != NULL) {
3254 if (doc->intSubset == (xmlDtdPtr) cur)
3255 doc->intSubset = NULL;
3256 if (doc->extSubset == (xmlDtdPtr) cur)
3257 doc->extSubset = NULL;
3258 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003259 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003260 if (cur->parent != NULL) {
3261 xmlNodePtr parent;
3262 parent = cur->parent;
3263 if (cur->type == XML_ATTRIBUTE_NODE) {
3264 if (parent->properties == (xmlAttrPtr) cur)
3265 parent->properties = ((xmlAttrPtr) cur)->next;
3266 } else {
3267 if (parent->children == cur)
3268 parent->children = cur->next;
3269 if (parent->last == cur)
3270 parent->last = cur->prev;
3271 }
3272 cur->parent = NULL;
3273 }
Owen Taylor3473f882001-02-23 17:55:21 +00003274 if (cur->next != NULL)
3275 cur->next->prev = cur->prev;
3276 if (cur->prev != NULL)
3277 cur->prev->next = cur->next;
3278 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003279}
3280
3281/**
3282 * xmlReplaceNode:
3283 * @old: the old node
3284 * @cur: the node
3285 *
3286 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003287 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003288 * first unlinked from its existing context.
3289 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003290 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003291 */
3292xmlNodePtr
3293xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3294 if (old == NULL) {
3295#ifdef DEBUG_TREE
3296 xmlGenericError(xmlGenericErrorContext,
3297 "xmlReplaceNode : old == NULL\n");
3298#endif
3299 return(NULL);
3300 }
3301 if (cur == NULL) {
3302 xmlUnlinkNode(old);
3303 return(old);
3304 }
3305 if (cur == old) {
3306 return(old);
3307 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003308 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3309#ifdef DEBUG_TREE
3310 xmlGenericError(xmlGenericErrorContext,
3311 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3312#endif
3313 return(old);
3314 }
3315 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3316#ifdef DEBUG_TREE
3317 xmlGenericError(xmlGenericErrorContext,
3318 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3319#endif
3320 return(old);
3321 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003322 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3323#ifdef DEBUG_TREE
3324 xmlGenericError(xmlGenericErrorContext,
3325 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3326#endif
3327 return(old);
3328 }
3329 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3330#ifdef DEBUG_TREE
3331 xmlGenericError(xmlGenericErrorContext,
3332 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3333#endif
3334 return(old);
3335 }
Owen Taylor3473f882001-02-23 17:55:21 +00003336 xmlUnlinkNode(cur);
3337 cur->doc = old->doc;
3338 cur->parent = old->parent;
3339 cur->next = old->next;
3340 if (cur->next != NULL)
3341 cur->next->prev = cur;
3342 cur->prev = old->prev;
3343 if (cur->prev != NULL)
3344 cur->prev->next = cur;
3345 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003346 if (cur->type == XML_ATTRIBUTE_NODE) {
3347 if (cur->parent->properties == (xmlAttrPtr)old)
3348 cur->parent->properties = ((xmlAttrPtr) cur);
3349 } else {
3350 if (cur->parent->children == old)
3351 cur->parent->children = cur;
3352 if (cur->parent->last == old)
3353 cur->parent->last = cur;
3354 }
Owen Taylor3473f882001-02-23 17:55:21 +00003355 }
3356 old->next = old->prev = NULL;
3357 old->parent = NULL;
3358 return(old);
3359}
3360
3361/************************************************************************
3362 * *
3363 * Copy operations *
3364 * *
3365 ************************************************************************/
3366
3367/**
3368 * xmlCopyNamespace:
3369 * @cur: the namespace
3370 *
3371 * Do a copy of the namespace.
3372 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003373 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003374 */
3375xmlNsPtr
3376xmlCopyNamespace(xmlNsPtr cur) {
3377 xmlNsPtr ret;
3378
3379 if (cur == NULL) return(NULL);
3380 switch (cur->type) {
3381 case XML_LOCAL_NAMESPACE:
3382 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3383 break;
3384 default:
3385#ifdef DEBUG_TREE
3386 xmlGenericError(xmlGenericErrorContext,
3387 "xmlCopyNamespace: invalid type %d\n", cur->type);
3388#endif
3389 return(NULL);
3390 }
3391 return(ret);
3392}
3393
3394/**
3395 * xmlCopyNamespaceList:
3396 * @cur: the first namespace
3397 *
3398 * Do a copy of an namespace list.
3399 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003400 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003401 */
3402xmlNsPtr
3403xmlCopyNamespaceList(xmlNsPtr cur) {
3404 xmlNsPtr ret = NULL;
3405 xmlNsPtr p = NULL,q;
3406
3407 while (cur != NULL) {
3408 q = xmlCopyNamespace(cur);
3409 if (p == NULL) {
3410 ret = p = q;
3411 } else {
3412 p->next = q;
3413 p = q;
3414 }
3415 cur = cur->next;
3416 }
3417 return(ret);
3418}
3419
3420static xmlNodePtr
3421xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3422/**
3423 * xmlCopyProp:
3424 * @target: the element where the attribute will be grafted
3425 * @cur: the attribute
3426 *
3427 * Do a copy of the attribute.
3428 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003429 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003430 */
3431xmlAttrPtr
3432xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3433 xmlAttrPtr ret;
3434
3435 if (cur == NULL) return(NULL);
3436 if (target != NULL)
3437 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3438 else if (cur->parent != NULL)
3439 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3440 else if (cur->children != NULL)
3441 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3442 else
3443 ret = xmlNewDocProp(NULL, cur->name, NULL);
3444 if (ret == NULL) return(NULL);
3445 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003446
Owen Taylor3473f882001-02-23 17:55:21 +00003447 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003448 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003449/*
3450 * if (target->doc)
3451 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3452 * else if (cur->doc) / * target may not yet have a doc : KPI * /
3453 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
3454 * else
3455 * ns = NULL;
3456 * ret->ns = ns;
3457 */
3458 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3459 if (ns == NULL) {
3460 /*
3461 * Humm, we are copying an element whose namespace is defined
3462 * out of the new tree scope. Search it in the original tree
3463 * and add it at the top of the new tree
3464 */
3465 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3466 if (ns != NULL) {
3467 xmlNodePtr root = target;
3468 xmlNodePtr pred = NULL;
3469
3470 while (root->parent != NULL) {
3471 pred = root;
3472 root = root->parent;
3473 }
3474 if (root == (xmlNodePtr) target->doc) {
3475 /* correct possibly cycling above the document elt */
3476 root = pred;
3477 }
3478 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3479 }
3480 } else {
3481 /*
3482 * we have to find something appropriate here since
3483 * we cant be sure, that the namespce we found is identified
3484 * by the prefix
3485 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003486 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003487 /* this is the nice case */
3488 ret->ns = ns;
3489 } else {
3490 /*
3491 * we are in trouble: we need a new reconcilied namespace.
3492 * This is expensive
3493 */
3494 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3495 }
3496 }
3497
Owen Taylor3473f882001-02-23 17:55:21 +00003498 } else
3499 ret->ns = NULL;
3500
3501 if (cur->children != NULL) {
3502 xmlNodePtr tmp;
3503
3504 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3505 ret->last = NULL;
3506 tmp = ret->children;
3507 while (tmp != NULL) {
3508 /* tmp->parent = (xmlNodePtr)ret; */
3509 if (tmp->next == NULL)
3510 ret->last = tmp;
3511 tmp = tmp->next;
3512 }
3513 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003514 /*
3515 * Try to handle IDs
3516 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003517 if ((target!= NULL) && (cur!= NULL) &&
3518 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003519 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3520 if (xmlIsID(cur->doc, cur->parent, cur)) {
3521 xmlChar *id;
3522
3523 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3524 if (id != NULL) {
3525 xmlAddID(NULL, target->doc, id, ret);
3526 xmlFree(id);
3527 }
3528 }
3529 }
Owen Taylor3473f882001-02-23 17:55:21 +00003530 return(ret);
3531}
3532
3533/**
3534 * xmlCopyPropList:
3535 * @target: the element where the attributes will be grafted
3536 * @cur: the first attribute
3537 *
3538 * Do a copy of an attribute list.
3539 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003540 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003541 */
3542xmlAttrPtr
3543xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3544 xmlAttrPtr ret = NULL;
3545 xmlAttrPtr p = NULL,q;
3546
3547 while (cur != NULL) {
3548 q = xmlCopyProp(target, cur);
3549 if (p == NULL) {
3550 ret = p = q;
3551 } else {
3552 p->next = q;
3553 q->prev = p;
3554 p = q;
3555 }
3556 cur = cur->next;
3557 }
3558 return(ret);
3559}
3560
3561/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003562 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003563 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003564 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003565 * tricky reason: namespaces. Doing a direct copy of a node
3566 * say RPM:Copyright without changing the namespace pointer to
3567 * something else can produce stale links. One way to do it is
3568 * to keep a reference counter but this doesn't work as soon
3569 * as one move the element or the subtree out of the scope of
3570 * the existing namespace. The actual solution seems to add
3571 * a copy of the namespace at the top of the copied tree if
3572 * not available in the subtree.
3573 * Hence two functions, the public front-end call the inner ones
3574 */
3575
3576static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003577xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003578 int recursive) {
3579 xmlNodePtr ret;
3580
3581 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003582 switch (node->type) {
3583 case XML_TEXT_NODE:
3584 case XML_CDATA_SECTION_NODE:
3585 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003586 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003587 case XML_ENTITY_REF_NODE:
3588 case XML_ENTITY_NODE:
3589 case XML_PI_NODE:
3590 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003591 case XML_XINCLUDE_START:
3592 case XML_XINCLUDE_END:
3593 break;
3594 case XML_ATTRIBUTE_NODE:
3595 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3596 case XML_NAMESPACE_DECL:
3597 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3598
Daniel Veillard39196eb2001-06-19 18:09:42 +00003599 case XML_DOCUMENT_NODE:
3600 case XML_HTML_DOCUMENT_NODE:
3601#ifdef LIBXML_DOCB_ENABLED
3602 case XML_DOCB_DOCUMENT_NODE:
3603#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003604 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00003605 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003606 case XML_NOTATION_NODE:
3607 case XML_DTD_NODE:
3608 case XML_ELEMENT_DECL:
3609 case XML_ATTRIBUTE_DECL:
3610 case XML_ENTITY_DECL:
3611 return(NULL);
3612 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003613
Owen Taylor3473f882001-02-23 17:55:21 +00003614 /*
3615 * Allocate a new node and fill the fields.
3616 */
3617 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3618 if (ret == NULL) {
3619 xmlGenericError(xmlGenericErrorContext,
3620 "xmlStaticCopyNode : malloc failed\n");
3621 return(NULL);
3622 }
3623 memset(ret, 0, sizeof(xmlNode));
3624 ret->type = node->type;
3625
3626 ret->doc = doc;
3627 ret->parent = parent;
3628 if (node->name == xmlStringText)
3629 ret->name = xmlStringText;
3630 else if (node->name == xmlStringTextNoenc)
3631 ret->name = xmlStringTextNoenc;
3632 else if (node->name == xmlStringComment)
3633 ret->name = xmlStringComment;
3634 else if (node->name != NULL)
3635 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003636 if ((node->type != XML_ELEMENT_NODE) &&
3637 (node->content != NULL) &&
3638 (node->type != XML_ENTITY_REF_NODE) &&
3639 (node->type != XML_XINCLUDE_END) &&
3640 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003641 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003642 }else{
3643 if (node->type == XML_ELEMENT_NODE)
3644 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00003645 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003646 if (parent != NULL) {
3647 xmlNodePtr tmp;
3648
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003649 /*
3650 * this is a tricky part for the node register thing:
3651 * in case ret does get coalesced in xmlAddChild
3652 * the deregister-node callback is called; so we register ret now already
3653 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003654 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003655 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3656
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003657 tmp = xmlAddChild(parent, ret);
3658 /* node could have coalesced */
3659 if (tmp != ret)
3660 return(tmp);
3661 }
Owen Taylor3473f882001-02-23 17:55:21 +00003662
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003663 if (!recursive)
3664 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003665 if (node->nsDef != NULL)
3666 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3667
3668 if (node->ns != NULL) {
3669 xmlNsPtr ns;
3670
3671 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3672 if (ns == NULL) {
3673 /*
3674 * Humm, we are copying an element whose namespace is defined
3675 * out of the new tree scope. Search it in the original tree
3676 * and add it at the top of the new tree
3677 */
3678 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3679 if (ns != NULL) {
3680 xmlNodePtr root = ret;
3681
3682 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003683 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003684 }
3685 } else {
3686 /*
3687 * reference the existing namespace definition in our own tree.
3688 */
3689 ret->ns = ns;
3690 }
3691 }
3692 if (node->properties != NULL)
3693 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003694 if (node->type == XML_ENTITY_REF_NODE) {
3695 if ((doc == NULL) || (node->doc != doc)) {
3696 /*
3697 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003698 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003699 * we cannot keep the reference. Try to find it in the
3700 * target document.
3701 */
3702 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3703 } else {
3704 ret->children = node->children;
3705 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003706 ret->last = ret->children;
3707 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003708 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003709 UPDATE_LAST_CHILD_AND_PARENT(ret)
3710 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003711
3712out:
3713 /* if parent != NULL we already registered the node above */
3714 if (parent == NULL && xmlRegisterNodeDefaultValue)
3715 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003716 return(ret);
3717}
3718
3719static xmlNodePtr
3720xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3721 xmlNodePtr ret = NULL;
3722 xmlNodePtr p = NULL,q;
3723
3724 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003725 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003726 if (doc == NULL) {
3727 node = node->next;
3728 continue;
3729 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003730 if (doc->intSubset == NULL) {
3731 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3732 q->doc = doc;
3733 q->parent = parent;
3734 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003735 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003736 } else {
3737 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003738 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003739 }
3740 } else
3741 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003742 if (ret == NULL) {
3743 q->prev = NULL;
3744 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003745 } else if (p != q) {
3746 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003747 p->next = q;
3748 q->prev = p;
3749 p = q;
3750 }
3751 node = node->next;
3752 }
3753 return(ret);
3754}
3755
3756/**
3757 * xmlCopyNode:
3758 * @node: the node
3759 * @recursive: if 1 do a recursive copy.
3760 *
3761 * Do a copy of the node.
3762 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003763 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003764 */
3765xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003766xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003767 xmlNodePtr ret;
3768
3769 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3770 return(ret);
3771}
3772
3773/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003774 * xmlDocCopyNode:
3775 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003776 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003777 * @recursive: if 1 do a recursive copy.
3778 *
3779 * Do a copy of the node to a given document.
3780 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003781 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003782 */
3783xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003784xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003785 xmlNodePtr ret;
3786
3787 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3788 return(ret);
3789}
3790
3791/**
Owen Taylor3473f882001-02-23 17:55:21 +00003792 * xmlCopyNodeList:
3793 * @node: the first node in the list.
3794 *
3795 * Do a recursive copy of the node list.
3796 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003797 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003798 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003799xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003800 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3801 return(ret);
3802}
3803
3804/**
Owen Taylor3473f882001-02-23 17:55:21 +00003805 * xmlCopyDtd:
3806 * @dtd: the dtd
3807 *
3808 * Do a copy of the dtd.
3809 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003810 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003811 */
3812xmlDtdPtr
3813xmlCopyDtd(xmlDtdPtr dtd) {
3814 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003815 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003816
3817 if (dtd == NULL) return(NULL);
3818 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3819 if (ret == NULL) return(NULL);
3820 if (dtd->entities != NULL)
3821 ret->entities = (void *) xmlCopyEntitiesTable(
3822 (xmlEntitiesTablePtr) dtd->entities);
3823 if (dtd->notations != NULL)
3824 ret->notations = (void *) xmlCopyNotationTable(
3825 (xmlNotationTablePtr) dtd->notations);
3826 if (dtd->elements != NULL)
3827 ret->elements = (void *) xmlCopyElementTable(
3828 (xmlElementTablePtr) dtd->elements);
3829 if (dtd->attributes != NULL)
3830 ret->attributes = (void *) xmlCopyAttributeTable(
3831 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003832 if (dtd->pentities != NULL)
3833 ret->pentities = (void *) xmlCopyEntitiesTable(
3834 (xmlEntitiesTablePtr) dtd->pentities);
3835
3836 cur = dtd->children;
3837 while (cur != NULL) {
3838 q = NULL;
3839
3840 if (cur->type == XML_ENTITY_DECL) {
3841 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3842 switch (tmp->etype) {
3843 case XML_INTERNAL_GENERAL_ENTITY:
3844 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3845 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3846 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3847 break;
3848 case XML_INTERNAL_PARAMETER_ENTITY:
3849 case XML_EXTERNAL_PARAMETER_ENTITY:
3850 q = (xmlNodePtr)
3851 xmlGetParameterEntityFromDtd(ret, tmp->name);
3852 break;
3853 case XML_INTERNAL_PREDEFINED_ENTITY:
3854 break;
3855 }
3856 } else if (cur->type == XML_ELEMENT_DECL) {
3857 xmlElementPtr tmp = (xmlElementPtr) cur;
3858 q = (xmlNodePtr)
3859 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3860 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3861 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3862 q = (xmlNodePtr)
3863 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3864 } else if (cur->type == XML_COMMENT_NODE) {
3865 q = xmlCopyNode(cur, 0);
3866 }
3867
3868 if (q == NULL) {
3869 cur = cur->next;
3870 continue;
3871 }
3872
3873 if (p == NULL)
3874 ret->children = q;
3875 else
3876 p->next = q;
3877
3878 q->prev = p;
3879 q->parent = (xmlNodePtr) ret;
3880 q->next = NULL;
3881 ret->last = q;
3882 p = q;
3883 cur = cur->next;
3884 }
3885
Owen Taylor3473f882001-02-23 17:55:21 +00003886 return(ret);
3887}
3888
3889/**
3890 * xmlCopyDoc:
3891 * @doc: the document
3892 * @recursive: if 1 do a recursive copy.
3893 *
3894 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003895 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003896 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003897 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003898 */
3899xmlDocPtr
3900xmlCopyDoc(xmlDocPtr doc, int recursive) {
3901 xmlDocPtr ret;
3902
3903 if (doc == NULL) return(NULL);
3904 ret = xmlNewDoc(doc->version);
3905 if (ret == NULL) return(NULL);
3906 if (doc->name != NULL)
3907 ret->name = xmlMemStrdup(doc->name);
3908 if (doc->encoding != NULL)
3909 ret->encoding = xmlStrdup(doc->encoding);
3910 ret->charset = doc->charset;
3911 ret->compression = doc->compression;
3912 ret->standalone = doc->standalone;
3913 if (!recursive) return(ret);
3914
Daniel Veillardb33c2012001-04-25 12:59:04 +00003915 ret->last = NULL;
3916 ret->children = NULL;
3917 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003918 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003919 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003920 ret->intSubset->parent = ret;
3921 }
Owen Taylor3473f882001-02-23 17:55:21 +00003922 if (doc->oldNs != NULL)
3923 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3924 if (doc->children != NULL) {
3925 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003926
3927 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3928 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003929 ret->last = NULL;
3930 tmp = ret->children;
3931 while (tmp != NULL) {
3932 if (tmp->next == NULL)
3933 ret->last = tmp;
3934 tmp = tmp->next;
3935 }
3936 }
3937 return(ret);
3938}
3939
3940/************************************************************************
3941 * *
3942 * Content access functions *
3943 * *
3944 ************************************************************************/
3945
3946/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003947 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003948 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00003949 *
3950 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003951 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003952 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003953 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003954 */
3955long
3956xmlGetLineNo(xmlNodePtr node)
3957{
3958 long result = -1;
3959
3960 if (!node)
3961 return result;
3962 if (node->type == XML_ELEMENT_NODE)
3963 result = (long) node->content;
3964 else if ((node->prev != NULL) &&
3965 ((node->prev->type == XML_ELEMENT_NODE) ||
3966 (node->prev->type == XML_TEXT_NODE)))
3967 result = xmlGetLineNo(node->prev);
3968 else if ((node->parent != NULL) &&
3969 ((node->parent->type == XML_ELEMENT_NODE) ||
3970 (node->parent->type == XML_TEXT_NODE)))
3971 result = xmlGetLineNo(node->parent);
3972
3973 return result;
3974}
3975
3976/**
3977 * xmlGetNodePath:
3978 * @node: a node
3979 *
3980 * Build a structure based Path for the given node
3981 *
3982 * Returns the new path or NULL in case of error. The caller must free
3983 * the returned string
3984 */
3985xmlChar *
3986xmlGetNodePath(xmlNodePtr node)
3987{
3988 xmlNodePtr cur, tmp, next;
3989 xmlChar *buffer = NULL, *temp;
3990 size_t buf_len;
3991 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00003992 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00003993 const char *name;
3994 char nametemp[100];
3995 int occur = 0;
3996
3997 if (node == NULL)
3998 return (NULL);
3999
4000 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004001 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004002 if (buffer == NULL)
4003 return (NULL);
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004004 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004005 if (buf == NULL) {
4006 xmlFree(buffer);
4007 return (NULL);
4008 }
4009
4010 buffer[0] = 0;
4011 cur = node;
4012 do {
4013 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004014 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004015 occur = 0;
4016 if ((cur->type == XML_DOCUMENT_NODE) ||
4017 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4018 if (buffer[0] == '/')
4019 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004020 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004021 next = NULL;
4022 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004023 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004024 name = (const char *) cur->name;
4025 if (cur->ns) {
4026 snprintf(nametemp, sizeof(nametemp) - 1,
4027 "%s:%s", cur->ns->prefix, cur->name);
4028 nametemp[sizeof(nametemp) - 1] = 0;
4029 name = nametemp;
4030 }
4031 next = cur->parent;
4032
4033 /*
4034 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004035 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004036 */
4037 tmp = cur->prev;
4038 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004039 if ((tmp->type == XML_ELEMENT_NODE) &&
4040 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004041 occur++;
4042 tmp = tmp->prev;
4043 }
4044 if (occur == 0) {
4045 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004046 while (tmp != NULL && occur == 0) {
4047 if ((tmp->type == XML_ELEMENT_NODE) &&
4048 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004049 occur++;
4050 tmp = tmp->next;
4051 }
4052 if (occur != 0)
4053 occur = 1;
4054 } else
4055 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004056 } else if (cur->type == XML_COMMENT_NODE) {
4057 sep = "/";
4058 name = "comment()";
4059 next = cur->parent;
4060
4061 /*
4062 * Thumbler index computation
4063 */
4064 tmp = cur->prev;
4065 while (tmp != NULL) {
4066 if (tmp->type == XML_COMMENT_NODE)
4067 occur++;
4068 tmp = tmp->prev;
4069 }
4070 if (occur == 0) {
4071 tmp = cur->next;
4072 while (tmp != NULL && occur == 0) {
4073 if (tmp->type == XML_COMMENT_NODE)
4074 occur++;
4075 tmp = tmp->next;
4076 }
4077 if (occur != 0)
4078 occur = 1;
4079 } else
4080 occur++;
4081 } else if ((cur->type == XML_TEXT_NODE) ||
4082 (cur->type == XML_CDATA_SECTION_NODE)) {
4083 sep = "/";
4084 name = "text()";
4085 next = cur->parent;
4086
4087 /*
4088 * Thumbler index computation
4089 */
4090 tmp = cur->prev;
4091 while (tmp != NULL) {
4092 if ((cur->type == XML_TEXT_NODE) ||
4093 (cur->type == XML_CDATA_SECTION_NODE))
4094 occur++;
4095 tmp = tmp->prev;
4096 }
4097 if (occur == 0) {
4098 tmp = cur->next;
4099 while (tmp != NULL && occur == 0) {
4100 if ((cur->type == XML_TEXT_NODE) ||
4101 (cur->type == XML_CDATA_SECTION_NODE))
4102 occur++;
4103 tmp = tmp->next;
4104 }
4105 if (occur != 0)
4106 occur = 1;
4107 } else
4108 occur++;
4109 } else if (cur->type == XML_PI_NODE) {
4110 sep = "/";
4111 snprintf(nametemp, sizeof(nametemp) - 1,
4112 "processing-instruction('%s')", cur->name);
4113 nametemp[sizeof(nametemp) - 1] = 0;
4114 name = nametemp;
4115
4116 next = cur->parent;
4117
4118 /*
4119 * Thumbler index computation
4120 */
4121 tmp = cur->prev;
4122 while (tmp != NULL) {
4123 if ((tmp->type == XML_PI_NODE) &&
4124 (xmlStrEqual(cur->name, tmp->name)))
4125 occur++;
4126 tmp = tmp->prev;
4127 }
4128 if (occur == 0) {
4129 tmp = cur->next;
4130 while (tmp != NULL && occur == 0) {
4131 if ((tmp->type == XML_PI_NODE) &&
4132 (xmlStrEqual(cur->name, tmp->name)))
4133 occur++;
4134 tmp = tmp->next;
4135 }
4136 if (occur != 0)
4137 occur = 1;
4138 } else
4139 occur++;
4140
Daniel Veillard8faa7832001-11-26 15:58:08 +00004141 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004142 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004143 name = (const char *) (((xmlAttrPtr) cur)->name);
4144 next = ((xmlAttrPtr) cur)->parent;
4145 } else {
4146 next = cur->parent;
4147 }
4148
4149 /*
4150 * Make sure there is enough room
4151 */
4152 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4153 buf_len =
4154 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4155 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4156 if (temp == NULL) {
4157 xmlFree(buf);
4158 xmlFree(buffer);
4159 return (NULL);
4160 }
4161 buffer = temp;
4162 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4163 if (temp == NULL) {
4164 xmlFree(buf);
4165 xmlFree(buffer);
4166 return (NULL);
4167 }
4168 buf = temp;
4169 }
4170 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004171 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004172 sep, name, (char *) buffer);
4173 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004174 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004175 sep, name, occur, (char *) buffer);
4176 snprintf((char *) buffer, buf_len, "%s", buf);
4177 cur = next;
4178 } while (cur != NULL);
4179 xmlFree(buf);
4180 return (buffer);
4181}
4182
4183/**
Owen Taylor3473f882001-02-23 17:55:21 +00004184 * xmlDocGetRootElement:
4185 * @doc: the document
4186 *
4187 * Get the root element of the document (doc->children is a list
4188 * containing possibly comments, PIs, etc ...).
4189 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004190 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004191 */
4192xmlNodePtr
4193xmlDocGetRootElement(xmlDocPtr doc) {
4194 xmlNodePtr ret;
4195
4196 if (doc == NULL) return(NULL);
4197 ret = doc->children;
4198 while (ret != NULL) {
4199 if (ret->type == XML_ELEMENT_NODE)
4200 return(ret);
4201 ret = ret->next;
4202 }
4203 return(ret);
4204}
4205
4206/**
4207 * xmlDocSetRootElement:
4208 * @doc: the document
4209 * @root: the new document root element
4210 *
4211 * Set the root element of the document (doc->children is a list
4212 * containing possibly comments, PIs, etc ...).
4213 *
4214 * Returns the old root element if any was found
4215 */
4216xmlNodePtr
4217xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4218 xmlNodePtr old = NULL;
4219
4220 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004221 if (root == NULL)
4222 return(NULL);
4223 xmlUnlinkNode(root);
4224 root->doc = doc;
4225 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004226 old = doc->children;
4227 while (old != NULL) {
4228 if (old->type == XML_ELEMENT_NODE)
4229 break;
4230 old = old->next;
4231 }
4232 if (old == NULL) {
4233 if (doc->children == NULL) {
4234 doc->children = root;
4235 doc->last = root;
4236 } else {
4237 xmlAddSibling(doc->children, root);
4238 }
4239 } else {
4240 xmlReplaceNode(old, root);
4241 }
4242 return(old);
4243}
4244
4245/**
4246 * xmlNodeSetLang:
4247 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004248 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004249 *
4250 * Set the language of a node, i.e. the values of the xml:lang
4251 * attribute.
4252 */
4253void
4254xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004255 xmlNsPtr ns;
4256
Owen Taylor3473f882001-02-23 17:55:21 +00004257 if (cur == NULL) return;
4258 switch(cur->type) {
4259 case XML_TEXT_NODE:
4260 case XML_CDATA_SECTION_NODE:
4261 case XML_COMMENT_NODE:
4262 case XML_DOCUMENT_NODE:
4263 case XML_DOCUMENT_TYPE_NODE:
4264 case XML_DOCUMENT_FRAG_NODE:
4265 case XML_NOTATION_NODE:
4266 case XML_HTML_DOCUMENT_NODE:
4267 case XML_DTD_NODE:
4268 case XML_ELEMENT_DECL:
4269 case XML_ATTRIBUTE_DECL:
4270 case XML_ENTITY_DECL:
4271 case XML_PI_NODE:
4272 case XML_ENTITY_REF_NODE:
4273 case XML_ENTITY_NODE:
4274 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004275#ifdef LIBXML_DOCB_ENABLED
4276 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004277#endif
4278 case XML_XINCLUDE_START:
4279 case XML_XINCLUDE_END:
4280 return;
4281 case XML_ELEMENT_NODE:
4282 case XML_ATTRIBUTE_NODE:
4283 break;
4284 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004285 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4286 if (ns == NULL)
4287 return;
4288 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004289}
4290
4291/**
4292 * xmlNodeGetLang:
4293 * @cur: the node being checked
4294 *
4295 * Searches the language of a node, i.e. the values of the xml:lang
4296 * attribute or the one carried by the nearest ancestor.
4297 *
4298 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004299 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004300 */
4301xmlChar *
4302xmlNodeGetLang(xmlNodePtr cur) {
4303 xmlChar *lang;
4304
4305 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004306 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004307 if (lang != NULL)
4308 return(lang);
4309 cur = cur->parent;
4310 }
4311 return(NULL);
4312}
4313
4314
4315/**
4316 * xmlNodeSetSpacePreserve:
4317 * @cur: the node being changed
4318 * @val: the xml:space value ("0": default, 1: "preserve")
4319 *
4320 * Set (or reset) the space preserving behaviour of a node, i.e. the
4321 * value of the xml:space attribute.
4322 */
4323void
4324xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004325 xmlNsPtr ns;
4326
Owen Taylor3473f882001-02-23 17:55:21 +00004327 if (cur == NULL) return;
4328 switch(cur->type) {
4329 case XML_TEXT_NODE:
4330 case XML_CDATA_SECTION_NODE:
4331 case XML_COMMENT_NODE:
4332 case XML_DOCUMENT_NODE:
4333 case XML_DOCUMENT_TYPE_NODE:
4334 case XML_DOCUMENT_FRAG_NODE:
4335 case XML_NOTATION_NODE:
4336 case XML_HTML_DOCUMENT_NODE:
4337 case XML_DTD_NODE:
4338 case XML_ELEMENT_DECL:
4339 case XML_ATTRIBUTE_DECL:
4340 case XML_ENTITY_DECL:
4341 case XML_PI_NODE:
4342 case XML_ENTITY_REF_NODE:
4343 case XML_ENTITY_NODE:
4344 case XML_NAMESPACE_DECL:
4345 case XML_XINCLUDE_START:
4346 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004347#ifdef LIBXML_DOCB_ENABLED
4348 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004349#endif
4350 return;
4351 case XML_ELEMENT_NODE:
4352 case XML_ATTRIBUTE_NODE:
4353 break;
4354 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004355 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4356 if (ns == NULL)
4357 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004358 switch (val) {
4359 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004360 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004361 break;
4362 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004363 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004364 break;
4365 }
4366}
4367
4368/**
4369 * xmlNodeGetSpacePreserve:
4370 * @cur: the node being checked
4371 *
4372 * Searches the space preserving behaviour of a node, i.e. the values
4373 * of the xml:space attribute or the one carried by the nearest
4374 * ancestor.
4375 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004376 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004377 */
4378int
4379xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4380 xmlChar *space;
4381
4382 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004383 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004384 if (space != NULL) {
4385 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4386 xmlFree(space);
4387 return(1);
4388 }
4389 if (xmlStrEqual(space, BAD_CAST "default")) {
4390 xmlFree(space);
4391 return(0);
4392 }
4393 xmlFree(space);
4394 }
4395 cur = cur->parent;
4396 }
4397 return(-1);
4398}
4399
4400/**
4401 * xmlNodeSetName:
4402 * @cur: the node being changed
4403 * @name: the new tag name
4404 *
4405 * Set (or reset) the name of a node.
4406 */
4407void
4408xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
4409 if (cur == NULL) return;
4410 if (name == NULL) return;
4411 switch(cur->type) {
4412 case XML_TEXT_NODE:
4413 case XML_CDATA_SECTION_NODE:
4414 case XML_COMMENT_NODE:
4415 case XML_DOCUMENT_TYPE_NODE:
4416 case XML_DOCUMENT_FRAG_NODE:
4417 case XML_NOTATION_NODE:
4418 case XML_HTML_DOCUMENT_NODE:
4419 case XML_NAMESPACE_DECL:
4420 case XML_XINCLUDE_START:
4421 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004422#ifdef LIBXML_DOCB_ENABLED
4423 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004424#endif
4425 return;
4426 case XML_ELEMENT_NODE:
4427 case XML_ATTRIBUTE_NODE:
4428 case XML_PI_NODE:
4429 case XML_ENTITY_REF_NODE:
4430 case XML_ENTITY_NODE:
4431 case XML_DTD_NODE:
4432 case XML_DOCUMENT_NODE:
4433 case XML_ELEMENT_DECL:
4434 case XML_ATTRIBUTE_DECL:
4435 case XML_ENTITY_DECL:
4436 break;
4437 }
4438 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4439 cur->name = xmlStrdup(name);
4440}
4441
4442/**
4443 * xmlNodeSetBase:
4444 * @cur: the node being changed
4445 * @uri: the new base URI
4446 *
4447 * Set (or reset) the base URI of a node, i.e. the value of the
4448 * xml:base attribute.
4449 */
4450void
4451xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004452 xmlNsPtr ns;
4453
Owen Taylor3473f882001-02-23 17:55:21 +00004454 if (cur == NULL) return;
4455 switch(cur->type) {
4456 case XML_TEXT_NODE:
4457 case XML_CDATA_SECTION_NODE:
4458 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004459 case XML_DOCUMENT_TYPE_NODE:
4460 case XML_DOCUMENT_FRAG_NODE:
4461 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004462 case XML_DTD_NODE:
4463 case XML_ELEMENT_DECL:
4464 case XML_ATTRIBUTE_DECL:
4465 case XML_ENTITY_DECL:
4466 case XML_PI_NODE:
4467 case XML_ENTITY_REF_NODE:
4468 case XML_ENTITY_NODE:
4469 case XML_NAMESPACE_DECL:
4470 case XML_XINCLUDE_START:
4471 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004472 return;
4473 case XML_ELEMENT_NODE:
4474 case XML_ATTRIBUTE_NODE:
4475 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004476 case XML_DOCUMENT_NODE:
4477#ifdef LIBXML_DOCB_ENABLED
4478 case XML_DOCB_DOCUMENT_NODE:
4479#endif
4480 case XML_HTML_DOCUMENT_NODE: {
4481 xmlDocPtr doc = (xmlDocPtr) cur;
4482
4483 if (doc->URL != NULL)
4484 xmlFree((xmlChar *) doc->URL);
4485 if (uri == NULL)
4486 doc->URL = NULL;
4487 else
4488 doc->URL = xmlStrdup(uri);
4489 return;
4490 }
Owen Taylor3473f882001-02-23 17:55:21 +00004491 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004492
4493 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4494 if (ns == NULL)
4495 return;
4496 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004497}
4498
4499/**
Owen Taylor3473f882001-02-23 17:55:21 +00004500 * xmlNodeGetBase:
4501 * @doc: the document the node pertains to
4502 * @cur: the node being checked
4503 *
4504 * Searches for the BASE URL. The code should work on both XML
4505 * and HTML document even if base mechanisms are completely different.
4506 * It returns the base as defined in RFC 2396 sections
4507 * 5.1.1. Base URI within Document Content
4508 * and
4509 * 5.1.2. Base URI from the Encapsulating Entity
4510 * However it does not return the document base (5.1.3), use
4511 * xmlDocumentGetBase() for this
4512 *
4513 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004514 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004515 */
4516xmlChar *
4517xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004518 xmlChar *oldbase = NULL;
4519 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004520
4521 if ((cur == NULL) && (doc == NULL))
4522 return(NULL);
4523 if (doc == NULL) doc = cur->doc;
4524 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4525 cur = doc->children;
4526 while ((cur != NULL) && (cur->name != NULL)) {
4527 if (cur->type != XML_ELEMENT_NODE) {
4528 cur = cur->next;
4529 continue;
4530 }
4531 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4532 cur = cur->children;
4533 continue;
4534 }
4535 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4536 cur = cur->children;
4537 continue;
4538 }
4539 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4540 return(xmlGetProp(cur, BAD_CAST "href"));
4541 }
4542 cur = cur->next;
4543 }
4544 return(NULL);
4545 }
4546 while (cur != NULL) {
4547 if (cur->type == XML_ENTITY_DECL) {
4548 xmlEntityPtr ent = (xmlEntityPtr) cur;
4549 return(xmlStrdup(ent->URI));
4550 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004551 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004552 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004553 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004554 if (oldbase != NULL) {
4555 newbase = xmlBuildURI(oldbase, base);
4556 if (newbase != NULL) {
4557 xmlFree(oldbase);
4558 xmlFree(base);
4559 oldbase = newbase;
4560 } else {
4561 xmlFree(oldbase);
4562 xmlFree(base);
4563 return(NULL);
4564 }
4565 } else {
4566 oldbase = base;
4567 }
4568 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4569 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4570 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4571 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004572 }
4573 }
Owen Taylor3473f882001-02-23 17:55:21 +00004574 cur = cur->parent;
4575 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004576 if ((doc != NULL) && (doc->URL != NULL)) {
4577 if (oldbase == NULL)
4578 return(xmlStrdup(doc->URL));
4579 newbase = xmlBuildURI(oldbase, doc->URL);
4580 xmlFree(oldbase);
4581 return(newbase);
4582 }
4583 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004584}
4585
4586/**
4587 * xmlNodeGetContent:
4588 * @cur: the node being read
4589 *
4590 * Read the value of a node, this can be either the text carried
4591 * directly by this node if it's a TEXT node or the aggregate string
4592 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004593 * Entity references are substituted.
4594 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004595 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004596 */
4597xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004598xmlNodeGetContent(xmlNodePtr cur)
4599{
4600 if (cur == NULL)
4601 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004602 switch (cur->type) {
4603 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004604 case XML_ELEMENT_NODE:{
4605 xmlNodePtr tmp = cur;
4606 xmlBufferPtr buffer;
4607 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004608
Daniel Veillard814a76d2003-01-23 18:24:20 +00004609 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004610 if (buffer == NULL)
4611 return (NULL);
4612 while (tmp != NULL) {
4613 switch (tmp->type) {
4614 case XML_CDATA_SECTION_NODE:
4615 case XML_TEXT_NODE:
4616 if (tmp->content != NULL)
4617 xmlBufferCat(buffer, tmp->content);
4618 break;
4619 case XML_ENTITY_REF_NODE:{
4620 /* recursive substitution of entity references */
4621 xmlChar *cont = xmlNodeGetContent(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00004622
Daniel Veillard7646b182002-04-20 06:41:40 +00004623 if (cont) {
4624 xmlBufferCat(buffer,
4625 (const xmlChar *) cont);
4626 xmlFree(cont);
4627 }
4628 break;
4629 }
4630 default:
4631 break;
4632 }
4633 /*
4634 * Skip to next node
4635 */
4636 if (tmp->children != NULL) {
4637 if (tmp->children->type != XML_ENTITY_DECL) {
4638 tmp = tmp->children;
4639 continue;
4640 }
4641 }
4642 if (tmp == cur)
4643 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00004644
Daniel Veillard7646b182002-04-20 06:41:40 +00004645 if (tmp->next != NULL) {
4646 tmp = tmp->next;
4647 continue;
4648 }
4649
4650 do {
4651 tmp = tmp->parent;
4652 if (tmp == NULL)
4653 break;
4654 if (tmp == cur) {
4655 tmp = NULL;
4656 break;
4657 }
4658 if (tmp->next != NULL) {
4659 tmp = tmp->next;
4660 break;
4661 }
4662 } while (tmp != NULL);
4663 }
4664 ret = buffer->content;
4665 buffer->content = NULL;
4666 xmlBufferFree(buffer);
4667 return (ret);
4668 }
4669 case XML_ATTRIBUTE_NODE:{
4670 xmlAttrPtr attr = (xmlAttrPtr) cur;
4671
4672 if (attr->parent != NULL)
4673 return (xmlNodeListGetString
4674 (attr->parent->doc, attr->children, 1));
4675 else
4676 return (xmlNodeListGetString(NULL, attr->children, 1));
4677 break;
4678 }
Owen Taylor3473f882001-02-23 17:55:21 +00004679 case XML_COMMENT_NODE:
4680 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004681 if (cur->content != NULL)
4682 return (xmlStrdup(cur->content));
4683 return (NULL);
4684 case XML_ENTITY_REF_NODE:{
4685 xmlEntityPtr ent;
4686 xmlNodePtr tmp;
4687 xmlBufferPtr buffer;
4688 xmlChar *ret;
4689
4690 /* lookup entity declaration */
4691 ent = xmlGetDocEntity(cur->doc, cur->name);
4692 if (ent == NULL)
4693 return (NULL);
4694
4695 buffer = xmlBufferCreate();
4696 if (buffer == NULL)
4697 return (NULL);
4698
4699 /* an entity content can be any "well balanced chunk",
4700 * i.e. the result of the content [43] production:
4701 * http://www.w3.org/TR/REC-xml#NT-content
4702 * -> we iterate through child nodes and recursive call
4703 * xmlNodeGetContent() which handles all possible node types */
4704 tmp = ent->children;
4705 while (tmp) {
4706 xmlChar *cont = xmlNodeGetContent(tmp);
4707
4708 if (cont) {
4709 xmlBufferCat(buffer, (const xmlChar *) cont);
4710 xmlFree(cont);
4711 }
4712 tmp = tmp->next;
4713 }
4714
4715 ret = buffer->content;
4716 buffer->content = NULL;
4717 xmlBufferFree(buffer);
4718 return (ret);
4719 }
Owen Taylor3473f882001-02-23 17:55:21 +00004720 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004721 case XML_DOCUMENT_TYPE_NODE:
4722 case XML_NOTATION_NODE:
4723 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004724 case XML_XINCLUDE_START:
4725 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00004726 return (NULL);
4727 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004728#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004729 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004730#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00004731 case XML_HTML_DOCUMENT_NODE: {
4732 xmlChar *tmp;
4733 xmlChar *res = NULL;
4734
4735 cur = cur->children;
4736 while (cur!= NULL) {
4737 if ((cur->type == XML_ELEMENT_NODE) ||
4738 (cur->type == XML_TEXT_NODE) ||
4739 (cur->type == XML_CDATA_SECTION_NODE)) {
4740 tmp = xmlNodeGetContent(cur);
4741 if (tmp != NULL) {
4742 if (res == NULL)
4743 res = tmp;
4744 else {
4745 res = xmlStrcat(res, tmp);
4746 xmlFree(tmp);
4747 }
4748 }
4749 }
4750 cur = cur->next;
4751 }
4752 return(res);
4753 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004754 case XML_NAMESPACE_DECL: {
4755 xmlChar *tmp;
4756
4757 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4758 return (tmp);
4759 }
Owen Taylor3473f882001-02-23 17:55:21 +00004760 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004761 /* TODO !!! */
4762 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004763 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004764 /* TODO !!! */
4765 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004766 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004767 /* TODO !!! */
4768 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004769 case XML_CDATA_SECTION_NODE:
4770 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004771 if (cur->content != NULL)
4772 return (xmlStrdup(cur->content));
4773 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004774 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004775 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004776}
Owen Taylor3473f882001-02-23 17:55:21 +00004777/**
4778 * xmlNodeSetContent:
4779 * @cur: the node being modified
4780 * @content: the new value of the content
4781 *
4782 * Replace the content of a node.
4783 */
4784void
4785xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4786 if (cur == NULL) {
4787#ifdef DEBUG_TREE
4788 xmlGenericError(xmlGenericErrorContext,
4789 "xmlNodeSetContent : node == NULL\n");
4790#endif
4791 return;
4792 }
4793 switch (cur->type) {
4794 case XML_DOCUMENT_FRAG_NODE:
4795 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004796 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004797 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4798 cur->children = xmlStringGetNodeList(cur->doc, content);
4799 UPDATE_LAST_CHILD_AND_PARENT(cur)
4800 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004801 case XML_TEXT_NODE:
4802 case XML_CDATA_SECTION_NODE:
4803 case XML_ENTITY_REF_NODE:
4804 case XML_ENTITY_NODE:
4805 case XML_PI_NODE:
4806 case XML_COMMENT_NODE:
4807 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004808 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004809 }
4810 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4811 cur->last = cur->children = NULL;
4812 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004813 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00004814 } else
4815 cur->content = NULL;
4816 break;
4817 case XML_DOCUMENT_NODE:
4818 case XML_HTML_DOCUMENT_NODE:
4819 case XML_DOCUMENT_TYPE_NODE:
4820 case XML_XINCLUDE_START:
4821 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004822#ifdef LIBXML_DOCB_ENABLED
4823 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004824#endif
4825 break;
4826 case XML_NOTATION_NODE:
4827 break;
4828 case XML_DTD_NODE:
4829 break;
4830 case XML_NAMESPACE_DECL:
4831 break;
4832 case XML_ELEMENT_DECL:
4833 /* TODO !!! */
4834 break;
4835 case XML_ATTRIBUTE_DECL:
4836 /* TODO !!! */
4837 break;
4838 case XML_ENTITY_DECL:
4839 /* TODO !!! */
4840 break;
4841 }
4842}
4843
4844/**
4845 * xmlNodeSetContentLen:
4846 * @cur: the node being modified
4847 * @content: the new value of the content
4848 * @len: the size of @content
4849 *
4850 * Replace the content of a node.
4851 */
4852void
4853xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4854 if (cur == NULL) {
4855#ifdef DEBUG_TREE
4856 xmlGenericError(xmlGenericErrorContext,
4857 "xmlNodeSetContentLen : node == NULL\n");
4858#endif
4859 return;
4860 }
4861 switch (cur->type) {
4862 case XML_DOCUMENT_FRAG_NODE:
4863 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004864 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004865 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4866 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
4867 UPDATE_LAST_CHILD_AND_PARENT(cur)
4868 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004869 case XML_TEXT_NODE:
4870 case XML_CDATA_SECTION_NODE:
4871 case XML_ENTITY_REF_NODE:
4872 case XML_ENTITY_NODE:
4873 case XML_PI_NODE:
4874 case XML_COMMENT_NODE:
4875 case XML_NOTATION_NODE:
4876 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004877 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004878 }
4879 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4880 cur->children = cur->last = NULL;
4881 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004882 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004883 } else
4884 cur->content = NULL;
4885 break;
4886 case XML_DOCUMENT_NODE:
4887 case XML_DTD_NODE:
4888 case XML_HTML_DOCUMENT_NODE:
4889 case XML_DOCUMENT_TYPE_NODE:
4890 case XML_NAMESPACE_DECL:
4891 case XML_XINCLUDE_START:
4892 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004893#ifdef LIBXML_DOCB_ENABLED
4894 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004895#endif
4896 break;
4897 case XML_ELEMENT_DECL:
4898 /* TODO !!! */
4899 break;
4900 case XML_ATTRIBUTE_DECL:
4901 /* TODO !!! */
4902 break;
4903 case XML_ENTITY_DECL:
4904 /* TODO !!! */
4905 break;
4906 }
4907}
4908
4909/**
4910 * xmlNodeAddContentLen:
4911 * @cur: the node being modified
4912 * @content: extra content
4913 * @len: the size of @content
4914 *
4915 * Append the extra substring to the node content.
4916 */
4917void
4918xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4919 if (cur == NULL) {
4920#ifdef DEBUG_TREE
4921 xmlGenericError(xmlGenericErrorContext,
4922 "xmlNodeAddContentLen : node == NULL\n");
4923#endif
4924 return;
4925 }
4926 if (len <= 0) return;
4927 switch (cur->type) {
4928 case XML_DOCUMENT_FRAG_NODE:
4929 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004930 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004931
Daniel Veillard7db37732001-07-12 01:20:08 +00004932 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004933 newNode = xmlNewTextLen(content, len);
4934 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004935 tmp = xmlAddChild(cur, newNode);
4936 if (tmp != newNode)
4937 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004938 if ((last != NULL) && (last->next == newNode)) {
4939 xmlTextMerge(last, newNode);
4940 }
4941 }
4942 break;
4943 }
4944 case XML_ATTRIBUTE_NODE:
4945 break;
4946 case XML_TEXT_NODE:
4947 case XML_CDATA_SECTION_NODE:
4948 case XML_ENTITY_REF_NODE:
4949 case XML_ENTITY_NODE:
4950 case XML_PI_NODE:
4951 case XML_COMMENT_NODE:
4952 case XML_NOTATION_NODE:
4953 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004954 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004955 }
4956 case XML_DOCUMENT_NODE:
4957 case XML_DTD_NODE:
4958 case XML_HTML_DOCUMENT_NODE:
4959 case XML_DOCUMENT_TYPE_NODE:
4960 case XML_NAMESPACE_DECL:
4961 case XML_XINCLUDE_START:
4962 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004963#ifdef LIBXML_DOCB_ENABLED
4964 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004965#endif
4966 break;
4967 case XML_ELEMENT_DECL:
4968 case XML_ATTRIBUTE_DECL:
4969 case XML_ENTITY_DECL:
4970 break;
4971 }
4972}
4973
4974/**
4975 * xmlNodeAddContent:
4976 * @cur: the node being modified
4977 * @content: extra content
4978 *
4979 * Append the extra substring to the node content.
4980 */
4981void
4982xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
4983 int len;
4984
4985 if (cur == NULL) {
4986#ifdef DEBUG_TREE
4987 xmlGenericError(xmlGenericErrorContext,
4988 "xmlNodeAddContent : node == NULL\n");
4989#endif
4990 return;
4991 }
4992 if (content == NULL) return;
4993 len = xmlStrlen(content);
4994 xmlNodeAddContentLen(cur, content, len);
4995}
4996
4997/**
4998 * xmlTextMerge:
4999 * @first: the first text node
5000 * @second: the second text node being merged
5001 *
5002 * Merge two text nodes into one
5003 * Returns the first text node augmented
5004 */
5005xmlNodePtr
5006xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5007 if (first == NULL) return(second);
5008 if (second == NULL) return(first);
5009 if (first->type != XML_TEXT_NODE) return(first);
5010 if (second->type != XML_TEXT_NODE) return(first);
5011 if (second->name != first->name)
5012 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005013 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005014 xmlUnlinkNode(second);
5015 xmlFreeNode(second);
5016 return(first);
5017}
5018
5019/**
5020 * xmlGetNsList:
5021 * @doc: the document
5022 * @node: the current node
5023 *
5024 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005025 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005026 * that need to be freed by the caller or NULL if no
5027 * namespace if defined
5028 */
5029xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005030xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5031{
Owen Taylor3473f882001-02-23 17:55:21 +00005032 xmlNsPtr cur;
5033 xmlNsPtr *ret = NULL;
5034 int nbns = 0;
5035 int maxns = 10;
5036 int i;
5037
5038 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005039 if (node->type == XML_ELEMENT_NODE) {
5040 cur = node->nsDef;
5041 while (cur != NULL) {
5042 if (ret == NULL) {
5043 ret =
5044 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5045 sizeof(xmlNsPtr));
5046 if (ret == NULL) {
5047 xmlGenericError(xmlGenericErrorContext,
5048 "xmlGetNsList : out of memory!\n");
5049 return (NULL);
5050 }
5051 ret[nbns] = NULL;
5052 }
5053 for (i = 0; i < nbns; i++) {
5054 if ((cur->prefix == ret[i]->prefix) ||
5055 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5056 break;
5057 }
5058 if (i >= nbns) {
5059 if (nbns >= maxns) {
5060 maxns *= 2;
5061 ret = (xmlNsPtr *) xmlRealloc(ret,
5062 (maxns +
5063 1) *
5064 sizeof(xmlNsPtr));
5065 if (ret == NULL) {
5066 xmlGenericError(xmlGenericErrorContext,
5067 "xmlGetNsList : realloc failed!\n");
5068 return (NULL);
5069 }
5070 }
5071 ret[nbns++] = cur;
5072 ret[nbns] = NULL;
5073 }
Owen Taylor3473f882001-02-23 17:55:21 +00005074
Daniel Veillard77044732001-06-29 21:31:07 +00005075 cur = cur->next;
5076 }
5077 }
5078 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005079 }
Daniel Veillard77044732001-06-29 21:31:07 +00005080 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005081}
5082
5083/**
5084 * xmlSearchNs:
5085 * @doc: the document
5086 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005087 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005088 *
5089 * Search a Ns registered under a given name space for a document.
5090 * recurse on the parents until it finds the defined namespace
5091 * or return NULL otherwise.
5092 * @nameSpace can be NULL, this is a search for the default namespace.
5093 * We don't allow to cross entities boundaries. If you don't declare
5094 * the namespace within those you will be in troubles !!! A warning
5095 * is generated to cover this case.
5096 *
5097 * Returns the namespace pointer or NULL.
5098 */
5099xmlNsPtr
5100xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
5101 xmlNsPtr cur;
5102
5103 if (node == NULL) return(NULL);
5104 if ((nameSpace != NULL) &&
5105 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005106 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5107 /*
5108 * The XML-1.0 namespace is normally held on the root
5109 * element. In this case exceptionally create it on the
5110 * node element.
5111 */
5112 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5113 if (cur == NULL) {
5114 xmlGenericError(xmlGenericErrorContext,
5115 "xmlSearchNs : malloc failed\n");
5116 return(NULL);
5117 }
5118 memset(cur, 0, sizeof(xmlNs));
5119 cur->type = XML_LOCAL_NAMESPACE;
5120 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5121 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5122 cur->next = node->nsDef;
5123 node->nsDef = cur;
5124 return(cur);
5125 }
Owen Taylor3473f882001-02-23 17:55:21 +00005126 if (doc->oldNs == NULL) {
5127 /*
5128 * Allocate a new Namespace and fill the fields.
5129 */
5130 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5131 if (doc->oldNs == NULL) {
5132 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005133 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005134 return(NULL);
5135 }
5136 memset(doc->oldNs, 0, sizeof(xmlNs));
5137 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5138
5139 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5140 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5141 }
5142 return(doc->oldNs);
5143 }
5144 while (node != NULL) {
5145 if ((node->type == XML_ENTITY_REF_NODE) ||
5146 (node->type == XML_ENTITY_NODE) ||
5147 (node->type == XML_ENTITY_DECL))
5148 return(NULL);
5149 if (node->type == XML_ELEMENT_NODE) {
5150 cur = node->nsDef;
5151 while (cur != NULL) {
5152 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5153 (cur->href != NULL))
5154 return(cur);
5155 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5156 (cur->href != NULL) &&
5157 (xmlStrEqual(cur->prefix, nameSpace)))
5158 return(cur);
5159 cur = cur->next;
5160 }
5161 }
5162 node = node->parent;
5163 }
5164 return(NULL);
5165}
5166
5167/**
5168 * xmlSearchNsByHref:
5169 * @doc: the document
5170 * @node: the current node
5171 * @href: the namespace value
5172 *
5173 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5174 * the defined namespace or return NULL otherwise.
5175 * Returns the namespace pointer or NULL.
5176 */
5177xmlNsPtr
5178xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
5179 xmlNsPtr cur;
5180 xmlNodePtr orig = node;
5181
5182 if ((node == NULL) || (href == NULL)) return(NULL);
5183 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00005184 /*
5185 * Only the document can hold the XML spec namespace.
5186 */
Daniel Veillardc1a0da32002-08-14 08:32:18 +00005187 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5188 /*
5189 * The XML-1.0 namespace is normally held on the root
5190 * element. In this case exceptionally create it on the
5191 * node element.
5192 */
5193 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5194 if (cur == NULL) {
5195 xmlGenericError(xmlGenericErrorContext,
5196 "xmlSearchNs : malloc failed\n");
5197 return(NULL);
5198 }
5199 memset(cur, 0, sizeof(xmlNs));
5200 cur->type = XML_LOCAL_NAMESPACE;
5201 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5202 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5203 cur->next = node->nsDef;
5204 node->nsDef = cur;
5205 return(cur);
5206 }
Owen Taylor3473f882001-02-23 17:55:21 +00005207 if (doc->oldNs == NULL) {
5208 /*
5209 * Allocate a new Namespace and fill the fields.
5210 */
5211 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5212 if (doc->oldNs == NULL) {
5213 xmlGenericError(xmlGenericErrorContext,
5214 "xmlSearchNsByHref : malloc failed\n");
5215 return(NULL);
5216 }
5217 memset(doc->oldNs, 0, sizeof(xmlNs));
5218 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5219
5220 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5221 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5222 }
5223 return(doc->oldNs);
5224 }
5225 while (node != NULL) {
5226 cur = node->nsDef;
5227 while (cur != NULL) {
5228 if ((cur->href != NULL) && (href != NULL) &&
5229 (xmlStrEqual(cur->href, href))) {
5230 /*
5231 * Check that the prefix is not shadowed between orig and node
5232 */
5233 xmlNodePtr check = orig;
5234 xmlNsPtr tst;
5235
5236 while (check != node) {
5237 tst = check->nsDef;
5238 while (tst != NULL) {
5239 if ((tst->prefix == NULL) && (cur->prefix == NULL))
5240 goto shadowed;
5241 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
5242 (xmlStrEqual(tst->prefix, cur->prefix)))
5243 goto shadowed;
5244 tst = tst->next;
5245 }
5246 check = check->parent;
5247 }
5248 return(cur);
5249 }
5250shadowed:
5251 cur = cur->next;
5252 }
5253 node = node->parent;
5254 }
5255 return(NULL);
5256}
5257
5258/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005259 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005260 * @doc: the document
5261 * @tree: a node expected to hold the new namespace
5262 * @ns: the original namespace
5263 *
5264 * This function tries to locate a namespace definition in a tree
5265 * ancestors, or create a new namespace definition node similar to
5266 * @ns trying to reuse the same prefix. However if the given prefix is
5267 * null (default namespace) or reused within the subtree defined by
5268 * @tree or on one of its ancestors then a new prefix is generated.
5269 * Returns the (new) namespace definition or NULL in case of error
5270 */
5271xmlNsPtr
5272xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5273 xmlNsPtr def;
5274 xmlChar prefix[50];
5275 int counter = 1;
5276
5277 if (tree == NULL) {
5278#ifdef DEBUG_TREE
5279 xmlGenericError(xmlGenericErrorContext,
5280 "xmlNewReconciliedNs : tree == NULL\n");
5281#endif
5282 return(NULL);
5283 }
5284 if (ns == NULL) {
5285#ifdef DEBUG_TREE
5286 xmlGenericError(xmlGenericErrorContext,
5287 "xmlNewReconciliedNs : ns == NULL\n");
5288#endif
5289 return(NULL);
5290 }
5291 /*
5292 * Search an existing namespace definition inherited.
5293 */
5294 def = xmlSearchNsByHref(doc, tree, ns->href);
5295 if (def != NULL)
5296 return(def);
5297
5298 /*
5299 * Find a close prefix which is not already in use.
5300 * Let's strip namespace prefixes longer than 20 chars !
5301 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005302 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005303 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005304 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005305 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005306
Owen Taylor3473f882001-02-23 17:55:21 +00005307 def = xmlSearchNs(doc, tree, prefix);
5308 while (def != NULL) {
5309 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005310 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005311 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005312 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005313 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005314 def = xmlSearchNs(doc, tree, prefix);
5315 }
5316
5317 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005318 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005319 */
5320 def = xmlNewNs(tree, ns->href, prefix);
5321 return(def);
5322}
5323
5324/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005325 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005326 * @doc: the document
5327 * @tree: a node defining the subtree to reconciliate
5328 *
5329 * This function checks that all the namespaces declared within the given
5330 * tree are properly declared. This is needed for example after Copy or Cut
5331 * and then paste operations. The subtree may still hold pointers to
5332 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005333 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005334 * the new environment. If not possible the new namespaces are redeclared
5335 * on @tree at the top of the given subtree.
5336 * Returns the number of namespace declarations created or -1 in case of error.
5337 */
5338int
5339xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5340 xmlNsPtr *oldNs = NULL;
5341 xmlNsPtr *newNs = NULL;
5342 int sizeCache = 0;
5343 int nbCache = 0;
5344
5345 xmlNsPtr n;
5346 xmlNodePtr node = tree;
5347 xmlAttrPtr attr;
5348 int ret = 0, i;
5349
5350 while (node != NULL) {
5351 /*
5352 * Reconciliate the node namespace
5353 */
5354 if (node->ns != NULL) {
5355 /*
5356 * initialize the cache if needed
5357 */
5358 if (sizeCache == 0) {
5359 sizeCache = 10;
5360 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5361 sizeof(xmlNsPtr));
5362 if (oldNs == NULL) {
5363 xmlGenericError(xmlGenericErrorContext,
5364 "xmlReconciliateNs : memory pbm\n");
5365 return(-1);
5366 }
5367 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5368 sizeof(xmlNsPtr));
5369 if (newNs == NULL) {
5370 xmlGenericError(xmlGenericErrorContext,
5371 "xmlReconciliateNs : memory pbm\n");
5372 xmlFree(oldNs);
5373 return(-1);
5374 }
5375 }
5376 for (i = 0;i < nbCache;i++) {
5377 if (oldNs[i] == node->ns) {
5378 node->ns = newNs[i];
5379 break;
5380 }
5381 }
5382 if (i == nbCache) {
5383 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005384 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005385 */
5386 n = xmlNewReconciliedNs(doc, tree, node->ns);
5387 if (n != NULL) { /* :-( what if else ??? */
5388 /*
5389 * check if we need to grow the cache buffers.
5390 */
5391 if (sizeCache <= nbCache) {
5392 sizeCache *= 2;
5393 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5394 sizeof(xmlNsPtr));
5395 if (oldNs == NULL) {
5396 xmlGenericError(xmlGenericErrorContext,
5397 "xmlReconciliateNs : memory pbm\n");
5398 xmlFree(newNs);
5399 return(-1);
5400 }
5401 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5402 sizeof(xmlNsPtr));
5403 if (newNs == NULL) {
5404 xmlGenericError(xmlGenericErrorContext,
5405 "xmlReconciliateNs : memory pbm\n");
5406 xmlFree(oldNs);
5407 return(-1);
5408 }
5409 }
5410 newNs[nbCache] = n;
5411 oldNs[nbCache++] = node->ns;
5412 node->ns = n;
5413 }
5414 }
5415 }
5416 /*
5417 * now check for namespace hold by attributes on the node.
5418 */
5419 attr = node->properties;
5420 while (attr != NULL) {
5421 if (attr->ns != NULL) {
5422 /*
5423 * initialize the cache if needed
5424 */
5425 if (sizeCache == 0) {
5426 sizeCache = 10;
5427 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5428 sizeof(xmlNsPtr));
5429 if (oldNs == NULL) {
5430 xmlGenericError(xmlGenericErrorContext,
5431 "xmlReconciliateNs : memory pbm\n");
5432 return(-1);
5433 }
5434 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5435 sizeof(xmlNsPtr));
5436 if (newNs == NULL) {
5437 xmlGenericError(xmlGenericErrorContext,
5438 "xmlReconciliateNs : memory pbm\n");
5439 xmlFree(oldNs);
5440 return(-1);
5441 }
5442 }
5443 for (i = 0;i < nbCache;i++) {
5444 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005445 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005446 break;
5447 }
5448 }
5449 if (i == nbCache) {
5450 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005451 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005452 */
5453 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5454 if (n != NULL) { /* :-( what if else ??? */
5455 /*
5456 * check if we need to grow the cache buffers.
5457 */
5458 if (sizeCache <= nbCache) {
5459 sizeCache *= 2;
5460 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5461 sizeof(xmlNsPtr));
5462 if (oldNs == NULL) {
5463 xmlGenericError(xmlGenericErrorContext,
5464 "xmlReconciliateNs : memory pbm\n");
5465 xmlFree(newNs);
5466 return(-1);
5467 }
5468 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5469 sizeof(xmlNsPtr));
5470 if (newNs == NULL) {
5471 xmlGenericError(xmlGenericErrorContext,
5472 "xmlReconciliateNs : memory pbm\n");
5473 xmlFree(oldNs);
5474 return(-1);
5475 }
5476 }
5477 newNs[nbCache] = n;
5478 oldNs[nbCache++] = attr->ns;
5479 attr->ns = n;
5480 }
5481 }
5482 }
5483 attr = attr->next;
5484 }
5485
5486 /*
5487 * Browse the full subtree, deep first
5488 */
5489 if (node->children != NULL) {
5490 /* deep first */
5491 node = node->children;
5492 } else if ((node != tree) && (node->next != NULL)) {
5493 /* then siblings */
5494 node = node->next;
5495 } else if (node != tree) {
5496 /* go up to parents->next if needed */
5497 while (node != tree) {
5498 if (node->parent != NULL)
5499 node = node->parent;
5500 if ((node != tree) && (node->next != NULL)) {
5501 node = node->next;
5502 break;
5503 }
5504 if (node->parent == NULL) {
5505 node = NULL;
5506 break;
5507 }
5508 }
5509 /* exit condition */
5510 if (node == tree)
5511 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005512 } else
5513 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005514 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005515 if (oldNs != NULL)
5516 xmlFree(oldNs);
5517 if (newNs != NULL)
5518 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005519 return(ret);
5520}
5521
5522/**
5523 * xmlHasProp:
5524 * @node: the node
5525 * @name: the attribute name
5526 *
5527 * Search an attribute associated to a node
5528 * This function also looks in DTD attribute declaration for #FIXED or
5529 * default declaration values unless DTD use has been turned off.
5530 *
5531 * Returns the attribute or the attribute declaration or NULL if
5532 * neither was found.
5533 */
5534xmlAttrPtr
5535xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5536 xmlAttrPtr prop;
5537 xmlDocPtr doc;
5538
5539 if ((node == NULL) || (name == NULL)) return(NULL);
5540 /*
5541 * Check on the properties attached to the node
5542 */
5543 prop = node->properties;
5544 while (prop != NULL) {
5545 if (xmlStrEqual(prop->name, name)) {
5546 return(prop);
5547 }
5548 prop = prop->next;
5549 }
5550 if (!xmlCheckDTD) return(NULL);
5551
5552 /*
5553 * Check if there is a default declaration in the internal
5554 * or external subsets
5555 */
5556 doc = node->doc;
5557 if (doc != NULL) {
5558 xmlAttributePtr attrDecl;
5559 if (doc->intSubset != NULL) {
5560 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5561 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5562 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005563 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5564 /* return attribute declaration only if a default value is given
5565 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005566 return((xmlAttrPtr) attrDecl);
5567 }
5568 }
5569 return(NULL);
5570}
5571
5572/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005573 * xmlHasNsProp:
5574 * @node: the node
5575 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005576 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005577 *
5578 * Search for an attribute associated to a node
5579 * This attribute has to be anchored in the namespace specified.
5580 * This does the entity substitution.
5581 * This function looks in DTD attribute declaration for #FIXED or
5582 * default declaration values unless DTD use has been turned off.
5583 *
5584 * Returns the attribute or the attribute declaration or NULL
5585 * if neither was found.
5586 */
5587xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005588xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005589 xmlAttrPtr prop;
5590 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005591
5592 if (node == NULL)
5593 return(NULL);
5594
5595 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005596 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005597 return(xmlHasProp(node, name));
5598 while (prop != NULL) {
5599 /*
5600 * One need to have
5601 * - same attribute names
5602 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005603 */
5604 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005605 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5606 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005607 }
5608 prop = prop->next;
5609 }
5610 if (!xmlCheckDTD) return(NULL);
5611
5612 /*
5613 * Check if there is a default declaration in the internal
5614 * or external subsets
5615 */
5616 doc = node->doc;
5617 if (doc != NULL) {
5618 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005619 xmlAttributePtr attrDecl = NULL;
5620 xmlNsPtr *nsList, *cur;
5621 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005622
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005623 nsList = xmlGetNsList(node->doc, node);
5624 if (nsList == NULL)
5625 return(NULL);
5626 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5627 ename = xmlStrdup(node->ns->prefix);
5628 ename = xmlStrcat(ename, BAD_CAST ":");
5629 ename = xmlStrcat(ename, node->name);
5630 } else {
5631 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005632 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005633 if (ename == NULL) {
5634 xmlFree(nsList);
5635 return(NULL);
5636 }
5637
5638 cur = nsList;
5639 while (*cur != NULL) {
5640 if (xmlStrEqual((*cur)->href, nameSpace)) {
5641 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5642 name, (*cur)->prefix);
5643 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5644 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5645 name, (*cur)->prefix);
5646 }
5647 cur++;
5648 }
5649 xmlFree(nsList);
5650 xmlFree(ename);
5651 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005652 }
5653 }
5654 return(NULL);
5655}
5656
5657/**
Owen Taylor3473f882001-02-23 17:55:21 +00005658 * xmlGetProp:
5659 * @node: the node
5660 * @name: the attribute name
5661 *
5662 * Search and get the value of an attribute associated to a node
5663 * This does the entity substitution.
5664 * This function looks in DTD attribute declaration for #FIXED or
5665 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00005666 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00005667 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
5668 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00005669 *
5670 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005671 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005672 */
5673xmlChar *
5674xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5675 xmlAttrPtr prop;
5676 xmlDocPtr doc;
5677
5678 if ((node == NULL) || (name == NULL)) return(NULL);
5679 /*
5680 * Check on the properties attached to the node
5681 */
5682 prop = node->properties;
5683 while (prop != NULL) {
5684 if (xmlStrEqual(prop->name, name)) {
5685 xmlChar *ret;
5686
5687 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5688 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5689 return(ret);
5690 }
5691 prop = prop->next;
5692 }
5693 if (!xmlCheckDTD) return(NULL);
5694
5695 /*
5696 * Check if there is a default declaration in the internal
5697 * or external subsets
5698 */
5699 doc = node->doc;
5700 if (doc != NULL) {
5701 xmlAttributePtr attrDecl;
5702 if (doc->intSubset != NULL) {
5703 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5704 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5705 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005706 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5707 /* return attribute declaration only if a default value is given
5708 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005709 return(xmlStrdup(attrDecl->defaultValue));
5710 }
5711 }
5712 return(NULL);
5713}
5714
5715/**
Daniel Veillard71531f32003-02-05 13:19:53 +00005716 * xmlGetNoNsProp:
5717 * @node: the node
5718 * @name: the attribute name
5719 *
5720 * Search and get the value of an attribute associated to a node
5721 * This does the entity substitution.
5722 * This function looks in DTD attribute declaration for #FIXED or
5723 * default declaration values unless DTD use has been turned off.
5724 * This function is similar to xmlGetProp except it will accept only
5725 * an attribute in no namespace.
5726 *
5727 * Returns the attribute value or NULL if not found.
5728 * It's up to the caller to free the memory with xmlFree().
5729 */
5730xmlChar *
5731xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
5732 xmlAttrPtr prop;
5733 xmlDocPtr doc;
5734
5735 if ((node == NULL) || (name == NULL)) return(NULL);
5736 /*
5737 * Check on the properties attached to the node
5738 */
5739 prop = node->properties;
5740 while (prop != NULL) {
5741 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
5742 xmlChar *ret;
5743
5744 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5745 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5746 return(ret);
5747 }
5748 prop = prop->next;
5749 }
5750 if (!xmlCheckDTD) return(NULL);
5751
5752 /*
5753 * Check if there is a default declaration in the internal
5754 * or external subsets
5755 */
5756 doc = node->doc;
5757 if (doc != NULL) {
5758 xmlAttributePtr attrDecl;
5759 if (doc->intSubset != NULL) {
5760 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5761 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5762 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005763 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5764 /* return attribute declaration only if a default value is given
5765 (that includes #FIXED declarations) */
Daniel Veillard71531f32003-02-05 13:19:53 +00005766 return(xmlStrdup(attrDecl->defaultValue));
5767 }
5768 }
5769 return(NULL);
5770}
5771
5772/**
Owen Taylor3473f882001-02-23 17:55:21 +00005773 * xmlGetNsProp:
5774 * @node: the node
5775 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005776 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005777 *
5778 * Search and get the value of an attribute associated to a node
5779 * This attribute has to be anchored in the namespace specified.
5780 * This does the entity substitution.
5781 * This function looks in DTD attribute declaration for #FIXED or
5782 * default declaration values unless DTD use has been turned off.
5783 *
5784 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005785 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005786 */
5787xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00005788xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00005789 xmlAttrPtr prop;
5790 xmlDocPtr doc;
5791 xmlNsPtr ns;
5792
5793 if (node == NULL)
5794 return(NULL);
5795
5796 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005797 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00005798 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00005799 while (prop != NULL) {
5800 /*
5801 * One need to have
5802 * - same attribute names
5803 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005804 */
5805 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00005806 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00005807 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005808 xmlChar *ret;
5809
5810 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5811 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5812 return(ret);
5813 }
5814 prop = prop->next;
5815 }
5816 if (!xmlCheckDTD) return(NULL);
5817
5818 /*
5819 * Check if there is a default declaration in the internal
5820 * or external subsets
5821 */
5822 doc = node->doc;
5823 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005824 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00005825 xmlAttributePtr attrDecl;
5826
Owen Taylor3473f882001-02-23 17:55:21 +00005827 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5828 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5829 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5830
5831 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
5832 /*
5833 * The DTD declaration only allows a prefix search
5834 */
5835 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00005836 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00005837 return(xmlStrdup(attrDecl->defaultValue));
5838 }
5839 }
5840 }
5841 return(NULL);
5842}
5843
5844/**
5845 * xmlSetProp:
5846 * @node: the node
5847 * @name: the attribute name
5848 * @value: the attribute value
5849 *
5850 * Set (or reset) an attribute carried by a node.
5851 * Returns the attribute pointer.
5852 */
5853xmlAttrPtr
5854xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005855 xmlAttrPtr prop;
5856 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00005857
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00005858 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00005859 return(NULL);
5860 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005861 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00005862 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005863 if ((xmlStrEqual(prop->name, name)) &&
5864 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005865 xmlNodePtr oldprop = prop->children;
5866
Owen Taylor3473f882001-02-23 17:55:21 +00005867 prop->children = NULL;
5868 prop->last = NULL;
5869 if (value != NULL) {
5870 xmlChar *buffer;
5871 xmlNodePtr tmp;
5872
5873 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5874 prop->children = xmlStringGetNodeList(node->doc, buffer);
5875 prop->last = NULL;
5876 prop->doc = doc;
5877 tmp = prop->children;
5878 while (tmp != NULL) {
5879 tmp->parent = (xmlNodePtr) prop;
5880 tmp->doc = doc;
5881 if (tmp->next == NULL)
5882 prop->last = tmp;
5883 tmp = tmp->next;
5884 }
5885 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00005886 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005887 if (oldprop != NULL)
5888 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00005889 return(prop);
5890 }
5891 prop = prop->next;
5892 }
5893 prop = xmlNewProp(node, name, value);
5894 return(prop);
5895}
5896
5897/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005898 * xmlUnsetProp:
5899 * @node: the node
5900 * @name: the attribute name
5901 *
5902 * Remove an attribute carried by a node.
5903 * Returns 0 if successful, -1 if not found
5904 */
5905int
5906xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Daniel Veillard814a76d2003-01-23 18:24:20 +00005907 xmlAttrPtr prop, prev = NULL;;
Daniel Veillard75bea542001-05-11 17:41:21 +00005908
5909 if ((node == NULL) || (name == NULL))
5910 return(-1);
Daniel Veillard814a76d2003-01-23 18:24:20 +00005911 prop = node->properties;
Daniel Veillard75bea542001-05-11 17:41:21 +00005912 while (prop != NULL) {
5913 if ((xmlStrEqual(prop->name, name)) &&
5914 (prop->ns == NULL)) {
5915 if (prev == NULL)
5916 node->properties = prop->next;
5917 else
5918 prev->next = prop->next;
5919 xmlFreeProp(prop);
5920 return(0);
5921 }
5922 prev = prop;
5923 prop = prop->next;
5924 }
5925 return(-1);
5926}
5927
5928/**
Owen Taylor3473f882001-02-23 17:55:21 +00005929 * xmlSetNsProp:
5930 * @node: the node
5931 * @ns: the namespace definition
5932 * @name: the attribute name
5933 * @value: the attribute value
5934 *
5935 * Set (or reset) an attribute carried by a node.
5936 * The ns structure must be in scope, this is not checked.
5937 *
5938 * Returns the attribute pointer.
5939 */
5940xmlAttrPtr
5941xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
5942 const xmlChar *value) {
5943 xmlAttrPtr prop;
5944
5945 if ((node == NULL) || (name == NULL))
5946 return(NULL);
5947
5948 if (ns == NULL)
5949 return(xmlSetProp(node, name, value));
5950 if (ns->href == NULL)
5951 return(NULL);
5952 prop = node->properties;
5953
5954 while (prop != NULL) {
5955 /*
5956 * One need to have
5957 * - same attribute names
5958 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005959 */
5960 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00005961 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005962 if (prop->children != NULL)
5963 xmlFreeNodeList(prop->children);
5964 prop->children = NULL;
5965 prop->last = NULL;
5966 prop->ns = ns;
5967 if (value != NULL) {
5968 xmlChar *buffer;
5969 xmlNodePtr tmp;
5970
5971 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5972 prop->children = xmlStringGetNodeList(node->doc, buffer);
5973 prop->last = NULL;
5974 tmp = prop->children;
5975 while (tmp != NULL) {
5976 tmp->parent = (xmlNodePtr) prop;
5977 if (tmp->next == NULL)
5978 prop->last = tmp;
5979 tmp = tmp->next;
5980 }
5981 xmlFree(buffer);
5982 }
5983 return(prop);
5984 }
5985 prop = prop->next;
5986 }
5987 prop = xmlNewNsProp(node, ns, name, value);
5988 return(prop);
5989}
5990
5991/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005992 * xmlUnsetNsProp:
5993 * @node: the node
5994 * @ns: the namespace definition
5995 * @name: the attribute name
5996 *
5997 * Remove an attribute carried by a node.
5998 * Returns 0 if successful, -1 if not found
5999 */
6000int
6001xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
6002 xmlAttrPtr prop = node->properties, prev = NULL;;
6003
6004 if ((node == NULL) || (name == NULL))
6005 return(-1);
6006 if (ns == NULL)
6007 return(xmlUnsetProp(node, name));
6008 if (ns->href == NULL)
6009 return(-1);
6010 while (prop != NULL) {
6011 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00006012 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006013 if (prev == NULL)
6014 node->properties = prop->next;
6015 else
6016 prev->next = prop->next;
6017 xmlFreeProp(prop);
6018 return(0);
6019 }
6020 prev = prop;
6021 prop = prop->next;
6022 }
6023 return(-1);
6024}
6025
6026/**
Owen Taylor3473f882001-02-23 17:55:21 +00006027 * xmlNodeIsText:
6028 * @node: the node
6029 *
6030 * Is this node a Text node ?
6031 * Returns 1 yes, 0 no
6032 */
6033int
6034xmlNodeIsText(xmlNodePtr node) {
6035 if (node == NULL) return(0);
6036
6037 if (node->type == XML_TEXT_NODE) return(1);
6038 return(0);
6039}
6040
6041/**
6042 * xmlIsBlankNode:
6043 * @node: the node
6044 *
6045 * Checks whether this node is an empty or whitespace only
6046 * (and possibly ignorable) text-node.
6047 *
6048 * Returns 1 yes, 0 no
6049 */
6050int
6051xmlIsBlankNode(xmlNodePtr node) {
6052 const xmlChar *cur;
6053 if (node == NULL) return(0);
6054
Daniel Veillard7db37732001-07-12 01:20:08 +00006055 if ((node->type != XML_TEXT_NODE) &&
6056 (node->type != XML_CDATA_SECTION_NODE))
6057 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006058 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006059 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006060 while (*cur != 0) {
6061 if (!IS_BLANK(*cur)) return(0);
6062 cur++;
6063 }
6064
6065 return(1);
6066}
6067
6068/**
6069 * xmlTextConcat:
6070 * @node: the node
6071 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006072 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006073 *
6074 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006075 *
6076 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006077 */
6078
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006079int
Owen Taylor3473f882001-02-23 17:55:21 +00006080xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006081 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006082
6083 if ((node->type != XML_TEXT_NODE) &&
6084 (node->type != XML_CDATA_SECTION_NODE)) {
6085#ifdef DEBUG_TREE
6086 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006087 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006088#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006089 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006090 }
Owen Taylor3473f882001-02-23 17:55:21 +00006091 node->content = xmlStrncat(node->content, content, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006092 if (node->content == NULL)
6093 return(-1);
6094 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006095}
6096
6097/************************************************************************
6098 * *
6099 * Output : to a FILE or in memory *
6100 * *
6101 ************************************************************************/
6102
Owen Taylor3473f882001-02-23 17:55:21 +00006103/**
6104 * xmlBufferCreate:
6105 *
6106 * routine to create an XML buffer.
6107 * returns the new structure.
6108 */
6109xmlBufferPtr
6110xmlBufferCreate(void) {
6111 xmlBufferPtr ret;
6112
6113 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6114 if (ret == NULL) {
6115 xmlGenericError(xmlGenericErrorContext,
6116 "xmlBufferCreate : out of memory!\n");
6117 return(NULL);
6118 }
6119 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006120 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006121 ret->alloc = xmlBufferAllocScheme;
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 return(ret);
6131}
6132
6133/**
6134 * xmlBufferCreateSize:
6135 * @size: initial size of buffer
6136 *
6137 * routine to create an XML buffer.
6138 * returns the new structure.
6139 */
6140xmlBufferPtr
6141xmlBufferCreateSize(size_t size) {
6142 xmlBufferPtr ret;
6143
6144 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6145 if (ret == NULL) {
6146 xmlGenericError(xmlGenericErrorContext,
6147 "xmlBufferCreate : out of memory!\n");
6148 return(NULL);
6149 }
6150 ret->use = 0;
6151 ret->alloc = xmlBufferAllocScheme;
6152 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6153 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006154 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006155 if (ret->content == NULL) {
6156 xmlGenericError(xmlGenericErrorContext,
6157 "xmlBufferCreate : out of memory!\n");
6158 xmlFree(ret);
6159 return(NULL);
6160 }
6161 ret->content[0] = 0;
6162 } else
6163 ret->content = NULL;
6164 return(ret);
6165}
6166
6167/**
6168 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006169 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006170 * @scheme: allocation scheme to use
6171 *
6172 * Sets the allocation scheme for this buffer
6173 */
6174void
6175xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6176 xmlBufferAllocationScheme scheme) {
6177 if (buf == NULL) {
6178#ifdef DEBUG_BUFFER
6179 xmlGenericError(xmlGenericErrorContext,
6180 "xmlBufferSetAllocationScheme: buf == NULL\n");
6181#endif
6182 return;
6183 }
6184
6185 buf->alloc = scheme;
6186}
6187
6188/**
6189 * xmlBufferFree:
6190 * @buf: the buffer to free
6191 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006192 * Frees an XML buffer. It frees both the content and the structure which
6193 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006194 */
6195void
6196xmlBufferFree(xmlBufferPtr buf) {
6197 if (buf == NULL) {
6198#ifdef DEBUG_BUFFER
6199 xmlGenericError(xmlGenericErrorContext,
6200 "xmlBufferFree: buf == NULL\n");
6201#endif
6202 return;
6203 }
Daniel Veillard561b7f82002-03-20 21:55:57 +00006204 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006205 xmlFree(buf->content);
6206 }
Owen Taylor3473f882001-02-23 17:55:21 +00006207 xmlFree(buf);
6208}
6209
6210/**
6211 * xmlBufferEmpty:
6212 * @buf: the buffer
6213 *
6214 * empty a buffer.
6215 */
6216void
6217xmlBufferEmpty(xmlBufferPtr buf) {
6218 if (buf->content == NULL) return;
6219 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006220 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00006221}
6222
6223/**
6224 * xmlBufferShrink:
6225 * @buf: the buffer to dump
6226 * @len: the number of xmlChar to remove
6227 *
6228 * Remove the beginning of an XML buffer.
6229 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006230 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006231 */
6232int
6233xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
6234 if (len == 0) return(0);
6235 if (len > buf->use) return(-1);
6236
6237 buf->use -= len;
6238 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6239
6240 buf->content[buf->use] = 0;
6241 return(len);
6242}
6243
6244/**
6245 * xmlBufferGrow:
6246 * @buf: the buffer
6247 * @len: the minimum free size to allocate
6248 *
6249 * Grow the available space of an XML buffer.
6250 *
6251 * Returns the new available space or -1 in case of error
6252 */
6253int
6254xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6255 int size;
6256 xmlChar *newbuf;
6257
6258 if (len + buf->use < buf->size) return(0);
6259
6260 size = buf->use + len + 100;
6261
6262 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
6263 if (newbuf == NULL) return(-1);
6264 buf->content = newbuf;
6265 buf->size = size;
6266 return(buf->size - buf->use);
6267}
6268
6269/**
6270 * xmlBufferDump:
6271 * @file: the file output
6272 * @buf: the buffer to dump
6273 *
6274 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006275 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006276 */
6277int
6278xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6279 int ret;
6280
6281 if (buf == NULL) {
6282#ifdef DEBUG_BUFFER
6283 xmlGenericError(xmlGenericErrorContext,
6284 "xmlBufferDump: buf == NULL\n");
6285#endif
6286 return(0);
6287 }
6288 if (buf->content == NULL) {
6289#ifdef DEBUG_BUFFER
6290 xmlGenericError(xmlGenericErrorContext,
6291 "xmlBufferDump: buf->content == NULL\n");
6292#endif
6293 return(0);
6294 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006295 if (file == NULL)
6296 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006297 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6298 return(ret);
6299}
6300
6301/**
6302 * xmlBufferContent:
6303 * @buf: the buffer
6304 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006305 * Function to extract the content of a buffer
6306 *
Owen Taylor3473f882001-02-23 17:55:21 +00006307 * Returns the internal content
6308 */
6309
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006310const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006311xmlBufferContent(const xmlBufferPtr buf)
6312{
6313 if(!buf)
6314 return NULL;
6315
6316 return buf->content;
6317}
6318
6319/**
6320 * xmlBufferLength:
6321 * @buf: the buffer
6322 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006323 * Function to get the length of a buffer
6324 *
Owen Taylor3473f882001-02-23 17:55:21 +00006325 * Returns the length of data in the internal content
6326 */
6327
6328int
6329xmlBufferLength(const xmlBufferPtr buf)
6330{
6331 if(!buf)
6332 return 0;
6333
6334 return buf->use;
6335}
6336
6337/**
6338 * xmlBufferResize:
6339 * @buf: the buffer to resize
6340 * @size: the desired size
6341 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006342 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006343 *
6344 * Returns 0 in case of problems, 1 otherwise
6345 */
6346int
6347xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6348{
6349 unsigned int newSize;
6350 xmlChar* rebuf = NULL;
6351
6352 /*take care of empty case*/
6353 newSize = (buf->size ? buf->size*2 : size);
6354
6355 /* Don't resize if we don't have to */
6356 if (size < buf->size)
6357 return 1;
6358
6359 /* figure out new size */
6360 switch (buf->alloc){
6361 case XML_BUFFER_ALLOC_DOUBLEIT:
6362 while (size > newSize) newSize *= 2;
6363 break;
6364 case XML_BUFFER_ALLOC_EXACT:
6365 newSize = size+10;
6366 break;
6367 default:
6368 newSize = size+10;
6369 break;
6370 }
6371
6372 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006373 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006374 else
6375 rebuf = (xmlChar *) xmlRealloc(buf->content,
6376 newSize * sizeof(xmlChar));
6377 if (rebuf == NULL) {
6378 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006379 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006380 return 0;
6381 }
6382 buf->content = rebuf;
6383 buf->size = newSize;
6384
6385 return 1;
6386}
6387
6388/**
6389 * xmlBufferAdd:
6390 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006391 * @str: the #xmlChar string
6392 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006393 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006394 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006395 * str is recomputed.
6396 */
6397void
6398xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6399 unsigned int needSize;
6400
6401 if (str == NULL) {
6402#ifdef DEBUG_BUFFER
6403 xmlGenericError(xmlGenericErrorContext,
6404 "xmlBufferAdd: str == NULL\n");
6405#endif
6406 return;
6407 }
6408 if (len < -1) {
6409#ifdef DEBUG_BUFFER
6410 xmlGenericError(xmlGenericErrorContext,
6411 "xmlBufferAdd: len < 0\n");
6412#endif
6413 return;
6414 }
6415 if (len == 0) return;
6416
6417 if (len < 0)
6418 len = xmlStrlen(str);
6419
6420 if (len <= 0) return;
6421
6422 needSize = buf->use + len + 2;
6423 if (needSize > buf->size){
6424 if (!xmlBufferResize(buf, needSize)){
6425 xmlGenericError(xmlGenericErrorContext,
6426 "xmlBufferAdd : out of memory!\n");
6427 return;
6428 }
6429 }
6430
6431 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6432 buf->use += len;
6433 buf->content[buf->use] = 0;
6434}
6435
6436/**
6437 * xmlBufferAddHead:
6438 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006439 * @str: the #xmlChar string
6440 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006441 *
6442 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006443 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00006444 */
6445void
6446xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6447 unsigned int needSize;
6448
6449 if (str == NULL) {
6450#ifdef DEBUG_BUFFER
6451 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006452 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006453#endif
6454 return;
6455 }
6456 if (len < -1) {
6457#ifdef DEBUG_BUFFER
6458 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006459 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006460#endif
6461 return;
6462 }
6463 if (len == 0) return;
6464
6465 if (len < 0)
6466 len = xmlStrlen(str);
6467
6468 if (len <= 0) return;
6469
6470 needSize = buf->use + len + 2;
6471 if (needSize > buf->size){
6472 if (!xmlBufferResize(buf, needSize)){
6473 xmlGenericError(xmlGenericErrorContext,
6474 "xmlBufferAddHead : out of memory!\n");
6475 return;
6476 }
6477 }
6478
6479 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6480 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6481 buf->use += len;
6482 buf->content[buf->use] = 0;
6483}
6484
6485/**
6486 * xmlBufferCat:
6487 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006488 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006489 *
6490 * Append a zero terminated string to an XML buffer.
6491 */
6492void
6493xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
6494 if (str != NULL)
6495 xmlBufferAdd(buf, str, -1);
6496}
6497
6498/**
6499 * xmlBufferCCat:
6500 * @buf: the buffer to dump
6501 * @str: the C char string
6502 *
6503 * Append a zero terminated C string to an XML buffer.
6504 */
6505void
6506xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6507 const char *cur;
6508
6509 if (str == NULL) {
6510#ifdef DEBUG_BUFFER
6511 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006512 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006513#endif
6514 return;
6515 }
6516 for (cur = str;*cur != 0;cur++) {
6517 if (buf->use + 10 >= buf->size) {
6518 if (!xmlBufferResize(buf, buf->use+10)){
6519 xmlGenericError(xmlGenericErrorContext,
6520 "xmlBufferCCat : out of memory!\n");
6521 return;
6522 }
6523 }
6524 buf->content[buf->use++] = *cur;
6525 }
6526 buf->content[buf->use] = 0;
6527}
6528
6529/**
6530 * xmlBufferWriteCHAR:
6531 * @buf: the XML buffer
6532 * @string: the string to add
6533 *
6534 * routine which manages and grows an output buffer. This one adds
6535 * xmlChars at the end of the buffer.
6536 */
6537void
Owen Taylor3473f882001-02-23 17:55:21 +00006538xmlBufferWriteCHAR
Owen Taylor3473f882001-02-23 17:55:21 +00006539(xmlBufferPtr buf, const xmlChar *string) {
6540 xmlBufferCat(buf, string);
6541}
6542
6543/**
6544 * xmlBufferWriteChar:
6545 * @buf: the XML buffer output
6546 * @string: the string to add
6547 *
6548 * routine which manage and grows an output buffer. This one add
6549 * C chars at the end of the array.
6550 */
6551void
6552xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
6553 xmlBufferCCat(buf, string);
6554}
6555
6556
6557/**
6558 * xmlBufferWriteQuotedString:
6559 * @buf: the XML buffer output
6560 * @string: the string to add
6561 *
6562 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00006563 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00006564 * quote or double-quotes internally
6565 */
6566void
6567xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
6568 if (xmlStrchr(string, '"')) {
6569 if (xmlStrchr(string, '\'')) {
6570#ifdef DEBUG_BUFFER
6571 xmlGenericError(xmlGenericErrorContext,
6572 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
6573#endif
6574 }
6575 xmlBufferCCat(buf, "'");
6576 xmlBufferCat(buf, string);
6577 xmlBufferCCat(buf, "'");
6578 } else {
6579 xmlBufferCCat(buf, "\"");
6580 xmlBufferCat(buf, string);
6581 xmlBufferCCat(buf, "\"");
6582 }
6583}
6584
6585
6586/************************************************************************
6587 * *
6588 * Dumping XML tree content to a simple buffer *
6589 * *
6590 ************************************************************************/
6591
Owen Taylor3473f882001-02-23 17:55:21 +00006592/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00006593 * xmlAttrSerializeContent:
6594 * @buf: the XML buffer output
6595 * @doc: the document
6596 * @attr: the attribute pointer
6597 *
6598 * Serialize the attribute in the buffer
6599 */
6600static void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006601xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr)
6602{
Daniel Veillarda6d05382002-02-13 13:07:41 +00006603 const xmlChar *cur, *base;
6604 xmlNodePtr children;
6605
6606 children = attr->children;
6607 while (children != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006608 switch (children->type) {
6609 case XML_TEXT_NODE:
6610 base = cur = children->content;
6611 while (*cur != 0) {
6612 if (*cur == '\n') {
6613 if (base != cur)
6614 xmlBufferAdd(buf, base, cur - base);
6615 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
6616 cur++;
6617 base = cur;
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006618 } else if (*cur == '\r') {
6619 if (base != cur)
6620 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006621 xmlBufferAdd(buf, BAD_CAST "&#13;", 5);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006622 cur++;
6623 base = cur;
6624 } else if (*cur == '\t') {
6625 if (base != cur)
6626 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006627 xmlBufferAdd(buf, BAD_CAST "&#9;", 4);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006628 cur++;
6629 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006630#if 0
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006631 } else if (*cur == '\'') {
6632 if (base != cur)
6633 xmlBufferAdd(buf, base, cur - base);
6634 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
6635 cur++;
6636 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006637#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006638 } else if (*cur == '"') {
6639 if (base != cur)
6640 xmlBufferAdd(buf, base, cur - base);
6641 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6642 cur++;
6643 base = cur;
6644 } else if (*cur == '<') {
6645 if (base != cur)
6646 xmlBufferAdd(buf, base, cur - base);
6647 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
6648 cur++;
6649 base = cur;
6650 } else if (*cur == '>') {
6651 if (base != cur)
6652 xmlBufferAdd(buf, base, cur - base);
6653 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
6654 cur++;
6655 base = cur;
6656 } else if (*cur == '&') {
6657 if (base != cur)
6658 xmlBufferAdd(buf, base, cur - base);
6659 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
6660 cur++;
6661 base = cur;
6662 } else if ((*cur >= 0x80) && ((doc == NULL) ||
6663 (doc->encoding ==
6664 NULL))) {
6665 /*
6666 * We assume we have UTF-8 content.
6667 */
6668 char tmp[10];
6669 int val = 0, l = 1;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006670
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006671 if (base != cur)
6672 xmlBufferAdd(buf, base, cur - base);
6673 if (*cur < 0xC0) {
6674 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6d05382002-02-13 13:07:41 +00006675 "xmlAttrSerializeContent : input not UTF-8\n");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006676 if (doc != NULL)
6677 doc->encoding =
6678 xmlStrdup(BAD_CAST "ISO-8859-1");
6679 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6680 tmp[sizeof(tmp) - 1] = 0;
6681 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6682 cur++;
6683 base = cur;
6684 continue;
6685 } else if (*cur < 0xE0) {
6686 val = (cur[0]) & 0x1F;
6687 val <<= 6;
6688 val |= (cur[1]) & 0x3F;
6689 l = 2;
6690 } else if (*cur < 0xF0) {
6691 val = (cur[0]) & 0x0F;
6692 val <<= 6;
6693 val |= (cur[1]) & 0x3F;
6694 val <<= 6;
6695 val |= (cur[2]) & 0x3F;
6696 l = 3;
6697 } else if (*cur < 0xF8) {
6698 val = (cur[0]) & 0x07;
6699 val <<= 6;
6700 val |= (cur[1]) & 0x3F;
6701 val <<= 6;
6702 val |= (cur[2]) & 0x3F;
6703 val <<= 6;
6704 val |= (cur[3]) & 0x3F;
6705 l = 4;
6706 }
6707 if ((l == 1) || (!IS_CHAR(val))) {
6708 xmlGenericError(xmlGenericErrorContext,
6709 "xmlAttrSerializeContent : char out of range\n");
6710 if (doc != NULL)
6711 doc->encoding =
6712 xmlStrdup(BAD_CAST "ISO-8859-1");
6713 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6714 tmp[sizeof(tmp) - 1] = 0;
6715 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6716 cur++;
6717 base = cur;
6718 continue;
6719 }
6720 /*
6721 * We could do multiple things here. Just save
6722 * as a char ref
6723 */
6724 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
6725 tmp[sizeof(tmp) - 1] = 0;
6726 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6727 cur += l;
6728 base = cur;
6729 } else {
6730 cur++;
6731 }
6732 }
6733 if (base != cur)
6734 xmlBufferAdd(buf, base, cur - base);
6735 break;
6736 case XML_ENTITY_REF_NODE:
6737 xmlBufferAdd(buf, BAD_CAST "&", 1);
6738 xmlBufferAdd(buf, children->name,
6739 xmlStrlen(children->name));
6740 xmlBufferAdd(buf, BAD_CAST ";", 1);
6741 break;
6742 default:
6743 /* should not happen unless we have a badly built tree */
6744 break;
6745 }
6746 children = children->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006747 }
6748}
6749
6750/**
6751 * xmlNodeDump:
6752 * @buf: the XML buffer output
6753 * @doc: the document
6754 * @cur: the current node
6755 * @level: the imbrication level for indenting
6756 * @format: is formatting allowed
6757 *
6758 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00006759 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006760 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006761 *
6762 * Returns the number of bytes written to the buffer or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00006763 */
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006764int
Owen Taylor3473f882001-02-23 17:55:21 +00006765xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006766 int format)
6767{
6768 unsigned int use;
6769 int ret;
6770 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006771
6772 if (cur == NULL) {
6773#ifdef DEBUG_TREE
6774 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006775 "xmlNodeDump : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006776#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006777 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006778 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006779 if (buf == NULL) {
6780#ifdef DEBUG_TREE
6781 xmlGenericError(xmlGenericErrorContext,
6782 "xmlNodeDump : buf == NULL\n");
6783#endif
6784 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006785 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006786 outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
6787 if (outbuf == NULL) {
6788 xmlGenericError(xmlGenericErrorContext,
6789 "xmlNodeDump: out of memory!\n");
6790 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006791 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006792 memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
6793 outbuf->buffer = buf;
6794 outbuf->encoder = NULL;
6795 outbuf->writecallback = NULL;
6796 outbuf->closecallback = NULL;
6797 outbuf->context = NULL;
6798 outbuf->written = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006799
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006800 use = buf->use;
6801 xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
6802 xmlFree(outbuf);
6803 ret = buf->use - use;
6804 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006805}
6806
6807/**
6808 * xmlElemDump:
6809 * @f: the FILE * for the output
6810 * @doc: the document
6811 * @cur: the current node
6812 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006813 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006814 */
6815void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006816xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur)
6817{
6818 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006819
6820 if (cur == NULL) {
6821#ifdef DEBUG_TREE
6822 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006823 "xmlElemDump : cur == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006824#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006825 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006826 }
Owen Taylor3473f882001-02-23 17:55:21 +00006827#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006828 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006829 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006830 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006831 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006832#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006833
6834 outbuf = xmlOutputBufferCreateFile(f, NULL);
6835 if (outbuf == NULL)
6836 return;
6837 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006838#ifdef LIBXML_HTML_ENABLED
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006839 htmlNodeDumpOutput(outbuf, doc, cur, NULL);
6840#else
6841 xmlGenericError(xmlGenericErrorContext,
6842 "HTML support not compiled in\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006843#endif /* LIBXML_HTML_ENABLED */
6844 } else
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006845 xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL);
6846 xmlOutputBufferClose(outbuf);
Owen Taylor3473f882001-02-23 17:55:21 +00006847}
6848
6849/************************************************************************
6850 * *
6851 * Dumping XML tree content to an I/O output buffer *
6852 * *
6853 ************************************************************************/
6854
Owen Taylor3473f882001-02-23 17:55:21 +00006855static void
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006856xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6857 int level, int format, const char *encoding);
6858static void
Owen Taylor3473f882001-02-23 17:55:21 +00006859xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6860 int level, int format, const char *encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006861static void
6862xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
6863 xmlNodePtr cur, int level, int format, const char *encoding);
6864
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00006865void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
6866
Owen Taylor3473f882001-02-23 17:55:21 +00006867/**
6868 * xmlNsDumpOutput:
6869 * @buf: the XML buffer output
6870 * @cur: a namespace
6871 *
6872 * Dump a local Namespace definition.
6873 * Should be called in the context of attributes dumps.
6874 */
6875static void
6876xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6877 if (cur == NULL) {
6878#ifdef DEBUG_TREE
6879 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006880 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006881#endif
6882 return;
6883 }
6884 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00006885 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
6886 return;
6887
Owen Taylor3473f882001-02-23 17:55:21 +00006888 /* Within the context of an element attributes */
6889 if (cur->prefix != NULL) {
6890 xmlOutputBufferWriteString(buf, " xmlns:");
6891 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6892 } else
6893 xmlOutputBufferWriteString(buf, " xmlns");
6894 xmlOutputBufferWriteString(buf, "=");
6895 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6896 }
6897}
6898
6899/**
6900 * xmlNsListDumpOutput:
6901 * @buf: the XML buffer output
6902 * @cur: the first namespace
6903 *
6904 * Dump a list of local Namespace definitions.
6905 * Should be called in the context of attributes dumps.
6906 */
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00006907void
Owen Taylor3473f882001-02-23 17:55:21 +00006908xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6909 while (cur != NULL) {
6910 xmlNsDumpOutput(buf, cur);
6911 cur = cur->next;
6912 }
6913}
6914
6915/**
6916 * xmlDtdDumpOutput:
6917 * @buf: the XML buffer output
6918 * @doc: the document
6919 * @encoding: an optional encoding string
6920 *
6921 * Dump the XML document DTD, if any.
6922 */
6923static void
6924xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6925 if (dtd == NULL) {
6926#ifdef DEBUG_TREE
6927 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006928 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006929#endif
6930 return;
6931 }
6932 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6933 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6934 if (dtd->ExternalID != NULL) {
6935 xmlOutputBufferWriteString(buf, " PUBLIC ");
6936 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6937 xmlOutputBufferWriteString(buf, " ");
6938 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6939 } else if (dtd->SystemID != NULL) {
6940 xmlOutputBufferWriteString(buf, " SYSTEM ");
6941 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6942 }
6943 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6944 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6945 xmlOutputBufferWriteString(buf, ">");
6946 return;
6947 }
6948 xmlOutputBufferWriteString(buf, " [\n");
6949 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6950 xmlOutputBufferWriteString(buf, "]>");
6951}
6952
6953/**
6954 * xmlAttrDumpOutput:
6955 * @buf: the XML buffer output
6956 * @doc: the document
6957 * @cur: the attribute pointer
6958 * @encoding: an optional encoding string
6959 *
6960 * Dump an XML attribute
6961 */
6962static void
6963xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006964 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006965 if (cur == NULL) {
6966#ifdef DEBUG_TREE
6967 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006968 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006969#endif
6970 return;
6971 }
6972 xmlOutputBufferWriteString(buf, " ");
6973 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6974 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6975 xmlOutputBufferWriteString(buf, ":");
6976 }
6977 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006978 xmlOutputBufferWriteString(buf, "=\"");
6979 xmlAttrSerializeContent(buf->buffer, doc, cur);
6980 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006981}
6982
6983/**
6984 * xmlAttrListDumpOutput:
6985 * @buf: the XML buffer output
6986 * @doc: the document
6987 * @cur: the first attribute pointer
6988 * @encoding: an optional encoding string
6989 *
6990 * Dump a list of XML attributes
6991 */
6992static void
6993xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6994 xmlAttrPtr cur, const char *encoding) {
6995 if (cur == NULL) {
6996#ifdef DEBUG_TREE
6997 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006998 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006999#endif
7000 return;
7001 }
7002 while (cur != NULL) {
7003 xmlAttrDumpOutput(buf, doc, cur, encoding);
7004 cur = cur->next;
7005 }
7006}
7007
7008
7009
7010/**
7011 * xmlNodeListDumpOutput:
7012 * @buf: the XML buffer output
7013 * @doc: the document
7014 * @cur: the first node
7015 * @level: the imbrication level for indenting
7016 * @format: is formatting allowed
7017 * @encoding: an optional encoding string
7018 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007019 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007020 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007021 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007022 */
7023static void
7024xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7025 xmlNodePtr cur, int level, int format, const char *encoding) {
7026 int i;
7027
7028 if (cur == NULL) {
7029#ifdef DEBUG_TREE
7030 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007031 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007032#endif
7033 return;
7034 }
7035 while (cur != NULL) {
7036 if ((format) && (xmlIndentTreeOutput) &&
7037 (cur->type == XML_ELEMENT_NODE))
7038 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007039 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007040 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007041 if (format) {
7042 xmlOutputBufferWriteString(buf, "\n");
7043 }
7044 cur = cur->next;
7045 }
7046}
7047
7048/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007049 * xmlNodeDumpOutputInternal:
Owen Taylor3473f882001-02-23 17:55:21 +00007050 * @buf: the XML buffer output
7051 * @doc: the document
7052 * @cur: the current node
7053 * @level: the imbrication level for indenting
7054 * @format: is formatting allowed
7055 * @encoding: an optional encoding string
7056 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007057 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007058 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007059 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007060 */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007061static void
7062xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
7063 xmlNodePtr cur, int level, int format, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007064 int i;
7065 xmlNodePtr tmp;
7066
7067 if (cur == NULL) {
7068#ifdef DEBUG_TREE
7069 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007070 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007071#endif
7072 return;
7073 }
7074 if (cur->type == XML_XINCLUDE_START)
7075 return;
7076 if (cur->type == XML_XINCLUDE_END)
7077 return;
7078 if (cur->type == XML_DTD_NODE) {
7079 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7080 return;
7081 }
7082 if (cur->type == XML_ELEMENT_DECL) {
7083 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7084 return;
7085 }
7086 if (cur->type == XML_ATTRIBUTE_DECL) {
7087 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7088 return;
7089 }
7090 if (cur->type == XML_ENTITY_DECL) {
7091 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7092 return;
7093 }
7094 if (cur->type == XML_TEXT_NODE) {
7095 if (cur->content != NULL) {
7096 if ((cur->name == xmlStringText) ||
7097 (cur->name != xmlStringTextNoenc)) {
7098 xmlChar *buffer;
7099
Owen Taylor3473f882001-02-23 17:55:21 +00007100 if (encoding == NULL)
7101 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7102 else
7103 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007104 if (buffer != NULL) {
7105 xmlOutputBufferWriteString(buf, (const char *)buffer);
7106 xmlFree(buffer);
7107 }
7108 } else {
7109 /*
7110 * Disable escaping, needed for XSLT
7111 */
Owen Taylor3473f882001-02-23 17:55:21 +00007112 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007113 }
7114 }
7115
7116 return;
7117 }
7118 if (cur->type == XML_PI_NODE) {
7119 if (cur->content != NULL) {
7120 xmlOutputBufferWriteString(buf, "<?");
7121 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7122 if (cur->content != NULL) {
7123 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00007124 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007125 }
7126 xmlOutputBufferWriteString(buf, "?>");
7127 } else {
7128 xmlOutputBufferWriteString(buf, "<?");
7129 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7130 xmlOutputBufferWriteString(buf, "?>");
7131 }
7132 return;
7133 }
7134 if (cur->type == XML_COMMENT_NODE) {
7135 if (cur->content != NULL) {
7136 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00007137 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007138 xmlOutputBufferWriteString(buf, "-->");
7139 }
7140 return;
7141 }
7142 if (cur->type == XML_ENTITY_REF_NODE) {
7143 xmlOutputBufferWriteString(buf, "&");
7144 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7145 xmlOutputBufferWriteString(buf, ";");
7146 return;
7147 }
7148 if (cur->type == XML_CDATA_SECTION_NODE) {
7149 xmlOutputBufferWriteString(buf, "<![CDATA[");
7150 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007151 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007152 xmlOutputBufferWriteString(buf, "]]>");
7153 return;
7154 }
Daniel Veillard7b72ee52003-02-27 23:24:53 +00007155 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillarda1a9d042003-03-18 16:53:17 +00007156 xmlAttrDumpOutput(buf,doc, (xmlAttrPtr) cur,encoding);
Daniel Veillard7b72ee52003-02-27 23:24:53 +00007157 return;
7158 }
Daniel Veillard6aa2f602003-02-10 00:01:56 +00007159 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007160 xmlNsDumpOutput(buf, (xmlNsPtr) cur);
Daniel Veillard6aa2f602003-02-10 00:01:56 +00007161 return;
7162 }
Owen Taylor3473f882001-02-23 17:55:21 +00007163
7164 if (format == 1) {
7165 tmp = cur->children;
7166 while (tmp != NULL) {
7167 if ((tmp->type == XML_TEXT_NODE) ||
7168 (tmp->type == XML_ENTITY_REF_NODE)) {
7169 format = 0;
7170 break;
7171 }
7172 tmp = tmp->next;
7173 }
7174 }
7175 xmlOutputBufferWriteString(buf, "<");
7176 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7177 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7178 xmlOutputBufferWriteString(buf, ":");
7179 }
7180
7181 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7182 if (cur->nsDef)
7183 xmlNsListDumpOutput(buf, cur->nsDef);
7184 if (cur->properties != NULL)
7185 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7186
Daniel Veillard7db37732001-07-12 01:20:08 +00007187 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
7188 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007189 xmlOutputBufferWriteString(buf, "/>");
7190 return;
7191 }
7192 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00007193 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007194 xmlChar *buffer;
7195
Owen Taylor3473f882001-02-23 17:55:21 +00007196 if (encoding == NULL)
7197 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7198 else
7199 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007200 if (buffer != NULL) {
7201 xmlOutputBufferWriteString(buf, (const char *)buffer);
7202 xmlFree(buffer);
7203 }
7204 }
7205 if (cur->children != NULL) {
7206 if (format) xmlOutputBufferWriteString(buf, "\n");
7207 xmlNodeListDumpOutput(buf, doc, cur->children,
7208 (level >= 0?level+1:-1), format, encoding);
7209 if ((xmlIndentTreeOutput) && (format))
7210 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007211 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00007212 }
7213 xmlOutputBufferWriteString(buf, "</");
7214 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7215 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7216 xmlOutputBufferWriteString(buf, ":");
7217 }
7218
7219 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7220 xmlOutputBufferWriteString(buf, ">");
7221}
7222
7223/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007224 * xmlNodeDumpOutput:
7225 * @buf: the XML buffer output
7226 * @doc: the document
7227 * @cur: the current node
7228 * @level: the imbrication level for indenting
7229 * @format: is formatting allowed
7230 * @encoding: an optional encoding string
7231 *
7232 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007233 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007234 * or xmlKeepBlanksDefault(0) was called
7235 */
7236void
7237xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007238 int level, int format, const char *encoding)
7239{
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007240#ifdef LIBXML_HTML_ENABLED
7241 xmlDtdPtr dtd;
7242 int is_xhtml = 0;
7243
7244 dtd = xmlGetIntSubset(doc);
7245 if (dtd != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007246 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7247 if (is_xhtml < 0)
7248 is_xhtml = 0;
7249 if ((is_xhtml) && (cur->parent == (xmlNodePtr) doc) &&
7250 (cur->type == XML_ELEMENT_NODE) &&
7251 (xmlStrEqual(cur->name, BAD_CAST "html"))) {
7252 if (encoding != NULL)
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007253 htmlSetMetaEncoding((htmlDocPtr) doc,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007254 (const xmlChar *) encoding);
7255 else
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007256 htmlSetMetaEncoding((htmlDocPtr) doc, BAD_CAST "UTF-8");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007257 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007258 }
7259
7260 if (is_xhtml)
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007261 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007262 else
7263#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007264 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007265}
7266
7267/**
Owen Taylor3473f882001-02-23 17:55:21 +00007268 * xmlDocContentDumpOutput:
7269 * @buf: the XML buffer output
7270 * @cur: the document
7271 * @encoding: an optional encoding string
7272 * @format: should formatting spaces been added
7273 *
7274 * Dump an XML document.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007275 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007276 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007277 */
7278static void
7279xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
7280 const char *encoding, int format) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007281#ifdef LIBXML_HTML_ENABLED
7282 xmlDtdPtr dtd;
7283 int is_xhtml = 0;
7284#endif
7285
Owen Taylor3473f882001-02-23 17:55:21 +00007286 xmlOutputBufferWriteString(buf, "<?xml version=");
7287 if (cur->version != NULL)
7288 xmlBufferWriteQuotedString(buf->buffer, cur->version);
7289 else
7290 xmlOutputBufferWriteString(buf, "\"1.0\"");
7291 if (encoding == NULL) {
7292 if (cur->encoding != NULL)
7293 encoding = (const char *) cur->encoding;
7294 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
7295 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
7296 }
7297 if (encoding != NULL) {
7298 xmlOutputBufferWriteString(buf, " encoding=");
7299 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
7300 }
7301 switch (cur->standalone) {
7302 case 0:
7303 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
7304 break;
7305 case 1:
7306 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
7307 break;
7308 }
7309 xmlOutputBufferWriteString(buf, "?>\n");
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007310
7311#ifdef LIBXML_HTML_ENABLED
7312 dtd = xmlGetIntSubset(cur);
7313 if (dtd != NULL) {
7314 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7315 if (is_xhtml < 0) is_xhtml = 0;
7316 }
7317 if (is_xhtml) {
7318 if (encoding != NULL)
7319 htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
7320 else
7321 htmlSetMetaEncoding(cur, BAD_CAST "UTF-8");
7322 }
7323#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007324 if (cur->children != NULL) {
7325 xmlNodePtr child = cur->children;
7326
7327 while (child != NULL) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007328#ifdef LIBXML_HTML_ENABLED
7329 if (is_xhtml)
7330 xhtmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
7331 else
7332#endif
7333 xmlNodeDumpOutputInternal(buf, cur, child, 0, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007334 xmlOutputBufferWriteString(buf, "\n");
7335 child = child->next;
7336 }
7337 }
7338}
7339
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007340#ifdef LIBXML_HTML_ENABLED
7341/************************************************************************
7342 * *
7343 * Functions specific to XHTML serialization *
7344 * *
7345 ************************************************************************/
7346
7347#define XHTML_STRICT_PUBLIC_ID BAD_CAST \
7348 "-//W3C//DTD XHTML 1.0 Strict//EN"
7349#define XHTML_STRICT_SYSTEM_ID BAD_CAST \
7350 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
7351#define XHTML_FRAME_PUBLIC_ID BAD_CAST \
7352 "-//W3C//DTD XHTML 1.0 Frameset//EN"
7353#define XHTML_FRAME_SYSTEM_ID BAD_CAST \
7354 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
7355#define XHTML_TRANS_PUBLIC_ID BAD_CAST \
7356 "-//W3C//DTD XHTML 1.0 Transitional//EN"
7357#define XHTML_TRANS_SYSTEM_ID BAD_CAST \
7358 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
7359
7360#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
7361/**
7362 * xmlIsXHTML:
7363 * @systemID: the system identifier
7364 * @publicID: the public identifier
7365 *
7366 * Try to find if the document correspond to an XHTML DTD
7367 *
7368 * Returns 1 if true, 0 if not and -1 in case of error
7369 */
7370int
7371xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) {
7372 if ((systemID == NULL) && (publicID == NULL))
7373 return(-1);
7374 if (publicID != NULL) {
7375 if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1);
7376 if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1);
7377 if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1);
7378 }
7379 if (systemID != NULL) {
7380 if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1);
7381 if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1);
7382 if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1);
7383 }
7384 return(0);
7385}
7386
7387/**
7388 * xhtmlIsEmpty:
7389 * @node: the node
7390 *
7391 * Check if a node is an empty xhtml node
7392 *
7393 * Returns 1 if the node is an empty node, 0 if not and -1 in case of error
7394 */
7395static int
7396xhtmlIsEmpty(xmlNodePtr node) {
7397 if (node == NULL)
7398 return(-1);
7399 if (node->type != XML_ELEMENT_NODE)
7400 return(0);
7401 if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME)))
7402 return(0);
7403 if (node->children != NULL)
7404 return(0);
7405 switch (node->name[0]) {
7406 case 'a':
7407 if (xmlStrEqual(node->name, BAD_CAST "area"))
7408 return(1);
7409 return(0);
7410 case 'b':
7411 if (xmlStrEqual(node->name, BAD_CAST "br"))
7412 return(1);
7413 if (xmlStrEqual(node->name, BAD_CAST "base"))
7414 return(1);
7415 if (xmlStrEqual(node->name, BAD_CAST "basefont"))
7416 return(1);
7417 return(0);
7418 case 'c':
7419 if (xmlStrEqual(node->name, BAD_CAST "col"))
7420 return(1);
7421 return(0);
7422 case 'f':
7423 if (xmlStrEqual(node->name, BAD_CAST "frame"))
7424 return(1);
7425 return(0);
7426 case 'h':
7427 if (xmlStrEqual(node->name, BAD_CAST "hr"))
7428 return(1);
7429 return(0);
7430 case 'i':
7431 if (xmlStrEqual(node->name, BAD_CAST "img"))
7432 return(1);
7433 if (xmlStrEqual(node->name, BAD_CAST "input"))
7434 return(1);
7435 if (xmlStrEqual(node->name, BAD_CAST "isindex"))
7436 return(1);
7437 return(0);
7438 case 'l':
7439 if (xmlStrEqual(node->name, BAD_CAST "link"))
7440 return(1);
7441 return(0);
7442 case 'm':
7443 if (xmlStrEqual(node->name, BAD_CAST "meta"))
7444 return(1);
7445 return(0);
7446 case 'p':
7447 if (xmlStrEqual(node->name, BAD_CAST "param"))
7448 return(1);
7449 return(0);
7450 }
7451 return(0);
7452}
7453
7454/**
7455 * xhtmlAttrListDumpOutput:
7456 * @buf: the XML buffer output
7457 * @doc: the document
7458 * @cur: the first attribute pointer
7459 * @encoding: an optional encoding string
7460 *
7461 * Dump a list of XML attributes
7462 */
7463static void
7464xhtmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7465 xmlAttrPtr cur, const char *encoding) {
7466 xmlAttrPtr xml_lang = NULL;
7467 xmlAttrPtr lang = NULL;
7468 xmlAttrPtr name = NULL;
7469 xmlAttrPtr id = NULL;
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007470 xmlNodePtr parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007471
7472 if (cur == NULL) {
7473#ifdef DEBUG_TREE
7474 xmlGenericError(xmlGenericErrorContext,
7475 "xmlAttrListDumpOutput : property == NULL\n");
7476#endif
7477 return;
7478 }
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007479 parent = cur->parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007480 while (cur != NULL) {
7481 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id")))
7482 id = cur;
7483 else
7484 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name")))
7485 name = cur;
7486 else
7487 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")))
7488 lang = cur;
7489 else
7490 if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) &&
7491 (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml")))
7492 xml_lang = cur;
7493 else if ((cur->ns == NULL) &&
7494 ((cur->children == NULL) ||
7495 (cur->children->content == NULL) ||
7496 (cur->children->content[0] == 0)) &&
7497 (htmlIsBooleanAttr(cur->name))) {
7498 if (cur->children != NULL)
7499 xmlFreeNode(cur->children);
7500 cur->children = xmlNewText(cur->name);
7501 if (cur->children != NULL)
7502 cur->children->parent = (xmlNodePtr) cur;
7503 }
7504 xmlAttrDumpOutput(buf, doc, cur, encoding);
7505 cur = cur->next;
7506 }
7507 /*
7508 * C.8
7509 */
7510 if ((name != NULL) && (id == NULL)) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007511 if ((parent != NULL) && (parent->name != NULL) &&
7512 ((xmlStrEqual(parent->name, BAD_CAST "a")) ||
7513 (xmlStrEqual(parent->name, BAD_CAST "p")) ||
7514 (xmlStrEqual(parent->name, BAD_CAST "div")) ||
7515 (xmlStrEqual(parent->name, BAD_CAST "img")) ||
7516 (xmlStrEqual(parent->name, BAD_CAST "map")) ||
7517 (xmlStrEqual(parent->name, BAD_CAST "applet")) ||
7518 (xmlStrEqual(parent->name, BAD_CAST "form")) ||
7519 (xmlStrEqual(parent->name, BAD_CAST "frame")) ||
7520 (xmlStrEqual(parent->name, BAD_CAST "iframe")))) {
7521 xmlOutputBufferWriteString(buf, " id=\"");
7522 xmlAttrSerializeContent(buf->buffer, doc, name);
7523 xmlOutputBufferWriteString(buf, "\"");
7524 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007525 }
7526 /*
7527 * C.7.
7528 */
7529 if ((lang != NULL) && (xml_lang == NULL)) {
7530 xmlOutputBufferWriteString(buf, " xml:lang=\"");
7531 xmlAttrSerializeContent(buf->buffer, doc, lang);
7532 xmlOutputBufferWriteString(buf, "\"");
7533 } else
7534 if ((xml_lang != NULL) && (lang == NULL)) {
7535 xmlOutputBufferWriteString(buf, " lang=\"");
7536 xmlAttrSerializeContent(buf->buffer, doc, xml_lang);
7537 xmlOutputBufferWriteString(buf, "\"");
7538 }
7539}
7540
7541/**
7542 * xhtmlNodeListDumpOutput:
7543 * @buf: the XML buffer output
7544 * @doc: the XHTML document
7545 * @cur: the first node
7546 * @level: the imbrication level for indenting
7547 * @format: is formatting allowed
7548 * @encoding: an optional encoding string
7549 *
7550 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007551 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007552 * or xmlKeepBlanksDefault(0) was called
7553 */
7554static void
7555xhtmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7556 xmlNodePtr cur, int level, int format, const char *encoding) {
7557 int i;
7558
7559 if (cur == NULL) {
7560#ifdef DEBUG_TREE
7561 xmlGenericError(xmlGenericErrorContext,
7562 "xhtmlNodeListDumpOutput : node == NULL\n");
7563#endif
7564 return;
7565 }
7566 while (cur != NULL) {
7567 if ((format) && (xmlIndentTreeOutput) &&
7568 (cur->type == XML_ELEMENT_NODE))
7569 for (i = 0;i < level;i++)
7570 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7571 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
7572 if (format) {
7573 xmlOutputBufferWriteString(buf, "\n");
7574 }
7575 cur = cur->next;
7576 }
7577}
7578
7579/**
7580 * xhtmlNodeDumpOutput:
7581 * @buf: the XML buffer output
7582 * @doc: the XHTML document
7583 * @cur: the current node
7584 * @level: the imbrication level for indenting
7585 * @format: is formatting allowed
7586 * @encoding: an optional encoding string
7587 *
7588 * Dump an XHTML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007589 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007590 * or xmlKeepBlanksDefault(0) was called
7591 */
7592static void
7593xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7594 int level, int format, const char *encoding) {
7595 int i;
7596 xmlNodePtr tmp;
7597
7598 if (cur == NULL) {
7599#ifdef DEBUG_TREE
7600 xmlGenericError(xmlGenericErrorContext,
7601 "xmlNodeDumpOutput : node == NULL\n");
7602#endif
7603 return;
7604 }
7605 if (cur->type == XML_XINCLUDE_START)
7606 return;
7607 if (cur->type == XML_XINCLUDE_END)
7608 return;
7609 if (cur->type == XML_DTD_NODE) {
7610 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7611 return;
7612 }
7613 if (cur->type == XML_ELEMENT_DECL) {
7614 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7615 return;
7616 }
7617 if (cur->type == XML_ATTRIBUTE_DECL) {
7618 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7619 return;
7620 }
7621 if (cur->type == XML_ENTITY_DECL) {
7622 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7623 return;
7624 }
7625 if (cur->type == XML_TEXT_NODE) {
7626 if (cur->content != NULL) {
7627 if ((cur->name == xmlStringText) ||
7628 (cur->name != xmlStringTextNoenc)) {
7629 xmlChar *buffer;
7630
7631 if (encoding == NULL)
7632 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7633 else
7634 buffer = xmlEncodeSpecialChars(doc, cur->content);
7635 if (buffer != NULL) {
7636 xmlOutputBufferWriteString(buf, (const char *)buffer);
7637 xmlFree(buffer);
7638 }
7639 } else {
7640 /*
7641 * Disable escaping, needed for XSLT
7642 */
7643 xmlOutputBufferWriteString(buf, (const char *) cur->content);
7644 }
7645 }
7646
7647 return;
7648 }
7649 if (cur->type == XML_PI_NODE) {
7650 if (cur->content != NULL) {
7651 xmlOutputBufferWriteString(buf, "<?");
7652 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7653 if (cur->content != NULL) {
7654 xmlOutputBufferWriteString(buf, " ");
7655 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7656 }
7657 xmlOutputBufferWriteString(buf, "?>");
7658 } else {
7659 xmlOutputBufferWriteString(buf, "<?");
7660 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7661 xmlOutputBufferWriteString(buf, "?>");
7662 }
7663 return;
7664 }
7665 if (cur->type == XML_COMMENT_NODE) {
7666 if (cur->content != NULL) {
7667 xmlOutputBufferWriteString(buf, "<!--");
7668 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7669 xmlOutputBufferWriteString(buf, "-->");
7670 }
7671 return;
7672 }
7673 if (cur->type == XML_ENTITY_REF_NODE) {
7674 xmlOutputBufferWriteString(buf, "&");
7675 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7676 xmlOutputBufferWriteString(buf, ";");
7677 return;
7678 }
7679 if (cur->type == XML_CDATA_SECTION_NODE) {
7680 xmlOutputBufferWriteString(buf, "<![CDATA[");
7681 if (cur->content != NULL)
7682 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7683 xmlOutputBufferWriteString(buf, "]]>");
7684 return;
7685 }
7686
7687 if (format == 1) {
7688 tmp = cur->children;
7689 while (tmp != NULL) {
7690 if ((tmp->type == XML_TEXT_NODE) ||
7691 (tmp->type == XML_ENTITY_REF_NODE)) {
7692 format = 0;
7693 break;
7694 }
7695 tmp = tmp->next;
7696 }
7697 }
7698 xmlOutputBufferWriteString(buf, "<");
7699 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7700 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7701 xmlOutputBufferWriteString(buf, ":");
7702 }
7703
7704 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7705 if (cur->nsDef)
7706 xmlNsListDumpOutput(buf, cur->nsDef);
7707 if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
7708 (cur->ns == NULL) && (cur->nsDef == NULL))) {
7709 /*
7710 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
7711 */
7712 xmlOutputBufferWriteString(buf,
7713 " xmlns=\"http://www.w3.org/1999/xhtml\"");
7714 }
7715 if (cur->properties != NULL)
7716 xhtmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7717
7718 if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) {
7719 if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
7720 (xhtmlIsEmpty(cur) == 1)) {
7721 /*
7722 * C.2. Empty Elements
7723 */
7724 xmlOutputBufferWriteString(buf, " />");
7725 } else {
7726 /*
7727 * C.3. Element Minimization and Empty Element Content
7728 */
7729 xmlOutputBufferWriteString(buf, "></");
7730 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7731 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7732 xmlOutputBufferWriteString(buf, ":");
7733 }
7734 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7735 xmlOutputBufferWriteString(buf, ">");
7736 }
7737 return;
7738 }
7739 xmlOutputBufferWriteString(buf, ">");
7740 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
7741 xmlChar *buffer;
7742
7743 if (encoding == NULL)
7744 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7745 else
7746 buffer = xmlEncodeSpecialChars(doc, cur->content);
7747 if (buffer != NULL) {
7748 xmlOutputBufferWriteString(buf, (const char *)buffer);
7749 xmlFree(buffer);
7750 }
7751 }
7752
7753 /*
7754 * 4.8. Script and Style elements
7755 */
7756 if ((cur->type == XML_ELEMENT_NODE) &&
7757 ((xmlStrEqual(cur->name, BAD_CAST "script")) ||
7758 (xmlStrEqual(cur->name, BAD_CAST "style"))) &&
7759 ((cur->ns == NULL) ||
7760 (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) {
7761 xmlNodePtr child = cur->children;
7762
7763 while (child != NULL) {
7764 if ((child->type == XML_TEXT_NODE) ||
7765 (child->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard64b35282002-12-04 15:10:40 +00007766 /*
7767 * Apparently CDATA escaping for style just break on IE,
7768 * mozilla and galeon, so ...
7769 */
7770 if (xmlStrEqual(cur->name, BAD_CAST "style") &&
7771 (xmlStrchr(child->content, '<') == NULL) &&
7772 (xmlStrchr(child->content, '>') == NULL) &&
7773 (xmlStrchr(child->content, '&') == NULL)) {
7774 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7775 } else {
7776 xmlOutputBufferWriteString(buf, "<![CDATA[");
7777 if (child->content != NULL)
7778 xmlOutputBufferWriteString(buf,
7779 (const char *)child->content);
7780 xmlOutputBufferWriteString(buf, "]]>");
7781 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007782 } else {
7783 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7784 }
7785 child = child->next;
7786 }
7787 } else if (cur->children != NULL) {
7788 if (format) xmlOutputBufferWriteString(buf, "\n");
7789 xhtmlNodeListDumpOutput(buf, doc, cur->children,
7790 (level >= 0?level+1:-1), format, encoding);
7791 if ((xmlIndentTreeOutput) && (format))
7792 for (i = 0;i < level;i++)
7793 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7794 }
7795 xmlOutputBufferWriteString(buf, "</");
7796 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7797 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7798 xmlOutputBufferWriteString(buf, ":");
7799 }
7800
7801 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7802 xmlOutputBufferWriteString(buf, ">");
7803}
7804#endif
7805
Owen Taylor3473f882001-02-23 17:55:21 +00007806/************************************************************************
7807 * *
7808 * Saving functions front-ends *
7809 * *
7810 ************************************************************************/
7811
7812/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00007813 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00007814 * @out_doc: Document to generate XML text from
7815 * @doc_txt_ptr: Memory pointer for allocated XML text
7816 * @doc_txt_len: Length of the generated XML text
7817 * @txt_encoding: Character encoding to use when generating XML text
7818 * @format: should formatting spaces been added
7819 *
7820 * Dump the current DOM tree into memory using the character encoding specified
7821 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007822 * allocated memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00007823 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007824 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007825 */
7826
7827void
7828xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007829 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007830 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007831 int dummy = 0;
7832
7833 xmlCharEncoding doc_charset;
7834 xmlOutputBufferPtr out_buff = NULL;
7835 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
7836
7837 if (doc_txt_len == NULL) {
7838 doc_txt_len = &dummy; /* Continue, caller just won't get length */
7839 }
7840
7841 if (doc_txt_ptr == NULL) {
7842 *doc_txt_len = 0;
7843 xmlGenericError(xmlGenericErrorContext,
7844 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
7845 return;
7846 }
7847
7848 *doc_txt_ptr = NULL;
7849 *doc_txt_len = 0;
7850
7851 if (out_doc == NULL) {
7852 /* No document, no output */
7853 xmlGenericError(xmlGenericErrorContext,
7854 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
7855 return;
7856 }
7857
7858 /*
7859 * Validate the encoding value, if provided.
7860 * This logic is copied from xmlSaveFileEnc.
7861 */
7862
7863 if (txt_encoding == NULL)
7864 txt_encoding = (const char *) out_doc->encoding;
7865 if (txt_encoding != NULL) {
7866 doc_charset = xmlParseCharEncoding(txt_encoding);
7867
7868 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
7869 xmlGenericError(xmlGenericErrorContext,
7870 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
7871 return;
7872
7873 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
Daniel Veillarde1326112003-06-05 09:32:20 +00007874 conv_hdlr = xmlGetCharEncodingHandler(doc_charset);
7875 if (conv_hdlr == NULL)
7876 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007877 if ( conv_hdlr == NULL ) {
7878 xmlGenericError(xmlGenericErrorContext,
7879 "%s: %s %s '%s'\n",
7880 "xmlDocDumpFormatMemoryEnc",
7881 "Failed to identify encoding handler for",
7882 "character set",
7883 txt_encoding);
7884 return;
7885 }
7886 }
7887 }
7888
7889 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
7890 xmlGenericError(xmlGenericErrorContext,
7891 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
7892 return;
7893 }
7894
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007895 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007896 xmlOutputBufferFlush(out_buff);
7897 if (out_buff->conv != NULL) {
7898 *doc_txt_len = out_buff->conv->use;
7899 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
7900 } else {
7901 *doc_txt_len = out_buff->buffer->use;
7902 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
7903 }
7904 (void)xmlOutputBufferClose(out_buff);
7905
7906 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
7907 *doc_txt_len = 0;
7908 xmlGenericError(xmlGenericErrorContext,
7909 "xmlDocDumpFormatMemoryEnc: %s\n",
7910 "Failed to allocate memory for document text representation.");
7911 }
7912
7913 return;
7914}
7915
7916/**
7917 * xmlDocDumpMemory:
7918 * @cur: the document
7919 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007920 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007921 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007922 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007923 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007924 */
7925void
7926xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
7927 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
7928}
7929
7930/**
7931 * xmlDocDumpFormatMemory:
7932 * @cur: the document
7933 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007934 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007935 * @format: should formatting spaces been added
7936 *
7937 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007938 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007939 * It's up to the caller to free the memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00007940 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007941 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007942 */
7943void
7944xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
7945 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
7946}
7947
7948/**
7949 * xmlDocDumpMemoryEnc:
7950 * @out_doc: Document to generate XML text from
7951 * @doc_txt_ptr: Memory pointer for allocated XML text
7952 * @doc_txt_len: Length of the generated XML text
7953 * @txt_encoding: Character encoding to use when generating XML text
7954 *
7955 * Dump the current DOM tree into memory using the character encoding specified
7956 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007957 * allocated memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007958 */
7959
7960void
7961xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
7962 int * doc_txt_len, const char * txt_encoding) {
7963 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007964 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007965}
7966
7967/**
7968 * xmlGetDocCompressMode:
7969 * @doc: the document
7970 *
7971 * get the compression ratio for a document, ZLIB based
7972 * Returns 0 (uncompressed) to 9 (max compression)
7973 */
7974int
7975xmlGetDocCompressMode (xmlDocPtr doc) {
7976 if (doc == NULL) return(-1);
7977 return(doc->compression);
7978}
7979
7980/**
7981 * xmlSetDocCompressMode:
7982 * @doc: the document
7983 * @mode: the compression ratio
7984 *
7985 * set the compression ratio for a document, ZLIB based
7986 * Correct values: 0 (uncompressed) to 9 (max compression)
7987 */
7988void
7989xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7990 if (doc == NULL) return;
7991 if (mode < 0) doc->compression = 0;
7992 else if (mode > 9) doc->compression = 9;
7993 else doc->compression = mode;
7994}
7995
7996/**
7997 * xmlGetCompressMode:
7998 *
7999 * get the default compression mode used, ZLIB based.
8000 * Returns 0 (uncompressed) to 9 (max compression)
8001 */
8002int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008003xmlGetCompressMode(void)
8004{
8005 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00008006}
8007
8008/**
8009 * xmlSetCompressMode:
8010 * @mode: the compression ratio
8011 *
8012 * set the default compression mode used, ZLIB based
8013 * Correct values: 0 (uncompressed) to 9 (max compression)
8014 */
8015void
8016xmlSetCompressMode(int mode) {
8017 if (mode < 0) xmlCompressMode = 0;
8018 else if (mode > 9) xmlCompressMode = 9;
8019 else xmlCompressMode = mode;
8020}
8021
8022/**
Daniel Veillard9e412302002-06-10 15:59:44 +00008023 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00008024 * @f: the FILE*
8025 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00008026 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00008027 *
8028 * Dump an XML document to an open FILE.
8029 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008030 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008031 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8032 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008033 */
8034int
Daniel Veillard9e412302002-06-10 15:59:44 +00008035xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00008036 xmlOutputBufferPtr buf;
8037 const char * encoding;
8038 xmlCharEncodingHandlerPtr handler = NULL;
8039 int ret;
8040
8041 if (cur == NULL) {
8042#ifdef DEBUG_TREE
8043 xmlGenericError(xmlGenericErrorContext,
8044 "xmlDocDump : document == NULL\n");
8045#endif
8046 return(-1);
8047 }
8048 encoding = (const char *) cur->encoding;
8049
8050 if (encoding != NULL) {
8051 xmlCharEncoding enc;
8052
8053 enc = xmlParseCharEncoding(encoding);
8054
8055 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
8056 xmlGenericError(xmlGenericErrorContext,
8057 "xmlDocDump: document not in UTF8\n");
8058 return(-1);
8059 }
8060 if (enc != XML_CHAR_ENCODING_UTF8) {
Daniel Veillarde1326112003-06-05 09:32:20 +00008061 handler = xmlGetCharEncodingHandler(enc);
8062 if (handler == NULL)
8063 handler = xmlFindCharEncodingHandler(encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00008064 if (handler == NULL) {
8065 xmlFree((char *) cur->encoding);
8066 cur->encoding = NULL;
8067 }
8068 }
8069 }
8070 buf = xmlOutputBufferCreateFile(f, handler);
8071 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00008072 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008073
8074 ret = xmlOutputBufferClose(buf);
8075 return(ret);
8076}
8077
8078/**
Daniel Veillard9e412302002-06-10 15:59:44 +00008079 * xmlDocDump:
8080 * @f: the FILE*
8081 * @cur: the document
8082 *
8083 * Dump an XML document to an open FILE.
8084 *
8085 * returns: the number of bytes written or -1 in case of failure.
8086 */
8087int
8088xmlDocDump(FILE *f, xmlDocPtr cur) {
8089 return(xmlDocFormatDump (f, cur, 0));
8090}
8091
8092/**
Owen Taylor3473f882001-02-23 17:55:21 +00008093 * xmlSaveFileTo:
8094 * @buf: an output I/O buffer
8095 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00008096 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00008097 *
8098 * Dump an XML document to an I/O buffer.
8099 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008100 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008101 */
8102int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00008103xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00008104 int ret;
8105
8106 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008107 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008108 ret = xmlOutputBufferClose(buf);
8109 return(ret);
8110}
8111
8112/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00008113 * xmlSaveFormatFileTo:
8114 * @buf: an output I/O buffer
8115 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00008116 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00008117 * @format: should formatting spaces been added
8118 *
8119 * Dump an XML document to an I/O buffer.
8120 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008121 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008122 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8123 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardeefd4492001-04-28 16:55:50 +00008124 */
8125int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00008126xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00008127 int ret;
8128
8129 if (buf == NULL) return(0);
8130 xmlDocContentDumpOutput(buf, cur, encoding, format);
8131 ret = xmlOutputBufferClose(buf);
8132 return(ret);
8133}
8134
8135/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00008136 * xmlSaveFormatFileEnc:
Daniel Veillardf012a642001-07-23 19:10:52 +00008137 * @filename: the filename or URL to output
8138 * @cur: the document being saved
8139 * @encoding: the name of the encoding to use or NULL.
8140 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00008141 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00008142 * Dump an XML document to a file or an URL.
8143 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008144 * Returns the number of bytes written or -1 in case of error.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008145 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8146 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008147 */
8148int
Daniel Veillardf012a642001-07-23 19:10:52 +00008149xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
8150 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00008151 xmlOutputBufferPtr buf;
8152 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00008153 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00008154 int ret;
8155
Daniel Veillard4dbe77a2003-01-14 00:17:42 +00008156 if (cur == NULL)
8157 return(-1);
8158
Daniel Veillardfb25a512002-01-13 20:32:08 +00008159 if (encoding == NULL)
8160 encoding = (const char *) cur->encoding;
8161
Owen Taylor3473f882001-02-23 17:55:21 +00008162 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00008163
8164 enc = xmlParseCharEncoding(encoding);
8165 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
8166 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00008167 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00008168 return(-1);
8169 }
8170 if (enc != XML_CHAR_ENCODING_UTF8) {
8171 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00008172 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00008173 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00008174 }
8175 }
8176
Daniel Veillardf012a642001-07-23 19:10:52 +00008177#ifdef HAVE_ZLIB_H
8178 if (cur->compression < 0) cur->compression = xmlCompressMode;
8179#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008180 /*
8181 * save the content to a temp buffer.
8182 */
Daniel Veillardf012a642001-07-23 19:10:52 +00008183 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00008184 if (buf == NULL) return(-1);
8185
Daniel Veillardf012a642001-07-23 19:10:52 +00008186 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008187
8188 ret = xmlOutputBufferClose(buf);
8189 return(ret);
8190}
8191
Daniel Veillardf012a642001-07-23 19:10:52 +00008192
8193/**
8194 * xmlSaveFileEnc:
8195 * @filename: the filename (or URL)
8196 * @cur: the document
8197 * @encoding: the name of an encoding (or NULL)
8198 *
8199 * Dump an XML document, converting it to the given encoding
8200 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008201 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00008202 */
8203int
8204xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
8205 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
8206}
8207
Owen Taylor3473f882001-02-23 17:55:21 +00008208/**
Daniel Veillard67fee942001-04-26 18:59:03 +00008209 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00008210 * @filename: the filename (or URL)
8211 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00008212 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00008213 *
8214 * Dump an XML document to a file. Will use compression if
8215 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00008216 * used. If @format is set then the document will be indented on output.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008217 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8218 * or xmlKeepBlanksDefault(0) was called
Daniel Veillard67fee942001-04-26 18:59:03 +00008219 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008220 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008221 */
8222int
Daniel Veillard67fee942001-04-26 18:59:03 +00008223xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008224 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00008225}
8226
Daniel Veillard67fee942001-04-26 18:59:03 +00008227/**
8228 * xmlSaveFile:
8229 * @filename: the filename (or URL)
8230 * @cur: the document
8231 *
8232 * Dump an XML document to a file. Will use compression if
8233 * compiled in and enabled. If @filename is "-" the stdout file is
8234 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00008235 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00008236 */
8237int
8238xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008239 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00008240}
8241