blob: 114989e01d7c1fa46b19494560dd2907fb756884 [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 Veillarda6874ca2003-07-29 16:47:24 +0000964 /*
965 * The in memory encoding is always UTF8
966 * This field will never change and would
967 * be obsolete if not for binary compatibility.
968 */
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000969 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +0000970
Daniel Veillarda880b122003-04-21 21:36:41 +0000971 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000972 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000973 return(cur);
974}
975
976/**
977 * xmlFreeDoc:
978 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +0000979 *
980 * Free up all the structures used by a document, tree included.
981 */
982void
983xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +0000984 xmlDtdPtr extSubset, intSubset;
985
Owen Taylor3473f882001-02-23 17:55:21 +0000986 if (cur == NULL) {
987#ifdef DEBUG_TREE
988 xmlGenericError(xmlGenericErrorContext,
989 "xmlFreeDoc : document == NULL\n");
990#endif
991 return;
992 }
Daniel Veillard5335dc52003-01-01 20:59:38 +0000993
Daniel Veillarda880b122003-04-21 21:36:41 +0000994 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000995 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
996
Daniel Veillard76d66f42001-05-16 21:05:17 +0000997 /*
998 * Do this before freeing the children list to avoid ID lookups
999 */
1000 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1001 cur->ids = NULL;
1002 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1003 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001004 extSubset = cur->extSubset;
1005 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +00001006 if (intSubset == extSubset)
1007 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001008 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001009 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001010 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001011 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001012 }
Daniel Veillarda9142e72001-06-19 11:07:54 +00001013 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001014 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001015 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001016 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001017 }
1018
1019 if (cur->children != NULL) xmlFreeNodeList(cur->children);
1020
Owen Taylor3473f882001-02-23 17:55:21 +00001021 if (cur->version != NULL) xmlFree((char *) cur->version);
1022 if (cur->name != NULL) xmlFree((char *) cur->name);
1023 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00001024 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00001025 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Owen Taylor3473f882001-02-23 17:55:21 +00001026 xmlFree(cur);
1027}
1028
1029/**
1030 * xmlStringLenGetNodeList:
1031 * @doc: the document
1032 * @value: the value of the text
1033 * @len: the length of the string value
1034 *
1035 * Parse the value string and build the node list associated. Should
1036 * produce a flat tree with only TEXTs and ENTITY_REFs.
1037 * Returns a pointer to the first child
1038 */
1039xmlNodePtr
1040xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1041 xmlNodePtr ret = NULL, last = NULL;
1042 xmlNodePtr node;
1043 xmlChar *val;
1044 const xmlChar *cur = value;
1045 const xmlChar *q;
1046 xmlEntityPtr ent;
1047
1048 if (value == NULL) return(NULL);
1049
1050 q = cur;
1051 while ((*cur != 0) && (cur - value < len)) {
1052 if (*cur == '&') {
1053 /*
1054 * Save the current text.
1055 */
1056 if (cur != q) {
1057 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1058 xmlNodeAddContentLen(last, q, cur - q);
1059 } else {
1060 node = xmlNewDocTextLen(doc, q, cur - q);
1061 if (node == NULL) return(ret);
1062 if (last == NULL)
1063 last = ret = node;
1064 else {
1065 last->next = node;
1066 node->prev = last;
1067 last = node;
1068 }
1069 }
1070 }
1071 /*
1072 * Read the entity string
1073 */
1074 cur++;
1075 q = cur;
1076 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
1077 if ((*cur == 0) || (cur - value >= len)) {
1078#ifdef DEBUG_TREE
1079 xmlGenericError(xmlGenericErrorContext,
1080 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
1081#endif
1082 return(ret);
1083 }
1084 if (cur != q) {
1085 /*
1086 * Predefined entities don't generate nodes
1087 */
1088 val = xmlStrndup(q, cur - q);
1089 ent = xmlGetDocEntity(doc, val);
1090 if ((ent != NULL) &&
1091 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1092 if (last == NULL) {
1093 node = xmlNewDocText(doc, ent->content);
1094 last = ret = node;
1095 } else
1096 xmlNodeAddContent(last, ent->content);
1097
1098 } else {
1099 /*
1100 * Create a new REFERENCE_REF node
1101 */
1102 node = xmlNewReference(doc, val);
1103 if (node == NULL) {
1104 if (val != NULL) xmlFree(val);
1105 return(ret);
1106 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001107 else if ((ent != NULL) && (ent->children == NULL)) {
1108 xmlNodePtr tmp;
1109
1110 ent->children =
1111 xmlStringGetNodeList(doc, (const xmlChar*)node->content);
1112 tmp = ent->children;
1113 while (tmp) {
1114 tmp->parent = (xmlNodePtr)ent;
1115 tmp = tmp->next;
1116 }
1117 }
Owen Taylor3473f882001-02-23 17:55:21 +00001118 if (last == NULL)
1119 last = ret = node;
1120 else {
1121 last->next = node;
1122 node->prev = last;
1123 last = node;
1124 }
1125 }
1126 xmlFree(val);
1127 }
1128 cur++;
1129 q = cur;
1130 } else
1131 cur++;
1132 }
1133 if (cur != q) {
1134 /*
1135 * Handle the last piece of text.
1136 */
1137 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1138 xmlNodeAddContentLen(last, q, cur - q);
1139 } else {
1140 node = xmlNewDocTextLen(doc, q, cur - q);
1141 if (node == NULL) return(ret);
1142 if (last == NULL)
1143 last = ret = node;
1144 else {
1145 last->next = node;
1146 node->prev = last;
1147 last = node;
1148 }
1149 }
1150 }
1151 return(ret);
1152}
1153
1154/**
1155 * xmlStringGetNodeList:
1156 * @doc: the document
1157 * @value: the value of the attribute
1158 *
1159 * Parse the value string and build the node list associated. Should
1160 * produce a flat tree with only TEXTs and ENTITY_REFs.
1161 * Returns a pointer to the first child
1162 */
1163xmlNodePtr
1164xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1165 xmlNodePtr ret = NULL, last = NULL;
1166 xmlNodePtr node;
1167 xmlChar *val;
1168 const xmlChar *cur = value;
1169 const xmlChar *q;
1170 xmlEntityPtr ent;
1171
1172 if (value == NULL) return(NULL);
1173
1174 q = cur;
1175 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001176 if (cur[0] == '&') {
1177 int charval = 0;
1178 xmlChar tmp;
1179
Owen Taylor3473f882001-02-23 17:55:21 +00001180 /*
1181 * Save the current text.
1182 */
1183 if (cur != q) {
1184 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1185 xmlNodeAddContentLen(last, q, cur - q);
1186 } else {
1187 node = xmlNewDocTextLen(doc, q, cur - q);
1188 if (node == NULL) return(ret);
1189 if (last == NULL)
1190 last = ret = node;
1191 else {
1192 last->next = node;
1193 node->prev = last;
1194 last = node;
1195 }
1196 }
1197 }
Owen Taylor3473f882001-02-23 17:55:21 +00001198 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001199 if ((cur[1] == '#') && (cur[2] == 'x')) {
1200 cur += 3;
1201 tmp = *cur;
1202 while (tmp != ';') { /* Non input consuming loop */
1203 if ((tmp >= '0') && (tmp <= '9'))
1204 charval = charval * 16 + (tmp - '0');
1205 else if ((tmp >= 'a') && (tmp <= 'f'))
1206 charval = charval * 16 + (tmp - 'a') + 10;
1207 else if ((tmp >= 'A') && (tmp <= 'F'))
1208 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001209 else {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001210 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001211 "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001212 charval = 0;
1213 break;
1214 }
1215 cur++;
1216 tmp = *cur;
1217 }
1218 if (tmp == ';')
1219 cur++;
1220 q = cur;
1221 } else if (cur[1] == '#') {
1222 cur += 2;
1223 tmp = *cur;
1224 while (tmp != ';') { /* Non input consuming loops */
1225 if ((tmp >= '0') && (tmp <= '9'))
1226 charval = charval * 10 + (tmp - '0');
1227 else {
1228 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001229 "xmlStringGetNodeList: invalid decimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001230 charval = 0;
1231 break;
1232 }
1233 cur++;
1234 tmp = *cur;
1235 }
1236 if (tmp == ';')
1237 cur++;
1238 q = cur;
1239 } else {
1240 /*
1241 * Read the entity string
1242 */
1243 cur++;
1244 q = cur;
1245 while ((*cur != 0) && (*cur != ';')) cur++;
1246 if (*cur == 0) {
1247#ifdef DEBUG_TREE
1248 xmlGenericError(xmlGenericErrorContext,
1249 "xmlStringGetNodeList: unterminated entity %30s\n", q);
1250#endif
1251 return(ret);
1252 }
1253 if (cur != q) {
1254 /*
1255 * Predefined entities don't generate nodes
1256 */
1257 val = xmlStrndup(q, cur - q);
1258 ent = xmlGetDocEntity(doc, val);
1259 if ((ent != NULL) &&
1260 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1261 if (last == NULL) {
1262 node = xmlNewDocText(doc, ent->content);
1263 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001264 } else if (last->type != XML_TEXT_NODE) {
1265 node = xmlNewDocText(doc, ent->content);
1266 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001267 } else
1268 xmlNodeAddContent(last, ent->content);
1269
1270 } else {
1271 /*
1272 * Create a new REFERENCE_REF node
1273 */
1274 node = xmlNewReference(doc, val);
1275 if (node == NULL) {
1276 if (val != NULL) xmlFree(val);
1277 return(ret);
1278 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001279 else if ((ent != NULL) && (ent->children == NULL)) {
1280 xmlNodePtr temp;
1281
1282 ent->children = xmlStringGetNodeList(doc,
1283 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001284 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001285 temp = ent->children;
1286 while (temp) {
1287 temp->parent = (xmlNodePtr)ent;
1288 temp = temp->next;
1289 }
1290 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001291 if (last == NULL) {
1292 last = ret = node;
1293 } else {
1294 last = xmlAddNextSibling(last, node);
1295 }
1296 }
1297 xmlFree(val);
1298 }
1299 cur++;
1300 q = cur;
1301 }
1302 if (charval != 0) {
1303 xmlChar buf[10];
1304 int len;
1305
1306 len = xmlCopyCharMultiByte(buf, charval);
1307 buf[len] = 0;
1308 node = xmlNewDocText(doc, buf);
1309 if (node != NULL) {
1310 if (last == NULL) {
1311 last = ret = node;
1312 } else {
1313 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001314 }
1315 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001316
1317 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001318 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001319 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001320 cur++;
1321 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001322 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001323 /*
1324 * Handle the last piece of text.
1325 */
1326 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1327 xmlNodeAddContentLen(last, q, cur - q);
1328 } else {
1329 node = xmlNewDocTextLen(doc, q, cur - q);
1330 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001331 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001332 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001333 } else {
1334 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001335 }
1336 }
1337 }
1338 return(ret);
1339}
1340
1341/**
1342 * xmlNodeListGetString:
1343 * @doc: the document
1344 * @list: a Node list
1345 * @inLine: should we replace entity contents or show their external form
1346 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001347 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001348 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001349 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001350 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001351 */
1352xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001353xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1354{
Owen Taylor3473f882001-02-23 17:55:21 +00001355 xmlNodePtr node = list;
1356 xmlChar *ret = NULL;
1357 xmlEntityPtr ent;
1358
Daniel Veillard7646b182002-04-20 06:41:40 +00001359 if (list == NULL)
1360 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001361
1362 while (node != NULL) {
1363 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001364 (node->type == XML_CDATA_SECTION_NODE)) {
1365 if (inLine) {
1366 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001367 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001368 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001369
Daniel Veillard7646b182002-04-20 06:41:40 +00001370 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1371 if (buffer != NULL) {
1372 ret = xmlStrcat(ret, buffer);
1373 xmlFree(buffer);
1374 }
1375 }
1376 } else if (node->type == XML_ENTITY_REF_NODE) {
1377 if (inLine) {
1378 ent = xmlGetDocEntity(doc, node->name);
1379 if (ent != NULL) {
1380 xmlChar *buffer;
1381
1382 /* an entity content can be any "well balanced chunk",
1383 * i.e. the result of the content [43] production:
1384 * http://www.w3.org/TR/REC-xml#NT-content.
1385 * So it can contain text, CDATA section or nested
1386 * entity reference nodes (among others).
1387 * -> we recursive call xmlNodeListGetString()
1388 * which handles these types */
1389 buffer = xmlNodeListGetString(doc, ent->children, 1);
1390 if (buffer != NULL) {
1391 ret = xmlStrcat(ret, buffer);
1392 xmlFree(buffer);
1393 }
1394 } else {
1395 ret = xmlStrcat(ret, node->content);
1396 }
1397 } else {
1398 xmlChar buf[2];
1399
1400 buf[0] = '&';
1401 buf[1] = 0;
1402 ret = xmlStrncat(ret, buf, 1);
1403 ret = xmlStrcat(ret, node->name);
1404 buf[0] = ';';
1405 buf[1] = 0;
1406 ret = xmlStrncat(ret, buf, 1);
1407 }
1408 }
1409#if 0
1410 else {
1411 xmlGenericError(xmlGenericErrorContext,
1412 "xmlGetNodeListString : invalid node type %d\n",
1413 node->type);
1414 }
1415#endif
1416 node = node->next;
1417 }
1418 return (ret);
1419}
Owen Taylor3473f882001-02-23 17:55:21 +00001420/**
1421 * xmlNodeListGetRawString:
1422 * @doc: the document
1423 * @list: a Node list
1424 * @inLine: should we replace entity contents or show their external form
1425 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001426 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001427 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1428 * this function doesn't do any character encoding handling.
1429 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001430 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001431 */
1432xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001433xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1434{
Owen Taylor3473f882001-02-23 17:55:21 +00001435 xmlNodePtr node = list;
1436 xmlChar *ret = NULL;
1437 xmlEntityPtr ent;
1438
Daniel Veillard7646b182002-04-20 06:41:40 +00001439 if (list == NULL)
1440 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001441
1442 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001443 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001444 (node->type == XML_CDATA_SECTION_NODE)) {
1445 if (inLine) {
1446 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001447 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001448 xmlChar *buffer;
1449
1450 buffer = xmlEncodeSpecialChars(doc, node->content);
1451 if (buffer != NULL) {
1452 ret = xmlStrcat(ret, buffer);
1453 xmlFree(buffer);
1454 }
1455 }
1456 } else if (node->type == XML_ENTITY_REF_NODE) {
1457 if (inLine) {
1458 ent = xmlGetDocEntity(doc, node->name);
1459 if (ent != NULL) {
1460 xmlChar *buffer;
1461
1462 /* an entity content can be any "well balanced chunk",
1463 * i.e. the result of the content [43] production:
1464 * http://www.w3.org/TR/REC-xml#NT-content.
1465 * So it can contain text, CDATA section or nested
1466 * entity reference nodes (among others).
1467 * -> we recursive call xmlNodeListGetRawString()
1468 * which handles these types */
1469 buffer =
1470 xmlNodeListGetRawString(doc, ent->children, 1);
1471 if (buffer != NULL) {
1472 ret = xmlStrcat(ret, buffer);
1473 xmlFree(buffer);
1474 }
1475 } else {
1476 ret = xmlStrcat(ret, node->content);
1477 }
1478 } else {
1479 xmlChar buf[2];
1480
1481 buf[0] = '&';
1482 buf[1] = 0;
1483 ret = xmlStrncat(ret, buf, 1);
1484 ret = xmlStrcat(ret, node->name);
1485 buf[0] = ';';
1486 buf[1] = 0;
1487 ret = xmlStrncat(ret, buf, 1);
1488 }
1489 }
Owen Taylor3473f882001-02-23 17:55:21 +00001490#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001491 else {
1492 xmlGenericError(xmlGenericErrorContext,
1493 "xmlGetNodeListString : invalid node type %d\n",
1494 node->type);
1495 }
Owen Taylor3473f882001-02-23 17:55:21 +00001496#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001497 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001498 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001499 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001500}
1501
1502/**
1503 * xmlNewProp:
1504 * @node: the holding node
1505 * @name: the name of the attribute
1506 * @value: the value of the attribute
1507 *
1508 * Create a new property carried by a node.
1509 * Returns a pointer to the attribute
1510 */
1511xmlAttrPtr
1512xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1513 xmlAttrPtr cur;
1514 xmlDocPtr doc = NULL;
1515
1516 if (name == NULL) {
1517#ifdef DEBUG_TREE
1518 xmlGenericError(xmlGenericErrorContext,
1519 "xmlNewProp : name == NULL\n");
1520#endif
1521 return(NULL);
1522 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00001523 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
1524 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001525
1526 /*
1527 * Allocate a new property and fill the fields.
1528 */
1529 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1530 if (cur == NULL) {
1531 xmlGenericError(xmlGenericErrorContext,
1532 "xmlNewProp : malloc failed\n");
1533 return(NULL);
1534 }
1535 memset(cur, 0, sizeof(xmlAttr));
1536 cur->type = XML_ATTRIBUTE_NODE;
1537
1538 cur->parent = node;
1539 if (node != NULL) {
1540 doc = node->doc;
1541 cur->doc = doc;
1542 }
1543 cur->name = xmlStrdup(name);
1544 if (value != NULL) {
1545 xmlChar *buffer;
1546 xmlNodePtr tmp;
1547
1548 buffer = xmlEncodeEntitiesReentrant(doc, value);
1549 cur->children = xmlStringGetNodeList(doc, buffer);
1550 cur->last = NULL;
1551 tmp = cur->children;
1552 while (tmp != NULL) {
1553 tmp->parent = (xmlNodePtr) cur;
1554 tmp->doc = doc;
1555 if (tmp->next == NULL)
1556 cur->last = tmp;
1557 tmp = tmp->next;
1558 }
1559 xmlFree(buffer);
1560 }
1561
1562 /*
1563 * Add it at the end to preserve parsing order ...
1564 */
1565 if (node != NULL) {
1566 if (node->properties == NULL) {
1567 node->properties = cur;
1568 } else {
1569 xmlAttrPtr prev = node->properties;
1570
1571 while (prev->next != NULL) prev = prev->next;
1572 prev->next = cur;
1573 cur->prev = prev;
1574 }
1575 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001576
Daniel Veillarda880b122003-04-21 21:36:41 +00001577 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001578 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001579 return(cur);
1580}
1581
1582/**
1583 * xmlNewNsProp:
1584 * @node: the holding node
1585 * @ns: the namespace
1586 * @name: the name of the attribute
1587 * @value: the value of the attribute
1588 *
1589 * Create a new property tagged with a namespace and carried by a node.
1590 * Returns a pointer to the attribute
1591 */
1592xmlAttrPtr
1593xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1594 const xmlChar *value) {
1595 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001596 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001597
1598 if (name == NULL) {
1599#ifdef DEBUG_TREE
1600 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001601 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001602#endif
1603 return(NULL);
1604 }
1605
1606 /*
1607 * Allocate a new property and fill the fields.
1608 */
1609 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1610 if (cur == NULL) {
1611 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001612 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001613 return(NULL);
1614 }
1615 memset(cur, 0, sizeof(xmlAttr));
1616 cur->type = XML_ATTRIBUTE_NODE;
1617
1618 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001619 if (node != NULL) {
1620 doc = node->doc;
1621 cur->doc = doc;
1622 }
Owen Taylor3473f882001-02-23 17:55:21 +00001623 cur->ns = ns;
1624 cur->name = xmlStrdup(name);
1625 if (value != NULL) {
1626 xmlChar *buffer;
1627 xmlNodePtr tmp;
1628
Daniel Veillarda682b212001-06-07 19:59:42 +00001629 buffer = xmlEncodeEntitiesReentrant(doc, value);
1630 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001631 cur->last = NULL;
1632 tmp = cur->children;
1633 while (tmp != NULL) {
1634 tmp->parent = (xmlNodePtr) cur;
1635 if (tmp->next == NULL)
1636 cur->last = tmp;
1637 tmp = tmp->next;
1638 }
1639 xmlFree(buffer);
1640 }
1641
1642 /*
1643 * Add it at the end to preserve parsing order ...
1644 */
1645 if (node != NULL) {
1646 if (node->properties == NULL) {
1647 node->properties = cur;
1648 } else {
1649 xmlAttrPtr prev = node->properties;
1650
1651 while (prev->next != NULL) prev = prev->next;
1652 prev->next = cur;
1653 cur->prev = prev;
1654 }
1655 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001656
Daniel Veillarda880b122003-04-21 21:36:41 +00001657 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001658 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001659 return(cur);
1660}
1661
1662/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001663 * xmlNewNsPropEatName:
1664 * @node: the holding node
1665 * @ns: the namespace
1666 * @name: the name of the attribute
1667 * @value: the value of the attribute
1668 *
1669 * Create a new property tagged with a namespace and carried by a node.
1670 * Returns a pointer to the attribute
1671 */
1672xmlAttrPtr
1673xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1674 const xmlChar *value) {
1675 xmlAttrPtr cur;
1676 xmlDocPtr doc = NULL;
1677
1678 if (name == NULL) {
1679#ifdef DEBUG_TREE
1680 xmlGenericError(xmlGenericErrorContext,
1681 "xmlNewNsPropEatName : name == NULL\n");
1682#endif
1683 return(NULL);
1684 }
1685
1686 /*
1687 * Allocate a new property and fill the fields.
1688 */
1689 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1690 if (cur == NULL) {
1691 xmlGenericError(xmlGenericErrorContext,
1692 "xmlNewNsPropEatName : malloc failed\n");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001693 xmlFree(name);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001694 return(NULL);
1695 }
1696 memset(cur, 0, sizeof(xmlAttr));
1697 cur->type = XML_ATTRIBUTE_NODE;
1698
1699 cur->parent = node;
1700 if (node != NULL) {
1701 doc = node->doc;
1702 cur->doc = doc;
1703 }
1704 cur->ns = ns;
1705 cur->name = name;
1706 if (value != NULL) {
1707 xmlChar *buffer;
1708 xmlNodePtr tmp;
1709
1710 buffer = xmlEncodeEntitiesReentrant(doc, value);
1711 cur->children = xmlStringGetNodeList(doc, buffer);
1712 cur->last = NULL;
1713 tmp = cur->children;
1714 while (tmp != NULL) {
1715 tmp->parent = (xmlNodePtr) cur;
1716 if (tmp->next == NULL)
1717 cur->last = tmp;
1718 tmp = tmp->next;
1719 }
1720 xmlFree(buffer);
1721 }
1722
1723 /*
1724 * Add it at the end to preserve parsing order ...
1725 */
1726 if (node != NULL) {
1727 if (node->properties == NULL) {
1728 node->properties = cur;
1729 } else {
1730 xmlAttrPtr prev = node->properties;
1731
1732 while (prev->next != NULL) prev = prev->next;
1733 prev->next = cur;
1734 cur->prev = prev;
1735 }
1736 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001737
Daniel Veillarda880b122003-04-21 21:36:41 +00001738 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001739 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001740 return(cur);
1741}
1742
1743/**
Owen Taylor3473f882001-02-23 17:55:21 +00001744 * xmlNewDocProp:
1745 * @doc: the document
1746 * @name: the name of the attribute
1747 * @value: the value of the attribute
1748 *
1749 * Create a new property carried by a document.
1750 * Returns a pointer to the attribute
1751 */
1752xmlAttrPtr
1753xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1754 xmlAttrPtr cur;
1755
1756 if (name == NULL) {
1757#ifdef DEBUG_TREE
1758 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001759 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001760#endif
1761 return(NULL);
1762 }
1763
1764 /*
1765 * Allocate a new property and fill the fields.
1766 */
1767 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1768 if (cur == NULL) {
1769 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001770 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001771 return(NULL);
1772 }
1773 memset(cur, 0, sizeof(xmlAttr));
1774 cur->type = XML_ATTRIBUTE_NODE;
1775
1776 cur->name = xmlStrdup(name);
1777 cur->doc = doc;
1778 if (value != NULL) {
1779 xmlNodePtr tmp;
1780
1781 cur->children = xmlStringGetNodeList(doc, value);
1782 cur->last = NULL;
1783
1784 tmp = cur->children;
1785 while (tmp != NULL) {
1786 tmp->parent = (xmlNodePtr) cur;
1787 if (tmp->next == NULL)
1788 cur->last = tmp;
1789 tmp = tmp->next;
1790 }
1791 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001792
Daniel Veillarda880b122003-04-21 21:36:41 +00001793 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001794 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001795 return(cur);
1796}
1797
1798/**
1799 * xmlFreePropList:
1800 * @cur: the first property in the list
1801 *
1802 * Free a property and all its siblings, all the children are freed too.
1803 */
1804void
1805xmlFreePropList(xmlAttrPtr cur) {
1806 xmlAttrPtr next;
1807 if (cur == NULL) {
1808#ifdef DEBUG_TREE
1809 xmlGenericError(xmlGenericErrorContext,
1810 "xmlFreePropList : property == NULL\n");
1811#endif
1812 return;
1813 }
1814 while (cur != NULL) {
1815 next = cur->next;
1816 xmlFreeProp(cur);
1817 cur = next;
1818 }
1819}
1820
1821/**
1822 * xmlFreeProp:
1823 * @cur: an attribute
1824 *
1825 * Free one attribute, all the content is freed too
1826 */
1827void
1828xmlFreeProp(xmlAttrPtr cur) {
1829 if (cur == NULL) {
1830#ifdef DEBUG_TREE
1831 xmlGenericError(xmlGenericErrorContext,
1832 "xmlFreeProp : property == NULL\n");
1833#endif
1834 return;
1835 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001836
Daniel Veillarda880b122003-04-21 21:36:41 +00001837 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001838 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1839
Owen Taylor3473f882001-02-23 17:55:21 +00001840 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001841 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1842 ((cur->parent->doc->intSubset != NULL) ||
1843 (cur->parent->doc->extSubset != NULL))) {
1844 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1845 xmlRemoveID(cur->parent->doc, cur);
1846 }
Owen Taylor3473f882001-02-23 17:55:21 +00001847 if (cur->name != NULL) xmlFree((char *) cur->name);
1848 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001849 xmlFree(cur);
1850}
1851
1852/**
1853 * xmlRemoveProp:
1854 * @cur: an attribute
1855 *
1856 * Unlink and free one attribute, all the content is freed too
1857 * Note this doesn't work for namespace definition attributes
1858 *
1859 * Returns 0 if success and -1 in case of error.
1860 */
1861int
1862xmlRemoveProp(xmlAttrPtr cur) {
1863 xmlAttrPtr tmp;
1864 if (cur == NULL) {
1865#ifdef DEBUG_TREE
1866 xmlGenericError(xmlGenericErrorContext,
1867 "xmlRemoveProp : cur == NULL\n");
1868#endif
1869 return(-1);
1870 }
1871 if (cur->parent == NULL) {
1872#ifdef DEBUG_TREE
1873 xmlGenericError(xmlGenericErrorContext,
1874 "xmlRemoveProp : cur->parent == NULL\n");
1875#endif
1876 return(-1);
1877 }
1878 tmp = cur->parent->properties;
1879 if (tmp == cur) {
1880 cur->parent->properties = cur->next;
1881 xmlFreeProp(cur);
1882 return(0);
1883 }
1884 while (tmp != NULL) {
1885 if (tmp->next == cur) {
1886 tmp->next = cur->next;
1887 if (tmp->next != NULL)
1888 tmp->next->prev = tmp;
1889 xmlFreeProp(cur);
1890 return(0);
1891 }
1892 tmp = tmp->next;
1893 }
1894#ifdef DEBUG_TREE
1895 xmlGenericError(xmlGenericErrorContext,
1896 "xmlRemoveProp : attribute not owned by its node\n");
1897#endif
1898 return(-1);
1899}
1900
1901/**
1902 * xmlNewPI:
1903 * @name: the processing instruction name
1904 * @content: the PI content
1905 *
1906 * Creation of a processing instruction element.
1907 * Returns a pointer to the new node object.
1908 */
1909xmlNodePtr
1910xmlNewPI(const xmlChar *name, const xmlChar *content) {
1911 xmlNodePtr cur;
1912
1913 if (name == NULL) {
1914#ifdef DEBUG_TREE
1915 xmlGenericError(xmlGenericErrorContext,
1916 "xmlNewPI : name == NULL\n");
1917#endif
1918 return(NULL);
1919 }
1920
1921 /*
1922 * Allocate a new node and fill the fields.
1923 */
1924 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1925 if (cur == NULL) {
1926 xmlGenericError(xmlGenericErrorContext,
1927 "xmlNewPI : malloc failed\n");
1928 return(NULL);
1929 }
1930 memset(cur, 0, sizeof(xmlNode));
1931 cur->type = XML_PI_NODE;
1932
1933 cur->name = xmlStrdup(name);
1934 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001935 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001936 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001937
Daniel Veillarda880b122003-04-21 21:36:41 +00001938 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001939 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001940 return(cur);
1941}
1942
1943/**
1944 * xmlNewNode:
1945 * @ns: namespace if any
1946 * @name: the node name
1947 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001948 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001949 *
1950 * Returns a pointer to the new node object.
1951 */
1952xmlNodePtr
1953xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1954 xmlNodePtr cur;
1955
1956 if (name == NULL) {
1957#ifdef DEBUG_TREE
1958 xmlGenericError(xmlGenericErrorContext,
1959 "xmlNewNode : name == NULL\n");
1960#endif
1961 return(NULL);
1962 }
1963
1964 /*
1965 * Allocate a new node and fill the fields.
1966 */
1967 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1968 if (cur == NULL) {
1969 xmlGenericError(xmlGenericErrorContext,
1970 "xmlNewNode : malloc failed\n");
1971 return(NULL);
1972 }
1973 memset(cur, 0, sizeof(xmlNode));
1974 cur->type = XML_ELEMENT_NODE;
1975
1976 cur->name = xmlStrdup(name);
1977 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001978
Daniel Veillarda880b122003-04-21 21:36:41 +00001979 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001980 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001981 return(cur);
1982}
1983
1984/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001985 * xmlNewNodeEatName:
1986 * @ns: namespace if any
1987 * @name: the node name
1988 *
1989 * Creation of a new node element. @ns is optional (NULL).
1990 *
1991 * Returns a pointer to the new node object.
1992 */
1993xmlNodePtr
1994xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
1995 xmlNodePtr cur;
1996
1997 if (name == NULL) {
1998#ifdef DEBUG_TREE
1999 xmlGenericError(xmlGenericErrorContext,
2000 "xmlNewNode : name == NULL\n");
2001#endif
2002 return(NULL);
2003 }
2004
2005 /*
2006 * Allocate a new node and fill the fields.
2007 */
2008 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2009 if (cur == NULL) {
2010 xmlGenericError(xmlGenericErrorContext,
2011 "xmlNewNode : malloc failed\n");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00002012 xmlFree(name);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002013 return(NULL);
2014 }
2015 memset(cur, 0, sizeof(xmlNode));
2016 cur->type = XML_ELEMENT_NODE;
2017
2018 cur->name = name;
2019 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002020
Daniel Veillarda880b122003-04-21 21:36:41 +00002021 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002022 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002023 return(cur);
2024}
2025
2026/**
Owen Taylor3473f882001-02-23 17:55:21 +00002027 * xmlNewDocNode:
2028 * @doc: the document
2029 * @ns: namespace if any
2030 * @name: the node name
2031 * @content: the XML text content if any
2032 *
2033 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002034 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002035 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2036 * references, but XML special chars need to be escaped first by using
2037 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2038 * need entities support.
2039 *
2040 * Returns a pointer to the new node object.
2041 */
2042xmlNodePtr
2043xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2044 const xmlChar *name, const xmlChar *content) {
2045 xmlNodePtr cur;
2046
2047 cur = xmlNewNode(ns, name);
2048 if (cur != NULL) {
2049 cur->doc = doc;
2050 if (content != NULL) {
2051 cur->children = xmlStringGetNodeList(doc, content);
2052 UPDATE_LAST_CHILD_AND_PARENT(cur)
2053 }
2054 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002055
Owen Taylor3473f882001-02-23 17:55:21 +00002056 return(cur);
2057}
2058
Daniel Veillard46de64e2002-05-29 08:21:33 +00002059/**
2060 * xmlNewDocNodeEatName:
2061 * @doc: the document
2062 * @ns: namespace if any
2063 * @name: the node name
2064 * @content: the XML text content if any
2065 *
2066 * Creation of a new node element within a document. @ns and @content
2067 * are optional (NULL).
2068 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2069 * references, but XML special chars need to be escaped first by using
2070 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2071 * need entities support.
2072 *
2073 * Returns a pointer to the new node object.
2074 */
2075xmlNodePtr
2076xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2077 xmlChar *name, const xmlChar *content) {
2078 xmlNodePtr cur;
2079
2080 cur = xmlNewNodeEatName(ns, name);
2081 if (cur != NULL) {
2082 cur->doc = doc;
2083 if (content != NULL) {
2084 cur->children = xmlStringGetNodeList(doc, content);
2085 UPDATE_LAST_CHILD_AND_PARENT(cur)
2086 }
2087 }
2088 return(cur);
2089}
2090
Owen Taylor3473f882001-02-23 17:55:21 +00002091
2092/**
2093 * xmlNewDocRawNode:
2094 * @doc: the document
2095 * @ns: namespace if any
2096 * @name: the node name
2097 * @content: the text content if any
2098 *
2099 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002100 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002101 *
2102 * Returns a pointer to the new node object.
2103 */
2104xmlNodePtr
2105xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2106 const xmlChar *name, const xmlChar *content) {
2107 xmlNodePtr cur;
2108
2109 cur = xmlNewNode(ns, name);
2110 if (cur != NULL) {
2111 cur->doc = doc;
2112 if (content != NULL) {
2113 cur->children = xmlNewDocText(doc, content);
2114 UPDATE_LAST_CHILD_AND_PARENT(cur)
2115 }
2116 }
2117 return(cur);
2118}
2119
2120/**
2121 * xmlNewDocFragment:
2122 * @doc: the document owning the fragment
2123 *
2124 * Creation of a new Fragment node.
2125 * Returns a pointer to the new node object.
2126 */
2127xmlNodePtr
2128xmlNewDocFragment(xmlDocPtr doc) {
2129 xmlNodePtr cur;
2130
2131 /*
2132 * Allocate a new DocumentFragment node and fill the fields.
2133 */
2134 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2135 if (cur == NULL) {
2136 xmlGenericError(xmlGenericErrorContext,
2137 "xmlNewDocFragment : malloc failed\n");
2138 return(NULL);
2139 }
2140 memset(cur, 0, sizeof(xmlNode));
2141 cur->type = XML_DOCUMENT_FRAG_NODE;
2142
2143 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002144
Daniel Veillarda880b122003-04-21 21:36:41 +00002145 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002146 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002147 return(cur);
2148}
2149
2150/**
2151 * xmlNewText:
2152 * @content: the text content
2153 *
2154 * Creation of a new text node.
2155 * Returns a pointer to the new node object.
2156 */
2157xmlNodePtr
2158xmlNewText(const xmlChar *content) {
2159 xmlNodePtr cur;
2160
2161 /*
2162 * Allocate a new node and fill the fields.
2163 */
2164 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2165 if (cur == NULL) {
2166 xmlGenericError(xmlGenericErrorContext,
2167 "xmlNewText : malloc failed\n");
2168 return(NULL);
2169 }
2170 memset(cur, 0, sizeof(xmlNode));
2171 cur->type = XML_TEXT_NODE;
2172
2173 cur->name = xmlStringText;
2174 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002175 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002176 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002177
Daniel Veillarda880b122003-04-21 21:36:41 +00002178 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002179 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002180 return(cur);
2181}
2182
2183/**
2184 * xmlNewTextChild:
2185 * @parent: the parent node
2186 * @ns: a namespace if any
2187 * @name: the name of the child
2188 * @content: the text content of the child if any.
2189 *
2190 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002191 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002192 * a child TEXT node will be created containing the string content.
2193 *
2194 * Returns a pointer to the new node object.
2195 */
2196xmlNodePtr
2197xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2198 const xmlChar *name, const xmlChar *content) {
2199 xmlNodePtr cur, prev;
2200
2201 if (parent == NULL) {
2202#ifdef DEBUG_TREE
2203 xmlGenericError(xmlGenericErrorContext,
2204 "xmlNewTextChild : parent == NULL\n");
2205#endif
2206 return(NULL);
2207 }
2208
2209 if (name == NULL) {
2210#ifdef DEBUG_TREE
2211 xmlGenericError(xmlGenericErrorContext,
2212 "xmlNewTextChild : name == NULL\n");
2213#endif
2214 return(NULL);
2215 }
2216
2217 /*
2218 * Allocate a new node
2219 */
2220 if (ns == NULL)
2221 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2222 else
2223 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2224 if (cur == NULL) return(NULL);
2225
2226 /*
2227 * add the new element at the end of the children list.
2228 */
2229 cur->type = XML_ELEMENT_NODE;
2230 cur->parent = parent;
2231 cur->doc = parent->doc;
2232 if (parent->children == NULL) {
2233 parent->children = cur;
2234 parent->last = cur;
2235 } else {
2236 prev = parent->last;
2237 prev->next = cur;
2238 cur->prev = prev;
2239 parent->last = cur;
2240 }
2241
2242 return(cur);
2243}
2244
2245/**
2246 * xmlNewCharRef:
2247 * @doc: the document
2248 * @name: the char ref string, starting with # or "&# ... ;"
2249 *
2250 * Creation of a new character reference node.
2251 * Returns a pointer to the new node object.
2252 */
2253xmlNodePtr
2254xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2255 xmlNodePtr cur;
2256
2257 /*
2258 * Allocate a new node and fill the fields.
2259 */
2260 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2261 if (cur == NULL) {
2262 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002263 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002264 return(NULL);
2265 }
2266 memset(cur, 0, sizeof(xmlNode));
2267 cur->type = XML_ENTITY_REF_NODE;
2268
2269 cur->doc = doc;
2270 if (name[0] == '&') {
2271 int len;
2272 name++;
2273 len = xmlStrlen(name);
2274 if (name[len - 1] == ';')
2275 cur->name = xmlStrndup(name, len - 1);
2276 else
2277 cur->name = xmlStrndup(name, len);
2278 } else
2279 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002280
Daniel Veillarda880b122003-04-21 21:36:41 +00002281 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002282 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002283 return(cur);
2284}
2285
2286/**
2287 * xmlNewReference:
2288 * @doc: the document
2289 * @name: the reference name, or the reference string with & and ;
2290 *
2291 * Creation of a new reference node.
2292 * Returns a pointer to the new node object.
2293 */
2294xmlNodePtr
2295xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2296 xmlNodePtr cur;
2297 xmlEntityPtr ent;
2298
2299 /*
2300 * Allocate a new node and fill the fields.
2301 */
2302 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2303 if (cur == NULL) {
2304 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002305 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002306 return(NULL);
2307 }
2308 memset(cur, 0, sizeof(xmlNode));
2309 cur->type = XML_ENTITY_REF_NODE;
2310
2311 cur->doc = doc;
2312 if (name[0] == '&') {
2313 int len;
2314 name++;
2315 len = xmlStrlen(name);
2316 if (name[len - 1] == ';')
2317 cur->name = xmlStrndup(name, len - 1);
2318 else
2319 cur->name = xmlStrndup(name, len);
2320 } else
2321 cur->name = xmlStrdup(name);
2322
2323 ent = xmlGetDocEntity(doc, cur->name);
2324 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002325 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002326 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002327 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002328 * updated. Not sure if this is 100% correct.
2329 * -George
2330 */
2331 cur->children = (xmlNodePtr) ent;
2332 cur->last = (xmlNodePtr) ent;
2333 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002334
Daniel Veillarda880b122003-04-21 21:36:41 +00002335 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002336 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002337 return(cur);
2338}
2339
2340/**
2341 * xmlNewDocText:
2342 * @doc: the document
2343 * @content: the text content
2344 *
2345 * Creation of a new text node within a document.
2346 * Returns a pointer to the new node object.
2347 */
2348xmlNodePtr
2349xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2350 xmlNodePtr cur;
2351
2352 cur = xmlNewText(content);
2353 if (cur != NULL) cur->doc = doc;
2354 return(cur);
2355}
2356
2357/**
2358 * xmlNewTextLen:
2359 * @content: the text content
2360 * @len: the text len.
2361 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002362 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002363 * Returns a pointer to the new node object.
2364 */
2365xmlNodePtr
2366xmlNewTextLen(const xmlChar *content, int len) {
2367 xmlNodePtr cur;
2368
2369 /*
2370 * Allocate a new node and fill the fields.
2371 */
2372 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2373 if (cur == NULL) {
2374 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002375 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002376 return(NULL);
2377 }
2378 memset(cur, 0, sizeof(xmlNode));
2379 cur->type = XML_TEXT_NODE;
2380
2381 cur->name = xmlStringText;
2382 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002383 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002384 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002385
Daniel Veillarda880b122003-04-21 21:36:41 +00002386 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002387 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002388 return(cur);
2389}
2390
2391/**
2392 * xmlNewDocTextLen:
2393 * @doc: the document
2394 * @content: the text content
2395 * @len: the text len.
2396 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002397 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002398 * text node pertain to a given document.
2399 * Returns a pointer to the new node object.
2400 */
2401xmlNodePtr
2402xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2403 xmlNodePtr cur;
2404
2405 cur = xmlNewTextLen(content, len);
2406 if (cur != NULL) cur->doc = doc;
2407 return(cur);
2408}
2409
2410/**
2411 * xmlNewComment:
2412 * @content: the comment content
2413 *
2414 * Creation of a new node containing a comment.
2415 * Returns a pointer to the new node object.
2416 */
2417xmlNodePtr
2418xmlNewComment(const xmlChar *content) {
2419 xmlNodePtr cur;
2420
2421 /*
2422 * Allocate a new node and fill the fields.
2423 */
2424 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2425 if (cur == NULL) {
2426 xmlGenericError(xmlGenericErrorContext,
2427 "xmlNewComment : malloc failed\n");
2428 return(NULL);
2429 }
2430 memset(cur, 0, sizeof(xmlNode));
2431 cur->type = XML_COMMENT_NODE;
2432
2433 cur->name = xmlStringComment;
2434 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002435 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002436 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002437
Daniel Veillarda880b122003-04-21 21:36:41 +00002438 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002439 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002440 return(cur);
2441}
2442
2443/**
2444 * xmlNewCDataBlock:
2445 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002446 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002447 * @len: the length of the block
2448 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002449 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002450 * Returns a pointer to the new node object.
2451 */
2452xmlNodePtr
2453xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2454 xmlNodePtr cur;
2455
2456 /*
2457 * Allocate a new node and fill the fields.
2458 */
2459 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2460 if (cur == NULL) {
2461 xmlGenericError(xmlGenericErrorContext,
2462 "xmlNewCDataBlock : malloc failed\n");
2463 return(NULL);
2464 }
2465 memset(cur, 0, sizeof(xmlNode));
2466 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002467 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002468
2469 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002470 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002471 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002472
Daniel Veillarda880b122003-04-21 21:36:41 +00002473 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002474 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002475 return(cur);
2476}
2477
2478/**
2479 * xmlNewDocComment:
2480 * @doc: the document
2481 * @content: the comment content
2482 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002483 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002484 * Returns a pointer to the new node object.
2485 */
2486xmlNodePtr
2487xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2488 xmlNodePtr cur;
2489
2490 cur = xmlNewComment(content);
2491 if (cur != NULL) cur->doc = doc;
2492 return(cur);
2493}
2494
2495/**
2496 * xmlSetTreeDoc:
2497 * @tree: the top element
2498 * @doc: the document
2499 *
2500 * update all nodes under the tree to point to the right document
2501 */
2502void
2503xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002504 xmlAttrPtr prop;
2505
Owen Taylor3473f882001-02-23 17:55:21 +00002506 if (tree == NULL)
2507 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002508 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002509 if(tree->type == XML_ELEMENT_NODE) {
2510 prop = tree->properties;
2511 while (prop != NULL) {
2512 prop->doc = doc;
2513 xmlSetListDoc(prop->children, doc);
2514 prop = prop->next;
2515 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002516 }
Owen Taylor3473f882001-02-23 17:55:21 +00002517 if (tree->children != NULL)
2518 xmlSetListDoc(tree->children, doc);
2519 tree->doc = doc;
2520 }
2521}
2522
2523/**
2524 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002525 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002526 * @doc: the document
2527 *
2528 * update all nodes in the list to point to the right document
2529 */
2530void
2531xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2532 xmlNodePtr cur;
2533
2534 if (list == NULL)
2535 return;
2536 cur = list;
2537 while (cur != NULL) {
2538 if (cur->doc != doc)
2539 xmlSetTreeDoc(cur, doc);
2540 cur = cur->next;
2541 }
2542}
2543
2544
2545/**
2546 * xmlNewChild:
2547 * @parent: the parent node
2548 * @ns: a namespace if any
2549 * @name: the name of the child
2550 * @content: the XML content of the child if any.
2551 *
2552 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002553 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002554 * a child list containing the TEXTs and ENTITY_REFs node will be created.
2555 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2556 * references, but XML special chars need to be escaped first by using
2557 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
2558 * support is not needed.
2559 *
2560 * Returns a pointer to the new node object.
2561 */
2562xmlNodePtr
2563xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2564 const xmlChar *name, const xmlChar *content) {
2565 xmlNodePtr cur, prev;
2566
2567 if (parent == NULL) {
2568#ifdef DEBUG_TREE
2569 xmlGenericError(xmlGenericErrorContext,
2570 "xmlNewChild : parent == NULL\n");
2571#endif
2572 return(NULL);
2573 }
2574
2575 if (name == NULL) {
2576#ifdef DEBUG_TREE
2577 xmlGenericError(xmlGenericErrorContext,
2578 "xmlNewChild : name == NULL\n");
2579#endif
2580 return(NULL);
2581 }
2582
2583 /*
2584 * Allocate a new node
2585 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002586 if (parent->type == XML_ELEMENT_NODE) {
2587 if (ns == NULL)
2588 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2589 else
2590 cur = xmlNewDocNode(parent->doc, ns, name, content);
2591 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2592 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2593 if (ns == NULL)
2594 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2595 else
2596 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002597 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2598 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002599 } else {
2600 return(NULL);
2601 }
Owen Taylor3473f882001-02-23 17:55:21 +00002602 if (cur == NULL) return(NULL);
2603
2604 /*
2605 * add the new element at the end of the children list.
2606 */
2607 cur->type = XML_ELEMENT_NODE;
2608 cur->parent = parent;
2609 cur->doc = parent->doc;
2610 if (parent->children == NULL) {
2611 parent->children = cur;
2612 parent->last = cur;
2613 } else {
2614 prev = parent->last;
2615 prev->next = cur;
2616 cur->prev = prev;
2617 parent->last = cur;
2618 }
2619
2620 return(cur);
2621}
2622
2623/**
2624 * xmlAddNextSibling:
2625 * @cur: the child node
2626 * @elem: the new node
2627 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002628 * Add a new node @elem as the next sibling of @cur
2629 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002630 * first unlinked from its existing context.
2631 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002632 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2633 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002634 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002635 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002636 */
2637xmlNodePtr
2638xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2639 if (cur == NULL) {
2640#ifdef DEBUG_TREE
2641 xmlGenericError(xmlGenericErrorContext,
2642 "xmlAddNextSibling : cur == NULL\n");
2643#endif
2644 return(NULL);
2645 }
2646 if (elem == NULL) {
2647#ifdef DEBUG_TREE
2648 xmlGenericError(xmlGenericErrorContext,
2649 "xmlAddNextSibling : elem == NULL\n");
2650#endif
2651 return(NULL);
2652 }
2653
2654 xmlUnlinkNode(elem);
2655
2656 if (elem->type == XML_TEXT_NODE) {
2657 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002658 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002659 xmlFreeNode(elem);
2660 return(cur);
2661 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002662 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2663 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002664 xmlChar *tmp;
2665
2666 tmp = xmlStrdup(elem->content);
2667 tmp = xmlStrcat(tmp, cur->next->content);
2668 xmlNodeSetContent(cur->next, tmp);
2669 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002670 xmlFreeNode(elem);
2671 return(cur->next);
2672 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002673 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2674 /* check if an attribute with the same name exists */
2675 xmlAttrPtr attr;
2676
2677 if (elem->ns == NULL)
2678 attr = xmlHasProp(cur->parent, elem->name);
2679 else
2680 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2681 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2682 /* different instance, destroy it (attributes must be unique) */
2683 xmlFreeProp(attr);
2684 }
Owen Taylor3473f882001-02-23 17:55:21 +00002685 }
2686
2687 if (elem->doc != cur->doc) {
2688 xmlSetTreeDoc(elem, cur->doc);
2689 }
2690 elem->parent = cur->parent;
2691 elem->prev = cur;
2692 elem->next = cur->next;
2693 cur->next = elem;
2694 if (elem->next != NULL)
2695 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002696 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002697 elem->parent->last = elem;
2698 return(elem);
2699}
2700
2701/**
2702 * xmlAddPrevSibling:
2703 * @cur: the child node
2704 * @elem: the new node
2705 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002706 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002707 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002708 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002709 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002710 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2711 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002712 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002713 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002714 */
2715xmlNodePtr
2716xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2717 if (cur == NULL) {
2718#ifdef DEBUG_TREE
2719 xmlGenericError(xmlGenericErrorContext,
2720 "xmlAddPrevSibling : cur == NULL\n");
2721#endif
2722 return(NULL);
2723 }
2724 if (elem == NULL) {
2725#ifdef DEBUG_TREE
2726 xmlGenericError(xmlGenericErrorContext,
2727 "xmlAddPrevSibling : elem == NULL\n");
2728#endif
2729 return(NULL);
2730 }
2731
2732 xmlUnlinkNode(elem);
2733
2734 if (elem->type == XML_TEXT_NODE) {
2735 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002736 xmlChar *tmp;
2737
2738 tmp = xmlStrdup(elem->content);
2739 tmp = xmlStrcat(tmp, cur->content);
2740 xmlNodeSetContent(cur, tmp);
2741 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002742 xmlFreeNode(elem);
2743 return(cur);
2744 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002745 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2746 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002747 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002748 xmlFreeNode(elem);
2749 return(cur->prev);
2750 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002751 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2752 /* check if an attribute with the same name exists */
2753 xmlAttrPtr attr;
2754
2755 if (elem->ns == NULL)
2756 attr = xmlHasProp(cur->parent, elem->name);
2757 else
2758 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2759 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2760 /* different instance, destroy it (attributes must be unique) */
2761 xmlFreeProp(attr);
2762 }
Owen Taylor3473f882001-02-23 17:55:21 +00002763 }
2764
2765 if (elem->doc != cur->doc) {
2766 xmlSetTreeDoc(elem, cur->doc);
2767 }
2768 elem->parent = cur->parent;
2769 elem->next = cur;
2770 elem->prev = cur->prev;
2771 cur->prev = elem;
2772 if (elem->prev != NULL)
2773 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002774 if (elem->parent != NULL) {
2775 if (elem->type == XML_ATTRIBUTE_NODE) {
2776 if (elem->parent->properties == (xmlAttrPtr) cur) {
2777 elem->parent->properties = (xmlAttrPtr) elem;
2778 }
2779 } else {
2780 if (elem->parent->children == cur) {
2781 elem->parent->children = elem;
2782 }
2783 }
2784 }
Owen Taylor3473f882001-02-23 17:55:21 +00002785 return(elem);
2786}
2787
2788/**
2789 * xmlAddSibling:
2790 * @cur: the child node
2791 * @elem: the new node
2792 *
2793 * Add a new element @elem to the list of siblings of @cur
2794 * merging adjacent TEXT nodes (@elem may be freed)
2795 * If the new element was already inserted in a document it is
2796 * first unlinked from its existing context.
2797 *
2798 * Returns the new element or NULL in case of error.
2799 */
2800xmlNodePtr
2801xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2802 xmlNodePtr parent;
2803
2804 if (cur == NULL) {
2805#ifdef DEBUG_TREE
2806 xmlGenericError(xmlGenericErrorContext,
2807 "xmlAddSibling : cur == NULL\n");
2808#endif
2809 return(NULL);
2810 }
2811
2812 if (elem == NULL) {
2813#ifdef DEBUG_TREE
2814 xmlGenericError(xmlGenericErrorContext,
2815 "xmlAddSibling : elem == NULL\n");
2816#endif
2817 return(NULL);
2818 }
2819
2820 /*
2821 * Constant time is we can rely on the ->parent->last to find
2822 * the last sibling.
2823 */
2824 if ((cur->parent != NULL) &&
2825 (cur->parent->children != NULL) &&
2826 (cur->parent->last != NULL) &&
2827 (cur->parent->last->next == NULL)) {
2828 cur = cur->parent->last;
2829 } else {
2830 while (cur->next != NULL) cur = cur->next;
2831 }
2832
2833 xmlUnlinkNode(elem);
2834
2835 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002836 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002837 xmlFreeNode(elem);
2838 return(cur);
2839 }
2840
2841 if (elem->doc != cur->doc) {
2842 xmlSetTreeDoc(elem, cur->doc);
2843 }
2844 parent = cur->parent;
2845 elem->prev = cur;
2846 elem->next = NULL;
2847 elem->parent = parent;
2848 cur->next = elem;
2849 if (parent != NULL)
2850 parent->last = elem;
2851
2852 return(elem);
2853}
2854
2855/**
2856 * xmlAddChildList:
2857 * @parent: the parent node
2858 * @cur: the first node in the list
2859 *
2860 * Add a list of node at the end of the child list of the parent
2861 * merging adjacent TEXT nodes (@cur may be freed)
2862 *
2863 * Returns the last child or NULL in case of error.
2864 */
2865xmlNodePtr
2866xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2867 xmlNodePtr prev;
2868
2869 if (parent == NULL) {
2870#ifdef DEBUG_TREE
2871 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002872 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002873#endif
2874 return(NULL);
2875 }
2876
2877 if (cur == NULL) {
2878#ifdef DEBUG_TREE
2879 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002880 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002881#endif
2882 return(NULL);
2883 }
2884
2885 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2886 (cur->doc != parent->doc)) {
2887#ifdef DEBUG_TREE
2888 xmlGenericError(xmlGenericErrorContext,
2889 "Elements moved to a different document\n");
2890#endif
2891 }
2892
2893 /*
2894 * add the first element at the end of the children list.
2895 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00002896
Owen Taylor3473f882001-02-23 17:55:21 +00002897 if (parent->children == NULL) {
2898 parent->children = cur;
2899 } else {
2900 /*
2901 * If cur and parent->last both are TEXT nodes, then merge them.
2902 */
2903 if ((cur->type == XML_TEXT_NODE) &&
2904 (parent->last->type == XML_TEXT_NODE) &&
2905 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00002906 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002907 /*
2908 * if it's the only child, nothing more to be done.
2909 */
2910 if (cur->next == NULL) {
2911 xmlFreeNode(cur);
2912 return(parent->last);
2913 }
2914 prev = cur;
2915 cur = cur->next;
2916 xmlFreeNode(prev);
2917 }
2918 prev = parent->last;
2919 prev->next = cur;
2920 cur->prev = prev;
2921 }
2922 while (cur->next != NULL) {
2923 cur->parent = parent;
2924 if (cur->doc != parent->doc) {
2925 xmlSetTreeDoc(cur, parent->doc);
2926 }
2927 cur = cur->next;
2928 }
2929 cur->parent = parent;
2930 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2931 parent->last = cur;
2932
2933 return(cur);
2934}
2935
2936/**
2937 * xmlAddChild:
2938 * @parent: the parent node
2939 * @cur: the child node
2940 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002941 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00002942 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002943 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2944 * If there is an attribute with equal name, it is first destroyed.
2945 *
Owen Taylor3473f882001-02-23 17:55:21 +00002946 * Returns the child or NULL in case of error.
2947 */
2948xmlNodePtr
2949xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2950 xmlNodePtr prev;
2951
2952 if (parent == NULL) {
2953#ifdef DEBUG_TREE
2954 xmlGenericError(xmlGenericErrorContext,
2955 "xmlAddChild : parent == NULL\n");
2956#endif
2957 return(NULL);
2958 }
2959
2960 if (cur == NULL) {
2961#ifdef DEBUG_TREE
2962 xmlGenericError(xmlGenericErrorContext,
2963 "xmlAddChild : child == NULL\n");
2964#endif
2965 return(NULL);
2966 }
2967
Owen Taylor3473f882001-02-23 17:55:21 +00002968 /*
2969 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002970 * cur is then freed.
2971 */
2972 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002973 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002974 (parent->content != NULL) &&
2975 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002976 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002977 xmlFreeNode(cur);
2978 return(parent);
2979 }
2980 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002981 (parent->last->name == cur->name) &&
2982 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002983 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002984 xmlFreeNode(cur);
2985 return(parent->last);
2986 }
2987 }
2988
2989 /*
2990 * add the new element at the end of the children list.
2991 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00002992 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00002993 cur->parent = parent;
2994 if (cur->doc != parent->doc) {
2995 xmlSetTreeDoc(cur, parent->doc);
2996 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002997 /* this check prevents a loop on tree-traversions if a developer
2998 * tries to add a node to its parent multiple times
2999 */
3000 if (prev == parent)
3001 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003002
3003 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003004 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003005 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003006 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003007 (parent->content != NULL) &&
3008 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003009 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003010 xmlFreeNode(cur);
3011 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003012 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003013 if (cur->type == XML_ATTRIBUTE_NODE) {
3014 if (parent->properties == NULL) {
3015 parent->properties = (xmlAttrPtr) cur;
3016 } else {
3017 /* check if an attribute with the same name exists */
3018 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003019
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003020 if (cur->ns == NULL)
3021 lastattr = xmlHasProp(parent, cur->name);
3022 else
3023 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3024 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
3025 /* different instance, destroy it (attributes must be unique) */
3026 xmlFreeProp(lastattr);
3027 }
3028 /* find the end */
3029 lastattr = parent->properties;
3030 while (lastattr->next != NULL) {
3031 lastattr = lastattr->next;
3032 }
3033 lastattr->next = (xmlAttrPtr) cur;
3034 ((xmlAttrPtr) cur)->prev = lastattr;
3035 }
3036 } else {
3037 if (parent->children == NULL) {
3038 parent->children = cur;
3039 parent->last = cur;
3040 } else {
3041 prev = parent->last;
3042 prev->next = cur;
3043 cur->prev = prev;
3044 parent->last = cur;
3045 }
3046 }
Owen Taylor3473f882001-02-23 17:55:21 +00003047 return(cur);
3048}
3049
3050/**
3051 * xmlGetLastChild:
3052 * @parent: the parent node
3053 *
3054 * Search the last child of a node.
3055 * Returns the last child or NULL if none.
3056 */
3057xmlNodePtr
3058xmlGetLastChild(xmlNodePtr parent) {
3059 if (parent == NULL) {
3060#ifdef DEBUG_TREE
3061 xmlGenericError(xmlGenericErrorContext,
3062 "xmlGetLastChild : parent == NULL\n");
3063#endif
3064 return(NULL);
3065 }
3066 return(parent->last);
3067}
3068
3069/**
3070 * xmlFreeNodeList:
3071 * @cur: the first node in the list
3072 *
3073 * Free a node and all its siblings, this is a recursive behaviour, all
3074 * the children are freed too.
3075 */
3076void
3077xmlFreeNodeList(xmlNodePtr cur) {
3078 xmlNodePtr next;
3079 if (cur == NULL) {
3080#ifdef DEBUG_TREE
3081 xmlGenericError(xmlGenericErrorContext,
3082 "xmlFreeNodeList : node == NULL\n");
3083#endif
3084 return;
3085 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00003086 if (cur->type == XML_NAMESPACE_DECL) {
3087 xmlFreeNsList((xmlNsPtr) cur);
3088 return;
3089 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003090 if ((cur->type == XML_DOCUMENT_NODE) ||
3091#ifdef LIBXML_DOCB_ENABLED
3092 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003093#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003094 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003095 xmlFreeDoc((xmlDocPtr) cur);
3096 return;
3097 }
Owen Taylor3473f882001-02-23 17:55:21 +00003098 while (cur != NULL) {
3099 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003100 /* unroll to speed up freeing the document */
3101 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003102
Daniel Veillarda880b122003-04-21 21:36:41 +00003103 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003104 xmlDeregisterNodeDefaultValue(cur);
3105
Daniel Veillard02141ea2001-04-30 11:46:40 +00003106 if ((cur->children != NULL) &&
3107 (cur->type != XML_ENTITY_REF_NODE))
3108 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003109 if (((cur->type == XML_ELEMENT_NODE) ||
3110 (cur->type == XML_XINCLUDE_START) ||
3111 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003112 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003113 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003114 if ((cur->type != XML_ELEMENT_NODE) &&
3115 (cur->type != XML_XINCLUDE_START) &&
3116 (cur->type != XML_XINCLUDE_END) &&
3117 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00003118 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003119 }
3120 if (((cur->type == XML_ELEMENT_NODE) ||
3121 (cur->type == XML_XINCLUDE_START) ||
3122 (cur->type == XML_XINCLUDE_END)) &&
3123 (cur->nsDef != NULL))
3124 xmlFreeNsList(cur->nsDef);
3125
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003126 /*
3127 * When a node is a text node or a comment, it uses a global static
3128 * variable for the name of the node.
3129 *
3130 * The xmlStrEqual comparisons need to be done when (happened with
3131 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003132 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00003133 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003134 * the string addresses compare are not sufficient.
3135 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003136 if ((cur->name != NULL) &&
3137 (cur->name != xmlStringText) &&
3138 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003139 (cur->name != xmlStringComment)) {
3140 if (cur->type == XML_TEXT_NODE) {
3141 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
3142 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
3143 xmlFree((char *) cur->name);
3144 } else if (cur->type == XML_COMMENT_NODE) {
3145 if (!xmlStrEqual(cur->name, xmlStringComment))
3146 xmlFree((char *) cur->name);
3147 } else
3148 xmlFree((char *) cur->name);
3149 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00003150 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003151 xmlFree(cur);
3152 }
Owen Taylor3473f882001-02-23 17:55:21 +00003153 cur = next;
3154 }
3155}
3156
3157/**
3158 * xmlFreeNode:
3159 * @cur: the node
3160 *
3161 * Free a node, this is a recursive behaviour, all the children are freed too.
3162 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3163 */
3164void
3165xmlFreeNode(xmlNodePtr cur) {
3166 if (cur == NULL) {
3167#ifdef DEBUG_TREE
3168 xmlGenericError(xmlGenericErrorContext,
3169 "xmlFreeNode : node == NULL\n");
3170#endif
3171 return;
3172 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003173
Daniel Veillard02141ea2001-04-30 11:46:40 +00003174 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003175 if (cur->type == XML_DTD_NODE) {
3176 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003177 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003178 }
3179 if (cur->type == XML_NAMESPACE_DECL) {
3180 xmlFreeNs((xmlNsPtr) cur);
3181 return;
3182 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003183 if (cur->type == XML_ATTRIBUTE_NODE) {
3184 xmlFreeProp((xmlAttrPtr) cur);
3185 return;
3186 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003187
Daniel Veillarda880b122003-04-21 21:36:41 +00003188 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003189 xmlDeregisterNodeDefaultValue(cur);
3190
Owen Taylor3473f882001-02-23 17:55:21 +00003191 if ((cur->children != NULL) &&
3192 (cur->type != XML_ENTITY_REF_NODE))
3193 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003194 if (((cur->type == XML_ELEMENT_NODE) ||
3195 (cur->type == XML_XINCLUDE_START) ||
3196 (cur->type == XML_XINCLUDE_END)) &&
3197 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003198 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003199 if ((cur->type != XML_ELEMENT_NODE) &&
3200 (cur->content != NULL) &&
3201 (cur->type != XML_ENTITY_REF_NODE) &&
3202 (cur->type != XML_XINCLUDE_END) &&
3203 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003204 xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003205 }
3206
Daniel Veillardacd370f2001-06-09 17:17:51 +00003207 /*
3208 * When a node is a text node or a comment, it uses a global static
3209 * variable for the name of the node.
3210 *
3211 * The xmlStrEqual comparisons need to be done when (happened with
3212 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003213 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00003214 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00003215 * are not sufficient.
3216 */
Owen Taylor3473f882001-02-23 17:55:21 +00003217 if ((cur->name != NULL) &&
3218 (cur->name != xmlStringText) &&
3219 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00003220 (cur->name != xmlStringComment)) {
3221 if (cur->type == XML_TEXT_NODE) {
3222 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
3223 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
3224 xmlFree((char *) cur->name);
3225 } else if (cur->type == XML_COMMENT_NODE) {
3226 if (!xmlStrEqual(cur->name, xmlStringComment))
3227 xmlFree((char *) cur->name);
3228 } else
3229 xmlFree((char *) cur->name);
3230 }
3231
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003232 if (((cur->type == XML_ELEMENT_NODE) ||
3233 (cur->type == XML_XINCLUDE_START) ||
3234 (cur->type == XML_XINCLUDE_END)) &&
3235 (cur->nsDef != NULL))
3236 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003237 xmlFree(cur);
3238}
3239
3240/**
3241 * xmlUnlinkNode:
3242 * @cur: the node
3243 *
3244 * Unlink a node from it's current context, the node is not freed
3245 */
3246void
3247xmlUnlinkNode(xmlNodePtr cur) {
3248 if (cur == NULL) {
3249#ifdef DEBUG_TREE
3250 xmlGenericError(xmlGenericErrorContext,
3251 "xmlUnlinkNode : node == NULL\n");
3252#endif
3253 return;
3254 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003255 if (cur->type == XML_DTD_NODE) {
3256 xmlDocPtr doc;
3257 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003258 if (doc != NULL) {
3259 if (doc->intSubset == (xmlDtdPtr) cur)
3260 doc->intSubset = NULL;
3261 if (doc->extSubset == (xmlDtdPtr) cur)
3262 doc->extSubset = NULL;
3263 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003264 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003265 if (cur->parent != NULL) {
3266 xmlNodePtr parent;
3267 parent = cur->parent;
3268 if (cur->type == XML_ATTRIBUTE_NODE) {
3269 if (parent->properties == (xmlAttrPtr) cur)
3270 parent->properties = ((xmlAttrPtr) cur)->next;
3271 } else {
3272 if (parent->children == cur)
3273 parent->children = cur->next;
3274 if (parent->last == cur)
3275 parent->last = cur->prev;
3276 }
3277 cur->parent = NULL;
3278 }
Owen Taylor3473f882001-02-23 17:55:21 +00003279 if (cur->next != NULL)
3280 cur->next->prev = cur->prev;
3281 if (cur->prev != NULL)
3282 cur->prev->next = cur->next;
3283 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003284}
3285
3286/**
3287 * xmlReplaceNode:
3288 * @old: the old node
3289 * @cur: the node
3290 *
3291 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003292 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003293 * first unlinked from its existing context.
3294 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003295 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003296 */
3297xmlNodePtr
3298xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3299 if (old == NULL) {
3300#ifdef DEBUG_TREE
3301 xmlGenericError(xmlGenericErrorContext,
3302 "xmlReplaceNode : old == NULL\n");
3303#endif
3304 return(NULL);
3305 }
3306 if (cur == NULL) {
3307 xmlUnlinkNode(old);
3308 return(old);
3309 }
3310 if (cur == old) {
3311 return(old);
3312 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003313 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3314#ifdef DEBUG_TREE
3315 xmlGenericError(xmlGenericErrorContext,
3316 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3317#endif
3318 return(old);
3319 }
3320 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3321#ifdef DEBUG_TREE
3322 xmlGenericError(xmlGenericErrorContext,
3323 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3324#endif
3325 return(old);
3326 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003327 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3328#ifdef DEBUG_TREE
3329 xmlGenericError(xmlGenericErrorContext,
3330 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3331#endif
3332 return(old);
3333 }
3334 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3335#ifdef DEBUG_TREE
3336 xmlGenericError(xmlGenericErrorContext,
3337 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3338#endif
3339 return(old);
3340 }
Owen Taylor3473f882001-02-23 17:55:21 +00003341 xmlUnlinkNode(cur);
3342 cur->doc = old->doc;
3343 cur->parent = old->parent;
3344 cur->next = old->next;
3345 if (cur->next != NULL)
3346 cur->next->prev = cur;
3347 cur->prev = old->prev;
3348 if (cur->prev != NULL)
3349 cur->prev->next = cur;
3350 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003351 if (cur->type == XML_ATTRIBUTE_NODE) {
3352 if (cur->parent->properties == (xmlAttrPtr)old)
3353 cur->parent->properties = ((xmlAttrPtr) cur);
3354 } else {
3355 if (cur->parent->children == old)
3356 cur->parent->children = cur;
3357 if (cur->parent->last == old)
3358 cur->parent->last = cur;
3359 }
Owen Taylor3473f882001-02-23 17:55:21 +00003360 }
3361 old->next = old->prev = NULL;
3362 old->parent = NULL;
3363 return(old);
3364}
3365
3366/************************************************************************
3367 * *
3368 * Copy operations *
3369 * *
3370 ************************************************************************/
3371
3372/**
3373 * xmlCopyNamespace:
3374 * @cur: the namespace
3375 *
3376 * Do a copy of the namespace.
3377 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003378 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003379 */
3380xmlNsPtr
3381xmlCopyNamespace(xmlNsPtr cur) {
3382 xmlNsPtr ret;
3383
3384 if (cur == NULL) return(NULL);
3385 switch (cur->type) {
3386 case XML_LOCAL_NAMESPACE:
3387 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3388 break;
3389 default:
3390#ifdef DEBUG_TREE
3391 xmlGenericError(xmlGenericErrorContext,
3392 "xmlCopyNamespace: invalid type %d\n", cur->type);
3393#endif
3394 return(NULL);
3395 }
3396 return(ret);
3397}
3398
3399/**
3400 * xmlCopyNamespaceList:
3401 * @cur: the first namespace
3402 *
3403 * Do a copy of an namespace list.
3404 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003405 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003406 */
3407xmlNsPtr
3408xmlCopyNamespaceList(xmlNsPtr cur) {
3409 xmlNsPtr ret = NULL;
3410 xmlNsPtr p = NULL,q;
3411
3412 while (cur != NULL) {
3413 q = xmlCopyNamespace(cur);
3414 if (p == NULL) {
3415 ret = p = q;
3416 } else {
3417 p->next = q;
3418 p = q;
3419 }
3420 cur = cur->next;
3421 }
3422 return(ret);
3423}
3424
3425static xmlNodePtr
3426xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3427/**
3428 * xmlCopyProp:
3429 * @target: the element where the attribute will be grafted
3430 * @cur: the attribute
3431 *
3432 * Do a copy of the attribute.
3433 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003434 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003435 */
3436xmlAttrPtr
3437xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3438 xmlAttrPtr ret;
3439
3440 if (cur == NULL) return(NULL);
3441 if (target != NULL)
3442 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3443 else if (cur->parent != NULL)
3444 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3445 else if (cur->children != NULL)
3446 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3447 else
3448 ret = xmlNewDocProp(NULL, cur->name, NULL);
3449 if (ret == NULL) return(NULL);
3450 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003451
Owen Taylor3473f882001-02-23 17:55:21 +00003452 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003453 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003454/*
3455 * if (target->doc)
3456 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3457 * else if (cur->doc) / * target may not yet have a doc : KPI * /
3458 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
3459 * else
3460 * ns = NULL;
3461 * ret->ns = ns;
3462 */
3463 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3464 if (ns == NULL) {
3465 /*
3466 * Humm, we are copying an element whose namespace is defined
3467 * out of the new tree scope. Search it in the original tree
3468 * and add it at the top of the new tree
3469 */
3470 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3471 if (ns != NULL) {
3472 xmlNodePtr root = target;
3473 xmlNodePtr pred = NULL;
3474
3475 while (root->parent != NULL) {
3476 pred = root;
3477 root = root->parent;
3478 }
3479 if (root == (xmlNodePtr) target->doc) {
3480 /* correct possibly cycling above the document elt */
3481 root = pred;
3482 }
3483 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3484 }
3485 } else {
3486 /*
3487 * we have to find something appropriate here since
3488 * we cant be sure, that the namespce we found is identified
3489 * by the prefix
3490 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003491 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003492 /* this is the nice case */
3493 ret->ns = ns;
3494 } else {
3495 /*
3496 * we are in trouble: we need a new reconcilied namespace.
3497 * This is expensive
3498 */
3499 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3500 }
3501 }
3502
Owen Taylor3473f882001-02-23 17:55:21 +00003503 } else
3504 ret->ns = NULL;
3505
3506 if (cur->children != NULL) {
3507 xmlNodePtr tmp;
3508
3509 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3510 ret->last = NULL;
3511 tmp = ret->children;
3512 while (tmp != NULL) {
3513 /* tmp->parent = (xmlNodePtr)ret; */
3514 if (tmp->next == NULL)
3515 ret->last = tmp;
3516 tmp = tmp->next;
3517 }
3518 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003519 /*
3520 * Try to handle IDs
3521 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003522 if ((target!= NULL) && (cur!= NULL) &&
3523 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003524 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3525 if (xmlIsID(cur->doc, cur->parent, cur)) {
3526 xmlChar *id;
3527
3528 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3529 if (id != NULL) {
3530 xmlAddID(NULL, target->doc, id, ret);
3531 xmlFree(id);
3532 }
3533 }
3534 }
Owen Taylor3473f882001-02-23 17:55:21 +00003535 return(ret);
3536}
3537
3538/**
3539 * xmlCopyPropList:
3540 * @target: the element where the attributes will be grafted
3541 * @cur: the first attribute
3542 *
3543 * Do a copy of an attribute list.
3544 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003545 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003546 */
3547xmlAttrPtr
3548xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3549 xmlAttrPtr ret = NULL;
3550 xmlAttrPtr p = NULL,q;
3551
3552 while (cur != NULL) {
3553 q = xmlCopyProp(target, cur);
3554 if (p == NULL) {
3555 ret = p = q;
3556 } else {
3557 p->next = q;
3558 q->prev = p;
3559 p = q;
3560 }
3561 cur = cur->next;
3562 }
3563 return(ret);
3564}
3565
3566/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003567 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003568 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003569 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003570 * tricky reason: namespaces. Doing a direct copy of a node
3571 * say RPM:Copyright without changing the namespace pointer to
3572 * something else can produce stale links. One way to do it is
3573 * to keep a reference counter but this doesn't work as soon
3574 * as one move the element or the subtree out of the scope of
3575 * the existing namespace. The actual solution seems to add
3576 * a copy of the namespace at the top of the copied tree if
3577 * not available in the subtree.
3578 * Hence two functions, the public front-end call the inner ones
3579 */
3580
3581static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003582xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003583 int recursive) {
3584 xmlNodePtr ret;
3585
3586 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003587 switch (node->type) {
3588 case XML_TEXT_NODE:
3589 case XML_CDATA_SECTION_NODE:
3590 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003591 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003592 case XML_ENTITY_REF_NODE:
3593 case XML_ENTITY_NODE:
3594 case XML_PI_NODE:
3595 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003596 case XML_XINCLUDE_START:
3597 case XML_XINCLUDE_END:
3598 break;
3599 case XML_ATTRIBUTE_NODE:
3600 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3601 case XML_NAMESPACE_DECL:
3602 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3603
Daniel Veillard39196eb2001-06-19 18:09:42 +00003604 case XML_DOCUMENT_NODE:
3605 case XML_HTML_DOCUMENT_NODE:
3606#ifdef LIBXML_DOCB_ENABLED
3607 case XML_DOCB_DOCUMENT_NODE:
3608#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003609 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00003610 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003611 case XML_NOTATION_NODE:
3612 case XML_DTD_NODE:
3613 case XML_ELEMENT_DECL:
3614 case XML_ATTRIBUTE_DECL:
3615 case XML_ENTITY_DECL:
3616 return(NULL);
3617 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003618
Owen Taylor3473f882001-02-23 17:55:21 +00003619 /*
3620 * Allocate a new node and fill the fields.
3621 */
3622 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3623 if (ret == NULL) {
3624 xmlGenericError(xmlGenericErrorContext,
3625 "xmlStaticCopyNode : malloc failed\n");
3626 return(NULL);
3627 }
3628 memset(ret, 0, sizeof(xmlNode));
3629 ret->type = node->type;
3630
3631 ret->doc = doc;
3632 ret->parent = parent;
3633 if (node->name == xmlStringText)
3634 ret->name = xmlStringText;
3635 else if (node->name == xmlStringTextNoenc)
3636 ret->name = xmlStringTextNoenc;
3637 else if (node->name == xmlStringComment)
3638 ret->name = xmlStringComment;
3639 else if (node->name != NULL)
3640 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003641 if ((node->type != XML_ELEMENT_NODE) &&
3642 (node->content != NULL) &&
3643 (node->type != XML_ENTITY_REF_NODE) &&
3644 (node->type != XML_XINCLUDE_END) &&
3645 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003646 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003647 }else{
3648 if (node->type == XML_ELEMENT_NODE)
3649 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00003650 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003651 if (parent != NULL) {
3652 xmlNodePtr tmp;
3653
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003654 /*
3655 * this is a tricky part for the node register thing:
3656 * in case ret does get coalesced in xmlAddChild
3657 * the deregister-node callback is called; so we register ret now already
3658 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003659 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003660 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3661
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003662 tmp = xmlAddChild(parent, ret);
3663 /* node could have coalesced */
3664 if (tmp != ret)
3665 return(tmp);
3666 }
Owen Taylor3473f882001-02-23 17:55:21 +00003667
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003668 if (!recursive)
3669 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003670 if (node->nsDef != NULL)
3671 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3672
3673 if (node->ns != NULL) {
3674 xmlNsPtr ns;
3675
3676 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3677 if (ns == NULL) {
3678 /*
3679 * Humm, we are copying an element whose namespace is defined
3680 * out of the new tree scope. Search it in the original tree
3681 * and add it at the top of the new tree
3682 */
3683 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3684 if (ns != NULL) {
3685 xmlNodePtr root = ret;
3686
3687 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003688 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003689 }
3690 } else {
3691 /*
3692 * reference the existing namespace definition in our own tree.
3693 */
3694 ret->ns = ns;
3695 }
3696 }
3697 if (node->properties != NULL)
3698 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003699 if (node->type == XML_ENTITY_REF_NODE) {
3700 if ((doc == NULL) || (node->doc != doc)) {
3701 /*
3702 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003703 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003704 * we cannot keep the reference. Try to find it in the
3705 * target document.
3706 */
3707 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3708 } else {
3709 ret->children = node->children;
3710 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003711 ret->last = ret->children;
3712 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003713 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003714 UPDATE_LAST_CHILD_AND_PARENT(ret)
3715 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003716
3717out:
3718 /* if parent != NULL we already registered the node above */
3719 if (parent == NULL && xmlRegisterNodeDefaultValue)
3720 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003721 return(ret);
3722}
3723
3724static xmlNodePtr
3725xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3726 xmlNodePtr ret = NULL;
3727 xmlNodePtr p = NULL,q;
3728
3729 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003730 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003731 if (doc == NULL) {
3732 node = node->next;
3733 continue;
3734 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003735 if (doc->intSubset == NULL) {
3736 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3737 q->doc = doc;
3738 q->parent = parent;
3739 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003740 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003741 } else {
3742 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003743 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003744 }
3745 } else
3746 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003747 if (ret == NULL) {
3748 q->prev = NULL;
3749 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003750 } else if (p != q) {
3751 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003752 p->next = q;
3753 q->prev = p;
3754 p = q;
3755 }
3756 node = node->next;
3757 }
3758 return(ret);
3759}
3760
3761/**
3762 * xmlCopyNode:
3763 * @node: the node
3764 * @recursive: if 1 do a recursive copy.
3765 *
3766 * Do a copy of the node.
3767 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003768 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003769 */
3770xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003771xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003772 xmlNodePtr ret;
3773
3774 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3775 return(ret);
3776}
3777
3778/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003779 * xmlDocCopyNode:
3780 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003781 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003782 * @recursive: if 1 do a recursive copy.
3783 *
3784 * Do a copy of the node to a given document.
3785 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003786 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003787 */
3788xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003789xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003790 xmlNodePtr ret;
3791
3792 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3793 return(ret);
3794}
3795
3796/**
Owen Taylor3473f882001-02-23 17:55:21 +00003797 * xmlCopyNodeList:
3798 * @node: the first node in the list.
3799 *
3800 * Do a recursive copy of the node list.
3801 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003802 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003803 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003804xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003805 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3806 return(ret);
3807}
3808
3809/**
Owen Taylor3473f882001-02-23 17:55:21 +00003810 * xmlCopyDtd:
3811 * @dtd: the dtd
3812 *
3813 * Do a copy of the dtd.
3814 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003815 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003816 */
3817xmlDtdPtr
3818xmlCopyDtd(xmlDtdPtr dtd) {
3819 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003820 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003821
3822 if (dtd == NULL) return(NULL);
3823 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3824 if (ret == NULL) return(NULL);
3825 if (dtd->entities != NULL)
3826 ret->entities = (void *) xmlCopyEntitiesTable(
3827 (xmlEntitiesTablePtr) dtd->entities);
3828 if (dtd->notations != NULL)
3829 ret->notations = (void *) xmlCopyNotationTable(
3830 (xmlNotationTablePtr) dtd->notations);
3831 if (dtd->elements != NULL)
3832 ret->elements = (void *) xmlCopyElementTable(
3833 (xmlElementTablePtr) dtd->elements);
3834 if (dtd->attributes != NULL)
3835 ret->attributes = (void *) xmlCopyAttributeTable(
3836 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003837 if (dtd->pentities != NULL)
3838 ret->pentities = (void *) xmlCopyEntitiesTable(
3839 (xmlEntitiesTablePtr) dtd->pentities);
3840
3841 cur = dtd->children;
3842 while (cur != NULL) {
3843 q = NULL;
3844
3845 if (cur->type == XML_ENTITY_DECL) {
3846 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3847 switch (tmp->etype) {
3848 case XML_INTERNAL_GENERAL_ENTITY:
3849 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3850 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3851 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3852 break;
3853 case XML_INTERNAL_PARAMETER_ENTITY:
3854 case XML_EXTERNAL_PARAMETER_ENTITY:
3855 q = (xmlNodePtr)
3856 xmlGetParameterEntityFromDtd(ret, tmp->name);
3857 break;
3858 case XML_INTERNAL_PREDEFINED_ENTITY:
3859 break;
3860 }
3861 } else if (cur->type == XML_ELEMENT_DECL) {
3862 xmlElementPtr tmp = (xmlElementPtr) cur;
3863 q = (xmlNodePtr)
3864 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3865 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3866 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3867 q = (xmlNodePtr)
3868 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3869 } else if (cur->type == XML_COMMENT_NODE) {
3870 q = xmlCopyNode(cur, 0);
3871 }
3872
3873 if (q == NULL) {
3874 cur = cur->next;
3875 continue;
3876 }
3877
3878 if (p == NULL)
3879 ret->children = q;
3880 else
3881 p->next = q;
3882
3883 q->prev = p;
3884 q->parent = (xmlNodePtr) ret;
3885 q->next = NULL;
3886 ret->last = q;
3887 p = q;
3888 cur = cur->next;
3889 }
3890
Owen Taylor3473f882001-02-23 17:55:21 +00003891 return(ret);
3892}
3893
3894/**
3895 * xmlCopyDoc:
3896 * @doc: the document
3897 * @recursive: if 1 do a recursive copy.
3898 *
3899 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003900 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003901 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003902 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003903 */
3904xmlDocPtr
3905xmlCopyDoc(xmlDocPtr doc, int recursive) {
3906 xmlDocPtr ret;
3907
3908 if (doc == NULL) return(NULL);
3909 ret = xmlNewDoc(doc->version);
3910 if (ret == NULL) return(NULL);
3911 if (doc->name != NULL)
3912 ret->name = xmlMemStrdup(doc->name);
3913 if (doc->encoding != NULL)
3914 ret->encoding = xmlStrdup(doc->encoding);
3915 ret->charset = doc->charset;
3916 ret->compression = doc->compression;
3917 ret->standalone = doc->standalone;
3918 if (!recursive) return(ret);
3919
Daniel Veillardb33c2012001-04-25 12:59:04 +00003920 ret->last = NULL;
3921 ret->children = NULL;
3922 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003923 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003924 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003925 ret->intSubset->parent = ret;
3926 }
Owen Taylor3473f882001-02-23 17:55:21 +00003927 if (doc->oldNs != NULL)
3928 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3929 if (doc->children != NULL) {
3930 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003931
3932 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3933 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003934 ret->last = NULL;
3935 tmp = ret->children;
3936 while (tmp != NULL) {
3937 if (tmp->next == NULL)
3938 ret->last = tmp;
3939 tmp = tmp->next;
3940 }
3941 }
3942 return(ret);
3943}
3944
3945/************************************************************************
3946 * *
3947 * Content access functions *
3948 * *
3949 ************************************************************************/
3950
3951/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003952 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003953 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00003954 *
3955 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003956 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003957 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003958 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003959 */
3960long
3961xmlGetLineNo(xmlNodePtr node)
3962{
3963 long result = -1;
3964
3965 if (!node)
3966 return result;
3967 if (node->type == XML_ELEMENT_NODE)
3968 result = (long) node->content;
3969 else if ((node->prev != NULL) &&
3970 ((node->prev->type == XML_ELEMENT_NODE) ||
3971 (node->prev->type == XML_TEXT_NODE)))
3972 result = xmlGetLineNo(node->prev);
3973 else if ((node->parent != NULL) &&
3974 ((node->parent->type == XML_ELEMENT_NODE) ||
3975 (node->parent->type == XML_TEXT_NODE)))
3976 result = xmlGetLineNo(node->parent);
3977
3978 return result;
3979}
3980
3981/**
3982 * xmlGetNodePath:
3983 * @node: a node
3984 *
3985 * Build a structure based Path for the given node
3986 *
3987 * Returns the new path or NULL in case of error. The caller must free
3988 * the returned string
3989 */
3990xmlChar *
3991xmlGetNodePath(xmlNodePtr node)
3992{
3993 xmlNodePtr cur, tmp, next;
3994 xmlChar *buffer = NULL, *temp;
3995 size_t buf_len;
3996 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00003997 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00003998 const char *name;
3999 char nametemp[100];
4000 int occur = 0;
4001
4002 if (node == NULL)
4003 return (NULL);
4004
4005 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004006 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004007 if (buffer == NULL)
4008 return (NULL);
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004009 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004010 if (buf == NULL) {
4011 xmlFree(buffer);
4012 return (NULL);
4013 }
4014
4015 buffer[0] = 0;
4016 cur = node;
4017 do {
4018 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004019 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004020 occur = 0;
4021 if ((cur->type == XML_DOCUMENT_NODE) ||
4022 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4023 if (buffer[0] == '/')
4024 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004025 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004026 next = NULL;
4027 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004028 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004029 name = (const char *) cur->name;
4030 if (cur->ns) {
4031 snprintf(nametemp, sizeof(nametemp) - 1,
4032 "%s:%s", cur->ns->prefix, cur->name);
4033 nametemp[sizeof(nametemp) - 1] = 0;
4034 name = nametemp;
4035 }
4036 next = cur->parent;
4037
4038 /*
4039 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004040 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004041 */
4042 tmp = cur->prev;
4043 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004044 if ((tmp->type == XML_ELEMENT_NODE) &&
4045 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004046 occur++;
4047 tmp = tmp->prev;
4048 }
4049 if (occur == 0) {
4050 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004051 while (tmp != NULL && occur == 0) {
4052 if ((tmp->type == XML_ELEMENT_NODE) &&
4053 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004054 occur++;
4055 tmp = tmp->next;
4056 }
4057 if (occur != 0)
4058 occur = 1;
4059 } else
4060 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004061 } else if (cur->type == XML_COMMENT_NODE) {
4062 sep = "/";
4063 name = "comment()";
4064 next = cur->parent;
4065
4066 /*
4067 * Thumbler index computation
4068 */
4069 tmp = cur->prev;
4070 while (tmp != NULL) {
4071 if (tmp->type == XML_COMMENT_NODE)
4072 occur++;
4073 tmp = tmp->prev;
4074 }
4075 if (occur == 0) {
4076 tmp = cur->next;
4077 while (tmp != NULL && occur == 0) {
4078 if (tmp->type == XML_COMMENT_NODE)
4079 occur++;
4080 tmp = tmp->next;
4081 }
4082 if (occur != 0)
4083 occur = 1;
4084 } else
4085 occur++;
4086 } else if ((cur->type == XML_TEXT_NODE) ||
4087 (cur->type == XML_CDATA_SECTION_NODE)) {
4088 sep = "/";
4089 name = "text()";
4090 next = cur->parent;
4091
4092 /*
4093 * Thumbler index computation
4094 */
4095 tmp = cur->prev;
4096 while (tmp != NULL) {
4097 if ((cur->type == XML_TEXT_NODE) ||
4098 (cur->type == XML_CDATA_SECTION_NODE))
4099 occur++;
4100 tmp = tmp->prev;
4101 }
4102 if (occur == 0) {
4103 tmp = cur->next;
4104 while (tmp != NULL && occur == 0) {
4105 if ((cur->type == XML_TEXT_NODE) ||
4106 (cur->type == XML_CDATA_SECTION_NODE))
4107 occur++;
4108 tmp = tmp->next;
4109 }
4110 if (occur != 0)
4111 occur = 1;
4112 } else
4113 occur++;
4114 } else if (cur->type == XML_PI_NODE) {
4115 sep = "/";
4116 snprintf(nametemp, sizeof(nametemp) - 1,
4117 "processing-instruction('%s')", cur->name);
4118 nametemp[sizeof(nametemp) - 1] = 0;
4119 name = nametemp;
4120
4121 next = cur->parent;
4122
4123 /*
4124 * Thumbler index computation
4125 */
4126 tmp = cur->prev;
4127 while (tmp != NULL) {
4128 if ((tmp->type == XML_PI_NODE) &&
4129 (xmlStrEqual(cur->name, tmp->name)))
4130 occur++;
4131 tmp = tmp->prev;
4132 }
4133 if (occur == 0) {
4134 tmp = cur->next;
4135 while (tmp != NULL && occur == 0) {
4136 if ((tmp->type == XML_PI_NODE) &&
4137 (xmlStrEqual(cur->name, tmp->name)))
4138 occur++;
4139 tmp = tmp->next;
4140 }
4141 if (occur != 0)
4142 occur = 1;
4143 } else
4144 occur++;
4145
Daniel Veillard8faa7832001-11-26 15:58:08 +00004146 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004147 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004148 name = (const char *) (((xmlAttrPtr) cur)->name);
4149 next = ((xmlAttrPtr) cur)->parent;
4150 } else {
4151 next = cur->parent;
4152 }
4153
4154 /*
4155 * Make sure there is enough room
4156 */
4157 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4158 buf_len =
4159 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4160 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4161 if (temp == NULL) {
4162 xmlFree(buf);
4163 xmlFree(buffer);
4164 return (NULL);
4165 }
4166 buffer = temp;
4167 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4168 if (temp == NULL) {
4169 xmlFree(buf);
4170 xmlFree(buffer);
4171 return (NULL);
4172 }
4173 buf = temp;
4174 }
4175 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004176 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004177 sep, name, (char *) buffer);
4178 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004179 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004180 sep, name, occur, (char *) buffer);
4181 snprintf((char *) buffer, buf_len, "%s", buf);
4182 cur = next;
4183 } while (cur != NULL);
4184 xmlFree(buf);
4185 return (buffer);
4186}
4187
4188/**
Owen Taylor3473f882001-02-23 17:55:21 +00004189 * xmlDocGetRootElement:
4190 * @doc: the document
4191 *
4192 * Get the root element of the document (doc->children is a list
4193 * containing possibly comments, PIs, etc ...).
4194 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004195 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004196 */
4197xmlNodePtr
4198xmlDocGetRootElement(xmlDocPtr doc) {
4199 xmlNodePtr ret;
4200
4201 if (doc == NULL) return(NULL);
4202 ret = doc->children;
4203 while (ret != NULL) {
4204 if (ret->type == XML_ELEMENT_NODE)
4205 return(ret);
4206 ret = ret->next;
4207 }
4208 return(ret);
4209}
4210
4211/**
4212 * xmlDocSetRootElement:
4213 * @doc: the document
4214 * @root: the new document root element
4215 *
4216 * Set the root element of the document (doc->children is a list
4217 * containing possibly comments, PIs, etc ...).
4218 *
4219 * Returns the old root element if any was found
4220 */
4221xmlNodePtr
4222xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4223 xmlNodePtr old = NULL;
4224
4225 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004226 if (root == NULL)
4227 return(NULL);
4228 xmlUnlinkNode(root);
4229 root->doc = doc;
4230 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004231 old = doc->children;
4232 while (old != NULL) {
4233 if (old->type == XML_ELEMENT_NODE)
4234 break;
4235 old = old->next;
4236 }
4237 if (old == NULL) {
4238 if (doc->children == NULL) {
4239 doc->children = root;
4240 doc->last = root;
4241 } else {
4242 xmlAddSibling(doc->children, root);
4243 }
4244 } else {
4245 xmlReplaceNode(old, root);
4246 }
4247 return(old);
4248}
4249
4250/**
4251 * xmlNodeSetLang:
4252 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004253 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004254 *
4255 * Set the language of a node, i.e. the values of the xml:lang
4256 * attribute.
4257 */
4258void
4259xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004260 xmlNsPtr ns;
4261
Owen Taylor3473f882001-02-23 17:55:21 +00004262 if (cur == NULL) return;
4263 switch(cur->type) {
4264 case XML_TEXT_NODE:
4265 case XML_CDATA_SECTION_NODE:
4266 case XML_COMMENT_NODE:
4267 case XML_DOCUMENT_NODE:
4268 case XML_DOCUMENT_TYPE_NODE:
4269 case XML_DOCUMENT_FRAG_NODE:
4270 case XML_NOTATION_NODE:
4271 case XML_HTML_DOCUMENT_NODE:
4272 case XML_DTD_NODE:
4273 case XML_ELEMENT_DECL:
4274 case XML_ATTRIBUTE_DECL:
4275 case XML_ENTITY_DECL:
4276 case XML_PI_NODE:
4277 case XML_ENTITY_REF_NODE:
4278 case XML_ENTITY_NODE:
4279 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004280#ifdef LIBXML_DOCB_ENABLED
4281 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004282#endif
4283 case XML_XINCLUDE_START:
4284 case XML_XINCLUDE_END:
4285 return;
4286 case XML_ELEMENT_NODE:
4287 case XML_ATTRIBUTE_NODE:
4288 break;
4289 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004290 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4291 if (ns == NULL)
4292 return;
4293 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004294}
4295
4296/**
4297 * xmlNodeGetLang:
4298 * @cur: the node being checked
4299 *
4300 * Searches the language of a node, i.e. the values of the xml:lang
4301 * attribute or the one carried by the nearest ancestor.
4302 *
4303 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004304 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004305 */
4306xmlChar *
4307xmlNodeGetLang(xmlNodePtr cur) {
4308 xmlChar *lang;
4309
4310 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004311 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004312 if (lang != NULL)
4313 return(lang);
4314 cur = cur->parent;
4315 }
4316 return(NULL);
4317}
4318
4319
4320/**
4321 * xmlNodeSetSpacePreserve:
4322 * @cur: the node being changed
4323 * @val: the xml:space value ("0": default, 1: "preserve")
4324 *
4325 * Set (or reset) the space preserving behaviour of a node, i.e. the
4326 * value of the xml:space attribute.
4327 */
4328void
4329xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004330 xmlNsPtr ns;
4331
Owen Taylor3473f882001-02-23 17:55:21 +00004332 if (cur == NULL) return;
4333 switch(cur->type) {
4334 case XML_TEXT_NODE:
4335 case XML_CDATA_SECTION_NODE:
4336 case XML_COMMENT_NODE:
4337 case XML_DOCUMENT_NODE:
4338 case XML_DOCUMENT_TYPE_NODE:
4339 case XML_DOCUMENT_FRAG_NODE:
4340 case XML_NOTATION_NODE:
4341 case XML_HTML_DOCUMENT_NODE:
4342 case XML_DTD_NODE:
4343 case XML_ELEMENT_DECL:
4344 case XML_ATTRIBUTE_DECL:
4345 case XML_ENTITY_DECL:
4346 case XML_PI_NODE:
4347 case XML_ENTITY_REF_NODE:
4348 case XML_ENTITY_NODE:
4349 case XML_NAMESPACE_DECL:
4350 case XML_XINCLUDE_START:
4351 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004352#ifdef LIBXML_DOCB_ENABLED
4353 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004354#endif
4355 return;
4356 case XML_ELEMENT_NODE:
4357 case XML_ATTRIBUTE_NODE:
4358 break;
4359 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004360 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4361 if (ns == NULL)
4362 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004363 switch (val) {
4364 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004365 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004366 break;
4367 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004368 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004369 break;
4370 }
4371}
4372
4373/**
4374 * xmlNodeGetSpacePreserve:
4375 * @cur: the node being checked
4376 *
4377 * Searches the space preserving behaviour of a node, i.e. the values
4378 * of the xml:space attribute or the one carried by the nearest
4379 * ancestor.
4380 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004381 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004382 */
4383int
4384xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4385 xmlChar *space;
4386
4387 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004388 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004389 if (space != NULL) {
4390 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4391 xmlFree(space);
4392 return(1);
4393 }
4394 if (xmlStrEqual(space, BAD_CAST "default")) {
4395 xmlFree(space);
4396 return(0);
4397 }
4398 xmlFree(space);
4399 }
4400 cur = cur->parent;
4401 }
4402 return(-1);
4403}
4404
4405/**
4406 * xmlNodeSetName:
4407 * @cur: the node being changed
4408 * @name: the new tag name
4409 *
4410 * Set (or reset) the name of a node.
4411 */
4412void
4413xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
4414 if (cur == NULL) return;
4415 if (name == NULL) return;
4416 switch(cur->type) {
4417 case XML_TEXT_NODE:
4418 case XML_CDATA_SECTION_NODE:
4419 case XML_COMMENT_NODE:
4420 case XML_DOCUMENT_TYPE_NODE:
4421 case XML_DOCUMENT_FRAG_NODE:
4422 case XML_NOTATION_NODE:
4423 case XML_HTML_DOCUMENT_NODE:
4424 case XML_NAMESPACE_DECL:
4425 case XML_XINCLUDE_START:
4426 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004427#ifdef LIBXML_DOCB_ENABLED
4428 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004429#endif
4430 return;
4431 case XML_ELEMENT_NODE:
4432 case XML_ATTRIBUTE_NODE:
4433 case XML_PI_NODE:
4434 case XML_ENTITY_REF_NODE:
4435 case XML_ENTITY_NODE:
4436 case XML_DTD_NODE:
4437 case XML_DOCUMENT_NODE:
4438 case XML_ELEMENT_DECL:
4439 case XML_ATTRIBUTE_DECL:
4440 case XML_ENTITY_DECL:
4441 break;
4442 }
4443 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4444 cur->name = xmlStrdup(name);
4445}
4446
4447/**
4448 * xmlNodeSetBase:
4449 * @cur: the node being changed
4450 * @uri: the new base URI
4451 *
4452 * Set (or reset) the base URI of a node, i.e. the value of the
4453 * xml:base attribute.
4454 */
4455void
4456xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004457 xmlNsPtr ns;
4458
Owen Taylor3473f882001-02-23 17:55:21 +00004459 if (cur == NULL) return;
4460 switch(cur->type) {
4461 case XML_TEXT_NODE:
4462 case XML_CDATA_SECTION_NODE:
4463 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004464 case XML_DOCUMENT_TYPE_NODE:
4465 case XML_DOCUMENT_FRAG_NODE:
4466 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004467 case XML_DTD_NODE:
4468 case XML_ELEMENT_DECL:
4469 case XML_ATTRIBUTE_DECL:
4470 case XML_ENTITY_DECL:
4471 case XML_PI_NODE:
4472 case XML_ENTITY_REF_NODE:
4473 case XML_ENTITY_NODE:
4474 case XML_NAMESPACE_DECL:
4475 case XML_XINCLUDE_START:
4476 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004477 return;
4478 case XML_ELEMENT_NODE:
4479 case XML_ATTRIBUTE_NODE:
4480 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004481 case XML_DOCUMENT_NODE:
4482#ifdef LIBXML_DOCB_ENABLED
4483 case XML_DOCB_DOCUMENT_NODE:
4484#endif
4485 case XML_HTML_DOCUMENT_NODE: {
4486 xmlDocPtr doc = (xmlDocPtr) cur;
4487
4488 if (doc->URL != NULL)
4489 xmlFree((xmlChar *) doc->URL);
4490 if (uri == NULL)
4491 doc->URL = NULL;
4492 else
4493 doc->URL = xmlStrdup(uri);
4494 return;
4495 }
Owen Taylor3473f882001-02-23 17:55:21 +00004496 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004497
4498 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4499 if (ns == NULL)
4500 return;
4501 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004502}
4503
4504/**
Owen Taylor3473f882001-02-23 17:55:21 +00004505 * xmlNodeGetBase:
4506 * @doc: the document the node pertains to
4507 * @cur: the node being checked
4508 *
4509 * Searches for the BASE URL. The code should work on both XML
4510 * and HTML document even if base mechanisms are completely different.
4511 * It returns the base as defined in RFC 2396 sections
4512 * 5.1.1. Base URI within Document Content
4513 * and
4514 * 5.1.2. Base URI from the Encapsulating Entity
4515 * However it does not return the document base (5.1.3), use
4516 * xmlDocumentGetBase() for this
4517 *
4518 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004519 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004520 */
4521xmlChar *
4522xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004523 xmlChar *oldbase = NULL;
4524 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004525
4526 if ((cur == NULL) && (doc == NULL))
4527 return(NULL);
4528 if (doc == NULL) doc = cur->doc;
4529 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4530 cur = doc->children;
4531 while ((cur != NULL) && (cur->name != NULL)) {
4532 if (cur->type != XML_ELEMENT_NODE) {
4533 cur = cur->next;
4534 continue;
4535 }
4536 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4537 cur = cur->children;
4538 continue;
4539 }
4540 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4541 cur = cur->children;
4542 continue;
4543 }
4544 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4545 return(xmlGetProp(cur, BAD_CAST "href"));
4546 }
4547 cur = cur->next;
4548 }
4549 return(NULL);
4550 }
4551 while (cur != NULL) {
4552 if (cur->type == XML_ENTITY_DECL) {
4553 xmlEntityPtr ent = (xmlEntityPtr) cur;
4554 return(xmlStrdup(ent->URI));
4555 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004556 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004557 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004558 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004559 if (oldbase != NULL) {
4560 newbase = xmlBuildURI(oldbase, base);
4561 if (newbase != NULL) {
4562 xmlFree(oldbase);
4563 xmlFree(base);
4564 oldbase = newbase;
4565 } else {
4566 xmlFree(oldbase);
4567 xmlFree(base);
4568 return(NULL);
4569 }
4570 } else {
4571 oldbase = base;
4572 }
4573 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4574 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4575 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4576 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004577 }
4578 }
Owen Taylor3473f882001-02-23 17:55:21 +00004579 cur = cur->parent;
4580 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004581 if ((doc != NULL) && (doc->URL != NULL)) {
4582 if (oldbase == NULL)
4583 return(xmlStrdup(doc->URL));
4584 newbase = xmlBuildURI(oldbase, doc->URL);
4585 xmlFree(oldbase);
4586 return(newbase);
4587 }
4588 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004589}
4590
4591/**
4592 * xmlNodeGetContent:
4593 * @cur: the node being read
4594 *
4595 * Read the value of a node, this can be either the text carried
4596 * directly by this node if it's a TEXT node or the aggregate string
4597 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004598 * Entity references are substituted.
4599 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004600 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004601 */
4602xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004603xmlNodeGetContent(xmlNodePtr cur)
4604{
4605 if (cur == NULL)
4606 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004607 switch (cur->type) {
4608 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004609 case XML_ELEMENT_NODE:{
4610 xmlNodePtr tmp = cur;
4611 xmlBufferPtr buffer;
4612 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004613
Daniel Veillard814a76d2003-01-23 18:24:20 +00004614 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004615 if (buffer == NULL)
4616 return (NULL);
4617 while (tmp != NULL) {
4618 switch (tmp->type) {
4619 case XML_CDATA_SECTION_NODE:
4620 case XML_TEXT_NODE:
4621 if (tmp->content != NULL)
4622 xmlBufferCat(buffer, tmp->content);
4623 break;
4624 case XML_ENTITY_REF_NODE:{
4625 /* recursive substitution of entity references */
4626 xmlChar *cont = xmlNodeGetContent(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00004627
Daniel Veillard7646b182002-04-20 06:41:40 +00004628 if (cont) {
4629 xmlBufferCat(buffer,
4630 (const xmlChar *) cont);
4631 xmlFree(cont);
4632 }
4633 break;
4634 }
4635 default:
4636 break;
4637 }
4638 /*
4639 * Skip to next node
4640 */
4641 if (tmp->children != NULL) {
4642 if (tmp->children->type != XML_ENTITY_DECL) {
4643 tmp = tmp->children;
4644 continue;
4645 }
4646 }
4647 if (tmp == cur)
4648 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00004649
Daniel Veillard7646b182002-04-20 06:41:40 +00004650 if (tmp->next != NULL) {
4651 tmp = tmp->next;
4652 continue;
4653 }
4654
4655 do {
4656 tmp = tmp->parent;
4657 if (tmp == NULL)
4658 break;
4659 if (tmp == cur) {
4660 tmp = NULL;
4661 break;
4662 }
4663 if (tmp->next != NULL) {
4664 tmp = tmp->next;
4665 break;
4666 }
4667 } while (tmp != NULL);
4668 }
4669 ret = buffer->content;
4670 buffer->content = NULL;
4671 xmlBufferFree(buffer);
4672 return (ret);
4673 }
4674 case XML_ATTRIBUTE_NODE:{
4675 xmlAttrPtr attr = (xmlAttrPtr) cur;
4676
4677 if (attr->parent != NULL)
4678 return (xmlNodeListGetString
4679 (attr->parent->doc, attr->children, 1));
4680 else
4681 return (xmlNodeListGetString(NULL, attr->children, 1));
4682 break;
4683 }
Owen Taylor3473f882001-02-23 17:55:21 +00004684 case XML_COMMENT_NODE:
4685 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004686 if (cur->content != NULL)
4687 return (xmlStrdup(cur->content));
4688 return (NULL);
4689 case XML_ENTITY_REF_NODE:{
4690 xmlEntityPtr ent;
4691 xmlNodePtr tmp;
4692 xmlBufferPtr buffer;
4693 xmlChar *ret;
4694
4695 /* lookup entity declaration */
4696 ent = xmlGetDocEntity(cur->doc, cur->name);
4697 if (ent == NULL)
4698 return (NULL);
4699
4700 buffer = xmlBufferCreate();
4701 if (buffer == NULL)
4702 return (NULL);
4703
4704 /* an entity content can be any "well balanced chunk",
4705 * i.e. the result of the content [43] production:
4706 * http://www.w3.org/TR/REC-xml#NT-content
4707 * -> we iterate through child nodes and recursive call
4708 * xmlNodeGetContent() which handles all possible node types */
4709 tmp = ent->children;
4710 while (tmp) {
4711 xmlChar *cont = xmlNodeGetContent(tmp);
4712
4713 if (cont) {
4714 xmlBufferCat(buffer, (const xmlChar *) cont);
4715 xmlFree(cont);
4716 }
4717 tmp = tmp->next;
4718 }
4719
4720 ret = buffer->content;
4721 buffer->content = NULL;
4722 xmlBufferFree(buffer);
4723 return (ret);
4724 }
Owen Taylor3473f882001-02-23 17:55:21 +00004725 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004726 case XML_DOCUMENT_TYPE_NODE:
4727 case XML_NOTATION_NODE:
4728 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004729 case XML_XINCLUDE_START:
4730 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00004731 return (NULL);
4732 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004733#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004734 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004735#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00004736 case XML_HTML_DOCUMENT_NODE: {
4737 xmlChar *tmp;
4738 xmlChar *res = NULL;
4739
4740 cur = cur->children;
4741 while (cur!= NULL) {
4742 if ((cur->type == XML_ELEMENT_NODE) ||
4743 (cur->type == XML_TEXT_NODE) ||
4744 (cur->type == XML_CDATA_SECTION_NODE)) {
4745 tmp = xmlNodeGetContent(cur);
4746 if (tmp != NULL) {
4747 if (res == NULL)
4748 res = tmp;
4749 else {
4750 res = xmlStrcat(res, tmp);
4751 xmlFree(tmp);
4752 }
4753 }
4754 }
4755 cur = cur->next;
4756 }
4757 return(res);
4758 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004759 case XML_NAMESPACE_DECL: {
4760 xmlChar *tmp;
4761
4762 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4763 return (tmp);
4764 }
Owen Taylor3473f882001-02-23 17:55:21 +00004765 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004766 /* TODO !!! */
4767 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004768 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004769 /* TODO !!! */
4770 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004771 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004772 /* TODO !!! */
4773 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004774 case XML_CDATA_SECTION_NODE:
4775 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004776 if (cur->content != NULL)
4777 return (xmlStrdup(cur->content));
4778 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004779 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004780 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004781}
Owen Taylor3473f882001-02-23 17:55:21 +00004782/**
4783 * xmlNodeSetContent:
4784 * @cur: the node being modified
4785 * @content: the new value of the content
4786 *
4787 * Replace the content of a node.
4788 */
4789void
4790xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4791 if (cur == NULL) {
4792#ifdef DEBUG_TREE
4793 xmlGenericError(xmlGenericErrorContext,
4794 "xmlNodeSetContent : node == NULL\n");
4795#endif
4796 return;
4797 }
4798 switch (cur->type) {
4799 case XML_DOCUMENT_FRAG_NODE:
4800 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004801 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004802 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4803 cur->children = xmlStringGetNodeList(cur->doc, content);
4804 UPDATE_LAST_CHILD_AND_PARENT(cur)
4805 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004806 case XML_TEXT_NODE:
4807 case XML_CDATA_SECTION_NODE:
4808 case XML_ENTITY_REF_NODE:
4809 case XML_ENTITY_NODE:
4810 case XML_PI_NODE:
4811 case XML_COMMENT_NODE:
4812 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004813 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004814 }
4815 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4816 cur->last = cur->children = NULL;
4817 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004818 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00004819 } else
4820 cur->content = NULL;
4821 break;
4822 case XML_DOCUMENT_NODE:
4823 case XML_HTML_DOCUMENT_NODE:
4824 case XML_DOCUMENT_TYPE_NODE:
4825 case XML_XINCLUDE_START:
4826 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004827#ifdef LIBXML_DOCB_ENABLED
4828 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004829#endif
4830 break;
4831 case XML_NOTATION_NODE:
4832 break;
4833 case XML_DTD_NODE:
4834 break;
4835 case XML_NAMESPACE_DECL:
4836 break;
4837 case XML_ELEMENT_DECL:
4838 /* TODO !!! */
4839 break;
4840 case XML_ATTRIBUTE_DECL:
4841 /* TODO !!! */
4842 break;
4843 case XML_ENTITY_DECL:
4844 /* TODO !!! */
4845 break;
4846 }
4847}
4848
4849/**
4850 * xmlNodeSetContentLen:
4851 * @cur: the node being modified
4852 * @content: the new value of the content
4853 * @len: the size of @content
4854 *
4855 * Replace the content of a node.
4856 */
4857void
4858xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4859 if (cur == NULL) {
4860#ifdef DEBUG_TREE
4861 xmlGenericError(xmlGenericErrorContext,
4862 "xmlNodeSetContentLen : node == NULL\n");
4863#endif
4864 return;
4865 }
4866 switch (cur->type) {
4867 case XML_DOCUMENT_FRAG_NODE:
4868 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004869 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004870 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4871 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
4872 UPDATE_LAST_CHILD_AND_PARENT(cur)
4873 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004874 case XML_TEXT_NODE:
4875 case XML_CDATA_SECTION_NODE:
4876 case XML_ENTITY_REF_NODE:
4877 case XML_ENTITY_NODE:
4878 case XML_PI_NODE:
4879 case XML_COMMENT_NODE:
4880 case XML_NOTATION_NODE:
4881 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004882 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004883 }
4884 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4885 cur->children = cur->last = NULL;
4886 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004887 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004888 } else
4889 cur->content = NULL;
4890 break;
4891 case XML_DOCUMENT_NODE:
4892 case XML_DTD_NODE:
4893 case XML_HTML_DOCUMENT_NODE:
4894 case XML_DOCUMENT_TYPE_NODE:
4895 case XML_NAMESPACE_DECL:
4896 case XML_XINCLUDE_START:
4897 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004898#ifdef LIBXML_DOCB_ENABLED
4899 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004900#endif
4901 break;
4902 case XML_ELEMENT_DECL:
4903 /* TODO !!! */
4904 break;
4905 case XML_ATTRIBUTE_DECL:
4906 /* TODO !!! */
4907 break;
4908 case XML_ENTITY_DECL:
4909 /* TODO !!! */
4910 break;
4911 }
4912}
4913
4914/**
4915 * xmlNodeAddContentLen:
4916 * @cur: the node being modified
4917 * @content: extra content
4918 * @len: the size of @content
4919 *
4920 * Append the extra substring to the node content.
4921 */
4922void
4923xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4924 if (cur == NULL) {
4925#ifdef DEBUG_TREE
4926 xmlGenericError(xmlGenericErrorContext,
4927 "xmlNodeAddContentLen : node == NULL\n");
4928#endif
4929 return;
4930 }
4931 if (len <= 0) return;
4932 switch (cur->type) {
4933 case XML_DOCUMENT_FRAG_NODE:
4934 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004935 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004936
Daniel Veillard7db37732001-07-12 01:20:08 +00004937 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004938 newNode = xmlNewTextLen(content, len);
4939 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004940 tmp = xmlAddChild(cur, newNode);
4941 if (tmp != newNode)
4942 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004943 if ((last != NULL) && (last->next == newNode)) {
4944 xmlTextMerge(last, newNode);
4945 }
4946 }
4947 break;
4948 }
4949 case XML_ATTRIBUTE_NODE:
4950 break;
4951 case XML_TEXT_NODE:
4952 case XML_CDATA_SECTION_NODE:
4953 case XML_ENTITY_REF_NODE:
4954 case XML_ENTITY_NODE:
4955 case XML_PI_NODE:
4956 case XML_COMMENT_NODE:
4957 case XML_NOTATION_NODE:
4958 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004959 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004960 }
4961 case XML_DOCUMENT_NODE:
4962 case XML_DTD_NODE:
4963 case XML_HTML_DOCUMENT_NODE:
4964 case XML_DOCUMENT_TYPE_NODE:
4965 case XML_NAMESPACE_DECL:
4966 case XML_XINCLUDE_START:
4967 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004968#ifdef LIBXML_DOCB_ENABLED
4969 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004970#endif
4971 break;
4972 case XML_ELEMENT_DECL:
4973 case XML_ATTRIBUTE_DECL:
4974 case XML_ENTITY_DECL:
4975 break;
4976 }
4977}
4978
4979/**
4980 * xmlNodeAddContent:
4981 * @cur: the node being modified
4982 * @content: extra content
4983 *
4984 * Append the extra substring to the node content.
4985 */
4986void
4987xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
4988 int len;
4989
4990 if (cur == NULL) {
4991#ifdef DEBUG_TREE
4992 xmlGenericError(xmlGenericErrorContext,
4993 "xmlNodeAddContent : node == NULL\n");
4994#endif
4995 return;
4996 }
4997 if (content == NULL) return;
4998 len = xmlStrlen(content);
4999 xmlNodeAddContentLen(cur, content, len);
5000}
5001
5002/**
5003 * xmlTextMerge:
5004 * @first: the first text node
5005 * @second: the second text node being merged
5006 *
5007 * Merge two text nodes into one
5008 * Returns the first text node augmented
5009 */
5010xmlNodePtr
5011xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5012 if (first == NULL) return(second);
5013 if (second == NULL) return(first);
5014 if (first->type != XML_TEXT_NODE) return(first);
5015 if (second->type != XML_TEXT_NODE) return(first);
5016 if (second->name != first->name)
5017 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005018 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005019 xmlUnlinkNode(second);
5020 xmlFreeNode(second);
5021 return(first);
5022}
5023
5024/**
5025 * xmlGetNsList:
5026 * @doc: the document
5027 * @node: the current node
5028 *
5029 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005030 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005031 * that need to be freed by the caller or NULL if no
5032 * namespace if defined
5033 */
5034xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005035xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5036{
Owen Taylor3473f882001-02-23 17:55:21 +00005037 xmlNsPtr cur;
5038 xmlNsPtr *ret = NULL;
5039 int nbns = 0;
5040 int maxns = 10;
5041 int i;
5042
5043 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005044 if (node->type == XML_ELEMENT_NODE) {
5045 cur = node->nsDef;
5046 while (cur != NULL) {
5047 if (ret == NULL) {
5048 ret =
5049 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5050 sizeof(xmlNsPtr));
5051 if (ret == NULL) {
5052 xmlGenericError(xmlGenericErrorContext,
5053 "xmlGetNsList : out of memory!\n");
5054 return (NULL);
5055 }
5056 ret[nbns] = NULL;
5057 }
5058 for (i = 0; i < nbns; i++) {
5059 if ((cur->prefix == ret[i]->prefix) ||
5060 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5061 break;
5062 }
5063 if (i >= nbns) {
5064 if (nbns >= maxns) {
5065 maxns *= 2;
5066 ret = (xmlNsPtr *) xmlRealloc(ret,
5067 (maxns +
5068 1) *
5069 sizeof(xmlNsPtr));
5070 if (ret == NULL) {
5071 xmlGenericError(xmlGenericErrorContext,
5072 "xmlGetNsList : realloc failed!\n");
5073 return (NULL);
5074 }
5075 }
5076 ret[nbns++] = cur;
5077 ret[nbns] = NULL;
5078 }
Owen Taylor3473f882001-02-23 17:55:21 +00005079
Daniel Veillard77044732001-06-29 21:31:07 +00005080 cur = cur->next;
5081 }
5082 }
5083 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005084 }
Daniel Veillard77044732001-06-29 21:31:07 +00005085 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005086}
5087
5088/**
5089 * xmlSearchNs:
5090 * @doc: the document
5091 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005092 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005093 *
5094 * Search a Ns registered under a given name space for a document.
5095 * recurse on the parents until it finds the defined namespace
5096 * or return NULL otherwise.
5097 * @nameSpace can be NULL, this is a search for the default namespace.
5098 * We don't allow to cross entities boundaries. If you don't declare
5099 * the namespace within those you will be in troubles !!! A warning
5100 * is generated to cover this case.
5101 *
5102 * Returns the namespace pointer or NULL.
5103 */
5104xmlNsPtr
5105xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
5106 xmlNsPtr cur;
5107
5108 if (node == NULL) return(NULL);
5109 if ((nameSpace != NULL) &&
5110 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005111 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5112 /*
5113 * The XML-1.0 namespace is normally held on the root
5114 * element. In this case exceptionally create it on the
5115 * node element.
5116 */
5117 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5118 if (cur == NULL) {
5119 xmlGenericError(xmlGenericErrorContext,
5120 "xmlSearchNs : malloc failed\n");
5121 return(NULL);
5122 }
5123 memset(cur, 0, sizeof(xmlNs));
5124 cur->type = XML_LOCAL_NAMESPACE;
5125 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5126 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5127 cur->next = node->nsDef;
5128 node->nsDef = cur;
5129 return(cur);
5130 }
Owen Taylor3473f882001-02-23 17:55:21 +00005131 if (doc->oldNs == NULL) {
5132 /*
5133 * Allocate a new Namespace and fill the fields.
5134 */
5135 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5136 if (doc->oldNs == NULL) {
5137 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005138 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005139 return(NULL);
5140 }
5141 memset(doc->oldNs, 0, sizeof(xmlNs));
5142 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5143
5144 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5145 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5146 }
5147 return(doc->oldNs);
5148 }
5149 while (node != NULL) {
5150 if ((node->type == XML_ENTITY_REF_NODE) ||
5151 (node->type == XML_ENTITY_NODE) ||
5152 (node->type == XML_ENTITY_DECL))
5153 return(NULL);
5154 if (node->type == XML_ELEMENT_NODE) {
5155 cur = node->nsDef;
5156 while (cur != NULL) {
5157 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5158 (cur->href != NULL))
5159 return(cur);
5160 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5161 (cur->href != NULL) &&
5162 (xmlStrEqual(cur->prefix, nameSpace)))
5163 return(cur);
5164 cur = cur->next;
5165 }
5166 }
5167 node = node->parent;
5168 }
5169 return(NULL);
5170}
5171
5172/**
5173 * xmlSearchNsByHref:
5174 * @doc: the document
5175 * @node: the current node
5176 * @href: the namespace value
5177 *
5178 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5179 * the defined namespace or return NULL otherwise.
5180 * Returns the namespace pointer or NULL.
5181 */
5182xmlNsPtr
5183xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
5184 xmlNsPtr cur;
5185 xmlNodePtr orig = node;
5186
5187 if ((node == NULL) || (href == NULL)) return(NULL);
5188 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00005189 /*
5190 * Only the document can hold the XML spec namespace.
5191 */
Daniel Veillardc1a0da32002-08-14 08:32:18 +00005192 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5193 /*
5194 * The XML-1.0 namespace is normally held on the root
5195 * element. In this case exceptionally create it on the
5196 * node element.
5197 */
5198 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5199 if (cur == NULL) {
5200 xmlGenericError(xmlGenericErrorContext,
5201 "xmlSearchNs : malloc failed\n");
5202 return(NULL);
5203 }
5204 memset(cur, 0, sizeof(xmlNs));
5205 cur->type = XML_LOCAL_NAMESPACE;
5206 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5207 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5208 cur->next = node->nsDef;
5209 node->nsDef = cur;
5210 return(cur);
5211 }
Owen Taylor3473f882001-02-23 17:55:21 +00005212 if (doc->oldNs == NULL) {
5213 /*
5214 * Allocate a new Namespace and fill the fields.
5215 */
5216 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5217 if (doc->oldNs == NULL) {
5218 xmlGenericError(xmlGenericErrorContext,
5219 "xmlSearchNsByHref : malloc failed\n");
5220 return(NULL);
5221 }
5222 memset(doc->oldNs, 0, sizeof(xmlNs));
5223 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5224
5225 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5226 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5227 }
5228 return(doc->oldNs);
5229 }
5230 while (node != NULL) {
5231 cur = node->nsDef;
5232 while (cur != NULL) {
5233 if ((cur->href != NULL) && (href != NULL) &&
5234 (xmlStrEqual(cur->href, href))) {
5235 /*
5236 * Check that the prefix is not shadowed between orig and node
5237 */
5238 xmlNodePtr check = orig;
5239 xmlNsPtr tst;
5240
5241 while (check != node) {
5242 tst = check->nsDef;
5243 while (tst != NULL) {
5244 if ((tst->prefix == NULL) && (cur->prefix == NULL))
5245 goto shadowed;
5246 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
5247 (xmlStrEqual(tst->prefix, cur->prefix)))
5248 goto shadowed;
5249 tst = tst->next;
5250 }
5251 check = check->parent;
5252 }
5253 return(cur);
5254 }
5255shadowed:
5256 cur = cur->next;
5257 }
5258 node = node->parent;
5259 }
5260 return(NULL);
5261}
5262
5263/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005264 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005265 * @doc: the document
5266 * @tree: a node expected to hold the new namespace
5267 * @ns: the original namespace
5268 *
5269 * This function tries to locate a namespace definition in a tree
5270 * ancestors, or create a new namespace definition node similar to
5271 * @ns trying to reuse the same prefix. However if the given prefix is
5272 * null (default namespace) or reused within the subtree defined by
5273 * @tree or on one of its ancestors then a new prefix is generated.
5274 * Returns the (new) namespace definition or NULL in case of error
5275 */
5276xmlNsPtr
5277xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5278 xmlNsPtr def;
5279 xmlChar prefix[50];
5280 int counter = 1;
5281
5282 if (tree == NULL) {
5283#ifdef DEBUG_TREE
5284 xmlGenericError(xmlGenericErrorContext,
5285 "xmlNewReconciliedNs : tree == NULL\n");
5286#endif
5287 return(NULL);
5288 }
5289 if (ns == NULL) {
5290#ifdef DEBUG_TREE
5291 xmlGenericError(xmlGenericErrorContext,
5292 "xmlNewReconciliedNs : ns == NULL\n");
5293#endif
5294 return(NULL);
5295 }
5296 /*
5297 * Search an existing namespace definition inherited.
5298 */
5299 def = xmlSearchNsByHref(doc, tree, ns->href);
5300 if (def != NULL)
5301 return(def);
5302
5303 /*
5304 * Find a close prefix which is not already in use.
5305 * Let's strip namespace prefixes longer than 20 chars !
5306 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005307 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005308 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005309 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005310 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005311
Owen Taylor3473f882001-02-23 17:55:21 +00005312 def = xmlSearchNs(doc, tree, prefix);
5313 while (def != NULL) {
5314 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005315 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005316 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005317 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005318 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005319 def = xmlSearchNs(doc, tree, prefix);
5320 }
5321
5322 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005323 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005324 */
5325 def = xmlNewNs(tree, ns->href, prefix);
5326 return(def);
5327}
5328
5329/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005330 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005331 * @doc: the document
5332 * @tree: a node defining the subtree to reconciliate
5333 *
5334 * This function checks that all the namespaces declared within the given
5335 * tree are properly declared. This is needed for example after Copy or Cut
5336 * and then paste operations. The subtree may still hold pointers to
5337 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005338 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005339 * the new environment. If not possible the new namespaces are redeclared
5340 * on @tree at the top of the given subtree.
5341 * Returns the number of namespace declarations created or -1 in case of error.
5342 */
5343int
5344xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5345 xmlNsPtr *oldNs = NULL;
5346 xmlNsPtr *newNs = NULL;
5347 int sizeCache = 0;
5348 int nbCache = 0;
5349
5350 xmlNsPtr n;
5351 xmlNodePtr node = tree;
5352 xmlAttrPtr attr;
5353 int ret = 0, i;
5354
5355 while (node != NULL) {
5356 /*
5357 * Reconciliate the node namespace
5358 */
5359 if (node->ns != NULL) {
5360 /*
5361 * initialize the cache if needed
5362 */
5363 if (sizeCache == 0) {
5364 sizeCache = 10;
5365 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5366 sizeof(xmlNsPtr));
5367 if (oldNs == NULL) {
5368 xmlGenericError(xmlGenericErrorContext,
5369 "xmlReconciliateNs : memory pbm\n");
5370 return(-1);
5371 }
5372 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5373 sizeof(xmlNsPtr));
5374 if (newNs == NULL) {
5375 xmlGenericError(xmlGenericErrorContext,
5376 "xmlReconciliateNs : memory pbm\n");
5377 xmlFree(oldNs);
5378 return(-1);
5379 }
5380 }
5381 for (i = 0;i < nbCache;i++) {
5382 if (oldNs[i] == node->ns) {
5383 node->ns = newNs[i];
5384 break;
5385 }
5386 }
5387 if (i == nbCache) {
5388 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005389 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005390 */
5391 n = xmlNewReconciliedNs(doc, tree, node->ns);
5392 if (n != NULL) { /* :-( what if else ??? */
5393 /*
5394 * check if we need to grow the cache buffers.
5395 */
5396 if (sizeCache <= nbCache) {
5397 sizeCache *= 2;
5398 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5399 sizeof(xmlNsPtr));
5400 if (oldNs == NULL) {
5401 xmlGenericError(xmlGenericErrorContext,
5402 "xmlReconciliateNs : memory pbm\n");
5403 xmlFree(newNs);
5404 return(-1);
5405 }
5406 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5407 sizeof(xmlNsPtr));
5408 if (newNs == NULL) {
5409 xmlGenericError(xmlGenericErrorContext,
5410 "xmlReconciliateNs : memory pbm\n");
5411 xmlFree(oldNs);
5412 return(-1);
5413 }
5414 }
5415 newNs[nbCache] = n;
5416 oldNs[nbCache++] = node->ns;
5417 node->ns = n;
5418 }
5419 }
5420 }
5421 /*
5422 * now check for namespace hold by attributes on the node.
5423 */
5424 attr = node->properties;
5425 while (attr != NULL) {
5426 if (attr->ns != NULL) {
5427 /*
5428 * initialize the cache if needed
5429 */
5430 if (sizeCache == 0) {
5431 sizeCache = 10;
5432 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5433 sizeof(xmlNsPtr));
5434 if (oldNs == NULL) {
5435 xmlGenericError(xmlGenericErrorContext,
5436 "xmlReconciliateNs : memory pbm\n");
5437 return(-1);
5438 }
5439 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5440 sizeof(xmlNsPtr));
5441 if (newNs == NULL) {
5442 xmlGenericError(xmlGenericErrorContext,
5443 "xmlReconciliateNs : memory pbm\n");
5444 xmlFree(oldNs);
5445 return(-1);
5446 }
5447 }
5448 for (i = 0;i < nbCache;i++) {
5449 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005450 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005451 break;
5452 }
5453 }
5454 if (i == nbCache) {
5455 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005456 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005457 */
5458 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5459 if (n != NULL) { /* :-( what if else ??? */
5460 /*
5461 * check if we need to grow the cache buffers.
5462 */
5463 if (sizeCache <= nbCache) {
5464 sizeCache *= 2;
5465 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5466 sizeof(xmlNsPtr));
5467 if (oldNs == NULL) {
5468 xmlGenericError(xmlGenericErrorContext,
5469 "xmlReconciliateNs : memory pbm\n");
5470 xmlFree(newNs);
5471 return(-1);
5472 }
5473 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5474 sizeof(xmlNsPtr));
5475 if (newNs == NULL) {
5476 xmlGenericError(xmlGenericErrorContext,
5477 "xmlReconciliateNs : memory pbm\n");
5478 xmlFree(oldNs);
5479 return(-1);
5480 }
5481 }
5482 newNs[nbCache] = n;
5483 oldNs[nbCache++] = attr->ns;
5484 attr->ns = n;
5485 }
5486 }
5487 }
5488 attr = attr->next;
5489 }
5490
5491 /*
5492 * Browse the full subtree, deep first
5493 */
5494 if (node->children != NULL) {
5495 /* deep first */
5496 node = node->children;
5497 } else if ((node != tree) && (node->next != NULL)) {
5498 /* then siblings */
5499 node = node->next;
5500 } else if (node != tree) {
5501 /* go up to parents->next if needed */
5502 while (node != tree) {
5503 if (node->parent != NULL)
5504 node = node->parent;
5505 if ((node != tree) && (node->next != NULL)) {
5506 node = node->next;
5507 break;
5508 }
5509 if (node->parent == NULL) {
5510 node = NULL;
5511 break;
5512 }
5513 }
5514 /* exit condition */
5515 if (node == tree)
5516 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005517 } else
5518 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005519 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005520 if (oldNs != NULL)
5521 xmlFree(oldNs);
5522 if (newNs != NULL)
5523 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005524 return(ret);
5525}
5526
5527/**
5528 * xmlHasProp:
5529 * @node: the node
5530 * @name: the attribute name
5531 *
5532 * Search an attribute associated to a node
5533 * This function also looks in DTD attribute declaration for #FIXED or
5534 * default declaration values unless DTD use has been turned off.
5535 *
5536 * Returns the attribute or the attribute declaration or NULL if
5537 * neither was found.
5538 */
5539xmlAttrPtr
5540xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5541 xmlAttrPtr prop;
5542 xmlDocPtr doc;
5543
5544 if ((node == NULL) || (name == NULL)) return(NULL);
5545 /*
5546 * Check on the properties attached to the node
5547 */
5548 prop = node->properties;
5549 while (prop != NULL) {
5550 if (xmlStrEqual(prop->name, name)) {
5551 return(prop);
5552 }
5553 prop = prop->next;
5554 }
5555 if (!xmlCheckDTD) return(NULL);
5556
5557 /*
5558 * Check if there is a default declaration in the internal
5559 * or external subsets
5560 */
5561 doc = node->doc;
5562 if (doc != NULL) {
5563 xmlAttributePtr attrDecl;
5564 if (doc->intSubset != NULL) {
5565 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5566 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5567 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005568 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5569 /* return attribute declaration only if a default value is given
5570 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005571 return((xmlAttrPtr) attrDecl);
5572 }
5573 }
5574 return(NULL);
5575}
5576
5577/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005578 * xmlHasNsProp:
5579 * @node: the node
5580 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005581 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005582 *
5583 * Search for an attribute associated to a node
5584 * This attribute has to be anchored in the namespace specified.
5585 * This does the entity substitution.
5586 * This function looks in DTD attribute declaration for #FIXED or
5587 * default declaration values unless DTD use has been turned off.
5588 *
5589 * Returns the attribute or the attribute declaration or NULL
5590 * if neither was found.
5591 */
5592xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005593xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005594 xmlAttrPtr prop;
5595 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005596
5597 if (node == NULL)
5598 return(NULL);
5599
5600 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005601 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005602 return(xmlHasProp(node, name));
5603 while (prop != NULL) {
5604 /*
5605 * One need to have
5606 * - same attribute names
5607 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005608 */
5609 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005610 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5611 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005612 }
5613 prop = prop->next;
5614 }
5615 if (!xmlCheckDTD) return(NULL);
5616
5617 /*
5618 * Check if there is a default declaration in the internal
5619 * or external subsets
5620 */
5621 doc = node->doc;
5622 if (doc != NULL) {
5623 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005624 xmlAttributePtr attrDecl = NULL;
5625 xmlNsPtr *nsList, *cur;
5626 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005627
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005628 nsList = xmlGetNsList(node->doc, node);
5629 if (nsList == NULL)
5630 return(NULL);
5631 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5632 ename = xmlStrdup(node->ns->prefix);
5633 ename = xmlStrcat(ename, BAD_CAST ":");
5634 ename = xmlStrcat(ename, node->name);
5635 } else {
5636 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005637 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005638 if (ename == NULL) {
5639 xmlFree(nsList);
5640 return(NULL);
5641 }
5642
5643 cur = nsList;
5644 while (*cur != NULL) {
5645 if (xmlStrEqual((*cur)->href, nameSpace)) {
5646 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5647 name, (*cur)->prefix);
5648 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5649 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5650 name, (*cur)->prefix);
5651 }
5652 cur++;
5653 }
5654 xmlFree(nsList);
5655 xmlFree(ename);
5656 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005657 }
5658 }
5659 return(NULL);
5660}
5661
5662/**
Owen Taylor3473f882001-02-23 17:55:21 +00005663 * xmlGetProp:
5664 * @node: the node
5665 * @name: the attribute name
5666 *
5667 * Search and get the value of an attribute associated to a node
5668 * This does the entity substitution.
5669 * This function looks in DTD attribute declaration for #FIXED or
5670 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00005671 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00005672 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
5673 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00005674 *
5675 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005676 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005677 */
5678xmlChar *
5679xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5680 xmlAttrPtr prop;
5681 xmlDocPtr doc;
5682
5683 if ((node == NULL) || (name == NULL)) return(NULL);
5684 /*
5685 * Check on the properties attached to the node
5686 */
5687 prop = node->properties;
5688 while (prop != NULL) {
5689 if (xmlStrEqual(prop->name, name)) {
5690 xmlChar *ret;
5691
5692 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5693 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5694 return(ret);
5695 }
5696 prop = prop->next;
5697 }
5698 if (!xmlCheckDTD) return(NULL);
5699
5700 /*
5701 * Check if there is a default declaration in the internal
5702 * or external subsets
5703 */
5704 doc = node->doc;
5705 if (doc != NULL) {
5706 xmlAttributePtr attrDecl;
5707 if (doc->intSubset != NULL) {
5708 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5709 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5710 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005711 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5712 /* return attribute declaration only if a default value is given
5713 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005714 return(xmlStrdup(attrDecl->defaultValue));
5715 }
5716 }
5717 return(NULL);
5718}
5719
5720/**
Daniel Veillard71531f32003-02-05 13:19:53 +00005721 * xmlGetNoNsProp:
5722 * @node: the node
5723 * @name: the attribute name
5724 *
5725 * Search and get the value of an attribute associated to a node
5726 * This does the entity substitution.
5727 * This function looks in DTD attribute declaration for #FIXED or
5728 * default declaration values unless DTD use has been turned off.
5729 * This function is similar to xmlGetProp except it will accept only
5730 * an attribute in no namespace.
5731 *
5732 * Returns the attribute value or NULL if not found.
5733 * It's up to the caller to free the memory with xmlFree().
5734 */
5735xmlChar *
5736xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
5737 xmlAttrPtr prop;
5738 xmlDocPtr doc;
5739
5740 if ((node == NULL) || (name == NULL)) return(NULL);
5741 /*
5742 * Check on the properties attached to the node
5743 */
5744 prop = node->properties;
5745 while (prop != NULL) {
5746 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
5747 xmlChar *ret;
5748
5749 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5750 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5751 return(ret);
5752 }
5753 prop = prop->next;
5754 }
5755 if (!xmlCheckDTD) return(NULL);
5756
5757 /*
5758 * Check if there is a default declaration in the internal
5759 * or external subsets
5760 */
5761 doc = node->doc;
5762 if (doc != NULL) {
5763 xmlAttributePtr attrDecl;
5764 if (doc->intSubset != NULL) {
5765 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5766 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5767 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005768 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5769 /* return attribute declaration only if a default value is given
5770 (that includes #FIXED declarations) */
Daniel Veillard71531f32003-02-05 13:19:53 +00005771 return(xmlStrdup(attrDecl->defaultValue));
5772 }
5773 }
5774 return(NULL);
5775}
5776
5777/**
Owen Taylor3473f882001-02-23 17:55:21 +00005778 * xmlGetNsProp:
5779 * @node: the node
5780 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005781 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005782 *
5783 * Search and get the value of an attribute associated to a node
5784 * This attribute has to be anchored in the namespace specified.
5785 * This does the entity substitution.
5786 * This function looks in DTD attribute declaration for #FIXED or
5787 * default declaration values unless DTD use has been turned off.
5788 *
5789 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005790 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005791 */
5792xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00005793xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00005794 xmlAttrPtr prop;
5795 xmlDocPtr doc;
5796 xmlNsPtr ns;
5797
5798 if (node == NULL)
5799 return(NULL);
5800
5801 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005802 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00005803 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00005804 while (prop != NULL) {
5805 /*
5806 * One need to have
5807 * - same attribute names
5808 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005809 */
5810 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00005811 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00005812 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005813 xmlChar *ret;
5814
5815 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5816 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5817 return(ret);
5818 }
5819 prop = prop->next;
5820 }
5821 if (!xmlCheckDTD) return(NULL);
5822
5823 /*
5824 * Check if there is a default declaration in the internal
5825 * or external subsets
5826 */
5827 doc = node->doc;
5828 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005829 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00005830 xmlAttributePtr attrDecl;
5831
Owen Taylor3473f882001-02-23 17:55:21 +00005832 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5833 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5834 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5835
5836 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
5837 /*
5838 * The DTD declaration only allows a prefix search
5839 */
5840 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00005841 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00005842 return(xmlStrdup(attrDecl->defaultValue));
5843 }
5844 }
5845 }
5846 return(NULL);
5847}
5848
5849/**
5850 * xmlSetProp:
5851 * @node: the node
5852 * @name: the attribute name
5853 * @value: the attribute value
5854 *
5855 * Set (or reset) an attribute carried by a node.
5856 * Returns the attribute pointer.
5857 */
5858xmlAttrPtr
5859xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005860 xmlAttrPtr prop;
5861 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00005862
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00005863 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00005864 return(NULL);
5865 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005866 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00005867 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005868 if ((xmlStrEqual(prop->name, name)) &&
5869 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005870 xmlNodePtr oldprop = prop->children;
5871
Owen Taylor3473f882001-02-23 17:55:21 +00005872 prop->children = NULL;
5873 prop->last = NULL;
5874 if (value != NULL) {
5875 xmlChar *buffer;
5876 xmlNodePtr tmp;
5877
5878 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5879 prop->children = xmlStringGetNodeList(node->doc, buffer);
5880 prop->last = NULL;
5881 prop->doc = doc;
5882 tmp = prop->children;
5883 while (tmp != NULL) {
5884 tmp->parent = (xmlNodePtr) prop;
5885 tmp->doc = doc;
5886 if (tmp->next == NULL)
5887 prop->last = tmp;
5888 tmp = tmp->next;
5889 }
5890 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00005891 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005892 if (oldprop != NULL)
5893 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00005894 return(prop);
5895 }
5896 prop = prop->next;
5897 }
5898 prop = xmlNewProp(node, name, value);
5899 return(prop);
5900}
5901
5902/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005903 * xmlUnsetProp:
5904 * @node: the node
5905 * @name: the attribute name
5906 *
5907 * Remove an attribute carried by a node.
5908 * Returns 0 if successful, -1 if not found
5909 */
5910int
5911xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Daniel Veillard814a76d2003-01-23 18:24:20 +00005912 xmlAttrPtr prop, prev = NULL;;
Daniel Veillard75bea542001-05-11 17:41:21 +00005913
5914 if ((node == NULL) || (name == NULL))
5915 return(-1);
Daniel Veillard814a76d2003-01-23 18:24:20 +00005916 prop = node->properties;
Daniel Veillard75bea542001-05-11 17:41:21 +00005917 while (prop != NULL) {
5918 if ((xmlStrEqual(prop->name, name)) &&
5919 (prop->ns == NULL)) {
5920 if (prev == NULL)
5921 node->properties = prop->next;
5922 else
5923 prev->next = prop->next;
5924 xmlFreeProp(prop);
5925 return(0);
5926 }
5927 prev = prop;
5928 prop = prop->next;
5929 }
5930 return(-1);
5931}
5932
5933/**
Owen Taylor3473f882001-02-23 17:55:21 +00005934 * xmlSetNsProp:
5935 * @node: the node
5936 * @ns: the namespace definition
5937 * @name: the attribute name
5938 * @value: the attribute value
5939 *
5940 * Set (or reset) an attribute carried by a node.
5941 * The ns structure must be in scope, this is not checked.
5942 *
5943 * Returns the attribute pointer.
5944 */
5945xmlAttrPtr
5946xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
5947 const xmlChar *value) {
5948 xmlAttrPtr prop;
5949
5950 if ((node == NULL) || (name == NULL))
5951 return(NULL);
5952
5953 if (ns == NULL)
5954 return(xmlSetProp(node, name, value));
5955 if (ns->href == NULL)
5956 return(NULL);
5957 prop = node->properties;
5958
5959 while (prop != NULL) {
5960 /*
5961 * One need to have
5962 * - same attribute names
5963 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005964 */
5965 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00005966 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005967 if (prop->children != NULL)
5968 xmlFreeNodeList(prop->children);
5969 prop->children = NULL;
5970 prop->last = NULL;
5971 prop->ns = ns;
5972 if (value != NULL) {
5973 xmlChar *buffer;
5974 xmlNodePtr tmp;
5975
5976 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5977 prop->children = xmlStringGetNodeList(node->doc, buffer);
5978 prop->last = NULL;
5979 tmp = prop->children;
5980 while (tmp != NULL) {
5981 tmp->parent = (xmlNodePtr) prop;
5982 if (tmp->next == NULL)
5983 prop->last = tmp;
5984 tmp = tmp->next;
5985 }
5986 xmlFree(buffer);
5987 }
5988 return(prop);
5989 }
5990 prop = prop->next;
5991 }
5992 prop = xmlNewNsProp(node, ns, name, value);
5993 return(prop);
5994}
5995
5996/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005997 * xmlUnsetNsProp:
5998 * @node: the node
5999 * @ns: the namespace definition
6000 * @name: the attribute name
6001 *
6002 * Remove an attribute carried by a node.
6003 * Returns 0 if successful, -1 if not found
6004 */
6005int
6006xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
6007 xmlAttrPtr prop = node->properties, prev = NULL;;
6008
6009 if ((node == NULL) || (name == NULL))
6010 return(-1);
6011 if (ns == NULL)
6012 return(xmlUnsetProp(node, name));
6013 if (ns->href == NULL)
6014 return(-1);
6015 while (prop != NULL) {
6016 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00006017 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006018 if (prev == NULL)
6019 node->properties = prop->next;
6020 else
6021 prev->next = prop->next;
6022 xmlFreeProp(prop);
6023 return(0);
6024 }
6025 prev = prop;
6026 prop = prop->next;
6027 }
6028 return(-1);
6029}
6030
6031/**
Owen Taylor3473f882001-02-23 17:55:21 +00006032 * xmlNodeIsText:
6033 * @node: the node
6034 *
6035 * Is this node a Text node ?
6036 * Returns 1 yes, 0 no
6037 */
6038int
6039xmlNodeIsText(xmlNodePtr node) {
6040 if (node == NULL) return(0);
6041
6042 if (node->type == XML_TEXT_NODE) return(1);
6043 return(0);
6044}
6045
6046/**
6047 * xmlIsBlankNode:
6048 * @node: the node
6049 *
6050 * Checks whether this node is an empty or whitespace only
6051 * (and possibly ignorable) text-node.
6052 *
6053 * Returns 1 yes, 0 no
6054 */
6055int
6056xmlIsBlankNode(xmlNodePtr node) {
6057 const xmlChar *cur;
6058 if (node == NULL) return(0);
6059
Daniel Veillard7db37732001-07-12 01:20:08 +00006060 if ((node->type != XML_TEXT_NODE) &&
6061 (node->type != XML_CDATA_SECTION_NODE))
6062 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006063 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006064 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006065 while (*cur != 0) {
6066 if (!IS_BLANK(*cur)) return(0);
6067 cur++;
6068 }
6069
6070 return(1);
6071}
6072
6073/**
6074 * xmlTextConcat:
6075 * @node: the node
6076 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006077 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006078 *
6079 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006080 *
6081 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006082 */
6083
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006084int
Owen Taylor3473f882001-02-23 17:55:21 +00006085xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006086 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006087
6088 if ((node->type != XML_TEXT_NODE) &&
6089 (node->type != XML_CDATA_SECTION_NODE)) {
6090#ifdef DEBUG_TREE
6091 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006092 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006093#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006094 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006095 }
Owen Taylor3473f882001-02-23 17:55:21 +00006096 node->content = xmlStrncat(node->content, content, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006097 if (node->content == NULL)
6098 return(-1);
6099 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006100}
6101
6102/************************************************************************
6103 * *
6104 * Output : to a FILE or in memory *
6105 * *
6106 ************************************************************************/
6107
Owen Taylor3473f882001-02-23 17:55:21 +00006108/**
6109 * xmlBufferCreate:
6110 *
6111 * routine to create an XML buffer.
6112 * returns the new structure.
6113 */
6114xmlBufferPtr
6115xmlBufferCreate(void) {
6116 xmlBufferPtr ret;
6117
6118 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6119 if (ret == NULL) {
6120 xmlGenericError(xmlGenericErrorContext,
6121 "xmlBufferCreate : out of memory!\n");
6122 return(NULL);
6123 }
6124 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006125 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006126 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006127 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006128 if (ret->content == NULL) {
6129 xmlGenericError(xmlGenericErrorContext,
6130 "xmlBufferCreate : out of memory!\n");
6131 xmlFree(ret);
6132 return(NULL);
6133 }
6134 ret->content[0] = 0;
6135 return(ret);
6136}
6137
6138/**
6139 * xmlBufferCreateSize:
6140 * @size: initial size of buffer
6141 *
6142 * routine to create an XML buffer.
6143 * returns the new structure.
6144 */
6145xmlBufferPtr
6146xmlBufferCreateSize(size_t size) {
6147 xmlBufferPtr ret;
6148
6149 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6150 if (ret == NULL) {
6151 xmlGenericError(xmlGenericErrorContext,
6152 "xmlBufferCreate : out of memory!\n");
6153 return(NULL);
6154 }
6155 ret->use = 0;
6156 ret->alloc = xmlBufferAllocScheme;
6157 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6158 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006159 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006160 if (ret->content == NULL) {
6161 xmlGenericError(xmlGenericErrorContext,
6162 "xmlBufferCreate : out of memory!\n");
6163 xmlFree(ret);
6164 return(NULL);
6165 }
6166 ret->content[0] = 0;
6167 } else
6168 ret->content = NULL;
6169 return(ret);
6170}
6171
6172/**
6173 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006174 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006175 * @scheme: allocation scheme to use
6176 *
6177 * Sets the allocation scheme for this buffer
6178 */
6179void
6180xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6181 xmlBufferAllocationScheme scheme) {
6182 if (buf == NULL) {
6183#ifdef DEBUG_BUFFER
6184 xmlGenericError(xmlGenericErrorContext,
6185 "xmlBufferSetAllocationScheme: buf == NULL\n");
6186#endif
6187 return;
6188 }
6189
6190 buf->alloc = scheme;
6191}
6192
6193/**
6194 * xmlBufferFree:
6195 * @buf: the buffer to free
6196 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006197 * Frees an XML buffer. It frees both the content and the structure which
6198 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006199 */
6200void
6201xmlBufferFree(xmlBufferPtr buf) {
6202 if (buf == NULL) {
6203#ifdef DEBUG_BUFFER
6204 xmlGenericError(xmlGenericErrorContext,
6205 "xmlBufferFree: buf == NULL\n");
6206#endif
6207 return;
6208 }
Daniel Veillard561b7f82002-03-20 21:55:57 +00006209 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006210 xmlFree(buf->content);
6211 }
Owen Taylor3473f882001-02-23 17:55:21 +00006212 xmlFree(buf);
6213}
6214
6215/**
6216 * xmlBufferEmpty:
6217 * @buf: the buffer
6218 *
6219 * empty a buffer.
6220 */
6221void
6222xmlBufferEmpty(xmlBufferPtr buf) {
6223 if (buf->content == NULL) return;
6224 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006225 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00006226}
6227
6228/**
6229 * xmlBufferShrink:
6230 * @buf: the buffer to dump
6231 * @len: the number of xmlChar to remove
6232 *
6233 * Remove the beginning of an XML buffer.
6234 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006235 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006236 */
6237int
6238xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
6239 if (len == 0) return(0);
6240 if (len > buf->use) return(-1);
6241
6242 buf->use -= len;
6243 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6244
6245 buf->content[buf->use] = 0;
6246 return(len);
6247}
6248
6249/**
6250 * xmlBufferGrow:
6251 * @buf: the buffer
6252 * @len: the minimum free size to allocate
6253 *
6254 * Grow the available space of an XML buffer.
6255 *
6256 * Returns the new available space or -1 in case of error
6257 */
6258int
6259xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6260 int size;
6261 xmlChar *newbuf;
6262
6263 if (len + buf->use < buf->size) return(0);
6264
6265 size = buf->use + len + 100;
6266
6267 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
6268 if (newbuf == NULL) return(-1);
6269 buf->content = newbuf;
6270 buf->size = size;
6271 return(buf->size - buf->use);
6272}
6273
6274/**
6275 * xmlBufferDump:
6276 * @file: the file output
6277 * @buf: the buffer to dump
6278 *
6279 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006280 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006281 */
6282int
6283xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6284 int ret;
6285
6286 if (buf == NULL) {
6287#ifdef DEBUG_BUFFER
6288 xmlGenericError(xmlGenericErrorContext,
6289 "xmlBufferDump: buf == NULL\n");
6290#endif
6291 return(0);
6292 }
6293 if (buf->content == NULL) {
6294#ifdef DEBUG_BUFFER
6295 xmlGenericError(xmlGenericErrorContext,
6296 "xmlBufferDump: buf->content == NULL\n");
6297#endif
6298 return(0);
6299 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006300 if (file == NULL)
6301 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006302 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6303 return(ret);
6304}
6305
6306/**
6307 * xmlBufferContent:
6308 * @buf: the buffer
6309 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006310 * Function to extract the content of a buffer
6311 *
Owen Taylor3473f882001-02-23 17:55:21 +00006312 * Returns the internal content
6313 */
6314
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006315const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006316xmlBufferContent(const xmlBufferPtr buf)
6317{
6318 if(!buf)
6319 return NULL;
6320
6321 return buf->content;
6322}
6323
6324/**
6325 * xmlBufferLength:
6326 * @buf: the buffer
6327 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006328 * Function to get the length of a buffer
6329 *
Owen Taylor3473f882001-02-23 17:55:21 +00006330 * Returns the length of data in the internal content
6331 */
6332
6333int
6334xmlBufferLength(const xmlBufferPtr buf)
6335{
6336 if(!buf)
6337 return 0;
6338
6339 return buf->use;
6340}
6341
6342/**
6343 * xmlBufferResize:
6344 * @buf: the buffer to resize
6345 * @size: the desired size
6346 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006347 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006348 *
6349 * Returns 0 in case of problems, 1 otherwise
6350 */
6351int
6352xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6353{
6354 unsigned int newSize;
6355 xmlChar* rebuf = NULL;
6356
6357 /*take care of empty case*/
6358 newSize = (buf->size ? buf->size*2 : size);
6359
6360 /* Don't resize if we don't have to */
6361 if (size < buf->size)
6362 return 1;
6363
6364 /* figure out new size */
6365 switch (buf->alloc){
6366 case XML_BUFFER_ALLOC_DOUBLEIT:
6367 while (size > newSize) newSize *= 2;
6368 break;
6369 case XML_BUFFER_ALLOC_EXACT:
6370 newSize = size+10;
6371 break;
6372 default:
6373 newSize = size+10;
6374 break;
6375 }
6376
6377 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006378 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006379 else
6380 rebuf = (xmlChar *) xmlRealloc(buf->content,
6381 newSize * sizeof(xmlChar));
6382 if (rebuf == NULL) {
6383 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006384 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006385 return 0;
6386 }
6387 buf->content = rebuf;
6388 buf->size = newSize;
6389
6390 return 1;
6391}
6392
6393/**
6394 * xmlBufferAdd:
6395 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006396 * @str: the #xmlChar string
6397 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006398 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006399 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006400 * str is recomputed.
6401 */
6402void
6403xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6404 unsigned int needSize;
6405
6406 if (str == NULL) {
6407#ifdef DEBUG_BUFFER
6408 xmlGenericError(xmlGenericErrorContext,
6409 "xmlBufferAdd: str == NULL\n");
6410#endif
6411 return;
6412 }
6413 if (len < -1) {
6414#ifdef DEBUG_BUFFER
6415 xmlGenericError(xmlGenericErrorContext,
6416 "xmlBufferAdd: len < 0\n");
6417#endif
6418 return;
6419 }
6420 if (len == 0) return;
6421
6422 if (len < 0)
6423 len = xmlStrlen(str);
6424
6425 if (len <= 0) return;
6426
6427 needSize = buf->use + len + 2;
6428 if (needSize > buf->size){
6429 if (!xmlBufferResize(buf, needSize)){
6430 xmlGenericError(xmlGenericErrorContext,
6431 "xmlBufferAdd : out of memory!\n");
6432 return;
6433 }
6434 }
6435
6436 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6437 buf->use += len;
6438 buf->content[buf->use] = 0;
6439}
6440
6441/**
6442 * xmlBufferAddHead:
6443 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006444 * @str: the #xmlChar string
6445 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006446 *
6447 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006448 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00006449 */
6450void
6451xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6452 unsigned int needSize;
6453
6454 if (str == NULL) {
6455#ifdef DEBUG_BUFFER
6456 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006457 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006458#endif
6459 return;
6460 }
6461 if (len < -1) {
6462#ifdef DEBUG_BUFFER
6463 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006464 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006465#endif
6466 return;
6467 }
6468 if (len == 0) return;
6469
6470 if (len < 0)
6471 len = xmlStrlen(str);
6472
6473 if (len <= 0) return;
6474
6475 needSize = buf->use + len + 2;
6476 if (needSize > buf->size){
6477 if (!xmlBufferResize(buf, needSize)){
6478 xmlGenericError(xmlGenericErrorContext,
6479 "xmlBufferAddHead : out of memory!\n");
6480 return;
6481 }
6482 }
6483
6484 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6485 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6486 buf->use += len;
6487 buf->content[buf->use] = 0;
6488}
6489
6490/**
6491 * xmlBufferCat:
6492 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006493 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006494 *
6495 * Append a zero terminated string to an XML buffer.
6496 */
6497void
6498xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
6499 if (str != NULL)
6500 xmlBufferAdd(buf, str, -1);
6501}
6502
6503/**
6504 * xmlBufferCCat:
6505 * @buf: the buffer to dump
6506 * @str: the C char string
6507 *
6508 * Append a zero terminated C string to an XML buffer.
6509 */
6510void
6511xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6512 const char *cur;
6513
6514 if (str == NULL) {
6515#ifdef DEBUG_BUFFER
6516 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006517 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006518#endif
6519 return;
6520 }
6521 for (cur = str;*cur != 0;cur++) {
6522 if (buf->use + 10 >= buf->size) {
6523 if (!xmlBufferResize(buf, buf->use+10)){
6524 xmlGenericError(xmlGenericErrorContext,
6525 "xmlBufferCCat : out of memory!\n");
6526 return;
6527 }
6528 }
6529 buf->content[buf->use++] = *cur;
6530 }
6531 buf->content[buf->use] = 0;
6532}
6533
6534/**
6535 * xmlBufferWriteCHAR:
6536 * @buf: the XML buffer
6537 * @string: the string to add
6538 *
6539 * routine which manages and grows an output buffer. This one adds
6540 * xmlChars at the end of the buffer.
6541 */
6542void
Owen Taylor3473f882001-02-23 17:55:21 +00006543xmlBufferWriteCHAR
Owen Taylor3473f882001-02-23 17:55:21 +00006544(xmlBufferPtr buf, const xmlChar *string) {
6545 xmlBufferCat(buf, string);
6546}
6547
6548/**
6549 * xmlBufferWriteChar:
6550 * @buf: the XML buffer output
6551 * @string: the string to add
6552 *
6553 * routine which manage and grows an output buffer. This one add
6554 * C chars at the end of the array.
6555 */
6556void
6557xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
6558 xmlBufferCCat(buf, string);
6559}
6560
6561
6562/**
6563 * xmlBufferWriteQuotedString:
6564 * @buf: the XML buffer output
6565 * @string: the string to add
6566 *
6567 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00006568 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00006569 * quote or double-quotes internally
6570 */
6571void
6572xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
6573 if (xmlStrchr(string, '"')) {
6574 if (xmlStrchr(string, '\'')) {
6575#ifdef DEBUG_BUFFER
6576 xmlGenericError(xmlGenericErrorContext,
6577 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
6578#endif
6579 }
6580 xmlBufferCCat(buf, "'");
6581 xmlBufferCat(buf, string);
6582 xmlBufferCCat(buf, "'");
6583 } else {
6584 xmlBufferCCat(buf, "\"");
6585 xmlBufferCat(buf, string);
6586 xmlBufferCCat(buf, "\"");
6587 }
6588}
6589
6590
6591/************************************************************************
6592 * *
6593 * Dumping XML tree content to a simple buffer *
6594 * *
6595 ************************************************************************/
6596
Owen Taylor3473f882001-02-23 17:55:21 +00006597/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00006598 * xmlAttrSerializeContent:
6599 * @buf: the XML buffer output
6600 * @doc: the document
6601 * @attr: the attribute pointer
6602 *
6603 * Serialize the attribute in the buffer
6604 */
6605static void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006606xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr)
6607{
Daniel Veillarda6d05382002-02-13 13:07:41 +00006608 const xmlChar *cur, *base;
6609 xmlNodePtr children;
6610
6611 children = attr->children;
6612 while (children != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006613 switch (children->type) {
6614 case XML_TEXT_NODE:
6615 base = cur = children->content;
6616 while (*cur != 0) {
6617 if (*cur == '\n') {
6618 if (base != cur)
6619 xmlBufferAdd(buf, base, cur - base);
6620 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
6621 cur++;
6622 base = cur;
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006623 } else if (*cur == '\r') {
6624 if (base != cur)
6625 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006626 xmlBufferAdd(buf, BAD_CAST "&#13;", 5);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006627 cur++;
6628 base = cur;
6629 } else if (*cur == '\t') {
6630 if (base != cur)
6631 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006632 xmlBufferAdd(buf, BAD_CAST "&#9;", 4);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006633 cur++;
6634 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006635#if 0
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006636 } else if (*cur == '\'') {
6637 if (base != cur)
6638 xmlBufferAdd(buf, base, cur - base);
6639 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
6640 cur++;
6641 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006642#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006643 } else if (*cur == '"') {
6644 if (base != cur)
6645 xmlBufferAdd(buf, base, cur - base);
6646 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6647 cur++;
6648 base = cur;
6649 } else if (*cur == '<') {
6650 if (base != cur)
6651 xmlBufferAdd(buf, base, cur - base);
6652 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
6653 cur++;
6654 base = cur;
6655 } else if (*cur == '>') {
6656 if (base != cur)
6657 xmlBufferAdd(buf, base, cur - base);
6658 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
6659 cur++;
6660 base = cur;
6661 } else if (*cur == '&') {
6662 if (base != cur)
6663 xmlBufferAdd(buf, base, cur - base);
6664 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
6665 cur++;
6666 base = cur;
6667 } else if ((*cur >= 0x80) && ((doc == NULL) ||
6668 (doc->encoding ==
6669 NULL))) {
6670 /*
6671 * We assume we have UTF-8 content.
6672 */
6673 char tmp[10];
6674 int val = 0, l = 1;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006675
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006676 if (base != cur)
6677 xmlBufferAdd(buf, base, cur - base);
6678 if (*cur < 0xC0) {
6679 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6d05382002-02-13 13:07:41 +00006680 "xmlAttrSerializeContent : input not UTF-8\n");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006681 if (doc != NULL)
6682 doc->encoding =
6683 xmlStrdup(BAD_CAST "ISO-8859-1");
6684 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6685 tmp[sizeof(tmp) - 1] = 0;
6686 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6687 cur++;
6688 base = cur;
6689 continue;
6690 } else if (*cur < 0xE0) {
6691 val = (cur[0]) & 0x1F;
6692 val <<= 6;
6693 val |= (cur[1]) & 0x3F;
6694 l = 2;
6695 } else if (*cur < 0xF0) {
6696 val = (cur[0]) & 0x0F;
6697 val <<= 6;
6698 val |= (cur[1]) & 0x3F;
6699 val <<= 6;
6700 val |= (cur[2]) & 0x3F;
6701 l = 3;
6702 } else if (*cur < 0xF8) {
6703 val = (cur[0]) & 0x07;
6704 val <<= 6;
6705 val |= (cur[1]) & 0x3F;
6706 val <<= 6;
6707 val |= (cur[2]) & 0x3F;
6708 val <<= 6;
6709 val |= (cur[3]) & 0x3F;
6710 l = 4;
6711 }
6712 if ((l == 1) || (!IS_CHAR(val))) {
6713 xmlGenericError(xmlGenericErrorContext,
6714 "xmlAttrSerializeContent : char out of range\n");
6715 if (doc != NULL)
6716 doc->encoding =
6717 xmlStrdup(BAD_CAST "ISO-8859-1");
6718 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6719 tmp[sizeof(tmp) - 1] = 0;
6720 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6721 cur++;
6722 base = cur;
6723 continue;
6724 }
6725 /*
6726 * We could do multiple things here. Just save
6727 * as a char ref
6728 */
6729 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
6730 tmp[sizeof(tmp) - 1] = 0;
6731 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6732 cur += l;
6733 base = cur;
6734 } else {
6735 cur++;
6736 }
6737 }
6738 if (base != cur)
6739 xmlBufferAdd(buf, base, cur - base);
6740 break;
6741 case XML_ENTITY_REF_NODE:
6742 xmlBufferAdd(buf, BAD_CAST "&", 1);
6743 xmlBufferAdd(buf, children->name,
6744 xmlStrlen(children->name));
6745 xmlBufferAdd(buf, BAD_CAST ";", 1);
6746 break;
6747 default:
6748 /* should not happen unless we have a badly built tree */
6749 break;
6750 }
6751 children = children->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006752 }
6753}
6754
6755/**
6756 * xmlNodeDump:
6757 * @buf: the XML buffer output
6758 * @doc: the document
6759 * @cur: the current node
6760 * @level: the imbrication level for indenting
6761 * @format: is formatting allowed
6762 *
6763 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00006764 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006765 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006766 *
6767 * Returns the number of bytes written to the buffer or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00006768 */
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006769int
Owen Taylor3473f882001-02-23 17:55:21 +00006770xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006771 int format)
6772{
6773 unsigned int use;
6774 int ret;
6775 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006776
6777 if (cur == NULL) {
6778#ifdef DEBUG_TREE
6779 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006780 "xmlNodeDump : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006781#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006782 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006783 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006784 if (buf == NULL) {
6785#ifdef DEBUG_TREE
6786 xmlGenericError(xmlGenericErrorContext,
6787 "xmlNodeDump : buf == NULL\n");
6788#endif
6789 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006790 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006791 outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
6792 if (outbuf == NULL) {
6793 xmlGenericError(xmlGenericErrorContext,
6794 "xmlNodeDump: out of memory!\n");
6795 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006796 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006797 memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
6798 outbuf->buffer = buf;
6799 outbuf->encoder = NULL;
6800 outbuf->writecallback = NULL;
6801 outbuf->closecallback = NULL;
6802 outbuf->context = NULL;
6803 outbuf->written = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006804
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006805 use = buf->use;
6806 xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
6807 xmlFree(outbuf);
6808 ret = buf->use - use;
6809 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006810}
6811
6812/**
6813 * xmlElemDump:
6814 * @f: the FILE * for the output
6815 * @doc: the document
6816 * @cur: the current node
6817 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006818 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006819 */
6820void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006821xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur)
6822{
6823 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006824
6825 if (cur == NULL) {
6826#ifdef DEBUG_TREE
6827 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006828 "xmlElemDump : cur == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006829#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006830 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006831 }
Owen Taylor3473f882001-02-23 17:55:21 +00006832#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006833 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006834 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006835 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006836 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006837#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006838
6839 outbuf = xmlOutputBufferCreateFile(f, NULL);
6840 if (outbuf == NULL)
6841 return;
6842 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006843#ifdef LIBXML_HTML_ENABLED
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006844 htmlNodeDumpOutput(outbuf, doc, cur, NULL);
6845#else
6846 xmlGenericError(xmlGenericErrorContext,
6847 "HTML support not compiled in\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006848#endif /* LIBXML_HTML_ENABLED */
6849 } else
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006850 xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL);
6851 xmlOutputBufferClose(outbuf);
Owen Taylor3473f882001-02-23 17:55:21 +00006852}
6853
6854/************************************************************************
6855 * *
6856 * Dumping XML tree content to an I/O output buffer *
6857 * *
6858 ************************************************************************/
6859
Owen Taylor3473f882001-02-23 17:55:21 +00006860static void
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006861xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6862 int level, int format, const char *encoding);
6863static void
Owen Taylor3473f882001-02-23 17:55:21 +00006864xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6865 int level, int format, const char *encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006866static void
6867xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
6868 xmlNodePtr cur, int level, int format, const char *encoding);
6869
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00006870void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
6871
Owen Taylor3473f882001-02-23 17:55:21 +00006872/**
6873 * xmlNsDumpOutput:
6874 * @buf: the XML buffer output
6875 * @cur: a namespace
6876 *
6877 * Dump a local Namespace definition.
6878 * Should be called in the context of attributes dumps.
6879 */
6880static void
6881xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6882 if (cur == NULL) {
6883#ifdef DEBUG_TREE
6884 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006885 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006886#endif
6887 return;
6888 }
6889 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00006890 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
6891 return;
6892
Owen Taylor3473f882001-02-23 17:55:21 +00006893 /* Within the context of an element attributes */
6894 if (cur->prefix != NULL) {
6895 xmlOutputBufferWriteString(buf, " xmlns:");
6896 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6897 } else
6898 xmlOutputBufferWriteString(buf, " xmlns");
6899 xmlOutputBufferWriteString(buf, "=");
6900 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6901 }
6902}
6903
6904/**
6905 * xmlNsListDumpOutput:
6906 * @buf: the XML buffer output
6907 * @cur: the first namespace
6908 *
6909 * Dump a list of local Namespace definitions.
6910 * Should be called in the context of attributes dumps.
6911 */
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00006912void
Owen Taylor3473f882001-02-23 17:55:21 +00006913xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6914 while (cur != NULL) {
6915 xmlNsDumpOutput(buf, cur);
6916 cur = cur->next;
6917 }
6918}
6919
6920/**
6921 * xmlDtdDumpOutput:
6922 * @buf: the XML buffer output
6923 * @doc: the document
6924 * @encoding: an optional encoding string
6925 *
6926 * Dump the XML document DTD, if any.
6927 */
6928static void
6929xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6930 if (dtd == NULL) {
6931#ifdef DEBUG_TREE
6932 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006933 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006934#endif
6935 return;
6936 }
6937 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6938 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6939 if (dtd->ExternalID != NULL) {
6940 xmlOutputBufferWriteString(buf, " PUBLIC ");
6941 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6942 xmlOutputBufferWriteString(buf, " ");
6943 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6944 } else if (dtd->SystemID != NULL) {
6945 xmlOutputBufferWriteString(buf, " SYSTEM ");
6946 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6947 }
6948 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6949 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6950 xmlOutputBufferWriteString(buf, ">");
6951 return;
6952 }
6953 xmlOutputBufferWriteString(buf, " [\n");
6954 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6955 xmlOutputBufferWriteString(buf, "]>");
6956}
6957
6958/**
6959 * xmlAttrDumpOutput:
6960 * @buf: the XML buffer output
6961 * @doc: the document
6962 * @cur: the attribute pointer
6963 * @encoding: an optional encoding string
6964 *
6965 * Dump an XML attribute
6966 */
6967static void
6968xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006969 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006970 if (cur == NULL) {
6971#ifdef DEBUG_TREE
6972 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006973 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006974#endif
6975 return;
6976 }
6977 xmlOutputBufferWriteString(buf, " ");
6978 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6979 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6980 xmlOutputBufferWriteString(buf, ":");
6981 }
6982 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006983 xmlOutputBufferWriteString(buf, "=\"");
6984 xmlAttrSerializeContent(buf->buffer, doc, cur);
6985 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006986}
6987
6988/**
6989 * xmlAttrListDumpOutput:
6990 * @buf: the XML buffer output
6991 * @doc: the document
6992 * @cur: the first attribute pointer
6993 * @encoding: an optional encoding string
6994 *
6995 * Dump a list of XML attributes
6996 */
6997static void
6998xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6999 xmlAttrPtr cur, const char *encoding) {
7000 if (cur == NULL) {
7001#ifdef DEBUG_TREE
7002 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007003 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007004#endif
7005 return;
7006 }
7007 while (cur != NULL) {
7008 xmlAttrDumpOutput(buf, doc, cur, encoding);
7009 cur = cur->next;
7010 }
7011}
7012
7013
7014
7015/**
7016 * xmlNodeListDumpOutput:
7017 * @buf: the XML buffer output
7018 * @doc: the document
7019 * @cur: the first node
7020 * @level: the imbrication level for indenting
7021 * @format: is formatting allowed
7022 * @encoding: an optional encoding string
7023 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007024 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007025 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007026 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007027 */
7028static void
7029xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7030 xmlNodePtr cur, int level, int format, const char *encoding) {
7031 int i;
7032
7033 if (cur == NULL) {
7034#ifdef DEBUG_TREE
7035 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007036 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007037#endif
7038 return;
7039 }
7040 while (cur != NULL) {
7041 if ((format) && (xmlIndentTreeOutput) &&
7042 (cur->type == XML_ELEMENT_NODE))
7043 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007044 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007045 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007046 if (format) {
7047 xmlOutputBufferWriteString(buf, "\n");
7048 }
7049 cur = cur->next;
7050 }
7051}
7052
7053/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007054 * xmlNodeDumpOutputInternal:
Owen Taylor3473f882001-02-23 17:55:21 +00007055 * @buf: the XML buffer output
7056 * @doc: the document
7057 * @cur: the current node
7058 * @level: the imbrication level for indenting
7059 * @format: is formatting allowed
7060 * @encoding: an optional encoding string
7061 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007062 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007063 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007064 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007065 */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007066static void
7067xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
7068 xmlNodePtr cur, int level, int format, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007069 int i;
7070 xmlNodePtr tmp;
7071
7072 if (cur == NULL) {
7073#ifdef DEBUG_TREE
7074 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007075 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007076#endif
7077 return;
7078 }
7079 if (cur->type == XML_XINCLUDE_START)
7080 return;
7081 if (cur->type == XML_XINCLUDE_END)
7082 return;
7083 if (cur->type == XML_DTD_NODE) {
7084 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7085 return;
7086 }
7087 if (cur->type == XML_ELEMENT_DECL) {
7088 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7089 return;
7090 }
7091 if (cur->type == XML_ATTRIBUTE_DECL) {
7092 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7093 return;
7094 }
7095 if (cur->type == XML_ENTITY_DECL) {
7096 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7097 return;
7098 }
7099 if (cur->type == XML_TEXT_NODE) {
7100 if (cur->content != NULL) {
7101 if ((cur->name == xmlStringText) ||
7102 (cur->name != xmlStringTextNoenc)) {
7103 xmlChar *buffer;
7104
Owen Taylor3473f882001-02-23 17:55:21 +00007105 if (encoding == NULL)
7106 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7107 else
7108 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007109 if (buffer != NULL) {
7110 xmlOutputBufferWriteString(buf, (const char *)buffer);
7111 xmlFree(buffer);
7112 }
7113 } else {
7114 /*
7115 * Disable escaping, needed for XSLT
7116 */
Owen Taylor3473f882001-02-23 17:55:21 +00007117 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007118 }
7119 }
7120
7121 return;
7122 }
7123 if (cur->type == XML_PI_NODE) {
7124 if (cur->content != NULL) {
7125 xmlOutputBufferWriteString(buf, "<?");
7126 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7127 if (cur->content != NULL) {
7128 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00007129 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007130 }
7131 xmlOutputBufferWriteString(buf, "?>");
7132 } else {
7133 xmlOutputBufferWriteString(buf, "<?");
7134 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7135 xmlOutputBufferWriteString(buf, "?>");
7136 }
7137 return;
7138 }
7139 if (cur->type == XML_COMMENT_NODE) {
7140 if (cur->content != NULL) {
7141 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00007142 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007143 xmlOutputBufferWriteString(buf, "-->");
7144 }
7145 return;
7146 }
7147 if (cur->type == XML_ENTITY_REF_NODE) {
7148 xmlOutputBufferWriteString(buf, "&");
7149 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7150 xmlOutputBufferWriteString(buf, ";");
7151 return;
7152 }
7153 if (cur->type == XML_CDATA_SECTION_NODE) {
7154 xmlOutputBufferWriteString(buf, "<![CDATA[");
7155 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007156 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007157 xmlOutputBufferWriteString(buf, "]]>");
7158 return;
7159 }
Daniel Veillard7b72ee52003-02-27 23:24:53 +00007160 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillarda1a9d042003-03-18 16:53:17 +00007161 xmlAttrDumpOutput(buf,doc, (xmlAttrPtr) cur,encoding);
Daniel Veillard7b72ee52003-02-27 23:24:53 +00007162 return;
7163 }
Daniel Veillard6aa2f602003-02-10 00:01:56 +00007164 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007165 xmlNsDumpOutput(buf, (xmlNsPtr) cur);
Daniel Veillard6aa2f602003-02-10 00:01:56 +00007166 return;
7167 }
Owen Taylor3473f882001-02-23 17:55:21 +00007168
7169 if (format == 1) {
7170 tmp = cur->children;
7171 while (tmp != NULL) {
7172 if ((tmp->type == XML_TEXT_NODE) ||
7173 (tmp->type == XML_ENTITY_REF_NODE)) {
7174 format = 0;
7175 break;
7176 }
7177 tmp = tmp->next;
7178 }
7179 }
7180 xmlOutputBufferWriteString(buf, "<");
7181 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7182 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7183 xmlOutputBufferWriteString(buf, ":");
7184 }
7185
7186 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7187 if (cur->nsDef)
7188 xmlNsListDumpOutput(buf, cur->nsDef);
7189 if (cur->properties != NULL)
7190 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7191
Daniel Veillard7db37732001-07-12 01:20:08 +00007192 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
7193 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007194 xmlOutputBufferWriteString(buf, "/>");
7195 return;
7196 }
7197 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00007198 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007199 xmlChar *buffer;
7200
Owen Taylor3473f882001-02-23 17:55:21 +00007201 if (encoding == NULL)
7202 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7203 else
7204 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007205 if (buffer != NULL) {
7206 xmlOutputBufferWriteString(buf, (const char *)buffer);
7207 xmlFree(buffer);
7208 }
7209 }
7210 if (cur->children != NULL) {
7211 if (format) xmlOutputBufferWriteString(buf, "\n");
7212 xmlNodeListDumpOutput(buf, doc, cur->children,
7213 (level >= 0?level+1:-1), format, encoding);
7214 if ((xmlIndentTreeOutput) && (format))
7215 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007216 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00007217 }
7218 xmlOutputBufferWriteString(buf, "</");
7219 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7220 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7221 xmlOutputBufferWriteString(buf, ":");
7222 }
7223
7224 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7225 xmlOutputBufferWriteString(buf, ">");
7226}
7227
7228/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007229 * xmlNodeDumpOutput:
7230 * @buf: the XML buffer output
7231 * @doc: the document
7232 * @cur: the current node
7233 * @level: the imbrication level for indenting
7234 * @format: is formatting allowed
7235 * @encoding: an optional encoding string
7236 *
7237 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007238 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007239 * or xmlKeepBlanksDefault(0) was called
7240 */
7241void
7242xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007243 int level, int format, const char *encoding)
7244{
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007245#ifdef LIBXML_HTML_ENABLED
7246 xmlDtdPtr dtd;
7247 int is_xhtml = 0;
7248
7249 dtd = xmlGetIntSubset(doc);
7250 if (dtd != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007251 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7252 if (is_xhtml < 0)
7253 is_xhtml = 0;
7254 if ((is_xhtml) && (cur->parent == (xmlNodePtr) doc) &&
7255 (cur->type == XML_ELEMENT_NODE) &&
7256 (xmlStrEqual(cur->name, BAD_CAST "html"))) {
7257 if (encoding != NULL)
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007258 htmlSetMetaEncoding((htmlDocPtr) doc,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007259 (const xmlChar *) encoding);
7260 else
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007261 htmlSetMetaEncoding((htmlDocPtr) doc, BAD_CAST "UTF-8");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007262 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007263 }
7264
7265 if (is_xhtml)
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007266 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007267 else
7268#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007269 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007270}
7271
7272/**
Owen Taylor3473f882001-02-23 17:55:21 +00007273 * xmlDocContentDumpOutput:
7274 * @buf: the XML buffer output
7275 * @cur: the document
7276 * @encoding: an optional encoding string
7277 * @format: should formatting spaces been added
7278 *
7279 * Dump an XML document.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007280 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007281 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007282 */
7283static void
7284xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
7285 const char *encoding, int format) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007286#ifdef LIBXML_HTML_ENABLED
7287 xmlDtdPtr dtd;
7288 int is_xhtml = 0;
7289#endif
7290
Owen Taylor3473f882001-02-23 17:55:21 +00007291 xmlOutputBufferWriteString(buf, "<?xml version=");
7292 if (cur->version != NULL)
7293 xmlBufferWriteQuotedString(buf->buffer, cur->version);
7294 else
7295 xmlOutputBufferWriteString(buf, "\"1.0\"");
7296 if (encoding == NULL) {
7297 if (cur->encoding != NULL)
7298 encoding = (const char *) cur->encoding;
7299 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
7300 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
7301 }
7302 if (encoding != NULL) {
7303 xmlOutputBufferWriteString(buf, " encoding=");
7304 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
7305 }
7306 switch (cur->standalone) {
7307 case 0:
7308 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
7309 break;
7310 case 1:
7311 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
7312 break;
7313 }
7314 xmlOutputBufferWriteString(buf, "?>\n");
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007315
7316#ifdef LIBXML_HTML_ENABLED
7317 dtd = xmlGetIntSubset(cur);
7318 if (dtd != NULL) {
7319 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7320 if (is_xhtml < 0) is_xhtml = 0;
7321 }
7322 if (is_xhtml) {
7323 if (encoding != NULL)
7324 htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
7325 else
7326 htmlSetMetaEncoding(cur, BAD_CAST "UTF-8");
7327 }
7328#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007329 if (cur->children != NULL) {
7330 xmlNodePtr child = cur->children;
7331
7332 while (child != NULL) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007333#ifdef LIBXML_HTML_ENABLED
7334 if (is_xhtml)
7335 xhtmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
7336 else
7337#endif
7338 xmlNodeDumpOutputInternal(buf, cur, child, 0, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007339 xmlOutputBufferWriteString(buf, "\n");
7340 child = child->next;
7341 }
7342 }
7343}
7344
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007345#ifdef LIBXML_HTML_ENABLED
7346/************************************************************************
7347 * *
7348 * Functions specific to XHTML serialization *
7349 * *
7350 ************************************************************************/
7351
7352#define XHTML_STRICT_PUBLIC_ID BAD_CAST \
7353 "-//W3C//DTD XHTML 1.0 Strict//EN"
7354#define XHTML_STRICT_SYSTEM_ID BAD_CAST \
7355 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
7356#define XHTML_FRAME_PUBLIC_ID BAD_CAST \
7357 "-//W3C//DTD XHTML 1.0 Frameset//EN"
7358#define XHTML_FRAME_SYSTEM_ID BAD_CAST \
7359 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
7360#define XHTML_TRANS_PUBLIC_ID BAD_CAST \
7361 "-//W3C//DTD XHTML 1.0 Transitional//EN"
7362#define XHTML_TRANS_SYSTEM_ID BAD_CAST \
7363 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
7364
7365#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
7366/**
7367 * xmlIsXHTML:
7368 * @systemID: the system identifier
7369 * @publicID: the public identifier
7370 *
7371 * Try to find if the document correspond to an XHTML DTD
7372 *
7373 * Returns 1 if true, 0 if not and -1 in case of error
7374 */
7375int
7376xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) {
7377 if ((systemID == NULL) && (publicID == NULL))
7378 return(-1);
7379 if (publicID != NULL) {
7380 if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1);
7381 if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1);
7382 if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1);
7383 }
7384 if (systemID != NULL) {
7385 if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1);
7386 if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1);
7387 if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1);
7388 }
7389 return(0);
7390}
7391
7392/**
7393 * xhtmlIsEmpty:
7394 * @node: the node
7395 *
7396 * Check if a node is an empty xhtml node
7397 *
7398 * Returns 1 if the node is an empty node, 0 if not and -1 in case of error
7399 */
7400static int
7401xhtmlIsEmpty(xmlNodePtr node) {
7402 if (node == NULL)
7403 return(-1);
7404 if (node->type != XML_ELEMENT_NODE)
7405 return(0);
7406 if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME)))
7407 return(0);
7408 if (node->children != NULL)
7409 return(0);
7410 switch (node->name[0]) {
7411 case 'a':
7412 if (xmlStrEqual(node->name, BAD_CAST "area"))
7413 return(1);
7414 return(0);
7415 case 'b':
7416 if (xmlStrEqual(node->name, BAD_CAST "br"))
7417 return(1);
7418 if (xmlStrEqual(node->name, BAD_CAST "base"))
7419 return(1);
7420 if (xmlStrEqual(node->name, BAD_CAST "basefont"))
7421 return(1);
7422 return(0);
7423 case 'c':
7424 if (xmlStrEqual(node->name, BAD_CAST "col"))
7425 return(1);
7426 return(0);
7427 case 'f':
7428 if (xmlStrEqual(node->name, BAD_CAST "frame"))
7429 return(1);
7430 return(0);
7431 case 'h':
7432 if (xmlStrEqual(node->name, BAD_CAST "hr"))
7433 return(1);
7434 return(0);
7435 case 'i':
7436 if (xmlStrEqual(node->name, BAD_CAST "img"))
7437 return(1);
7438 if (xmlStrEqual(node->name, BAD_CAST "input"))
7439 return(1);
7440 if (xmlStrEqual(node->name, BAD_CAST "isindex"))
7441 return(1);
7442 return(0);
7443 case 'l':
7444 if (xmlStrEqual(node->name, BAD_CAST "link"))
7445 return(1);
7446 return(0);
7447 case 'm':
7448 if (xmlStrEqual(node->name, BAD_CAST "meta"))
7449 return(1);
7450 return(0);
7451 case 'p':
7452 if (xmlStrEqual(node->name, BAD_CAST "param"))
7453 return(1);
7454 return(0);
7455 }
7456 return(0);
7457}
7458
7459/**
7460 * xhtmlAttrListDumpOutput:
7461 * @buf: the XML buffer output
7462 * @doc: the document
7463 * @cur: the first attribute pointer
7464 * @encoding: an optional encoding string
7465 *
7466 * Dump a list of XML attributes
7467 */
7468static void
7469xhtmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7470 xmlAttrPtr cur, const char *encoding) {
7471 xmlAttrPtr xml_lang = NULL;
7472 xmlAttrPtr lang = NULL;
7473 xmlAttrPtr name = NULL;
7474 xmlAttrPtr id = NULL;
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007475 xmlNodePtr parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007476
7477 if (cur == NULL) {
7478#ifdef DEBUG_TREE
7479 xmlGenericError(xmlGenericErrorContext,
7480 "xmlAttrListDumpOutput : property == NULL\n");
7481#endif
7482 return;
7483 }
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007484 parent = cur->parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007485 while (cur != NULL) {
7486 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id")))
7487 id = cur;
7488 else
7489 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name")))
7490 name = cur;
7491 else
7492 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")))
7493 lang = cur;
7494 else
7495 if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) &&
7496 (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml")))
7497 xml_lang = cur;
7498 else if ((cur->ns == NULL) &&
7499 ((cur->children == NULL) ||
7500 (cur->children->content == NULL) ||
7501 (cur->children->content[0] == 0)) &&
7502 (htmlIsBooleanAttr(cur->name))) {
7503 if (cur->children != NULL)
7504 xmlFreeNode(cur->children);
7505 cur->children = xmlNewText(cur->name);
7506 if (cur->children != NULL)
7507 cur->children->parent = (xmlNodePtr) cur;
7508 }
7509 xmlAttrDumpOutput(buf, doc, cur, encoding);
7510 cur = cur->next;
7511 }
7512 /*
7513 * C.8
7514 */
7515 if ((name != NULL) && (id == NULL)) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007516 if ((parent != NULL) && (parent->name != NULL) &&
7517 ((xmlStrEqual(parent->name, BAD_CAST "a")) ||
7518 (xmlStrEqual(parent->name, BAD_CAST "p")) ||
7519 (xmlStrEqual(parent->name, BAD_CAST "div")) ||
7520 (xmlStrEqual(parent->name, BAD_CAST "img")) ||
7521 (xmlStrEqual(parent->name, BAD_CAST "map")) ||
7522 (xmlStrEqual(parent->name, BAD_CAST "applet")) ||
7523 (xmlStrEqual(parent->name, BAD_CAST "form")) ||
7524 (xmlStrEqual(parent->name, BAD_CAST "frame")) ||
7525 (xmlStrEqual(parent->name, BAD_CAST "iframe")))) {
7526 xmlOutputBufferWriteString(buf, " id=\"");
7527 xmlAttrSerializeContent(buf->buffer, doc, name);
7528 xmlOutputBufferWriteString(buf, "\"");
7529 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007530 }
7531 /*
7532 * C.7.
7533 */
7534 if ((lang != NULL) && (xml_lang == NULL)) {
7535 xmlOutputBufferWriteString(buf, " xml:lang=\"");
7536 xmlAttrSerializeContent(buf->buffer, doc, lang);
7537 xmlOutputBufferWriteString(buf, "\"");
7538 } else
7539 if ((xml_lang != NULL) && (lang == NULL)) {
7540 xmlOutputBufferWriteString(buf, " lang=\"");
7541 xmlAttrSerializeContent(buf->buffer, doc, xml_lang);
7542 xmlOutputBufferWriteString(buf, "\"");
7543 }
7544}
7545
7546/**
7547 * xhtmlNodeListDumpOutput:
7548 * @buf: the XML buffer output
7549 * @doc: the XHTML document
7550 * @cur: the first node
7551 * @level: the imbrication level for indenting
7552 * @format: is formatting allowed
7553 * @encoding: an optional encoding string
7554 *
7555 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007556 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007557 * or xmlKeepBlanksDefault(0) was called
7558 */
7559static void
7560xhtmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7561 xmlNodePtr cur, int level, int format, const char *encoding) {
7562 int i;
7563
7564 if (cur == NULL) {
7565#ifdef DEBUG_TREE
7566 xmlGenericError(xmlGenericErrorContext,
7567 "xhtmlNodeListDumpOutput : node == NULL\n");
7568#endif
7569 return;
7570 }
7571 while (cur != NULL) {
7572 if ((format) && (xmlIndentTreeOutput) &&
7573 (cur->type == XML_ELEMENT_NODE))
7574 for (i = 0;i < level;i++)
7575 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7576 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
7577 if (format) {
7578 xmlOutputBufferWriteString(buf, "\n");
7579 }
7580 cur = cur->next;
7581 }
7582}
7583
7584/**
7585 * xhtmlNodeDumpOutput:
7586 * @buf: the XML buffer output
7587 * @doc: the XHTML document
7588 * @cur: the current node
7589 * @level: the imbrication level for indenting
7590 * @format: is formatting allowed
7591 * @encoding: an optional encoding string
7592 *
7593 * Dump an XHTML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007594 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007595 * or xmlKeepBlanksDefault(0) was called
7596 */
7597static void
7598xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7599 int level, int format, const char *encoding) {
7600 int i;
7601 xmlNodePtr tmp;
7602
7603 if (cur == NULL) {
7604#ifdef DEBUG_TREE
7605 xmlGenericError(xmlGenericErrorContext,
7606 "xmlNodeDumpOutput : node == NULL\n");
7607#endif
7608 return;
7609 }
7610 if (cur->type == XML_XINCLUDE_START)
7611 return;
7612 if (cur->type == XML_XINCLUDE_END)
7613 return;
7614 if (cur->type == XML_DTD_NODE) {
7615 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7616 return;
7617 }
7618 if (cur->type == XML_ELEMENT_DECL) {
7619 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7620 return;
7621 }
7622 if (cur->type == XML_ATTRIBUTE_DECL) {
7623 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7624 return;
7625 }
7626 if (cur->type == XML_ENTITY_DECL) {
7627 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7628 return;
7629 }
7630 if (cur->type == XML_TEXT_NODE) {
7631 if (cur->content != NULL) {
7632 if ((cur->name == xmlStringText) ||
7633 (cur->name != xmlStringTextNoenc)) {
7634 xmlChar *buffer;
7635
7636 if (encoding == NULL)
7637 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7638 else
7639 buffer = xmlEncodeSpecialChars(doc, cur->content);
7640 if (buffer != NULL) {
7641 xmlOutputBufferWriteString(buf, (const char *)buffer);
7642 xmlFree(buffer);
7643 }
7644 } else {
7645 /*
7646 * Disable escaping, needed for XSLT
7647 */
7648 xmlOutputBufferWriteString(buf, (const char *) cur->content);
7649 }
7650 }
7651
7652 return;
7653 }
7654 if (cur->type == XML_PI_NODE) {
7655 if (cur->content != NULL) {
7656 xmlOutputBufferWriteString(buf, "<?");
7657 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7658 if (cur->content != NULL) {
7659 xmlOutputBufferWriteString(buf, " ");
7660 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7661 }
7662 xmlOutputBufferWriteString(buf, "?>");
7663 } else {
7664 xmlOutputBufferWriteString(buf, "<?");
7665 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7666 xmlOutputBufferWriteString(buf, "?>");
7667 }
7668 return;
7669 }
7670 if (cur->type == XML_COMMENT_NODE) {
7671 if (cur->content != NULL) {
7672 xmlOutputBufferWriteString(buf, "<!--");
7673 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7674 xmlOutputBufferWriteString(buf, "-->");
7675 }
7676 return;
7677 }
7678 if (cur->type == XML_ENTITY_REF_NODE) {
7679 xmlOutputBufferWriteString(buf, "&");
7680 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7681 xmlOutputBufferWriteString(buf, ";");
7682 return;
7683 }
7684 if (cur->type == XML_CDATA_SECTION_NODE) {
7685 xmlOutputBufferWriteString(buf, "<![CDATA[");
7686 if (cur->content != NULL)
7687 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7688 xmlOutputBufferWriteString(buf, "]]>");
7689 return;
7690 }
7691
7692 if (format == 1) {
7693 tmp = cur->children;
7694 while (tmp != NULL) {
7695 if ((tmp->type == XML_TEXT_NODE) ||
7696 (tmp->type == XML_ENTITY_REF_NODE)) {
7697 format = 0;
7698 break;
7699 }
7700 tmp = tmp->next;
7701 }
7702 }
7703 xmlOutputBufferWriteString(buf, "<");
7704 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7705 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7706 xmlOutputBufferWriteString(buf, ":");
7707 }
7708
7709 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7710 if (cur->nsDef)
7711 xmlNsListDumpOutput(buf, cur->nsDef);
7712 if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
7713 (cur->ns == NULL) && (cur->nsDef == NULL))) {
7714 /*
7715 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
7716 */
7717 xmlOutputBufferWriteString(buf,
7718 " xmlns=\"http://www.w3.org/1999/xhtml\"");
7719 }
7720 if (cur->properties != NULL)
7721 xhtmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7722
7723 if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) {
7724 if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
7725 (xhtmlIsEmpty(cur) == 1)) {
7726 /*
7727 * C.2. Empty Elements
7728 */
7729 xmlOutputBufferWriteString(buf, " />");
7730 } else {
7731 /*
7732 * C.3. Element Minimization and Empty Element Content
7733 */
7734 xmlOutputBufferWriteString(buf, "></");
7735 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7736 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7737 xmlOutputBufferWriteString(buf, ":");
7738 }
7739 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7740 xmlOutputBufferWriteString(buf, ">");
7741 }
7742 return;
7743 }
7744 xmlOutputBufferWriteString(buf, ">");
7745 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
7746 xmlChar *buffer;
7747
7748 if (encoding == NULL)
7749 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7750 else
7751 buffer = xmlEncodeSpecialChars(doc, cur->content);
7752 if (buffer != NULL) {
7753 xmlOutputBufferWriteString(buf, (const char *)buffer);
7754 xmlFree(buffer);
7755 }
7756 }
7757
7758 /*
7759 * 4.8. Script and Style elements
7760 */
7761 if ((cur->type == XML_ELEMENT_NODE) &&
7762 ((xmlStrEqual(cur->name, BAD_CAST "script")) ||
7763 (xmlStrEqual(cur->name, BAD_CAST "style"))) &&
7764 ((cur->ns == NULL) ||
7765 (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) {
7766 xmlNodePtr child = cur->children;
7767
7768 while (child != NULL) {
7769 if ((child->type == XML_TEXT_NODE) ||
7770 (child->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard64b35282002-12-04 15:10:40 +00007771 /*
7772 * Apparently CDATA escaping for style just break on IE,
7773 * mozilla and galeon, so ...
7774 */
7775 if (xmlStrEqual(cur->name, BAD_CAST "style") &&
7776 (xmlStrchr(child->content, '<') == NULL) &&
7777 (xmlStrchr(child->content, '>') == NULL) &&
7778 (xmlStrchr(child->content, '&') == NULL)) {
7779 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7780 } else {
7781 xmlOutputBufferWriteString(buf, "<![CDATA[");
7782 if (child->content != NULL)
7783 xmlOutputBufferWriteString(buf,
7784 (const char *)child->content);
7785 xmlOutputBufferWriteString(buf, "]]>");
7786 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007787 } else {
7788 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7789 }
7790 child = child->next;
7791 }
7792 } else if (cur->children != NULL) {
7793 if (format) xmlOutputBufferWriteString(buf, "\n");
7794 xhtmlNodeListDumpOutput(buf, doc, cur->children,
7795 (level >= 0?level+1:-1), format, encoding);
7796 if ((xmlIndentTreeOutput) && (format))
7797 for (i = 0;i < level;i++)
7798 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7799 }
7800 xmlOutputBufferWriteString(buf, "</");
7801 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7802 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7803 xmlOutputBufferWriteString(buf, ":");
7804 }
7805
7806 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7807 xmlOutputBufferWriteString(buf, ">");
7808}
7809#endif
7810
Owen Taylor3473f882001-02-23 17:55:21 +00007811/************************************************************************
7812 * *
7813 * Saving functions front-ends *
7814 * *
7815 ************************************************************************/
7816
7817/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00007818 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00007819 * @out_doc: Document to generate XML text from
7820 * @doc_txt_ptr: Memory pointer for allocated XML text
7821 * @doc_txt_len: Length of the generated XML text
7822 * @txt_encoding: Character encoding to use when generating XML text
7823 * @format: should formatting spaces been added
7824 *
7825 * Dump the current DOM tree into memory using the character encoding specified
7826 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007827 * allocated memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00007828 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007829 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007830 */
7831
7832void
7833xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007834 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007835 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007836 int dummy = 0;
7837
Owen Taylor3473f882001-02-23 17:55:21 +00007838 xmlOutputBufferPtr out_buff = NULL;
7839 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
7840
7841 if (doc_txt_len == NULL) {
7842 doc_txt_len = &dummy; /* Continue, caller just won't get length */
7843 }
7844
7845 if (doc_txt_ptr == NULL) {
7846 *doc_txt_len = 0;
7847 xmlGenericError(xmlGenericErrorContext,
7848 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
7849 return;
7850 }
7851
7852 *doc_txt_ptr = NULL;
7853 *doc_txt_len = 0;
7854
7855 if (out_doc == NULL) {
7856 /* No document, no output */
7857 xmlGenericError(xmlGenericErrorContext,
7858 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
7859 return;
7860 }
7861
7862 /*
7863 * Validate the encoding value, if provided.
7864 * This logic is copied from xmlSaveFileEnc.
7865 */
7866
7867 if (txt_encoding == NULL)
7868 txt_encoding = (const char *) out_doc->encoding;
7869 if (txt_encoding != NULL) {
Daniel Veillarde1326112003-06-05 09:32:20 +00007870 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007871 if ( conv_hdlr == NULL ) {
7872 xmlGenericError(xmlGenericErrorContext,
7873 "%s: %s %s '%s'\n",
7874 "xmlDocDumpFormatMemoryEnc",
7875 "Failed to identify encoding handler for",
7876 "character set",
7877 txt_encoding);
7878 return;
7879 }
7880 }
Owen Taylor3473f882001-02-23 17:55:21 +00007881
7882 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
7883 xmlGenericError(xmlGenericErrorContext,
7884 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
7885 return;
7886 }
7887
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007888 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007889 xmlOutputBufferFlush(out_buff);
7890 if (out_buff->conv != NULL) {
7891 *doc_txt_len = out_buff->conv->use;
7892 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
7893 } else {
7894 *doc_txt_len = out_buff->buffer->use;
7895 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
7896 }
7897 (void)xmlOutputBufferClose(out_buff);
7898
7899 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
7900 *doc_txt_len = 0;
7901 xmlGenericError(xmlGenericErrorContext,
7902 "xmlDocDumpFormatMemoryEnc: %s\n",
7903 "Failed to allocate memory for document text representation.");
7904 }
7905
7906 return;
7907}
7908
7909/**
7910 * xmlDocDumpMemory:
7911 * @cur: the document
7912 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007913 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007914 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007915 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007916 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007917 */
7918void
7919xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
7920 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
7921}
7922
7923/**
7924 * xmlDocDumpFormatMemory:
7925 * @cur: the document
7926 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007927 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007928 * @format: should formatting spaces been added
7929 *
7930 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007931 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007932 * It's up to the caller to free the memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00007933 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007934 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007935 */
7936void
7937xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
7938 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
7939}
7940
7941/**
7942 * xmlDocDumpMemoryEnc:
7943 * @out_doc: Document to generate XML text from
7944 * @doc_txt_ptr: Memory pointer for allocated XML text
7945 * @doc_txt_len: Length of the generated XML text
7946 * @txt_encoding: Character encoding to use when generating XML text
7947 *
7948 * Dump the current DOM tree into memory using the character encoding specified
7949 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007950 * allocated memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007951 */
7952
7953void
7954xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
7955 int * doc_txt_len, const char * txt_encoding) {
7956 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007957 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007958}
7959
7960/**
7961 * xmlGetDocCompressMode:
7962 * @doc: the document
7963 *
7964 * get the compression ratio for a document, ZLIB based
7965 * Returns 0 (uncompressed) to 9 (max compression)
7966 */
7967int
7968xmlGetDocCompressMode (xmlDocPtr doc) {
7969 if (doc == NULL) return(-1);
7970 return(doc->compression);
7971}
7972
7973/**
7974 * xmlSetDocCompressMode:
7975 * @doc: the document
7976 * @mode: the compression ratio
7977 *
7978 * set the compression ratio for a document, ZLIB based
7979 * Correct values: 0 (uncompressed) to 9 (max compression)
7980 */
7981void
7982xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7983 if (doc == NULL) return;
7984 if (mode < 0) doc->compression = 0;
7985 else if (mode > 9) doc->compression = 9;
7986 else doc->compression = mode;
7987}
7988
7989/**
7990 * xmlGetCompressMode:
7991 *
7992 * get the default compression mode used, ZLIB based.
7993 * Returns 0 (uncompressed) to 9 (max compression)
7994 */
7995int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007996xmlGetCompressMode(void)
7997{
7998 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00007999}
8000
8001/**
8002 * xmlSetCompressMode:
8003 * @mode: the compression ratio
8004 *
8005 * set the default compression mode used, ZLIB based
8006 * Correct values: 0 (uncompressed) to 9 (max compression)
8007 */
8008void
8009xmlSetCompressMode(int mode) {
8010 if (mode < 0) xmlCompressMode = 0;
8011 else if (mode > 9) xmlCompressMode = 9;
8012 else xmlCompressMode = mode;
8013}
8014
8015/**
Daniel Veillard9e412302002-06-10 15:59:44 +00008016 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00008017 * @f: the FILE*
8018 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00008019 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00008020 *
8021 * Dump an XML document to an open FILE.
8022 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008023 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008024 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8025 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008026 */
8027int
Daniel Veillard9e412302002-06-10 15:59:44 +00008028xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00008029 xmlOutputBufferPtr buf;
8030 const char * encoding;
8031 xmlCharEncodingHandlerPtr handler = NULL;
8032 int ret;
8033
8034 if (cur == NULL) {
8035#ifdef DEBUG_TREE
8036 xmlGenericError(xmlGenericErrorContext,
8037 "xmlDocDump : document == NULL\n");
8038#endif
8039 return(-1);
8040 }
8041 encoding = (const char *) cur->encoding;
8042
8043 if (encoding != NULL) {
Daniel Veillarde1326112003-06-05 09:32:20 +00008044 handler = xmlFindCharEncodingHandler(encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00008045 if (handler == NULL) {
8046 xmlFree((char *) cur->encoding);
8047 cur->encoding = NULL;
8048 }
8049 }
Owen Taylor3473f882001-02-23 17:55:21 +00008050 buf = xmlOutputBufferCreateFile(f, handler);
8051 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00008052 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008053
8054 ret = xmlOutputBufferClose(buf);
8055 return(ret);
8056}
8057
8058/**
Daniel Veillard9e412302002-06-10 15:59:44 +00008059 * xmlDocDump:
8060 * @f: the FILE*
8061 * @cur: the document
8062 *
8063 * Dump an XML document to an open FILE.
8064 *
8065 * returns: the number of bytes written or -1 in case of failure.
8066 */
8067int
8068xmlDocDump(FILE *f, xmlDocPtr cur) {
8069 return(xmlDocFormatDump (f, cur, 0));
8070}
8071
8072/**
Owen Taylor3473f882001-02-23 17:55:21 +00008073 * xmlSaveFileTo:
8074 * @buf: an output I/O buffer
8075 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00008076 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00008077 *
8078 * Dump an XML document to an I/O buffer.
8079 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008080 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008081 */
8082int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00008083xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00008084 int ret;
8085
8086 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008087 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008088 ret = xmlOutputBufferClose(buf);
8089 return(ret);
8090}
8091
8092/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00008093 * xmlSaveFormatFileTo:
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
Daniel Veillardeefd4492001-04-28 16:55:50 +00008097 * @format: should formatting spaces been added
8098 *
8099 * Dump an XML document to an I/O buffer.
8100 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008101 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008102 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8103 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardeefd4492001-04-28 16:55:50 +00008104 */
8105int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00008106xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00008107 int ret;
8108
8109 if (buf == NULL) return(0);
8110 xmlDocContentDumpOutput(buf, cur, encoding, format);
8111 ret = xmlOutputBufferClose(buf);
8112 return(ret);
8113}
8114
8115/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00008116 * xmlSaveFormatFileEnc:
Daniel Veillardf012a642001-07-23 19:10:52 +00008117 * @filename: the filename or URL to output
8118 * @cur: the document being saved
8119 * @encoding: the name of the encoding to use or NULL.
8120 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00008121 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00008122 * Dump an XML document to a file or an URL.
8123 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008124 * Returns the number of bytes written or -1 in case of error.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008125 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8126 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008127 */
8128int
Daniel Veillardf012a642001-07-23 19:10:52 +00008129xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
8130 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00008131 xmlOutputBufferPtr buf;
8132 xmlCharEncodingHandlerPtr handler = NULL;
8133 int ret;
8134
Daniel Veillard4dbe77a2003-01-14 00:17:42 +00008135 if (cur == NULL)
8136 return(-1);
8137
Daniel Veillardfb25a512002-01-13 20:32:08 +00008138 if (encoding == NULL)
8139 encoding = (const char *) cur->encoding;
8140
Owen Taylor3473f882001-02-23 17:55:21 +00008141 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00008142
Owen Taylor3473f882001-02-23 17:55:21 +00008143 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00008144 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00008145 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00008146 }
8147
Daniel Veillardf012a642001-07-23 19:10:52 +00008148#ifdef HAVE_ZLIB_H
8149 if (cur->compression < 0) cur->compression = xmlCompressMode;
8150#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008151 /*
8152 * save the content to a temp buffer.
8153 */
Daniel Veillardf012a642001-07-23 19:10:52 +00008154 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00008155 if (buf == NULL) return(-1);
8156
Daniel Veillardf012a642001-07-23 19:10:52 +00008157 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008158
8159 ret = xmlOutputBufferClose(buf);
8160 return(ret);
8161}
8162
Daniel Veillardf012a642001-07-23 19:10:52 +00008163
8164/**
8165 * xmlSaveFileEnc:
8166 * @filename: the filename (or URL)
8167 * @cur: the document
8168 * @encoding: the name of an encoding (or NULL)
8169 *
8170 * Dump an XML document, converting it to the given encoding
8171 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008172 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00008173 */
8174int
8175xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
8176 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
8177}
8178
Owen Taylor3473f882001-02-23 17:55:21 +00008179/**
Daniel Veillard67fee942001-04-26 18:59:03 +00008180 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00008181 * @filename: the filename (or URL)
8182 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00008183 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00008184 *
8185 * Dump an XML document to a file. Will use compression if
8186 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00008187 * used. If @format is set then the document will be indented on output.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008188 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8189 * or xmlKeepBlanksDefault(0) was called
Daniel Veillard67fee942001-04-26 18:59:03 +00008190 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008191 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008192 */
8193int
Daniel Veillard67fee942001-04-26 18:59:03 +00008194xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008195 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00008196}
8197
Daniel Veillard67fee942001-04-26 18:59:03 +00008198/**
8199 * xmlSaveFile:
8200 * @filename: the filename (or URL)
8201 * @cur: the document
8202 *
8203 * Dump an XML document to a file. Will use compression if
8204 * compiled in and enabled. If @filename is "-" the stdout file is
8205 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00008206 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00008207 */
8208int
8209xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008210 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00008211}
8212