blob: b2445f0081cbdab23d3a47edc780d4937550151b [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;
907 if (c->type == XML_COMMENT_NODE) {
908 xmlUnlinkNode(c);
909 xmlFreeNode(c);
910 }
911 c = next;
912 }
913 }
914 if (cur->name != NULL) xmlFree((char *) cur->name);
915 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
916 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
917 /* TODO !!! */
918 if (cur->notations != NULL)
919 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
920
921 if (cur->elements != NULL)
922 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
923 if (cur->attributes != NULL)
924 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
925 if (cur->entities != NULL)
926 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
927 if (cur->pentities != NULL)
928 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
929
Owen Taylor3473f882001-02-23 17:55:21 +0000930 xmlFree(cur);
931}
932
933/**
934 * xmlNewDoc:
935 * @version: xmlChar string giving the version of XML "1.0"
936 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000937 * Creates a new XML document
938 *
Owen Taylor3473f882001-02-23 17:55:21 +0000939 * Returns a new document
940 */
941xmlDocPtr
942xmlNewDoc(const xmlChar *version) {
943 xmlDocPtr cur;
944
945 if (version == NULL)
946 version = (const xmlChar *) "1.0";
947
948 /*
949 * Allocate a new document and fill the fields.
950 */
951 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
952 if (cur == NULL) {
953 xmlGenericError(xmlGenericErrorContext,
954 "xmlNewDoc : malloc failed\n");
955 return(NULL);
956 }
957 memset(cur, 0, sizeof(xmlDoc));
958 cur->type = XML_DOCUMENT_NODE;
959
960 cur->version = xmlStrdup(version);
961 cur->standalone = -1;
962 cur->compression = -1; /* not initialized */
963 cur->doc = cur;
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000964 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +0000965
Daniel Veillarda880b122003-04-21 21:36:41 +0000966 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000967 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000968 return(cur);
969}
970
971/**
972 * xmlFreeDoc:
973 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +0000974 *
975 * Free up all the structures used by a document, tree included.
976 */
977void
978xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +0000979 xmlDtdPtr extSubset, intSubset;
980
Owen Taylor3473f882001-02-23 17:55:21 +0000981 if (cur == NULL) {
982#ifdef DEBUG_TREE
983 xmlGenericError(xmlGenericErrorContext,
984 "xmlFreeDoc : document == NULL\n");
985#endif
986 return;
987 }
Daniel Veillard5335dc52003-01-01 20:59:38 +0000988
Daniel Veillarda880b122003-04-21 21:36:41 +0000989 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000990 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
991
Daniel Veillard76d66f42001-05-16 21:05:17 +0000992 /*
993 * Do this before freeing the children list to avoid ID lookups
994 */
995 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
996 cur->ids = NULL;
997 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
998 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000999 extSubset = cur->extSubset;
1000 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +00001001 if (intSubset == extSubset)
1002 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001003 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001004 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001005 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001006 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001007 }
Daniel Veillarda9142e72001-06-19 11:07:54 +00001008 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001009 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001010 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001011 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001012 }
1013
1014 if (cur->children != NULL) xmlFreeNodeList(cur->children);
1015
Owen Taylor3473f882001-02-23 17:55:21 +00001016 if (cur->version != NULL) xmlFree((char *) cur->version);
1017 if (cur->name != NULL) xmlFree((char *) cur->name);
1018 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00001019 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00001020 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Owen Taylor3473f882001-02-23 17:55:21 +00001021 xmlFree(cur);
1022}
1023
1024/**
1025 * xmlStringLenGetNodeList:
1026 * @doc: the document
1027 * @value: the value of the text
1028 * @len: the length of the string value
1029 *
1030 * Parse the value string and build the node list associated. Should
1031 * produce a flat tree with only TEXTs and ENTITY_REFs.
1032 * Returns a pointer to the first child
1033 */
1034xmlNodePtr
1035xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1036 xmlNodePtr ret = NULL, last = NULL;
1037 xmlNodePtr node;
1038 xmlChar *val;
1039 const xmlChar *cur = value;
1040 const xmlChar *q;
1041 xmlEntityPtr ent;
1042
1043 if (value == NULL) return(NULL);
1044
1045 q = cur;
1046 while ((*cur != 0) && (cur - value < len)) {
1047 if (*cur == '&') {
1048 /*
1049 * Save the current text.
1050 */
1051 if (cur != q) {
1052 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1053 xmlNodeAddContentLen(last, q, cur - q);
1054 } else {
1055 node = xmlNewDocTextLen(doc, q, cur - q);
1056 if (node == NULL) return(ret);
1057 if (last == NULL)
1058 last = ret = node;
1059 else {
1060 last->next = node;
1061 node->prev = last;
1062 last = node;
1063 }
1064 }
1065 }
1066 /*
1067 * Read the entity string
1068 */
1069 cur++;
1070 q = cur;
1071 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
1072 if ((*cur == 0) || (cur - value >= len)) {
1073#ifdef DEBUG_TREE
1074 xmlGenericError(xmlGenericErrorContext,
1075 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
1076#endif
1077 return(ret);
1078 }
1079 if (cur != q) {
1080 /*
1081 * Predefined entities don't generate nodes
1082 */
1083 val = xmlStrndup(q, cur - q);
1084 ent = xmlGetDocEntity(doc, val);
1085 if ((ent != NULL) &&
1086 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1087 if (last == NULL) {
1088 node = xmlNewDocText(doc, ent->content);
1089 last = ret = node;
1090 } else
1091 xmlNodeAddContent(last, ent->content);
1092
1093 } else {
1094 /*
1095 * Create a new REFERENCE_REF node
1096 */
1097 node = xmlNewReference(doc, val);
1098 if (node == NULL) {
1099 if (val != NULL) xmlFree(val);
1100 return(ret);
1101 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001102 else if ((ent != NULL) && (ent->children == NULL)) {
1103 xmlNodePtr tmp;
1104
1105 ent->children =
1106 xmlStringGetNodeList(doc, (const xmlChar*)node->content);
1107 tmp = ent->children;
1108 while (tmp) {
1109 tmp->parent = (xmlNodePtr)ent;
1110 tmp = tmp->next;
1111 }
1112 }
Owen Taylor3473f882001-02-23 17:55:21 +00001113 if (last == NULL)
1114 last = ret = node;
1115 else {
1116 last->next = node;
1117 node->prev = last;
1118 last = node;
1119 }
1120 }
1121 xmlFree(val);
1122 }
1123 cur++;
1124 q = cur;
1125 } else
1126 cur++;
1127 }
1128 if (cur != q) {
1129 /*
1130 * Handle the last piece of text.
1131 */
1132 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1133 xmlNodeAddContentLen(last, q, cur - q);
1134 } else {
1135 node = xmlNewDocTextLen(doc, q, cur - q);
1136 if (node == NULL) return(ret);
1137 if (last == NULL)
1138 last = ret = node;
1139 else {
1140 last->next = node;
1141 node->prev = last;
1142 last = node;
1143 }
1144 }
1145 }
1146 return(ret);
1147}
1148
1149/**
1150 * xmlStringGetNodeList:
1151 * @doc: the document
1152 * @value: the value of the attribute
1153 *
1154 * Parse the value string and build the node list associated. Should
1155 * produce a flat tree with only TEXTs and ENTITY_REFs.
1156 * Returns a pointer to the first child
1157 */
1158xmlNodePtr
1159xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1160 xmlNodePtr ret = NULL, last = NULL;
1161 xmlNodePtr node;
1162 xmlChar *val;
1163 const xmlChar *cur = value;
1164 const xmlChar *q;
1165 xmlEntityPtr ent;
1166
1167 if (value == NULL) return(NULL);
1168
1169 q = cur;
1170 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001171 if (cur[0] == '&') {
1172 int charval = 0;
1173 xmlChar tmp;
1174
Owen Taylor3473f882001-02-23 17:55:21 +00001175 /*
1176 * Save the current text.
1177 */
1178 if (cur != q) {
1179 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1180 xmlNodeAddContentLen(last, q, cur - q);
1181 } else {
1182 node = xmlNewDocTextLen(doc, q, cur - q);
1183 if (node == NULL) return(ret);
1184 if (last == NULL)
1185 last = ret = node;
1186 else {
1187 last->next = node;
1188 node->prev = last;
1189 last = node;
1190 }
1191 }
1192 }
Owen Taylor3473f882001-02-23 17:55:21 +00001193 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001194 if ((cur[1] == '#') && (cur[2] == 'x')) {
1195 cur += 3;
1196 tmp = *cur;
1197 while (tmp != ';') { /* Non input consuming loop */
1198 if ((tmp >= '0') && (tmp <= '9'))
1199 charval = charval * 16 + (tmp - '0');
1200 else if ((tmp >= 'a') && (tmp <= 'f'))
1201 charval = charval * 16 + (tmp - 'a') + 10;
1202 else if ((tmp >= 'A') && (tmp <= 'F'))
1203 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001204 else {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001205 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001206 "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001207 charval = 0;
1208 break;
1209 }
1210 cur++;
1211 tmp = *cur;
1212 }
1213 if (tmp == ';')
1214 cur++;
1215 q = cur;
1216 } else if (cur[1] == '#') {
1217 cur += 2;
1218 tmp = *cur;
1219 while (tmp != ';') { /* Non input consuming loops */
1220 if ((tmp >= '0') && (tmp <= '9'))
1221 charval = charval * 10 + (tmp - '0');
1222 else {
1223 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001224 "xmlStringGetNodeList: invalid decimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001225 charval = 0;
1226 break;
1227 }
1228 cur++;
1229 tmp = *cur;
1230 }
1231 if (tmp == ';')
1232 cur++;
1233 q = cur;
1234 } else {
1235 /*
1236 * Read the entity string
1237 */
1238 cur++;
1239 q = cur;
1240 while ((*cur != 0) && (*cur != ';')) cur++;
1241 if (*cur == 0) {
1242#ifdef DEBUG_TREE
1243 xmlGenericError(xmlGenericErrorContext,
1244 "xmlStringGetNodeList: unterminated entity %30s\n", q);
1245#endif
1246 return(ret);
1247 }
1248 if (cur != q) {
1249 /*
1250 * Predefined entities don't generate nodes
1251 */
1252 val = xmlStrndup(q, cur - q);
1253 ent = xmlGetDocEntity(doc, val);
1254 if ((ent != NULL) &&
1255 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1256 if (last == NULL) {
1257 node = xmlNewDocText(doc, ent->content);
1258 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001259 } else if (last->type != XML_TEXT_NODE) {
1260 node = xmlNewDocText(doc, ent->content);
1261 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001262 } else
1263 xmlNodeAddContent(last, ent->content);
1264
1265 } else {
1266 /*
1267 * Create a new REFERENCE_REF node
1268 */
1269 node = xmlNewReference(doc, val);
1270 if (node == NULL) {
1271 if (val != NULL) xmlFree(val);
1272 return(ret);
1273 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001274 else if ((ent != NULL) && (ent->children == NULL)) {
1275 xmlNodePtr temp;
1276
1277 ent->children = xmlStringGetNodeList(doc,
1278 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001279 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001280 temp = ent->children;
1281 while (temp) {
1282 temp->parent = (xmlNodePtr)ent;
1283 temp = temp->next;
1284 }
1285 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001286 if (last == NULL) {
1287 last = ret = node;
1288 } else {
1289 last = xmlAddNextSibling(last, node);
1290 }
1291 }
1292 xmlFree(val);
1293 }
1294 cur++;
1295 q = cur;
1296 }
1297 if (charval != 0) {
1298 xmlChar buf[10];
1299 int len;
1300
1301 len = xmlCopyCharMultiByte(buf, charval);
1302 buf[len] = 0;
1303 node = xmlNewDocText(doc, buf);
1304 if (node != NULL) {
1305 if (last == NULL) {
1306 last = ret = node;
1307 } else {
1308 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001309 }
1310 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001311
1312 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001313 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001314 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001315 cur++;
1316 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001317 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001318 /*
1319 * Handle the last piece of text.
1320 */
1321 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1322 xmlNodeAddContentLen(last, q, cur - q);
1323 } else {
1324 node = xmlNewDocTextLen(doc, q, cur - q);
1325 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001326 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001327 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001328 } else {
1329 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001330 }
1331 }
1332 }
1333 return(ret);
1334}
1335
1336/**
1337 * xmlNodeListGetString:
1338 * @doc: the document
1339 * @list: a Node list
1340 * @inLine: should we replace entity contents or show their external form
1341 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001342 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001343 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001344 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001345 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001346 */
1347xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001348xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1349{
Owen Taylor3473f882001-02-23 17:55:21 +00001350 xmlNodePtr node = list;
1351 xmlChar *ret = NULL;
1352 xmlEntityPtr ent;
1353
Daniel Veillard7646b182002-04-20 06:41:40 +00001354 if (list == NULL)
1355 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001356
1357 while (node != NULL) {
1358 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001359 (node->type == XML_CDATA_SECTION_NODE)) {
1360 if (inLine) {
1361 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001362 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001363 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001364
Daniel Veillard7646b182002-04-20 06:41:40 +00001365 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1366 if (buffer != NULL) {
1367 ret = xmlStrcat(ret, buffer);
1368 xmlFree(buffer);
1369 }
1370 }
1371 } else if (node->type == XML_ENTITY_REF_NODE) {
1372 if (inLine) {
1373 ent = xmlGetDocEntity(doc, node->name);
1374 if (ent != NULL) {
1375 xmlChar *buffer;
1376
1377 /* an entity content can be any "well balanced chunk",
1378 * i.e. the result of the content [43] production:
1379 * http://www.w3.org/TR/REC-xml#NT-content.
1380 * So it can contain text, CDATA section or nested
1381 * entity reference nodes (among others).
1382 * -> we recursive call xmlNodeListGetString()
1383 * which handles these types */
1384 buffer = xmlNodeListGetString(doc, ent->children, 1);
1385 if (buffer != NULL) {
1386 ret = xmlStrcat(ret, buffer);
1387 xmlFree(buffer);
1388 }
1389 } else {
1390 ret = xmlStrcat(ret, node->content);
1391 }
1392 } else {
1393 xmlChar buf[2];
1394
1395 buf[0] = '&';
1396 buf[1] = 0;
1397 ret = xmlStrncat(ret, buf, 1);
1398 ret = xmlStrcat(ret, node->name);
1399 buf[0] = ';';
1400 buf[1] = 0;
1401 ret = xmlStrncat(ret, buf, 1);
1402 }
1403 }
1404#if 0
1405 else {
1406 xmlGenericError(xmlGenericErrorContext,
1407 "xmlGetNodeListString : invalid node type %d\n",
1408 node->type);
1409 }
1410#endif
1411 node = node->next;
1412 }
1413 return (ret);
1414}
Owen Taylor3473f882001-02-23 17:55:21 +00001415/**
1416 * xmlNodeListGetRawString:
1417 * @doc: the document
1418 * @list: a Node list
1419 * @inLine: should we replace entity contents or show their external form
1420 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001421 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001422 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1423 * this function doesn't do any character encoding handling.
1424 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001425 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001426 */
1427xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001428xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1429{
Owen Taylor3473f882001-02-23 17:55:21 +00001430 xmlNodePtr node = list;
1431 xmlChar *ret = NULL;
1432 xmlEntityPtr ent;
1433
Daniel Veillard7646b182002-04-20 06:41:40 +00001434 if (list == NULL)
1435 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001436
1437 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001438 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001439 (node->type == XML_CDATA_SECTION_NODE)) {
1440 if (inLine) {
1441 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001442 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001443 xmlChar *buffer;
1444
1445 buffer = xmlEncodeSpecialChars(doc, node->content);
1446 if (buffer != NULL) {
1447 ret = xmlStrcat(ret, buffer);
1448 xmlFree(buffer);
1449 }
1450 }
1451 } else if (node->type == XML_ENTITY_REF_NODE) {
1452 if (inLine) {
1453 ent = xmlGetDocEntity(doc, node->name);
1454 if (ent != NULL) {
1455 xmlChar *buffer;
1456
1457 /* an entity content can be any "well balanced chunk",
1458 * i.e. the result of the content [43] production:
1459 * http://www.w3.org/TR/REC-xml#NT-content.
1460 * So it can contain text, CDATA section or nested
1461 * entity reference nodes (among others).
1462 * -> we recursive call xmlNodeListGetRawString()
1463 * which handles these types */
1464 buffer =
1465 xmlNodeListGetRawString(doc, ent->children, 1);
1466 if (buffer != NULL) {
1467 ret = xmlStrcat(ret, buffer);
1468 xmlFree(buffer);
1469 }
1470 } else {
1471 ret = xmlStrcat(ret, node->content);
1472 }
1473 } else {
1474 xmlChar buf[2];
1475
1476 buf[0] = '&';
1477 buf[1] = 0;
1478 ret = xmlStrncat(ret, buf, 1);
1479 ret = xmlStrcat(ret, node->name);
1480 buf[0] = ';';
1481 buf[1] = 0;
1482 ret = xmlStrncat(ret, buf, 1);
1483 }
1484 }
Owen Taylor3473f882001-02-23 17:55:21 +00001485#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001486 else {
1487 xmlGenericError(xmlGenericErrorContext,
1488 "xmlGetNodeListString : invalid node type %d\n",
1489 node->type);
1490 }
Owen Taylor3473f882001-02-23 17:55:21 +00001491#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001492 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001493 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001494 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001495}
1496
1497/**
1498 * xmlNewProp:
1499 * @node: the holding node
1500 * @name: the name of the attribute
1501 * @value: the value of the attribute
1502 *
1503 * Create a new property carried by a node.
1504 * Returns a pointer to the attribute
1505 */
1506xmlAttrPtr
1507xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1508 xmlAttrPtr cur;
1509 xmlDocPtr doc = NULL;
1510
1511 if (name == NULL) {
1512#ifdef DEBUG_TREE
1513 xmlGenericError(xmlGenericErrorContext,
1514 "xmlNewProp : name == NULL\n");
1515#endif
1516 return(NULL);
1517 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00001518 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
1519 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001520
1521 /*
1522 * Allocate a new property and fill the fields.
1523 */
1524 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1525 if (cur == NULL) {
1526 xmlGenericError(xmlGenericErrorContext,
1527 "xmlNewProp : malloc failed\n");
1528 return(NULL);
1529 }
1530 memset(cur, 0, sizeof(xmlAttr));
1531 cur->type = XML_ATTRIBUTE_NODE;
1532
1533 cur->parent = node;
1534 if (node != NULL) {
1535 doc = node->doc;
1536 cur->doc = doc;
1537 }
1538 cur->name = xmlStrdup(name);
1539 if (value != NULL) {
1540 xmlChar *buffer;
1541 xmlNodePtr tmp;
1542
1543 buffer = xmlEncodeEntitiesReentrant(doc, value);
1544 cur->children = xmlStringGetNodeList(doc, buffer);
1545 cur->last = NULL;
1546 tmp = cur->children;
1547 while (tmp != NULL) {
1548 tmp->parent = (xmlNodePtr) cur;
1549 tmp->doc = doc;
1550 if (tmp->next == NULL)
1551 cur->last = tmp;
1552 tmp = tmp->next;
1553 }
1554 xmlFree(buffer);
1555 }
1556
1557 /*
1558 * Add it at the end to preserve parsing order ...
1559 */
1560 if (node != NULL) {
1561 if (node->properties == NULL) {
1562 node->properties = cur;
1563 } else {
1564 xmlAttrPtr prev = node->properties;
1565
1566 while (prev->next != NULL) prev = prev->next;
1567 prev->next = cur;
1568 cur->prev = prev;
1569 }
1570 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001571
Daniel Veillarda880b122003-04-21 21:36:41 +00001572 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001573 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001574 return(cur);
1575}
1576
1577/**
1578 * xmlNewNsProp:
1579 * @node: the holding node
1580 * @ns: the namespace
1581 * @name: the name of the attribute
1582 * @value: the value of the attribute
1583 *
1584 * Create a new property tagged with a namespace and carried by a node.
1585 * Returns a pointer to the attribute
1586 */
1587xmlAttrPtr
1588xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1589 const xmlChar *value) {
1590 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001591 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001592
1593 if (name == NULL) {
1594#ifdef DEBUG_TREE
1595 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001596 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001597#endif
1598 return(NULL);
1599 }
1600
1601 /*
1602 * Allocate a new property and fill the fields.
1603 */
1604 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1605 if (cur == NULL) {
1606 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001607 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001608 return(NULL);
1609 }
1610 memset(cur, 0, sizeof(xmlAttr));
1611 cur->type = XML_ATTRIBUTE_NODE;
1612
1613 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001614 if (node != NULL) {
1615 doc = node->doc;
1616 cur->doc = doc;
1617 }
Owen Taylor3473f882001-02-23 17:55:21 +00001618 cur->ns = ns;
1619 cur->name = xmlStrdup(name);
1620 if (value != NULL) {
1621 xmlChar *buffer;
1622 xmlNodePtr tmp;
1623
Daniel Veillarda682b212001-06-07 19:59:42 +00001624 buffer = xmlEncodeEntitiesReentrant(doc, value);
1625 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001626 cur->last = NULL;
1627 tmp = cur->children;
1628 while (tmp != NULL) {
1629 tmp->parent = (xmlNodePtr) cur;
1630 if (tmp->next == NULL)
1631 cur->last = tmp;
1632 tmp = tmp->next;
1633 }
1634 xmlFree(buffer);
1635 }
1636
1637 /*
1638 * Add it at the end to preserve parsing order ...
1639 */
1640 if (node != NULL) {
1641 if (node->properties == NULL) {
1642 node->properties = cur;
1643 } else {
1644 xmlAttrPtr prev = node->properties;
1645
1646 while (prev->next != NULL) prev = prev->next;
1647 prev->next = cur;
1648 cur->prev = prev;
1649 }
1650 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001651
Daniel Veillarda880b122003-04-21 21:36:41 +00001652 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001653 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001654 return(cur);
1655}
1656
1657/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001658 * xmlNewNsPropEatName:
1659 * @node: the holding node
1660 * @ns: the namespace
1661 * @name: the name of the attribute
1662 * @value: the value of the attribute
1663 *
1664 * Create a new property tagged with a namespace and carried by a node.
1665 * Returns a pointer to the attribute
1666 */
1667xmlAttrPtr
1668xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1669 const xmlChar *value) {
1670 xmlAttrPtr cur;
1671 xmlDocPtr doc = NULL;
1672
1673 if (name == NULL) {
1674#ifdef DEBUG_TREE
1675 xmlGenericError(xmlGenericErrorContext,
1676 "xmlNewNsPropEatName : name == NULL\n");
1677#endif
1678 return(NULL);
1679 }
1680
1681 /*
1682 * Allocate a new property and fill the fields.
1683 */
1684 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1685 if (cur == NULL) {
1686 xmlGenericError(xmlGenericErrorContext,
1687 "xmlNewNsPropEatName : malloc failed\n");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001688 xmlFree(name);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001689 return(NULL);
1690 }
1691 memset(cur, 0, sizeof(xmlAttr));
1692 cur->type = XML_ATTRIBUTE_NODE;
1693
1694 cur->parent = node;
1695 if (node != NULL) {
1696 doc = node->doc;
1697 cur->doc = doc;
1698 }
1699 cur->ns = ns;
1700 cur->name = name;
1701 if (value != NULL) {
1702 xmlChar *buffer;
1703 xmlNodePtr tmp;
1704
1705 buffer = xmlEncodeEntitiesReentrant(doc, value);
1706 cur->children = xmlStringGetNodeList(doc, buffer);
1707 cur->last = NULL;
1708 tmp = cur->children;
1709 while (tmp != NULL) {
1710 tmp->parent = (xmlNodePtr) cur;
1711 if (tmp->next == NULL)
1712 cur->last = tmp;
1713 tmp = tmp->next;
1714 }
1715 xmlFree(buffer);
1716 }
1717
1718 /*
1719 * Add it at the end to preserve parsing order ...
1720 */
1721 if (node != NULL) {
1722 if (node->properties == NULL) {
1723 node->properties = cur;
1724 } else {
1725 xmlAttrPtr prev = node->properties;
1726
1727 while (prev->next != NULL) prev = prev->next;
1728 prev->next = cur;
1729 cur->prev = prev;
1730 }
1731 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001732
Daniel Veillarda880b122003-04-21 21:36:41 +00001733 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001734 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001735 return(cur);
1736}
1737
1738/**
Owen Taylor3473f882001-02-23 17:55:21 +00001739 * xmlNewDocProp:
1740 * @doc: the document
1741 * @name: the name of the attribute
1742 * @value: the value of the attribute
1743 *
1744 * Create a new property carried by a document.
1745 * Returns a pointer to the attribute
1746 */
1747xmlAttrPtr
1748xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1749 xmlAttrPtr cur;
1750
1751 if (name == NULL) {
1752#ifdef DEBUG_TREE
1753 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001754 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001755#endif
1756 return(NULL);
1757 }
1758
1759 /*
1760 * Allocate a new property and fill the fields.
1761 */
1762 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1763 if (cur == NULL) {
1764 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001765 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001766 return(NULL);
1767 }
1768 memset(cur, 0, sizeof(xmlAttr));
1769 cur->type = XML_ATTRIBUTE_NODE;
1770
1771 cur->name = xmlStrdup(name);
1772 cur->doc = doc;
1773 if (value != NULL) {
1774 xmlNodePtr tmp;
1775
1776 cur->children = xmlStringGetNodeList(doc, value);
1777 cur->last = NULL;
1778
1779 tmp = cur->children;
1780 while (tmp != NULL) {
1781 tmp->parent = (xmlNodePtr) cur;
1782 if (tmp->next == NULL)
1783 cur->last = tmp;
1784 tmp = tmp->next;
1785 }
1786 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001787
Daniel Veillarda880b122003-04-21 21:36:41 +00001788 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001789 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001790 return(cur);
1791}
1792
1793/**
1794 * xmlFreePropList:
1795 * @cur: the first property in the list
1796 *
1797 * Free a property and all its siblings, all the children are freed too.
1798 */
1799void
1800xmlFreePropList(xmlAttrPtr cur) {
1801 xmlAttrPtr next;
1802 if (cur == NULL) {
1803#ifdef DEBUG_TREE
1804 xmlGenericError(xmlGenericErrorContext,
1805 "xmlFreePropList : property == NULL\n");
1806#endif
1807 return;
1808 }
1809 while (cur != NULL) {
1810 next = cur->next;
1811 xmlFreeProp(cur);
1812 cur = next;
1813 }
1814}
1815
1816/**
1817 * xmlFreeProp:
1818 * @cur: an attribute
1819 *
1820 * Free one attribute, all the content is freed too
1821 */
1822void
1823xmlFreeProp(xmlAttrPtr cur) {
1824 if (cur == NULL) {
1825#ifdef DEBUG_TREE
1826 xmlGenericError(xmlGenericErrorContext,
1827 "xmlFreeProp : property == NULL\n");
1828#endif
1829 return;
1830 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001831
Daniel Veillarda880b122003-04-21 21:36:41 +00001832 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001833 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1834
Owen Taylor3473f882001-02-23 17:55:21 +00001835 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001836 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1837 ((cur->parent->doc->intSubset != NULL) ||
1838 (cur->parent->doc->extSubset != NULL))) {
1839 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1840 xmlRemoveID(cur->parent->doc, cur);
1841 }
Owen Taylor3473f882001-02-23 17:55:21 +00001842 if (cur->name != NULL) xmlFree((char *) cur->name);
1843 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001844 xmlFree(cur);
1845}
1846
1847/**
1848 * xmlRemoveProp:
1849 * @cur: an attribute
1850 *
1851 * Unlink and free one attribute, all the content is freed too
1852 * Note this doesn't work for namespace definition attributes
1853 *
1854 * Returns 0 if success and -1 in case of error.
1855 */
1856int
1857xmlRemoveProp(xmlAttrPtr cur) {
1858 xmlAttrPtr tmp;
1859 if (cur == NULL) {
1860#ifdef DEBUG_TREE
1861 xmlGenericError(xmlGenericErrorContext,
1862 "xmlRemoveProp : cur == NULL\n");
1863#endif
1864 return(-1);
1865 }
1866 if (cur->parent == NULL) {
1867#ifdef DEBUG_TREE
1868 xmlGenericError(xmlGenericErrorContext,
1869 "xmlRemoveProp : cur->parent == NULL\n");
1870#endif
1871 return(-1);
1872 }
1873 tmp = cur->parent->properties;
1874 if (tmp == cur) {
1875 cur->parent->properties = cur->next;
1876 xmlFreeProp(cur);
1877 return(0);
1878 }
1879 while (tmp != NULL) {
1880 if (tmp->next == cur) {
1881 tmp->next = cur->next;
1882 if (tmp->next != NULL)
1883 tmp->next->prev = tmp;
1884 xmlFreeProp(cur);
1885 return(0);
1886 }
1887 tmp = tmp->next;
1888 }
1889#ifdef DEBUG_TREE
1890 xmlGenericError(xmlGenericErrorContext,
1891 "xmlRemoveProp : attribute not owned by its node\n");
1892#endif
1893 return(-1);
1894}
1895
1896/**
1897 * xmlNewPI:
1898 * @name: the processing instruction name
1899 * @content: the PI content
1900 *
1901 * Creation of a processing instruction element.
1902 * Returns a pointer to the new node object.
1903 */
1904xmlNodePtr
1905xmlNewPI(const xmlChar *name, const xmlChar *content) {
1906 xmlNodePtr cur;
1907
1908 if (name == NULL) {
1909#ifdef DEBUG_TREE
1910 xmlGenericError(xmlGenericErrorContext,
1911 "xmlNewPI : name == NULL\n");
1912#endif
1913 return(NULL);
1914 }
1915
1916 /*
1917 * Allocate a new node and fill the fields.
1918 */
1919 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1920 if (cur == NULL) {
1921 xmlGenericError(xmlGenericErrorContext,
1922 "xmlNewPI : malloc failed\n");
1923 return(NULL);
1924 }
1925 memset(cur, 0, sizeof(xmlNode));
1926 cur->type = XML_PI_NODE;
1927
1928 cur->name = xmlStrdup(name);
1929 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001930 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001931 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001932
Daniel Veillarda880b122003-04-21 21:36:41 +00001933 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001934 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001935 return(cur);
1936}
1937
1938/**
1939 * xmlNewNode:
1940 * @ns: namespace if any
1941 * @name: the node name
1942 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001943 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001944 *
1945 * Returns a pointer to the new node object.
1946 */
1947xmlNodePtr
1948xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1949 xmlNodePtr cur;
1950
1951 if (name == NULL) {
1952#ifdef DEBUG_TREE
1953 xmlGenericError(xmlGenericErrorContext,
1954 "xmlNewNode : name == NULL\n");
1955#endif
1956 return(NULL);
1957 }
1958
1959 /*
1960 * Allocate a new node and fill the fields.
1961 */
1962 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1963 if (cur == NULL) {
1964 xmlGenericError(xmlGenericErrorContext,
1965 "xmlNewNode : malloc failed\n");
1966 return(NULL);
1967 }
1968 memset(cur, 0, sizeof(xmlNode));
1969 cur->type = XML_ELEMENT_NODE;
1970
1971 cur->name = xmlStrdup(name);
1972 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001973
Daniel Veillarda880b122003-04-21 21:36:41 +00001974 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001975 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001976 return(cur);
1977}
1978
1979/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001980 * xmlNewNodeEatName:
1981 * @ns: namespace if any
1982 * @name: the node name
1983 *
1984 * Creation of a new node element. @ns is optional (NULL).
1985 *
1986 * Returns a pointer to the new node object.
1987 */
1988xmlNodePtr
1989xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
1990 xmlNodePtr cur;
1991
1992 if (name == NULL) {
1993#ifdef DEBUG_TREE
1994 xmlGenericError(xmlGenericErrorContext,
1995 "xmlNewNode : name == NULL\n");
1996#endif
1997 return(NULL);
1998 }
1999
2000 /*
2001 * Allocate a new node and fill the fields.
2002 */
2003 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2004 if (cur == NULL) {
2005 xmlGenericError(xmlGenericErrorContext,
2006 "xmlNewNode : malloc failed\n");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00002007 xmlFree(name);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002008 return(NULL);
2009 }
2010 memset(cur, 0, sizeof(xmlNode));
2011 cur->type = XML_ELEMENT_NODE;
2012
2013 cur->name = name;
2014 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002015
Daniel Veillarda880b122003-04-21 21:36:41 +00002016 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002017 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002018 return(cur);
2019}
2020
2021/**
Owen Taylor3473f882001-02-23 17:55:21 +00002022 * xmlNewDocNode:
2023 * @doc: the document
2024 * @ns: namespace if any
2025 * @name: the node name
2026 * @content: the XML text content if any
2027 *
2028 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002029 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002030 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2031 * references, but XML special chars need to be escaped first by using
2032 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2033 * need entities support.
2034 *
2035 * Returns a pointer to the new node object.
2036 */
2037xmlNodePtr
2038xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2039 const xmlChar *name, const xmlChar *content) {
2040 xmlNodePtr cur;
2041
2042 cur = xmlNewNode(ns, name);
2043 if (cur != NULL) {
2044 cur->doc = doc;
2045 if (content != NULL) {
2046 cur->children = xmlStringGetNodeList(doc, content);
2047 UPDATE_LAST_CHILD_AND_PARENT(cur)
2048 }
2049 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002050
Owen Taylor3473f882001-02-23 17:55:21 +00002051 return(cur);
2052}
2053
Daniel Veillard46de64e2002-05-29 08:21:33 +00002054/**
2055 * xmlNewDocNodeEatName:
2056 * @doc: the document
2057 * @ns: namespace if any
2058 * @name: the node name
2059 * @content: the XML text content if any
2060 *
2061 * Creation of a new node element within a document. @ns and @content
2062 * are optional (NULL).
2063 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2064 * references, but XML special chars need to be escaped first by using
2065 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2066 * need entities support.
2067 *
2068 * Returns a pointer to the new node object.
2069 */
2070xmlNodePtr
2071xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2072 xmlChar *name, const xmlChar *content) {
2073 xmlNodePtr cur;
2074
2075 cur = xmlNewNodeEatName(ns, name);
2076 if (cur != NULL) {
2077 cur->doc = doc;
2078 if (content != NULL) {
2079 cur->children = xmlStringGetNodeList(doc, content);
2080 UPDATE_LAST_CHILD_AND_PARENT(cur)
2081 }
2082 }
2083 return(cur);
2084}
2085
Owen Taylor3473f882001-02-23 17:55:21 +00002086
2087/**
2088 * xmlNewDocRawNode:
2089 * @doc: the document
2090 * @ns: namespace if any
2091 * @name: the node name
2092 * @content: the text content if any
2093 *
2094 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002095 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002096 *
2097 * Returns a pointer to the new node object.
2098 */
2099xmlNodePtr
2100xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2101 const xmlChar *name, const xmlChar *content) {
2102 xmlNodePtr cur;
2103
2104 cur = xmlNewNode(ns, name);
2105 if (cur != NULL) {
2106 cur->doc = doc;
2107 if (content != NULL) {
2108 cur->children = xmlNewDocText(doc, content);
2109 UPDATE_LAST_CHILD_AND_PARENT(cur)
2110 }
2111 }
2112 return(cur);
2113}
2114
2115/**
2116 * xmlNewDocFragment:
2117 * @doc: the document owning the fragment
2118 *
2119 * Creation of a new Fragment node.
2120 * Returns a pointer to the new node object.
2121 */
2122xmlNodePtr
2123xmlNewDocFragment(xmlDocPtr doc) {
2124 xmlNodePtr cur;
2125
2126 /*
2127 * Allocate a new DocumentFragment node and fill the fields.
2128 */
2129 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2130 if (cur == NULL) {
2131 xmlGenericError(xmlGenericErrorContext,
2132 "xmlNewDocFragment : malloc failed\n");
2133 return(NULL);
2134 }
2135 memset(cur, 0, sizeof(xmlNode));
2136 cur->type = XML_DOCUMENT_FRAG_NODE;
2137
2138 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002139
Daniel Veillarda880b122003-04-21 21:36:41 +00002140 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002141 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002142 return(cur);
2143}
2144
2145/**
2146 * xmlNewText:
2147 * @content: the text content
2148 *
2149 * Creation of a new text node.
2150 * Returns a pointer to the new node object.
2151 */
2152xmlNodePtr
2153xmlNewText(const xmlChar *content) {
2154 xmlNodePtr cur;
2155
2156 /*
2157 * Allocate a new node and fill the fields.
2158 */
2159 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2160 if (cur == NULL) {
2161 xmlGenericError(xmlGenericErrorContext,
2162 "xmlNewText : malloc failed\n");
2163 return(NULL);
2164 }
2165 memset(cur, 0, sizeof(xmlNode));
2166 cur->type = XML_TEXT_NODE;
2167
2168 cur->name = xmlStringText;
2169 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002170 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002171 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002172
Daniel Veillarda880b122003-04-21 21:36:41 +00002173 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002174 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002175 return(cur);
2176}
2177
2178/**
2179 * xmlNewTextChild:
2180 * @parent: the parent node
2181 * @ns: a namespace if any
2182 * @name: the name of the child
2183 * @content: the text content of the child if any.
2184 *
2185 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002186 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002187 * a child TEXT node will be created containing the string content.
2188 *
2189 * Returns a pointer to the new node object.
2190 */
2191xmlNodePtr
2192xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2193 const xmlChar *name, const xmlChar *content) {
2194 xmlNodePtr cur, prev;
2195
2196 if (parent == NULL) {
2197#ifdef DEBUG_TREE
2198 xmlGenericError(xmlGenericErrorContext,
2199 "xmlNewTextChild : parent == NULL\n");
2200#endif
2201 return(NULL);
2202 }
2203
2204 if (name == NULL) {
2205#ifdef DEBUG_TREE
2206 xmlGenericError(xmlGenericErrorContext,
2207 "xmlNewTextChild : name == NULL\n");
2208#endif
2209 return(NULL);
2210 }
2211
2212 /*
2213 * Allocate a new node
2214 */
2215 if (ns == NULL)
2216 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2217 else
2218 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2219 if (cur == NULL) return(NULL);
2220
2221 /*
2222 * add the new element at the end of the children list.
2223 */
2224 cur->type = XML_ELEMENT_NODE;
2225 cur->parent = parent;
2226 cur->doc = parent->doc;
2227 if (parent->children == NULL) {
2228 parent->children = cur;
2229 parent->last = cur;
2230 } else {
2231 prev = parent->last;
2232 prev->next = cur;
2233 cur->prev = prev;
2234 parent->last = cur;
2235 }
2236
2237 return(cur);
2238}
2239
2240/**
2241 * xmlNewCharRef:
2242 * @doc: the document
2243 * @name: the char ref string, starting with # or "&# ... ;"
2244 *
2245 * Creation of a new character reference node.
2246 * Returns a pointer to the new node object.
2247 */
2248xmlNodePtr
2249xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2250 xmlNodePtr cur;
2251
2252 /*
2253 * Allocate a new node and fill the fields.
2254 */
2255 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2256 if (cur == NULL) {
2257 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002258 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002259 return(NULL);
2260 }
2261 memset(cur, 0, sizeof(xmlNode));
2262 cur->type = XML_ENTITY_REF_NODE;
2263
2264 cur->doc = doc;
2265 if (name[0] == '&') {
2266 int len;
2267 name++;
2268 len = xmlStrlen(name);
2269 if (name[len - 1] == ';')
2270 cur->name = xmlStrndup(name, len - 1);
2271 else
2272 cur->name = xmlStrndup(name, len);
2273 } else
2274 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002275
Daniel Veillarda880b122003-04-21 21:36:41 +00002276 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002277 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002278 return(cur);
2279}
2280
2281/**
2282 * xmlNewReference:
2283 * @doc: the document
2284 * @name: the reference name, or the reference string with & and ;
2285 *
2286 * Creation of a new reference node.
2287 * Returns a pointer to the new node object.
2288 */
2289xmlNodePtr
2290xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2291 xmlNodePtr cur;
2292 xmlEntityPtr ent;
2293
2294 /*
2295 * Allocate a new node and fill the fields.
2296 */
2297 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2298 if (cur == NULL) {
2299 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002300 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002301 return(NULL);
2302 }
2303 memset(cur, 0, sizeof(xmlNode));
2304 cur->type = XML_ENTITY_REF_NODE;
2305
2306 cur->doc = doc;
2307 if (name[0] == '&') {
2308 int len;
2309 name++;
2310 len = xmlStrlen(name);
2311 if (name[len - 1] == ';')
2312 cur->name = xmlStrndup(name, len - 1);
2313 else
2314 cur->name = xmlStrndup(name, len);
2315 } else
2316 cur->name = xmlStrdup(name);
2317
2318 ent = xmlGetDocEntity(doc, cur->name);
2319 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002320 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002321 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002322 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002323 * updated. Not sure if this is 100% correct.
2324 * -George
2325 */
2326 cur->children = (xmlNodePtr) ent;
2327 cur->last = (xmlNodePtr) ent;
2328 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002329
Daniel Veillarda880b122003-04-21 21:36:41 +00002330 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002331 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002332 return(cur);
2333}
2334
2335/**
2336 * xmlNewDocText:
2337 * @doc: the document
2338 * @content: the text content
2339 *
2340 * Creation of a new text node within a document.
2341 * Returns a pointer to the new node object.
2342 */
2343xmlNodePtr
2344xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2345 xmlNodePtr cur;
2346
2347 cur = xmlNewText(content);
2348 if (cur != NULL) cur->doc = doc;
2349 return(cur);
2350}
2351
2352/**
2353 * xmlNewTextLen:
2354 * @content: the text content
2355 * @len: the text len.
2356 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002357 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002358 * Returns a pointer to the new node object.
2359 */
2360xmlNodePtr
2361xmlNewTextLen(const xmlChar *content, int len) {
2362 xmlNodePtr cur;
2363
2364 /*
2365 * Allocate a new node and fill the fields.
2366 */
2367 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2368 if (cur == NULL) {
2369 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002370 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002371 return(NULL);
2372 }
2373 memset(cur, 0, sizeof(xmlNode));
2374 cur->type = XML_TEXT_NODE;
2375
2376 cur->name = xmlStringText;
2377 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002378 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002379 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002380
Daniel Veillarda880b122003-04-21 21:36:41 +00002381 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002382 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002383 return(cur);
2384}
2385
2386/**
2387 * xmlNewDocTextLen:
2388 * @doc: the document
2389 * @content: the text content
2390 * @len: the text len.
2391 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002392 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002393 * text node pertain to a given document.
2394 * Returns a pointer to the new node object.
2395 */
2396xmlNodePtr
2397xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2398 xmlNodePtr cur;
2399
2400 cur = xmlNewTextLen(content, len);
2401 if (cur != NULL) cur->doc = doc;
2402 return(cur);
2403}
2404
2405/**
2406 * xmlNewComment:
2407 * @content: the comment content
2408 *
2409 * Creation of a new node containing a comment.
2410 * Returns a pointer to the new node object.
2411 */
2412xmlNodePtr
2413xmlNewComment(const xmlChar *content) {
2414 xmlNodePtr cur;
2415
2416 /*
2417 * Allocate a new node and fill the fields.
2418 */
2419 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2420 if (cur == NULL) {
2421 xmlGenericError(xmlGenericErrorContext,
2422 "xmlNewComment : malloc failed\n");
2423 return(NULL);
2424 }
2425 memset(cur, 0, sizeof(xmlNode));
2426 cur->type = XML_COMMENT_NODE;
2427
2428 cur->name = xmlStringComment;
2429 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002430 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002431 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002432
Daniel Veillarda880b122003-04-21 21:36:41 +00002433 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002434 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002435 return(cur);
2436}
2437
2438/**
2439 * xmlNewCDataBlock:
2440 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002441 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002442 * @len: the length of the block
2443 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002444 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002445 * Returns a pointer to the new node object.
2446 */
2447xmlNodePtr
2448xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2449 xmlNodePtr cur;
2450
2451 /*
2452 * Allocate a new node and fill the fields.
2453 */
2454 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2455 if (cur == NULL) {
2456 xmlGenericError(xmlGenericErrorContext,
2457 "xmlNewCDataBlock : malloc failed\n");
2458 return(NULL);
2459 }
2460 memset(cur, 0, sizeof(xmlNode));
2461 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002462 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002463
2464 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002465 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002466 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002467
Daniel Veillarda880b122003-04-21 21:36:41 +00002468 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002469 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002470 return(cur);
2471}
2472
2473/**
2474 * xmlNewDocComment:
2475 * @doc: the document
2476 * @content: the comment content
2477 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002478 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002479 * Returns a pointer to the new node object.
2480 */
2481xmlNodePtr
2482xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2483 xmlNodePtr cur;
2484
2485 cur = xmlNewComment(content);
2486 if (cur != NULL) cur->doc = doc;
2487 return(cur);
2488}
2489
2490/**
2491 * xmlSetTreeDoc:
2492 * @tree: the top element
2493 * @doc: the document
2494 *
2495 * update all nodes under the tree to point to the right document
2496 */
2497void
2498xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002499 xmlAttrPtr prop;
2500
Owen Taylor3473f882001-02-23 17:55:21 +00002501 if (tree == NULL)
2502 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002503 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002504 if(tree->type == XML_ELEMENT_NODE) {
2505 prop = tree->properties;
2506 while (prop != NULL) {
2507 prop->doc = doc;
2508 xmlSetListDoc(prop->children, doc);
2509 prop = prop->next;
2510 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002511 }
Owen Taylor3473f882001-02-23 17:55:21 +00002512 if (tree->children != NULL)
2513 xmlSetListDoc(tree->children, doc);
2514 tree->doc = doc;
2515 }
2516}
2517
2518/**
2519 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002520 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002521 * @doc: the document
2522 *
2523 * update all nodes in the list to point to the right document
2524 */
2525void
2526xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2527 xmlNodePtr cur;
2528
2529 if (list == NULL)
2530 return;
2531 cur = list;
2532 while (cur != NULL) {
2533 if (cur->doc != doc)
2534 xmlSetTreeDoc(cur, doc);
2535 cur = cur->next;
2536 }
2537}
2538
2539
2540/**
2541 * xmlNewChild:
2542 * @parent: the parent node
2543 * @ns: a namespace if any
2544 * @name: the name of the child
2545 * @content: the XML content of the child if any.
2546 *
2547 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002548 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002549 * a child list containing the TEXTs and ENTITY_REFs node will be created.
2550 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2551 * references, but XML special chars need to be escaped first by using
2552 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
2553 * support is not needed.
2554 *
2555 * Returns a pointer to the new node object.
2556 */
2557xmlNodePtr
2558xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2559 const xmlChar *name, const xmlChar *content) {
2560 xmlNodePtr cur, prev;
2561
2562 if (parent == NULL) {
2563#ifdef DEBUG_TREE
2564 xmlGenericError(xmlGenericErrorContext,
2565 "xmlNewChild : parent == NULL\n");
2566#endif
2567 return(NULL);
2568 }
2569
2570 if (name == NULL) {
2571#ifdef DEBUG_TREE
2572 xmlGenericError(xmlGenericErrorContext,
2573 "xmlNewChild : name == NULL\n");
2574#endif
2575 return(NULL);
2576 }
2577
2578 /*
2579 * Allocate a new node
2580 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002581 if (parent->type == XML_ELEMENT_NODE) {
2582 if (ns == NULL)
2583 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2584 else
2585 cur = xmlNewDocNode(parent->doc, ns, name, content);
2586 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2587 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2588 if (ns == NULL)
2589 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2590 else
2591 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002592 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2593 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002594 } else {
2595 return(NULL);
2596 }
Owen Taylor3473f882001-02-23 17:55:21 +00002597 if (cur == NULL) return(NULL);
2598
2599 /*
2600 * add the new element at the end of the children list.
2601 */
2602 cur->type = XML_ELEMENT_NODE;
2603 cur->parent = parent;
2604 cur->doc = parent->doc;
2605 if (parent->children == NULL) {
2606 parent->children = cur;
2607 parent->last = cur;
2608 } else {
2609 prev = parent->last;
2610 prev->next = cur;
2611 cur->prev = prev;
2612 parent->last = cur;
2613 }
2614
2615 return(cur);
2616}
2617
2618/**
2619 * xmlAddNextSibling:
2620 * @cur: the child node
2621 * @elem: the new node
2622 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002623 * Add a new node @elem as the next sibling of @cur
2624 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002625 * first unlinked from its existing context.
2626 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002627 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2628 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002629 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002630 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002631 */
2632xmlNodePtr
2633xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2634 if (cur == NULL) {
2635#ifdef DEBUG_TREE
2636 xmlGenericError(xmlGenericErrorContext,
2637 "xmlAddNextSibling : cur == NULL\n");
2638#endif
2639 return(NULL);
2640 }
2641 if (elem == NULL) {
2642#ifdef DEBUG_TREE
2643 xmlGenericError(xmlGenericErrorContext,
2644 "xmlAddNextSibling : elem == NULL\n");
2645#endif
2646 return(NULL);
2647 }
2648
2649 xmlUnlinkNode(elem);
2650
2651 if (elem->type == XML_TEXT_NODE) {
2652 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002653 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002654 xmlFreeNode(elem);
2655 return(cur);
2656 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002657 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2658 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002659 xmlChar *tmp;
2660
2661 tmp = xmlStrdup(elem->content);
2662 tmp = xmlStrcat(tmp, cur->next->content);
2663 xmlNodeSetContent(cur->next, tmp);
2664 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002665 xmlFreeNode(elem);
2666 return(cur->next);
2667 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002668 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2669 /* check if an attribute with the same name exists */
2670 xmlAttrPtr attr;
2671
2672 if (elem->ns == NULL)
2673 attr = xmlHasProp(cur->parent, elem->name);
2674 else
2675 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2676 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2677 /* different instance, destroy it (attributes must be unique) */
2678 xmlFreeProp(attr);
2679 }
Owen Taylor3473f882001-02-23 17:55:21 +00002680 }
2681
2682 if (elem->doc != cur->doc) {
2683 xmlSetTreeDoc(elem, cur->doc);
2684 }
2685 elem->parent = cur->parent;
2686 elem->prev = cur;
2687 elem->next = cur->next;
2688 cur->next = elem;
2689 if (elem->next != NULL)
2690 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002691 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002692 elem->parent->last = elem;
2693 return(elem);
2694}
2695
2696/**
2697 * xmlAddPrevSibling:
2698 * @cur: the child node
2699 * @elem: the new node
2700 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002701 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002702 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002703 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002704 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002705 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2706 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002707 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002708 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002709 */
2710xmlNodePtr
2711xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2712 if (cur == NULL) {
2713#ifdef DEBUG_TREE
2714 xmlGenericError(xmlGenericErrorContext,
2715 "xmlAddPrevSibling : cur == NULL\n");
2716#endif
2717 return(NULL);
2718 }
2719 if (elem == NULL) {
2720#ifdef DEBUG_TREE
2721 xmlGenericError(xmlGenericErrorContext,
2722 "xmlAddPrevSibling : elem == NULL\n");
2723#endif
2724 return(NULL);
2725 }
2726
2727 xmlUnlinkNode(elem);
2728
2729 if (elem->type == XML_TEXT_NODE) {
2730 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002731 xmlChar *tmp;
2732
2733 tmp = xmlStrdup(elem->content);
2734 tmp = xmlStrcat(tmp, cur->content);
2735 xmlNodeSetContent(cur, tmp);
2736 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002737 xmlFreeNode(elem);
2738 return(cur);
2739 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002740 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2741 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002742 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002743 xmlFreeNode(elem);
2744 return(cur->prev);
2745 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002746 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2747 /* check if an attribute with the same name exists */
2748 xmlAttrPtr attr;
2749
2750 if (elem->ns == NULL)
2751 attr = xmlHasProp(cur->parent, elem->name);
2752 else
2753 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2754 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2755 /* different instance, destroy it (attributes must be unique) */
2756 xmlFreeProp(attr);
2757 }
Owen Taylor3473f882001-02-23 17:55:21 +00002758 }
2759
2760 if (elem->doc != cur->doc) {
2761 xmlSetTreeDoc(elem, cur->doc);
2762 }
2763 elem->parent = cur->parent;
2764 elem->next = cur;
2765 elem->prev = cur->prev;
2766 cur->prev = elem;
2767 if (elem->prev != NULL)
2768 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002769 if (elem->parent != NULL) {
2770 if (elem->type == XML_ATTRIBUTE_NODE) {
2771 if (elem->parent->properties == (xmlAttrPtr) cur) {
2772 elem->parent->properties = (xmlAttrPtr) elem;
2773 }
2774 } else {
2775 if (elem->parent->children == cur) {
2776 elem->parent->children = elem;
2777 }
2778 }
2779 }
Owen Taylor3473f882001-02-23 17:55:21 +00002780 return(elem);
2781}
2782
2783/**
2784 * xmlAddSibling:
2785 * @cur: the child node
2786 * @elem: the new node
2787 *
2788 * Add a new element @elem to the list of siblings of @cur
2789 * merging adjacent TEXT nodes (@elem may be freed)
2790 * If the new element was already inserted in a document it is
2791 * first unlinked from its existing context.
2792 *
2793 * Returns the new element or NULL in case of error.
2794 */
2795xmlNodePtr
2796xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2797 xmlNodePtr parent;
2798
2799 if (cur == NULL) {
2800#ifdef DEBUG_TREE
2801 xmlGenericError(xmlGenericErrorContext,
2802 "xmlAddSibling : cur == NULL\n");
2803#endif
2804 return(NULL);
2805 }
2806
2807 if (elem == NULL) {
2808#ifdef DEBUG_TREE
2809 xmlGenericError(xmlGenericErrorContext,
2810 "xmlAddSibling : elem == NULL\n");
2811#endif
2812 return(NULL);
2813 }
2814
2815 /*
2816 * Constant time is we can rely on the ->parent->last to find
2817 * the last sibling.
2818 */
2819 if ((cur->parent != NULL) &&
2820 (cur->parent->children != NULL) &&
2821 (cur->parent->last != NULL) &&
2822 (cur->parent->last->next == NULL)) {
2823 cur = cur->parent->last;
2824 } else {
2825 while (cur->next != NULL) cur = cur->next;
2826 }
2827
2828 xmlUnlinkNode(elem);
2829
2830 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002831 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002832 xmlFreeNode(elem);
2833 return(cur);
2834 }
2835
2836 if (elem->doc != cur->doc) {
2837 xmlSetTreeDoc(elem, cur->doc);
2838 }
2839 parent = cur->parent;
2840 elem->prev = cur;
2841 elem->next = NULL;
2842 elem->parent = parent;
2843 cur->next = elem;
2844 if (parent != NULL)
2845 parent->last = elem;
2846
2847 return(elem);
2848}
2849
2850/**
2851 * xmlAddChildList:
2852 * @parent: the parent node
2853 * @cur: the first node in the list
2854 *
2855 * Add a list of node at the end of the child list of the parent
2856 * merging adjacent TEXT nodes (@cur may be freed)
2857 *
2858 * Returns the last child or NULL in case of error.
2859 */
2860xmlNodePtr
2861xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2862 xmlNodePtr prev;
2863
2864 if (parent == NULL) {
2865#ifdef DEBUG_TREE
2866 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002867 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002868#endif
2869 return(NULL);
2870 }
2871
2872 if (cur == NULL) {
2873#ifdef DEBUG_TREE
2874 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002875 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002876#endif
2877 return(NULL);
2878 }
2879
2880 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2881 (cur->doc != parent->doc)) {
2882#ifdef DEBUG_TREE
2883 xmlGenericError(xmlGenericErrorContext,
2884 "Elements moved to a different document\n");
2885#endif
2886 }
2887
2888 /*
2889 * add the first element at the end of the children list.
2890 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00002891
Owen Taylor3473f882001-02-23 17:55:21 +00002892 if (parent->children == NULL) {
2893 parent->children = cur;
2894 } else {
2895 /*
2896 * If cur and parent->last both are TEXT nodes, then merge them.
2897 */
2898 if ((cur->type == XML_TEXT_NODE) &&
2899 (parent->last->type == XML_TEXT_NODE) &&
2900 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00002901 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002902 /*
2903 * if it's the only child, nothing more to be done.
2904 */
2905 if (cur->next == NULL) {
2906 xmlFreeNode(cur);
2907 return(parent->last);
2908 }
2909 prev = cur;
2910 cur = cur->next;
2911 xmlFreeNode(prev);
2912 }
2913 prev = parent->last;
2914 prev->next = cur;
2915 cur->prev = prev;
2916 }
2917 while (cur->next != NULL) {
2918 cur->parent = parent;
2919 if (cur->doc != parent->doc) {
2920 xmlSetTreeDoc(cur, parent->doc);
2921 }
2922 cur = cur->next;
2923 }
2924 cur->parent = parent;
2925 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2926 parent->last = cur;
2927
2928 return(cur);
2929}
2930
2931/**
2932 * xmlAddChild:
2933 * @parent: the parent node
2934 * @cur: the child node
2935 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002936 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00002937 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002938 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2939 * If there is an attribute with equal name, it is first destroyed.
2940 *
Owen Taylor3473f882001-02-23 17:55:21 +00002941 * Returns the child or NULL in case of error.
2942 */
2943xmlNodePtr
2944xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2945 xmlNodePtr prev;
2946
2947 if (parent == NULL) {
2948#ifdef DEBUG_TREE
2949 xmlGenericError(xmlGenericErrorContext,
2950 "xmlAddChild : parent == NULL\n");
2951#endif
2952 return(NULL);
2953 }
2954
2955 if (cur == NULL) {
2956#ifdef DEBUG_TREE
2957 xmlGenericError(xmlGenericErrorContext,
2958 "xmlAddChild : child == NULL\n");
2959#endif
2960 return(NULL);
2961 }
2962
Owen Taylor3473f882001-02-23 17:55:21 +00002963 /*
2964 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002965 * cur is then freed.
2966 */
2967 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002968 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002969 (parent->content != NULL) &&
2970 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002971 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002972 xmlFreeNode(cur);
2973 return(parent);
2974 }
2975 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002976 (parent->last->name == cur->name) &&
2977 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002978 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002979 xmlFreeNode(cur);
2980 return(parent->last);
2981 }
2982 }
2983
2984 /*
2985 * add the new element at the end of the children list.
2986 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00002987 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00002988 cur->parent = parent;
2989 if (cur->doc != parent->doc) {
2990 xmlSetTreeDoc(cur, parent->doc);
2991 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002992 /* this check prevents a loop on tree-traversions if a developer
2993 * tries to add a node to its parent multiple times
2994 */
2995 if (prev == parent)
2996 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002997
2998 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002999 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003000 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003001 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003002 (parent->content != NULL) &&
3003 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003004 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003005 xmlFreeNode(cur);
3006 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003007 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003008 if (cur->type == XML_ATTRIBUTE_NODE) {
3009 if (parent->properties == NULL) {
3010 parent->properties = (xmlAttrPtr) cur;
3011 } else {
3012 /* check if an attribute with the same name exists */
3013 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003014
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003015 if (cur->ns == NULL)
3016 lastattr = xmlHasProp(parent, cur->name);
3017 else
3018 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3019 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
3020 /* different instance, destroy it (attributes must be unique) */
3021 xmlFreeProp(lastattr);
3022 }
3023 /* find the end */
3024 lastattr = parent->properties;
3025 while (lastattr->next != NULL) {
3026 lastattr = lastattr->next;
3027 }
3028 lastattr->next = (xmlAttrPtr) cur;
3029 ((xmlAttrPtr) cur)->prev = lastattr;
3030 }
3031 } else {
3032 if (parent->children == NULL) {
3033 parent->children = cur;
3034 parent->last = cur;
3035 } else {
3036 prev = parent->last;
3037 prev->next = cur;
3038 cur->prev = prev;
3039 parent->last = cur;
3040 }
3041 }
Owen Taylor3473f882001-02-23 17:55:21 +00003042 return(cur);
3043}
3044
3045/**
3046 * xmlGetLastChild:
3047 * @parent: the parent node
3048 *
3049 * Search the last child of a node.
3050 * Returns the last child or NULL if none.
3051 */
3052xmlNodePtr
3053xmlGetLastChild(xmlNodePtr parent) {
3054 if (parent == NULL) {
3055#ifdef DEBUG_TREE
3056 xmlGenericError(xmlGenericErrorContext,
3057 "xmlGetLastChild : parent == NULL\n");
3058#endif
3059 return(NULL);
3060 }
3061 return(parent->last);
3062}
3063
3064/**
3065 * xmlFreeNodeList:
3066 * @cur: the first node in the list
3067 *
3068 * Free a node and all its siblings, this is a recursive behaviour, all
3069 * the children are freed too.
3070 */
3071void
3072xmlFreeNodeList(xmlNodePtr cur) {
3073 xmlNodePtr next;
3074 if (cur == NULL) {
3075#ifdef DEBUG_TREE
3076 xmlGenericError(xmlGenericErrorContext,
3077 "xmlFreeNodeList : node == NULL\n");
3078#endif
3079 return;
3080 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00003081 if (cur->type == XML_NAMESPACE_DECL) {
3082 xmlFreeNsList((xmlNsPtr) cur);
3083 return;
3084 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003085 if ((cur->type == XML_DOCUMENT_NODE) ||
3086#ifdef LIBXML_DOCB_ENABLED
3087 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003088#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003089 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003090 xmlFreeDoc((xmlDocPtr) cur);
3091 return;
3092 }
Owen Taylor3473f882001-02-23 17:55:21 +00003093 while (cur != NULL) {
3094 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003095 /* unroll to speed up freeing the document */
3096 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003097
Daniel Veillarda880b122003-04-21 21:36:41 +00003098 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003099 xmlDeregisterNodeDefaultValue(cur);
3100
Daniel Veillard02141ea2001-04-30 11:46:40 +00003101 if ((cur->children != NULL) &&
3102 (cur->type != XML_ENTITY_REF_NODE))
3103 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003104 if (((cur->type == XML_ELEMENT_NODE) ||
3105 (cur->type == XML_XINCLUDE_START) ||
3106 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003107 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003108 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003109 if ((cur->type != XML_ELEMENT_NODE) &&
3110 (cur->type != XML_XINCLUDE_START) &&
3111 (cur->type != XML_XINCLUDE_END) &&
3112 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00003113 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003114 }
3115 if (((cur->type == XML_ELEMENT_NODE) ||
3116 (cur->type == XML_XINCLUDE_START) ||
3117 (cur->type == XML_XINCLUDE_END)) &&
3118 (cur->nsDef != NULL))
3119 xmlFreeNsList(cur->nsDef);
3120
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003121 /*
3122 * When a node is a text node or a comment, it uses a global static
3123 * variable for the name of the node.
3124 *
3125 * The xmlStrEqual comparisons need to be done when (happened with
3126 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003127 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00003128 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003129 * the string addresses compare are not sufficient.
3130 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003131 if ((cur->name != NULL) &&
3132 (cur->name != xmlStringText) &&
3133 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003134 (cur->name != xmlStringComment)) {
3135 if (cur->type == XML_TEXT_NODE) {
3136 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
3137 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
3138 xmlFree((char *) cur->name);
3139 } else if (cur->type == XML_COMMENT_NODE) {
3140 if (!xmlStrEqual(cur->name, xmlStringComment))
3141 xmlFree((char *) cur->name);
3142 } else
3143 xmlFree((char *) cur->name);
3144 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00003145 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003146 xmlFree(cur);
3147 }
Owen Taylor3473f882001-02-23 17:55:21 +00003148 cur = next;
3149 }
3150}
3151
3152/**
3153 * xmlFreeNode:
3154 * @cur: the node
3155 *
3156 * Free a node, this is a recursive behaviour, all the children are freed too.
3157 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3158 */
3159void
3160xmlFreeNode(xmlNodePtr cur) {
3161 if (cur == NULL) {
3162#ifdef DEBUG_TREE
3163 xmlGenericError(xmlGenericErrorContext,
3164 "xmlFreeNode : node == NULL\n");
3165#endif
3166 return;
3167 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003168
Daniel Veillard02141ea2001-04-30 11:46:40 +00003169 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003170 if (cur->type == XML_DTD_NODE) {
3171 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003172 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003173 }
3174 if (cur->type == XML_NAMESPACE_DECL) {
3175 xmlFreeNs((xmlNsPtr) cur);
3176 return;
3177 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003178 if (cur->type == XML_ATTRIBUTE_NODE) {
3179 xmlFreeProp((xmlAttrPtr) cur);
3180 return;
3181 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003182
Daniel Veillarda880b122003-04-21 21:36:41 +00003183 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003184 xmlDeregisterNodeDefaultValue(cur);
3185
Owen Taylor3473f882001-02-23 17:55:21 +00003186 if ((cur->children != NULL) &&
3187 (cur->type != XML_ENTITY_REF_NODE))
3188 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003189 if (((cur->type == XML_ELEMENT_NODE) ||
3190 (cur->type == XML_XINCLUDE_START) ||
3191 (cur->type == XML_XINCLUDE_END)) &&
3192 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003193 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003194 if ((cur->type != XML_ELEMENT_NODE) &&
3195 (cur->content != NULL) &&
3196 (cur->type != XML_ENTITY_REF_NODE) &&
3197 (cur->type != XML_XINCLUDE_END) &&
3198 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003199 xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003200 }
3201
Daniel Veillardacd370f2001-06-09 17:17:51 +00003202 /*
3203 * When a node is a text node or a comment, it uses a global static
3204 * variable for the name of the node.
3205 *
3206 * The xmlStrEqual comparisons need to be done when (happened with
3207 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003208 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00003209 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00003210 * are not sufficient.
3211 */
Owen Taylor3473f882001-02-23 17:55:21 +00003212 if ((cur->name != NULL) &&
3213 (cur->name != xmlStringText) &&
3214 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00003215 (cur->name != xmlStringComment)) {
3216 if (cur->type == XML_TEXT_NODE) {
3217 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
3218 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
3219 xmlFree((char *) cur->name);
3220 } else if (cur->type == XML_COMMENT_NODE) {
3221 if (!xmlStrEqual(cur->name, xmlStringComment))
3222 xmlFree((char *) cur->name);
3223 } else
3224 xmlFree((char *) cur->name);
3225 }
3226
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003227 if (((cur->type == XML_ELEMENT_NODE) ||
3228 (cur->type == XML_XINCLUDE_START) ||
3229 (cur->type == XML_XINCLUDE_END)) &&
3230 (cur->nsDef != NULL))
3231 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003232 xmlFree(cur);
3233}
3234
3235/**
3236 * xmlUnlinkNode:
3237 * @cur: the node
3238 *
3239 * Unlink a node from it's current context, the node is not freed
3240 */
3241void
3242xmlUnlinkNode(xmlNodePtr cur) {
3243 if (cur == NULL) {
3244#ifdef DEBUG_TREE
3245 xmlGenericError(xmlGenericErrorContext,
3246 "xmlUnlinkNode : node == NULL\n");
3247#endif
3248 return;
3249 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003250 if (cur->type == XML_DTD_NODE) {
3251 xmlDocPtr doc;
3252 doc = cur->doc;
3253 if (doc->intSubset == (xmlDtdPtr) cur)
3254 doc->intSubset = NULL;
3255 if (doc->extSubset == (xmlDtdPtr) cur)
3256 doc->extSubset = NULL;
3257 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003258 if (cur->parent != NULL) {
3259 xmlNodePtr parent;
3260 parent = cur->parent;
3261 if (cur->type == XML_ATTRIBUTE_NODE) {
3262 if (parent->properties == (xmlAttrPtr) cur)
3263 parent->properties = ((xmlAttrPtr) cur)->next;
3264 } else {
3265 if (parent->children == cur)
3266 parent->children = cur->next;
3267 if (parent->last == cur)
3268 parent->last = cur->prev;
3269 }
3270 cur->parent = NULL;
3271 }
Owen Taylor3473f882001-02-23 17:55:21 +00003272 if (cur->next != NULL)
3273 cur->next->prev = cur->prev;
3274 if (cur->prev != NULL)
3275 cur->prev->next = cur->next;
3276 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003277}
3278
3279/**
3280 * xmlReplaceNode:
3281 * @old: the old node
3282 * @cur: the node
3283 *
3284 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003285 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003286 * first unlinked from its existing context.
3287 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003288 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003289 */
3290xmlNodePtr
3291xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3292 if (old == NULL) {
3293#ifdef DEBUG_TREE
3294 xmlGenericError(xmlGenericErrorContext,
3295 "xmlReplaceNode : old == NULL\n");
3296#endif
3297 return(NULL);
3298 }
3299 if (cur == NULL) {
3300 xmlUnlinkNode(old);
3301 return(old);
3302 }
3303 if (cur == old) {
3304 return(old);
3305 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003306 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3307#ifdef DEBUG_TREE
3308 xmlGenericError(xmlGenericErrorContext,
3309 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3310#endif
3311 return(old);
3312 }
3313 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3314#ifdef DEBUG_TREE
3315 xmlGenericError(xmlGenericErrorContext,
3316 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3317#endif
3318 return(old);
3319 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003320 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3321#ifdef DEBUG_TREE
3322 xmlGenericError(xmlGenericErrorContext,
3323 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3324#endif
3325 return(old);
3326 }
3327 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3328#ifdef DEBUG_TREE
3329 xmlGenericError(xmlGenericErrorContext,
3330 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3331#endif
3332 return(old);
3333 }
Owen Taylor3473f882001-02-23 17:55:21 +00003334 xmlUnlinkNode(cur);
3335 cur->doc = old->doc;
3336 cur->parent = old->parent;
3337 cur->next = old->next;
3338 if (cur->next != NULL)
3339 cur->next->prev = cur;
3340 cur->prev = old->prev;
3341 if (cur->prev != NULL)
3342 cur->prev->next = cur;
3343 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003344 if (cur->type == XML_ATTRIBUTE_NODE) {
3345 if (cur->parent->properties == (xmlAttrPtr)old)
3346 cur->parent->properties = ((xmlAttrPtr) cur);
3347 } else {
3348 if (cur->parent->children == old)
3349 cur->parent->children = cur;
3350 if (cur->parent->last == old)
3351 cur->parent->last = cur;
3352 }
Owen Taylor3473f882001-02-23 17:55:21 +00003353 }
3354 old->next = old->prev = NULL;
3355 old->parent = NULL;
3356 return(old);
3357}
3358
3359/************************************************************************
3360 * *
3361 * Copy operations *
3362 * *
3363 ************************************************************************/
3364
3365/**
3366 * xmlCopyNamespace:
3367 * @cur: the namespace
3368 *
3369 * Do a copy of the namespace.
3370 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003371 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003372 */
3373xmlNsPtr
3374xmlCopyNamespace(xmlNsPtr cur) {
3375 xmlNsPtr ret;
3376
3377 if (cur == NULL) return(NULL);
3378 switch (cur->type) {
3379 case XML_LOCAL_NAMESPACE:
3380 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3381 break;
3382 default:
3383#ifdef DEBUG_TREE
3384 xmlGenericError(xmlGenericErrorContext,
3385 "xmlCopyNamespace: invalid type %d\n", cur->type);
3386#endif
3387 return(NULL);
3388 }
3389 return(ret);
3390}
3391
3392/**
3393 * xmlCopyNamespaceList:
3394 * @cur: the first namespace
3395 *
3396 * Do a copy of an namespace list.
3397 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003398 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003399 */
3400xmlNsPtr
3401xmlCopyNamespaceList(xmlNsPtr cur) {
3402 xmlNsPtr ret = NULL;
3403 xmlNsPtr p = NULL,q;
3404
3405 while (cur != NULL) {
3406 q = xmlCopyNamespace(cur);
3407 if (p == NULL) {
3408 ret = p = q;
3409 } else {
3410 p->next = q;
3411 p = q;
3412 }
3413 cur = cur->next;
3414 }
3415 return(ret);
3416}
3417
3418static xmlNodePtr
3419xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3420/**
3421 * xmlCopyProp:
3422 * @target: the element where the attribute will be grafted
3423 * @cur: the attribute
3424 *
3425 * Do a copy of the attribute.
3426 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003427 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003428 */
3429xmlAttrPtr
3430xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3431 xmlAttrPtr ret;
3432
3433 if (cur == NULL) return(NULL);
3434 if (target != NULL)
3435 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3436 else if (cur->parent != NULL)
3437 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3438 else if (cur->children != NULL)
3439 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3440 else
3441 ret = xmlNewDocProp(NULL, cur->name, NULL);
3442 if (ret == NULL) return(NULL);
3443 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003444
Owen Taylor3473f882001-02-23 17:55:21 +00003445 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003446 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003447/*
3448 * if (target->doc)
3449 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3450 * else if (cur->doc) / * target may not yet have a doc : KPI * /
3451 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
3452 * else
3453 * ns = NULL;
3454 * ret->ns = ns;
3455 */
3456 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3457 if (ns == NULL) {
3458 /*
3459 * Humm, we are copying an element whose namespace is defined
3460 * out of the new tree scope. Search it in the original tree
3461 * and add it at the top of the new tree
3462 */
3463 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3464 if (ns != NULL) {
3465 xmlNodePtr root = target;
3466 xmlNodePtr pred = NULL;
3467
3468 while (root->parent != NULL) {
3469 pred = root;
3470 root = root->parent;
3471 }
3472 if (root == (xmlNodePtr) target->doc) {
3473 /* correct possibly cycling above the document elt */
3474 root = pred;
3475 }
3476 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3477 }
3478 } else {
3479 /*
3480 * we have to find something appropriate here since
3481 * we cant be sure, that the namespce we found is identified
3482 * by the prefix
3483 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003484 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003485 /* this is the nice case */
3486 ret->ns = ns;
3487 } else {
3488 /*
3489 * we are in trouble: we need a new reconcilied namespace.
3490 * This is expensive
3491 */
3492 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3493 }
3494 }
3495
Owen Taylor3473f882001-02-23 17:55:21 +00003496 } else
3497 ret->ns = NULL;
3498
3499 if (cur->children != NULL) {
3500 xmlNodePtr tmp;
3501
3502 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3503 ret->last = NULL;
3504 tmp = ret->children;
3505 while (tmp != NULL) {
3506 /* tmp->parent = (xmlNodePtr)ret; */
3507 if (tmp->next == NULL)
3508 ret->last = tmp;
3509 tmp = tmp->next;
3510 }
3511 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003512 /*
3513 * Try to handle IDs
3514 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003515 if ((target!= NULL) && (cur!= NULL) &&
3516 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003517 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3518 if (xmlIsID(cur->doc, cur->parent, cur)) {
3519 xmlChar *id;
3520
3521 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3522 if (id != NULL) {
3523 xmlAddID(NULL, target->doc, id, ret);
3524 xmlFree(id);
3525 }
3526 }
3527 }
Owen Taylor3473f882001-02-23 17:55:21 +00003528 return(ret);
3529}
3530
3531/**
3532 * xmlCopyPropList:
3533 * @target: the element where the attributes will be grafted
3534 * @cur: the first attribute
3535 *
3536 * Do a copy of an attribute list.
3537 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003538 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003539 */
3540xmlAttrPtr
3541xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3542 xmlAttrPtr ret = NULL;
3543 xmlAttrPtr p = NULL,q;
3544
3545 while (cur != NULL) {
3546 q = xmlCopyProp(target, cur);
3547 if (p == NULL) {
3548 ret = p = q;
3549 } else {
3550 p->next = q;
3551 q->prev = p;
3552 p = q;
3553 }
3554 cur = cur->next;
3555 }
3556 return(ret);
3557}
3558
3559/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003560 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003561 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003562 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003563 * tricky reason: namespaces. Doing a direct copy of a node
3564 * say RPM:Copyright without changing the namespace pointer to
3565 * something else can produce stale links. One way to do it is
3566 * to keep a reference counter but this doesn't work as soon
3567 * as one move the element or the subtree out of the scope of
3568 * the existing namespace. The actual solution seems to add
3569 * a copy of the namespace at the top of the copied tree if
3570 * not available in the subtree.
3571 * Hence two functions, the public front-end call the inner ones
3572 */
3573
3574static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003575xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003576 int recursive) {
3577 xmlNodePtr ret;
3578
3579 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003580 switch (node->type) {
3581 case XML_TEXT_NODE:
3582 case XML_CDATA_SECTION_NODE:
3583 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003584 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003585 case XML_ENTITY_REF_NODE:
3586 case XML_ENTITY_NODE:
3587 case XML_PI_NODE:
3588 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003589 case XML_XINCLUDE_START:
3590 case XML_XINCLUDE_END:
3591 break;
3592 case XML_ATTRIBUTE_NODE:
3593 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3594 case XML_NAMESPACE_DECL:
3595 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3596
Daniel Veillard39196eb2001-06-19 18:09:42 +00003597 case XML_DOCUMENT_NODE:
3598 case XML_HTML_DOCUMENT_NODE:
3599#ifdef LIBXML_DOCB_ENABLED
3600 case XML_DOCB_DOCUMENT_NODE:
3601#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003602 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00003603 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003604 case XML_NOTATION_NODE:
3605 case XML_DTD_NODE:
3606 case XML_ELEMENT_DECL:
3607 case XML_ATTRIBUTE_DECL:
3608 case XML_ENTITY_DECL:
3609 return(NULL);
3610 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003611
Owen Taylor3473f882001-02-23 17:55:21 +00003612 /*
3613 * Allocate a new node and fill the fields.
3614 */
3615 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3616 if (ret == NULL) {
3617 xmlGenericError(xmlGenericErrorContext,
3618 "xmlStaticCopyNode : malloc failed\n");
3619 return(NULL);
3620 }
3621 memset(ret, 0, sizeof(xmlNode));
3622 ret->type = node->type;
3623
3624 ret->doc = doc;
3625 ret->parent = parent;
3626 if (node->name == xmlStringText)
3627 ret->name = xmlStringText;
3628 else if (node->name == xmlStringTextNoenc)
3629 ret->name = xmlStringTextNoenc;
3630 else if (node->name == xmlStringComment)
3631 ret->name = xmlStringComment;
3632 else if (node->name != NULL)
3633 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003634 if ((node->type != XML_ELEMENT_NODE) &&
3635 (node->content != NULL) &&
3636 (node->type != XML_ENTITY_REF_NODE) &&
3637 (node->type != XML_XINCLUDE_END) &&
3638 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003639 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003640 }else{
3641 if (node->type == XML_ELEMENT_NODE)
3642 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00003643 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003644 if (parent != NULL) {
3645 xmlNodePtr tmp;
3646
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003647 /*
3648 * this is a tricky part for the node register thing:
3649 * in case ret does get coalesced in xmlAddChild
3650 * the deregister-node callback is called; so we register ret now already
3651 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003652 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003653 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3654
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003655 tmp = xmlAddChild(parent, ret);
3656 /* node could have coalesced */
3657 if (tmp != ret)
3658 return(tmp);
3659 }
Owen Taylor3473f882001-02-23 17:55:21 +00003660
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003661 if (!recursive)
3662 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003663 if (node->nsDef != NULL)
3664 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3665
3666 if (node->ns != NULL) {
3667 xmlNsPtr ns;
3668
3669 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3670 if (ns == NULL) {
3671 /*
3672 * Humm, we are copying an element whose namespace is defined
3673 * out of the new tree scope. Search it in the original tree
3674 * and add it at the top of the new tree
3675 */
3676 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3677 if (ns != NULL) {
3678 xmlNodePtr root = ret;
3679
3680 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003681 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003682 }
3683 } else {
3684 /*
3685 * reference the existing namespace definition in our own tree.
3686 */
3687 ret->ns = ns;
3688 }
3689 }
3690 if (node->properties != NULL)
3691 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003692 if (node->type == XML_ENTITY_REF_NODE) {
3693 if ((doc == NULL) || (node->doc != doc)) {
3694 /*
3695 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003696 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003697 * we cannot keep the reference. Try to find it in the
3698 * target document.
3699 */
3700 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3701 } else {
3702 ret->children = node->children;
3703 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003704 ret->last = ret->children;
3705 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003706 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003707 UPDATE_LAST_CHILD_AND_PARENT(ret)
3708 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003709
3710out:
3711 /* if parent != NULL we already registered the node above */
3712 if (parent == NULL && xmlRegisterNodeDefaultValue)
3713 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003714 return(ret);
3715}
3716
3717static xmlNodePtr
3718xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3719 xmlNodePtr ret = NULL;
3720 xmlNodePtr p = NULL,q;
3721
3722 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003723 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003724 if (doc == NULL) {
3725 node = node->next;
3726 continue;
3727 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003728 if (doc->intSubset == NULL) {
3729 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3730 q->doc = doc;
3731 q->parent = parent;
3732 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003733 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003734 } else {
3735 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003736 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003737 }
3738 } else
3739 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003740 if (ret == NULL) {
3741 q->prev = NULL;
3742 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003743 } else if (p != q) {
3744 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003745 p->next = q;
3746 q->prev = p;
3747 p = q;
3748 }
3749 node = node->next;
3750 }
3751 return(ret);
3752}
3753
3754/**
3755 * xmlCopyNode:
3756 * @node: the node
3757 * @recursive: if 1 do a recursive copy.
3758 *
3759 * Do a copy of the node.
3760 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003761 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003762 */
3763xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003764xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003765 xmlNodePtr ret;
3766
3767 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3768 return(ret);
3769}
3770
3771/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003772 * xmlDocCopyNode:
3773 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003774 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003775 * @recursive: if 1 do a recursive copy.
3776 *
3777 * Do a copy of the node to a given document.
3778 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003779 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003780 */
3781xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003782xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003783 xmlNodePtr ret;
3784
3785 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3786 return(ret);
3787}
3788
3789/**
Owen Taylor3473f882001-02-23 17:55:21 +00003790 * xmlCopyNodeList:
3791 * @node: the first node in the list.
3792 *
3793 * Do a recursive copy of the node list.
3794 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003795 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003796 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003797xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003798 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3799 return(ret);
3800}
3801
3802/**
Owen Taylor3473f882001-02-23 17:55:21 +00003803 * xmlCopyDtd:
3804 * @dtd: the dtd
3805 *
3806 * Do a copy of the dtd.
3807 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003808 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003809 */
3810xmlDtdPtr
3811xmlCopyDtd(xmlDtdPtr dtd) {
3812 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003813 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003814
3815 if (dtd == NULL) return(NULL);
3816 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3817 if (ret == NULL) return(NULL);
3818 if (dtd->entities != NULL)
3819 ret->entities = (void *) xmlCopyEntitiesTable(
3820 (xmlEntitiesTablePtr) dtd->entities);
3821 if (dtd->notations != NULL)
3822 ret->notations = (void *) xmlCopyNotationTable(
3823 (xmlNotationTablePtr) dtd->notations);
3824 if (dtd->elements != NULL)
3825 ret->elements = (void *) xmlCopyElementTable(
3826 (xmlElementTablePtr) dtd->elements);
3827 if (dtd->attributes != NULL)
3828 ret->attributes = (void *) xmlCopyAttributeTable(
3829 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003830 if (dtd->pentities != NULL)
3831 ret->pentities = (void *) xmlCopyEntitiesTable(
3832 (xmlEntitiesTablePtr) dtd->pentities);
3833
3834 cur = dtd->children;
3835 while (cur != NULL) {
3836 q = NULL;
3837
3838 if (cur->type == XML_ENTITY_DECL) {
3839 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3840 switch (tmp->etype) {
3841 case XML_INTERNAL_GENERAL_ENTITY:
3842 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3843 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3844 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3845 break;
3846 case XML_INTERNAL_PARAMETER_ENTITY:
3847 case XML_EXTERNAL_PARAMETER_ENTITY:
3848 q = (xmlNodePtr)
3849 xmlGetParameterEntityFromDtd(ret, tmp->name);
3850 break;
3851 case XML_INTERNAL_PREDEFINED_ENTITY:
3852 break;
3853 }
3854 } else if (cur->type == XML_ELEMENT_DECL) {
3855 xmlElementPtr tmp = (xmlElementPtr) cur;
3856 q = (xmlNodePtr)
3857 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3858 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3859 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3860 q = (xmlNodePtr)
3861 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3862 } else if (cur->type == XML_COMMENT_NODE) {
3863 q = xmlCopyNode(cur, 0);
3864 }
3865
3866 if (q == NULL) {
3867 cur = cur->next;
3868 continue;
3869 }
3870
3871 if (p == NULL)
3872 ret->children = q;
3873 else
3874 p->next = q;
3875
3876 q->prev = p;
3877 q->parent = (xmlNodePtr) ret;
3878 q->next = NULL;
3879 ret->last = q;
3880 p = q;
3881 cur = cur->next;
3882 }
3883
Owen Taylor3473f882001-02-23 17:55:21 +00003884 return(ret);
3885}
3886
3887/**
3888 * xmlCopyDoc:
3889 * @doc: the document
3890 * @recursive: if 1 do a recursive copy.
3891 *
3892 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003893 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003894 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003895 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003896 */
3897xmlDocPtr
3898xmlCopyDoc(xmlDocPtr doc, int recursive) {
3899 xmlDocPtr ret;
3900
3901 if (doc == NULL) return(NULL);
3902 ret = xmlNewDoc(doc->version);
3903 if (ret == NULL) return(NULL);
3904 if (doc->name != NULL)
3905 ret->name = xmlMemStrdup(doc->name);
3906 if (doc->encoding != NULL)
3907 ret->encoding = xmlStrdup(doc->encoding);
3908 ret->charset = doc->charset;
3909 ret->compression = doc->compression;
3910 ret->standalone = doc->standalone;
3911 if (!recursive) return(ret);
3912
Daniel Veillardb33c2012001-04-25 12:59:04 +00003913 ret->last = NULL;
3914 ret->children = NULL;
3915 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003916 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003917 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003918 ret->intSubset->parent = ret;
3919 }
Owen Taylor3473f882001-02-23 17:55:21 +00003920 if (doc->oldNs != NULL)
3921 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3922 if (doc->children != NULL) {
3923 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003924
3925 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3926 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003927 ret->last = NULL;
3928 tmp = ret->children;
3929 while (tmp != NULL) {
3930 if (tmp->next == NULL)
3931 ret->last = tmp;
3932 tmp = tmp->next;
3933 }
3934 }
3935 return(ret);
3936}
3937
3938/************************************************************************
3939 * *
3940 * Content access functions *
3941 * *
3942 ************************************************************************/
3943
3944/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003945 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003946 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00003947 *
3948 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003949 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003950 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003951 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003952 */
3953long
3954xmlGetLineNo(xmlNodePtr node)
3955{
3956 long result = -1;
3957
3958 if (!node)
3959 return result;
3960 if (node->type == XML_ELEMENT_NODE)
3961 result = (long) node->content;
3962 else if ((node->prev != NULL) &&
3963 ((node->prev->type == XML_ELEMENT_NODE) ||
3964 (node->prev->type == XML_TEXT_NODE)))
3965 result = xmlGetLineNo(node->prev);
3966 else if ((node->parent != NULL) &&
3967 ((node->parent->type == XML_ELEMENT_NODE) ||
3968 (node->parent->type == XML_TEXT_NODE)))
3969 result = xmlGetLineNo(node->parent);
3970
3971 return result;
3972}
3973
3974/**
3975 * xmlGetNodePath:
3976 * @node: a node
3977 *
3978 * Build a structure based Path for the given node
3979 *
3980 * Returns the new path or NULL in case of error. The caller must free
3981 * the returned string
3982 */
3983xmlChar *
3984xmlGetNodePath(xmlNodePtr node)
3985{
3986 xmlNodePtr cur, tmp, next;
3987 xmlChar *buffer = NULL, *temp;
3988 size_t buf_len;
3989 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00003990 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00003991 const char *name;
3992 char nametemp[100];
3993 int occur = 0;
3994
3995 if (node == NULL)
3996 return (NULL);
3997
3998 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00003999 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004000 if (buffer == NULL)
4001 return (NULL);
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004002 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004003 if (buf == NULL) {
4004 xmlFree(buffer);
4005 return (NULL);
4006 }
4007
4008 buffer[0] = 0;
4009 cur = node;
4010 do {
4011 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004012 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004013 occur = 0;
4014 if ((cur->type == XML_DOCUMENT_NODE) ||
4015 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4016 if (buffer[0] == '/')
4017 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004018 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004019 next = NULL;
4020 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004021 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004022 name = (const char *) cur->name;
4023 if (cur->ns) {
4024 snprintf(nametemp, sizeof(nametemp) - 1,
4025 "%s:%s", cur->ns->prefix, cur->name);
4026 nametemp[sizeof(nametemp) - 1] = 0;
4027 name = nametemp;
4028 }
4029 next = cur->parent;
4030
4031 /*
4032 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004033 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004034 */
4035 tmp = cur->prev;
4036 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004037 if ((tmp->type == XML_ELEMENT_NODE) &&
4038 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004039 occur++;
4040 tmp = tmp->prev;
4041 }
4042 if (occur == 0) {
4043 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004044 while (tmp != NULL && occur == 0) {
4045 if ((tmp->type == XML_ELEMENT_NODE) &&
4046 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004047 occur++;
4048 tmp = tmp->next;
4049 }
4050 if (occur != 0)
4051 occur = 1;
4052 } else
4053 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004054 } else if (cur->type == XML_COMMENT_NODE) {
4055 sep = "/";
4056 name = "comment()";
4057 next = cur->parent;
4058
4059 /*
4060 * Thumbler index computation
4061 */
4062 tmp = cur->prev;
4063 while (tmp != NULL) {
4064 if (tmp->type == XML_COMMENT_NODE)
4065 occur++;
4066 tmp = tmp->prev;
4067 }
4068 if (occur == 0) {
4069 tmp = cur->next;
4070 while (tmp != NULL && occur == 0) {
4071 if (tmp->type == XML_COMMENT_NODE)
4072 occur++;
4073 tmp = tmp->next;
4074 }
4075 if (occur != 0)
4076 occur = 1;
4077 } else
4078 occur++;
4079 } else if ((cur->type == XML_TEXT_NODE) ||
4080 (cur->type == XML_CDATA_SECTION_NODE)) {
4081 sep = "/";
4082 name = "text()";
4083 next = cur->parent;
4084
4085 /*
4086 * Thumbler index computation
4087 */
4088 tmp = cur->prev;
4089 while (tmp != NULL) {
4090 if ((cur->type == XML_TEXT_NODE) ||
4091 (cur->type == XML_CDATA_SECTION_NODE))
4092 occur++;
4093 tmp = tmp->prev;
4094 }
4095 if (occur == 0) {
4096 tmp = cur->next;
4097 while (tmp != NULL && occur == 0) {
4098 if ((cur->type == XML_TEXT_NODE) ||
4099 (cur->type == XML_CDATA_SECTION_NODE))
4100 occur++;
4101 tmp = tmp->next;
4102 }
4103 if (occur != 0)
4104 occur = 1;
4105 } else
4106 occur++;
4107 } else if (cur->type == XML_PI_NODE) {
4108 sep = "/";
4109 snprintf(nametemp, sizeof(nametemp) - 1,
4110 "processing-instruction('%s')", cur->name);
4111 nametemp[sizeof(nametemp) - 1] = 0;
4112 name = nametemp;
4113
4114 next = cur->parent;
4115
4116 /*
4117 * Thumbler index computation
4118 */
4119 tmp = cur->prev;
4120 while (tmp != NULL) {
4121 if ((tmp->type == XML_PI_NODE) &&
4122 (xmlStrEqual(cur->name, tmp->name)))
4123 occur++;
4124 tmp = tmp->prev;
4125 }
4126 if (occur == 0) {
4127 tmp = cur->next;
4128 while (tmp != NULL && occur == 0) {
4129 if ((tmp->type == XML_PI_NODE) &&
4130 (xmlStrEqual(cur->name, tmp->name)))
4131 occur++;
4132 tmp = tmp->next;
4133 }
4134 if (occur != 0)
4135 occur = 1;
4136 } else
4137 occur++;
4138
Daniel Veillard8faa7832001-11-26 15:58:08 +00004139 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004140 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004141 name = (const char *) (((xmlAttrPtr) cur)->name);
4142 next = ((xmlAttrPtr) cur)->parent;
4143 } else {
4144 next = cur->parent;
4145 }
4146
4147 /*
4148 * Make sure there is enough room
4149 */
4150 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4151 buf_len =
4152 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4153 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4154 if (temp == NULL) {
4155 xmlFree(buf);
4156 xmlFree(buffer);
4157 return (NULL);
4158 }
4159 buffer = temp;
4160 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4161 if (temp == NULL) {
4162 xmlFree(buf);
4163 xmlFree(buffer);
4164 return (NULL);
4165 }
4166 buf = temp;
4167 }
4168 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004169 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004170 sep, name, (char *) buffer);
4171 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004172 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004173 sep, name, occur, (char *) buffer);
4174 snprintf((char *) buffer, buf_len, "%s", buf);
4175 cur = next;
4176 } while (cur != NULL);
4177 xmlFree(buf);
4178 return (buffer);
4179}
4180
4181/**
Owen Taylor3473f882001-02-23 17:55:21 +00004182 * xmlDocGetRootElement:
4183 * @doc: the document
4184 *
4185 * Get the root element of the document (doc->children is a list
4186 * containing possibly comments, PIs, etc ...).
4187 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004188 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004189 */
4190xmlNodePtr
4191xmlDocGetRootElement(xmlDocPtr doc) {
4192 xmlNodePtr ret;
4193
4194 if (doc == NULL) return(NULL);
4195 ret = doc->children;
4196 while (ret != NULL) {
4197 if (ret->type == XML_ELEMENT_NODE)
4198 return(ret);
4199 ret = ret->next;
4200 }
4201 return(ret);
4202}
4203
4204/**
4205 * xmlDocSetRootElement:
4206 * @doc: the document
4207 * @root: the new document root element
4208 *
4209 * Set the root element of the document (doc->children is a list
4210 * containing possibly comments, PIs, etc ...).
4211 *
4212 * Returns the old root element if any was found
4213 */
4214xmlNodePtr
4215xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4216 xmlNodePtr old = NULL;
4217
4218 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004219 if (root == NULL)
4220 return(NULL);
4221 xmlUnlinkNode(root);
4222 root->doc = doc;
4223 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004224 old = doc->children;
4225 while (old != NULL) {
4226 if (old->type == XML_ELEMENT_NODE)
4227 break;
4228 old = old->next;
4229 }
4230 if (old == NULL) {
4231 if (doc->children == NULL) {
4232 doc->children = root;
4233 doc->last = root;
4234 } else {
4235 xmlAddSibling(doc->children, root);
4236 }
4237 } else {
4238 xmlReplaceNode(old, root);
4239 }
4240 return(old);
4241}
4242
4243/**
4244 * xmlNodeSetLang:
4245 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004246 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004247 *
4248 * Set the language of a node, i.e. the values of the xml:lang
4249 * attribute.
4250 */
4251void
4252xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004253 xmlNsPtr ns;
4254
Owen Taylor3473f882001-02-23 17:55:21 +00004255 if (cur == NULL) return;
4256 switch(cur->type) {
4257 case XML_TEXT_NODE:
4258 case XML_CDATA_SECTION_NODE:
4259 case XML_COMMENT_NODE:
4260 case XML_DOCUMENT_NODE:
4261 case XML_DOCUMENT_TYPE_NODE:
4262 case XML_DOCUMENT_FRAG_NODE:
4263 case XML_NOTATION_NODE:
4264 case XML_HTML_DOCUMENT_NODE:
4265 case XML_DTD_NODE:
4266 case XML_ELEMENT_DECL:
4267 case XML_ATTRIBUTE_DECL:
4268 case XML_ENTITY_DECL:
4269 case XML_PI_NODE:
4270 case XML_ENTITY_REF_NODE:
4271 case XML_ENTITY_NODE:
4272 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004273#ifdef LIBXML_DOCB_ENABLED
4274 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004275#endif
4276 case XML_XINCLUDE_START:
4277 case XML_XINCLUDE_END:
4278 return;
4279 case XML_ELEMENT_NODE:
4280 case XML_ATTRIBUTE_NODE:
4281 break;
4282 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004283 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4284 if (ns == NULL)
4285 return;
4286 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004287}
4288
4289/**
4290 * xmlNodeGetLang:
4291 * @cur: the node being checked
4292 *
4293 * Searches the language of a node, i.e. the values of the xml:lang
4294 * attribute or the one carried by the nearest ancestor.
4295 *
4296 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004297 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004298 */
4299xmlChar *
4300xmlNodeGetLang(xmlNodePtr cur) {
4301 xmlChar *lang;
4302
4303 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004304 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004305 if (lang != NULL)
4306 return(lang);
4307 cur = cur->parent;
4308 }
4309 return(NULL);
4310}
4311
4312
4313/**
4314 * xmlNodeSetSpacePreserve:
4315 * @cur: the node being changed
4316 * @val: the xml:space value ("0": default, 1: "preserve")
4317 *
4318 * Set (or reset) the space preserving behaviour of a node, i.e. the
4319 * value of the xml:space attribute.
4320 */
4321void
4322xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004323 xmlNsPtr ns;
4324
Owen Taylor3473f882001-02-23 17:55:21 +00004325 if (cur == NULL) return;
4326 switch(cur->type) {
4327 case XML_TEXT_NODE:
4328 case XML_CDATA_SECTION_NODE:
4329 case XML_COMMENT_NODE:
4330 case XML_DOCUMENT_NODE:
4331 case XML_DOCUMENT_TYPE_NODE:
4332 case XML_DOCUMENT_FRAG_NODE:
4333 case XML_NOTATION_NODE:
4334 case XML_HTML_DOCUMENT_NODE:
4335 case XML_DTD_NODE:
4336 case XML_ELEMENT_DECL:
4337 case XML_ATTRIBUTE_DECL:
4338 case XML_ENTITY_DECL:
4339 case XML_PI_NODE:
4340 case XML_ENTITY_REF_NODE:
4341 case XML_ENTITY_NODE:
4342 case XML_NAMESPACE_DECL:
4343 case XML_XINCLUDE_START:
4344 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004345#ifdef LIBXML_DOCB_ENABLED
4346 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004347#endif
4348 return;
4349 case XML_ELEMENT_NODE:
4350 case XML_ATTRIBUTE_NODE:
4351 break;
4352 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004353 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4354 if (ns == NULL)
4355 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004356 switch (val) {
4357 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004358 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004359 break;
4360 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004361 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004362 break;
4363 }
4364}
4365
4366/**
4367 * xmlNodeGetSpacePreserve:
4368 * @cur: the node being checked
4369 *
4370 * Searches the space preserving behaviour of a node, i.e. the values
4371 * of the xml:space attribute or the one carried by the nearest
4372 * ancestor.
4373 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004374 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004375 */
4376int
4377xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4378 xmlChar *space;
4379
4380 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004381 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004382 if (space != NULL) {
4383 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4384 xmlFree(space);
4385 return(1);
4386 }
4387 if (xmlStrEqual(space, BAD_CAST "default")) {
4388 xmlFree(space);
4389 return(0);
4390 }
4391 xmlFree(space);
4392 }
4393 cur = cur->parent;
4394 }
4395 return(-1);
4396}
4397
4398/**
4399 * xmlNodeSetName:
4400 * @cur: the node being changed
4401 * @name: the new tag name
4402 *
4403 * Set (or reset) the name of a node.
4404 */
4405void
4406xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
4407 if (cur == NULL) return;
4408 if (name == NULL) return;
4409 switch(cur->type) {
4410 case XML_TEXT_NODE:
4411 case XML_CDATA_SECTION_NODE:
4412 case XML_COMMENT_NODE:
4413 case XML_DOCUMENT_TYPE_NODE:
4414 case XML_DOCUMENT_FRAG_NODE:
4415 case XML_NOTATION_NODE:
4416 case XML_HTML_DOCUMENT_NODE:
4417 case XML_NAMESPACE_DECL:
4418 case XML_XINCLUDE_START:
4419 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004420#ifdef LIBXML_DOCB_ENABLED
4421 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004422#endif
4423 return;
4424 case XML_ELEMENT_NODE:
4425 case XML_ATTRIBUTE_NODE:
4426 case XML_PI_NODE:
4427 case XML_ENTITY_REF_NODE:
4428 case XML_ENTITY_NODE:
4429 case XML_DTD_NODE:
4430 case XML_DOCUMENT_NODE:
4431 case XML_ELEMENT_DECL:
4432 case XML_ATTRIBUTE_DECL:
4433 case XML_ENTITY_DECL:
4434 break;
4435 }
4436 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4437 cur->name = xmlStrdup(name);
4438}
4439
4440/**
4441 * xmlNodeSetBase:
4442 * @cur: the node being changed
4443 * @uri: the new base URI
4444 *
4445 * Set (or reset) the base URI of a node, i.e. the value of the
4446 * xml:base attribute.
4447 */
4448void
4449xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004450 xmlNsPtr ns;
4451
Owen Taylor3473f882001-02-23 17:55:21 +00004452 if (cur == NULL) return;
4453 switch(cur->type) {
4454 case XML_TEXT_NODE:
4455 case XML_CDATA_SECTION_NODE:
4456 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004457 case XML_DOCUMENT_TYPE_NODE:
4458 case XML_DOCUMENT_FRAG_NODE:
4459 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004460 case XML_DTD_NODE:
4461 case XML_ELEMENT_DECL:
4462 case XML_ATTRIBUTE_DECL:
4463 case XML_ENTITY_DECL:
4464 case XML_PI_NODE:
4465 case XML_ENTITY_REF_NODE:
4466 case XML_ENTITY_NODE:
4467 case XML_NAMESPACE_DECL:
4468 case XML_XINCLUDE_START:
4469 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004470 return;
4471 case XML_ELEMENT_NODE:
4472 case XML_ATTRIBUTE_NODE:
4473 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004474 case XML_DOCUMENT_NODE:
4475#ifdef LIBXML_DOCB_ENABLED
4476 case XML_DOCB_DOCUMENT_NODE:
4477#endif
4478 case XML_HTML_DOCUMENT_NODE: {
4479 xmlDocPtr doc = (xmlDocPtr) cur;
4480
4481 if (doc->URL != NULL)
4482 xmlFree((xmlChar *) doc->URL);
4483 if (uri == NULL)
4484 doc->URL = NULL;
4485 else
4486 doc->URL = xmlStrdup(uri);
4487 return;
4488 }
Owen Taylor3473f882001-02-23 17:55:21 +00004489 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004490
4491 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4492 if (ns == NULL)
4493 return;
4494 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004495}
4496
4497/**
Owen Taylor3473f882001-02-23 17:55:21 +00004498 * xmlNodeGetBase:
4499 * @doc: the document the node pertains to
4500 * @cur: the node being checked
4501 *
4502 * Searches for the BASE URL. The code should work on both XML
4503 * and HTML document even if base mechanisms are completely different.
4504 * It returns the base as defined in RFC 2396 sections
4505 * 5.1.1. Base URI within Document Content
4506 * and
4507 * 5.1.2. Base URI from the Encapsulating Entity
4508 * However it does not return the document base (5.1.3), use
4509 * xmlDocumentGetBase() for this
4510 *
4511 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004512 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004513 */
4514xmlChar *
4515xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004516 xmlChar *oldbase = NULL;
4517 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004518
4519 if ((cur == NULL) && (doc == NULL))
4520 return(NULL);
4521 if (doc == NULL) doc = cur->doc;
4522 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4523 cur = doc->children;
4524 while ((cur != NULL) && (cur->name != NULL)) {
4525 if (cur->type != XML_ELEMENT_NODE) {
4526 cur = cur->next;
4527 continue;
4528 }
4529 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4530 cur = cur->children;
4531 continue;
4532 }
4533 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4534 cur = cur->children;
4535 continue;
4536 }
4537 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4538 return(xmlGetProp(cur, BAD_CAST "href"));
4539 }
4540 cur = cur->next;
4541 }
4542 return(NULL);
4543 }
4544 while (cur != NULL) {
4545 if (cur->type == XML_ENTITY_DECL) {
4546 xmlEntityPtr ent = (xmlEntityPtr) cur;
4547 return(xmlStrdup(ent->URI));
4548 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004549 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004550 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004551 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004552 if (oldbase != NULL) {
4553 newbase = xmlBuildURI(oldbase, base);
4554 if (newbase != NULL) {
4555 xmlFree(oldbase);
4556 xmlFree(base);
4557 oldbase = newbase;
4558 } else {
4559 xmlFree(oldbase);
4560 xmlFree(base);
4561 return(NULL);
4562 }
4563 } else {
4564 oldbase = base;
4565 }
4566 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4567 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4568 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4569 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004570 }
4571 }
Owen Taylor3473f882001-02-23 17:55:21 +00004572 cur = cur->parent;
4573 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004574 if ((doc != NULL) && (doc->URL != NULL)) {
4575 if (oldbase == NULL)
4576 return(xmlStrdup(doc->URL));
4577 newbase = xmlBuildURI(oldbase, doc->URL);
4578 xmlFree(oldbase);
4579 return(newbase);
4580 }
4581 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004582}
4583
4584/**
4585 * xmlNodeGetContent:
4586 * @cur: the node being read
4587 *
4588 * Read the value of a node, this can be either the text carried
4589 * directly by this node if it's a TEXT node or the aggregate string
4590 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004591 * Entity references are substituted.
4592 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004593 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004594 */
4595xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004596xmlNodeGetContent(xmlNodePtr cur)
4597{
4598 if (cur == NULL)
4599 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004600 switch (cur->type) {
4601 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004602 case XML_ELEMENT_NODE:{
4603 xmlNodePtr tmp = cur;
4604 xmlBufferPtr buffer;
4605 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004606
Daniel Veillard814a76d2003-01-23 18:24:20 +00004607 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004608 if (buffer == NULL)
4609 return (NULL);
4610 while (tmp != NULL) {
4611 switch (tmp->type) {
4612 case XML_CDATA_SECTION_NODE:
4613 case XML_TEXT_NODE:
4614 if (tmp->content != NULL)
4615 xmlBufferCat(buffer, tmp->content);
4616 break;
4617 case XML_ENTITY_REF_NODE:{
4618 /* recursive substitution of entity references */
4619 xmlChar *cont = xmlNodeGetContent(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00004620
Daniel Veillard7646b182002-04-20 06:41:40 +00004621 if (cont) {
4622 xmlBufferCat(buffer,
4623 (const xmlChar *) cont);
4624 xmlFree(cont);
4625 }
4626 break;
4627 }
4628 default:
4629 break;
4630 }
4631 /*
4632 * Skip to next node
4633 */
4634 if (tmp->children != NULL) {
4635 if (tmp->children->type != XML_ENTITY_DECL) {
4636 tmp = tmp->children;
4637 continue;
4638 }
4639 }
4640 if (tmp == cur)
4641 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00004642
Daniel Veillard7646b182002-04-20 06:41:40 +00004643 if (tmp->next != NULL) {
4644 tmp = tmp->next;
4645 continue;
4646 }
4647
4648 do {
4649 tmp = tmp->parent;
4650 if (tmp == NULL)
4651 break;
4652 if (tmp == cur) {
4653 tmp = NULL;
4654 break;
4655 }
4656 if (tmp->next != NULL) {
4657 tmp = tmp->next;
4658 break;
4659 }
4660 } while (tmp != NULL);
4661 }
4662 ret = buffer->content;
4663 buffer->content = NULL;
4664 xmlBufferFree(buffer);
4665 return (ret);
4666 }
4667 case XML_ATTRIBUTE_NODE:{
4668 xmlAttrPtr attr = (xmlAttrPtr) cur;
4669
4670 if (attr->parent != NULL)
4671 return (xmlNodeListGetString
4672 (attr->parent->doc, attr->children, 1));
4673 else
4674 return (xmlNodeListGetString(NULL, attr->children, 1));
4675 break;
4676 }
Owen Taylor3473f882001-02-23 17:55:21 +00004677 case XML_COMMENT_NODE:
4678 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004679 if (cur->content != NULL)
4680 return (xmlStrdup(cur->content));
4681 return (NULL);
4682 case XML_ENTITY_REF_NODE:{
4683 xmlEntityPtr ent;
4684 xmlNodePtr tmp;
4685 xmlBufferPtr buffer;
4686 xmlChar *ret;
4687
4688 /* lookup entity declaration */
4689 ent = xmlGetDocEntity(cur->doc, cur->name);
4690 if (ent == NULL)
4691 return (NULL);
4692
4693 buffer = xmlBufferCreate();
4694 if (buffer == NULL)
4695 return (NULL);
4696
4697 /* an entity content can be any "well balanced chunk",
4698 * i.e. the result of the content [43] production:
4699 * http://www.w3.org/TR/REC-xml#NT-content
4700 * -> we iterate through child nodes and recursive call
4701 * xmlNodeGetContent() which handles all possible node types */
4702 tmp = ent->children;
4703 while (tmp) {
4704 xmlChar *cont = xmlNodeGetContent(tmp);
4705
4706 if (cont) {
4707 xmlBufferCat(buffer, (const xmlChar *) cont);
4708 xmlFree(cont);
4709 }
4710 tmp = tmp->next;
4711 }
4712
4713 ret = buffer->content;
4714 buffer->content = NULL;
4715 xmlBufferFree(buffer);
4716 return (ret);
4717 }
Owen Taylor3473f882001-02-23 17:55:21 +00004718 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004719 case XML_DOCUMENT_TYPE_NODE:
4720 case XML_NOTATION_NODE:
4721 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004722 case XML_XINCLUDE_START:
4723 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00004724 return (NULL);
4725 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004726#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004727 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004728#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00004729 case XML_HTML_DOCUMENT_NODE: {
4730 xmlChar *tmp;
4731 xmlChar *res = NULL;
4732
4733 cur = cur->children;
4734 while (cur!= NULL) {
4735 if ((cur->type == XML_ELEMENT_NODE) ||
4736 (cur->type == XML_TEXT_NODE) ||
4737 (cur->type == XML_CDATA_SECTION_NODE)) {
4738 tmp = xmlNodeGetContent(cur);
4739 if (tmp != NULL) {
4740 if (res == NULL)
4741 res = tmp;
4742 else {
4743 res = xmlStrcat(res, tmp);
4744 xmlFree(tmp);
4745 }
4746 }
4747 }
4748 cur = cur->next;
4749 }
4750 return(res);
4751 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004752 case XML_NAMESPACE_DECL: {
4753 xmlChar *tmp;
4754
4755 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4756 return (tmp);
4757 }
Owen Taylor3473f882001-02-23 17:55:21 +00004758 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004759 /* TODO !!! */
4760 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004761 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004762 /* TODO !!! */
4763 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004764 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004765 /* TODO !!! */
4766 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004767 case XML_CDATA_SECTION_NODE:
4768 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004769 if (cur->content != NULL)
4770 return (xmlStrdup(cur->content));
4771 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004772 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004773 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004774}
Owen Taylor3473f882001-02-23 17:55:21 +00004775/**
4776 * xmlNodeSetContent:
4777 * @cur: the node being modified
4778 * @content: the new value of the content
4779 *
4780 * Replace the content of a node.
4781 */
4782void
4783xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4784 if (cur == NULL) {
4785#ifdef DEBUG_TREE
4786 xmlGenericError(xmlGenericErrorContext,
4787 "xmlNodeSetContent : node == NULL\n");
4788#endif
4789 return;
4790 }
4791 switch (cur->type) {
4792 case XML_DOCUMENT_FRAG_NODE:
4793 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004794 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004795 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4796 cur->children = xmlStringGetNodeList(cur->doc, content);
4797 UPDATE_LAST_CHILD_AND_PARENT(cur)
4798 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004799 case XML_TEXT_NODE:
4800 case XML_CDATA_SECTION_NODE:
4801 case XML_ENTITY_REF_NODE:
4802 case XML_ENTITY_NODE:
4803 case XML_PI_NODE:
4804 case XML_COMMENT_NODE:
4805 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004806 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004807 }
4808 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4809 cur->last = cur->children = NULL;
4810 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004811 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00004812 } else
4813 cur->content = NULL;
4814 break;
4815 case XML_DOCUMENT_NODE:
4816 case XML_HTML_DOCUMENT_NODE:
4817 case XML_DOCUMENT_TYPE_NODE:
4818 case XML_XINCLUDE_START:
4819 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004820#ifdef LIBXML_DOCB_ENABLED
4821 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004822#endif
4823 break;
4824 case XML_NOTATION_NODE:
4825 break;
4826 case XML_DTD_NODE:
4827 break;
4828 case XML_NAMESPACE_DECL:
4829 break;
4830 case XML_ELEMENT_DECL:
4831 /* TODO !!! */
4832 break;
4833 case XML_ATTRIBUTE_DECL:
4834 /* TODO !!! */
4835 break;
4836 case XML_ENTITY_DECL:
4837 /* TODO !!! */
4838 break;
4839 }
4840}
4841
4842/**
4843 * xmlNodeSetContentLen:
4844 * @cur: the node being modified
4845 * @content: the new value of the content
4846 * @len: the size of @content
4847 *
4848 * Replace the content of a node.
4849 */
4850void
4851xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4852 if (cur == NULL) {
4853#ifdef DEBUG_TREE
4854 xmlGenericError(xmlGenericErrorContext,
4855 "xmlNodeSetContentLen : node == NULL\n");
4856#endif
4857 return;
4858 }
4859 switch (cur->type) {
4860 case XML_DOCUMENT_FRAG_NODE:
4861 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004862 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004863 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4864 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
4865 UPDATE_LAST_CHILD_AND_PARENT(cur)
4866 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004867 case XML_TEXT_NODE:
4868 case XML_CDATA_SECTION_NODE:
4869 case XML_ENTITY_REF_NODE:
4870 case XML_ENTITY_NODE:
4871 case XML_PI_NODE:
4872 case XML_COMMENT_NODE:
4873 case XML_NOTATION_NODE:
4874 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004875 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004876 }
4877 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4878 cur->children = cur->last = NULL;
4879 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004880 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004881 } else
4882 cur->content = NULL;
4883 break;
4884 case XML_DOCUMENT_NODE:
4885 case XML_DTD_NODE:
4886 case XML_HTML_DOCUMENT_NODE:
4887 case XML_DOCUMENT_TYPE_NODE:
4888 case XML_NAMESPACE_DECL:
4889 case XML_XINCLUDE_START:
4890 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004891#ifdef LIBXML_DOCB_ENABLED
4892 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004893#endif
4894 break;
4895 case XML_ELEMENT_DECL:
4896 /* TODO !!! */
4897 break;
4898 case XML_ATTRIBUTE_DECL:
4899 /* TODO !!! */
4900 break;
4901 case XML_ENTITY_DECL:
4902 /* TODO !!! */
4903 break;
4904 }
4905}
4906
4907/**
4908 * xmlNodeAddContentLen:
4909 * @cur: the node being modified
4910 * @content: extra content
4911 * @len: the size of @content
4912 *
4913 * Append the extra substring to the node content.
4914 */
4915void
4916xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4917 if (cur == NULL) {
4918#ifdef DEBUG_TREE
4919 xmlGenericError(xmlGenericErrorContext,
4920 "xmlNodeAddContentLen : node == NULL\n");
4921#endif
4922 return;
4923 }
4924 if (len <= 0) return;
4925 switch (cur->type) {
4926 case XML_DOCUMENT_FRAG_NODE:
4927 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004928 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004929
Daniel Veillard7db37732001-07-12 01:20:08 +00004930 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004931 newNode = xmlNewTextLen(content, len);
4932 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004933 tmp = xmlAddChild(cur, newNode);
4934 if (tmp != newNode)
4935 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004936 if ((last != NULL) && (last->next == newNode)) {
4937 xmlTextMerge(last, newNode);
4938 }
4939 }
4940 break;
4941 }
4942 case XML_ATTRIBUTE_NODE:
4943 break;
4944 case XML_TEXT_NODE:
4945 case XML_CDATA_SECTION_NODE:
4946 case XML_ENTITY_REF_NODE:
4947 case XML_ENTITY_NODE:
4948 case XML_PI_NODE:
4949 case XML_COMMENT_NODE:
4950 case XML_NOTATION_NODE:
4951 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004952 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004953 }
4954 case XML_DOCUMENT_NODE:
4955 case XML_DTD_NODE:
4956 case XML_HTML_DOCUMENT_NODE:
4957 case XML_DOCUMENT_TYPE_NODE:
4958 case XML_NAMESPACE_DECL:
4959 case XML_XINCLUDE_START:
4960 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004961#ifdef LIBXML_DOCB_ENABLED
4962 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004963#endif
4964 break;
4965 case XML_ELEMENT_DECL:
4966 case XML_ATTRIBUTE_DECL:
4967 case XML_ENTITY_DECL:
4968 break;
4969 }
4970}
4971
4972/**
4973 * xmlNodeAddContent:
4974 * @cur: the node being modified
4975 * @content: extra content
4976 *
4977 * Append the extra substring to the node content.
4978 */
4979void
4980xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
4981 int len;
4982
4983 if (cur == NULL) {
4984#ifdef DEBUG_TREE
4985 xmlGenericError(xmlGenericErrorContext,
4986 "xmlNodeAddContent : node == NULL\n");
4987#endif
4988 return;
4989 }
4990 if (content == NULL) return;
4991 len = xmlStrlen(content);
4992 xmlNodeAddContentLen(cur, content, len);
4993}
4994
4995/**
4996 * xmlTextMerge:
4997 * @first: the first text node
4998 * @second: the second text node being merged
4999 *
5000 * Merge two text nodes into one
5001 * Returns the first text node augmented
5002 */
5003xmlNodePtr
5004xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5005 if (first == NULL) return(second);
5006 if (second == NULL) return(first);
5007 if (first->type != XML_TEXT_NODE) return(first);
5008 if (second->type != XML_TEXT_NODE) return(first);
5009 if (second->name != first->name)
5010 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005011 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005012 xmlUnlinkNode(second);
5013 xmlFreeNode(second);
5014 return(first);
5015}
5016
5017/**
5018 * xmlGetNsList:
5019 * @doc: the document
5020 * @node: the current node
5021 *
5022 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005023 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005024 * that need to be freed by the caller or NULL if no
5025 * namespace if defined
5026 */
5027xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005028xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5029{
Owen Taylor3473f882001-02-23 17:55:21 +00005030 xmlNsPtr cur;
5031 xmlNsPtr *ret = NULL;
5032 int nbns = 0;
5033 int maxns = 10;
5034 int i;
5035
5036 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005037 if (node->type == XML_ELEMENT_NODE) {
5038 cur = node->nsDef;
5039 while (cur != NULL) {
5040 if (ret == NULL) {
5041 ret =
5042 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5043 sizeof(xmlNsPtr));
5044 if (ret == NULL) {
5045 xmlGenericError(xmlGenericErrorContext,
5046 "xmlGetNsList : out of memory!\n");
5047 return (NULL);
5048 }
5049 ret[nbns] = NULL;
5050 }
5051 for (i = 0; i < nbns; i++) {
5052 if ((cur->prefix == ret[i]->prefix) ||
5053 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5054 break;
5055 }
5056 if (i >= nbns) {
5057 if (nbns >= maxns) {
5058 maxns *= 2;
5059 ret = (xmlNsPtr *) xmlRealloc(ret,
5060 (maxns +
5061 1) *
5062 sizeof(xmlNsPtr));
5063 if (ret == NULL) {
5064 xmlGenericError(xmlGenericErrorContext,
5065 "xmlGetNsList : realloc failed!\n");
5066 return (NULL);
5067 }
5068 }
5069 ret[nbns++] = cur;
5070 ret[nbns] = NULL;
5071 }
Owen Taylor3473f882001-02-23 17:55:21 +00005072
Daniel Veillard77044732001-06-29 21:31:07 +00005073 cur = cur->next;
5074 }
5075 }
5076 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005077 }
Daniel Veillard77044732001-06-29 21:31:07 +00005078 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005079}
5080
5081/**
5082 * xmlSearchNs:
5083 * @doc: the document
5084 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005085 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005086 *
5087 * Search a Ns registered under a given name space for a document.
5088 * recurse on the parents until it finds the defined namespace
5089 * or return NULL otherwise.
5090 * @nameSpace can be NULL, this is a search for the default namespace.
5091 * We don't allow to cross entities boundaries. If you don't declare
5092 * the namespace within those you will be in troubles !!! A warning
5093 * is generated to cover this case.
5094 *
5095 * Returns the namespace pointer or NULL.
5096 */
5097xmlNsPtr
5098xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
5099 xmlNsPtr cur;
5100
5101 if (node == NULL) return(NULL);
5102 if ((nameSpace != NULL) &&
5103 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005104 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5105 /*
5106 * The XML-1.0 namespace is normally held on the root
5107 * element. In this case exceptionally create it on the
5108 * node element.
5109 */
5110 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5111 if (cur == NULL) {
5112 xmlGenericError(xmlGenericErrorContext,
5113 "xmlSearchNs : malloc failed\n");
5114 return(NULL);
5115 }
5116 memset(cur, 0, sizeof(xmlNs));
5117 cur->type = XML_LOCAL_NAMESPACE;
5118 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5119 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5120 cur->next = node->nsDef;
5121 node->nsDef = cur;
5122 return(cur);
5123 }
Owen Taylor3473f882001-02-23 17:55:21 +00005124 if (doc->oldNs == NULL) {
5125 /*
5126 * Allocate a new Namespace and fill the fields.
5127 */
5128 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5129 if (doc->oldNs == NULL) {
5130 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005131 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005132 return(NULL);
5133 }
5134 memset(doc->oldNs, 0, sizeof(xmlNs));
5135 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5136
5137 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5138 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5139 }
5140 return(doc->oldNs);
5141 }
5142 while (node != NULL) {
5143 if ((node->type == XML_ENTITY_REF_NODE) ||
5144 (node->type == XML_ENTITY_NODE) ||
5145 (node->type == XML_ENTITY_DECL))
5146 return(NULL);
5147 if (node->type == XML_ELEMENT_NODE) {
5148 cur = node->nsDef;
5149 while (cur != NULL) {
5150 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5151 (cur->href != NULL))
5152 return(cur);
5153 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5154 (cur->href != NULL) &&
5155 (xmlStrEqual(cur->prefix, nameSpace)))
5156 return(cur);
5157 cur = cur->next;
5158 }
5159 }
5160 node = node->parent;
5161 }
5162 return(NULL);
5163}
5164
5165/**
5166 * xmlSearchNsByHref:
5167 * @doc: the document
5168 * @node: the current node
5169 * @href: the namespace value
5170 *
5171 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5172 * the defined namespace or return NULL otherwise.
5173 * Returns the namespace pointer or NULL.
5174 */
5175xmlNsPtr
5176xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
5177 xmlNsPtr cur;
5178 xmlNodePtr orig = node;
5179
5180 if ((node == NULL) || (href == NULL)) return(NULL);
5181 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00005182 /*
5183 * Only the document can hold the XML spec namespace.
5184 */
Daniel Veillardc1a0da32002-08-14 08:32:18 +00005185 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5186 /*
5187 * The XML-1.0 namespace is normally held on the root
5188 * element. In this case exceptionally create it on the
5189 * node element.
5190 */
5191 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5192 if (cur == NULL) {
5193 xmlGenericError(xmlGenericErrorContext,
5194 "xmlSearchNs : malloc failed\n");
5195 return(NULL);
5196 }
5197 memset(cur, 0, sizeof(xmlNs));
5198 cur->type = XML_LOCAL_NAMESPACE;
5199 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5200 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5201 cur->next = node->nsDef;
5202 node->nsDef = cur;
5203 return(cur);
5204 }
Owen Taylor3473f882001-02-23 17:55:21 +00005205 if (doc->oldNs == NULL) {
5206 /*
5207 * Allocate a new Namespace and fill the fields.
5208 */
5209 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5210 if (doc->oldNs == NULL) {
5211 xmlGenericError(xmlGenericErrorContext,
5212 "xmlSearchNsByHref : malloc failed\n");
5213 return(NULL);
5214 }
5215 memset(doc->oldNs, 0, sizeof(xmlNs));
5216 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5217
5218 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5219 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5220 }
5221 return(doc->oldNs);
5222 }
5223 while (node != NULL) {
5224 cur = node->nsDef;
5225 while (cur != NULL) {
5226 if ((cur->href != NULL) && (href != NULL) &&
5227 (xmlStrEqual(cur->href, href))) {
5228 /*
5229 * Check that the prefix is not shadowed between orig and node
5230 */
5231 xmlNodePtr check = orig;
5232 xmlNsPtr tst;
5233
5234 while (check != node) {
5235 tst = check->nsDef;
5236 while (tst != NULL) {
5237 if ((tst->prefix == NULL) && (cur->prefix == NULL))
5238 goto shadowed;
5239 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
5240 (xmlStrEqual(tst->prefix, cur->prefix)))
5241 goto shadowed;
5242 tst = tst->next;
5243 }
5244 check = check->parent;
5245 }
5246 return(cur);
5247 }
5248shadowed:
5249 cur = cur->next;
5250 }
5251 node = node->parent;
5252 }
5253 return(NULL);
5254}
5255
5256/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005257 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005258 * @doc: the document
5259 * @tree: a node expected to hold the new namespace
5260 * @ns: the original namespace
5261 *
5262 * This function tries to locate a namespace definition in a tree
5263 * ancestors, or create a new namespace definition node similar to
5264 * @ns trying to reuse the same prefix. However if the given prefix is
5265 * null (default namespace) or reused within the subtree defined by
5266 * @tree or on one of its ancestors then a new prefix is generated.
5267 * Returns the (new) namespace definition or NULL in case of error
5268 */
5269xmlNsPtr
5270xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5271 xmlNsPtr def;
5272 xmlChar prefix[50];
5273 int counter = 1;
5274
5275 if (tree == NULL) {
5276#ifdef DEBUG_TREE
5277 xmlGenericError(xmlGenericErrorContext,
5278 "xmlNewReconciliedNs : tree == NULL\n");
5279#endif
5280 return(NULL);
5281 }
5282 if (ns == NULL) {
5283#ifdef DEBUG_TREE
5284 xmlGenericError(xmlGenericErrorContext,
5285 "xmlNewReconciliedNs : ns == NULL\n");
5286#endif
5287 return(NULL);
5288 }
5289 /*
5290 * Search an existing namespace definition inherited.
5291 */
5292 def = xmlSearchNsByHref(doc, tree, ns->href);
5293 if (def != NULL)
5294 return(def);
5295
5296 /*
5297 * Find a close prefix which is not already in use.
5298 * Let's strip namespace prefixes longer than 20 chars !
5299 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005300 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005301 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005302 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005303 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005304
Owen Taylor3473f882001-02-23 17:55:21 +00005305 def = xmlSearchNs(doc, tree, prefix);
5306 while (def != NULL) {
5307 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005308 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005309 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005310 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005311 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005312 def = xmlSearchNs(doc, tree, prefix);
5313 }
5314
5315 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005316 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005317 */
5318 def = xmlNewNs(tree, ns->href, prefix);
5319 return(def);
5320}
5321
5322/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005323 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005324 * @doc: the document
5325 * @tree: a node defining the subtree to reconciliate
5326 *
5327 * This function checks that all the namespaces declared within the given
5328 * tree are properly declared. This is needed for example after Copy or Cut
5329 * and then paste operations. The subtree may still hold pointers to
5330 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005331 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005332 * the new environment. If not possible the new namespaces are redeclared
5333 * on @tree at the top of the given subtree.
5334 * Returns the number of namespace declarations created or -1 in case of error.
5335 */
5336int
5337xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5338 xmlNsPtr *oldNs = NULL;
5339 xmlNsPtr *newNs = NULL;
5340 int sizeCache = 0;
5341 int nbCache = 0;
5342
5343 xmlNsPtr n;
5344 xmlNodePtr node = tree;
5345 xmlAttrPtr attr;
5346 int ret = 0, i;
5347
5348 while (node != NULL) {
5349 /*
5350 * Reconciliate the node namespace
5351 */
5352 if (node->ns != NULL) {
5353 /*
5354 * initialize the cache if needed
5355 */
5356 if (sizeCache == 0) {
5357 sizeCache = 10;
5358 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5359 sizeof(xmlNsPtr));
5360 if (oldNs == NULL) {
5361 xmlGenericError(xmlGenericErrorContext,
5362 "xmlReconciliateNs : memory pbm\n");
5363 return(-1);
5364 }
5365 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5366 sizeof(xmlNsPtr));
5367 if (newNs == NULL) {
5368 xmlGenericError(xmlGenericErrorContext,
5369 "xmlReconciliateNs : memory pbm\n");
5370 xmlFree(oldNs);
5371 return(-1);
5372 }
5373 }
5374 for (i = 0;i < nbCache;i++) {
5375 if (oldNs[i] == node->ns) {
5376 node->ns = newNs[i];
5377 break;
5378 }
5379 }
5380 if (i == nbCache) {
5381 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005382 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005383 */
5384 n = xmlNewReconciliedNs(doc, tree, node->ns);
5385 if (n != NULL) { /* :-( what if else ??? */
5386 /*
5387 * check if we need to grow the cache buffers.
5388 */
5389 if (sizeCache <= nbCache) {
5390 sizeCache *= 2;
5391 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5392 sizeof(xmlNsPtr));
5393 if (oldNs == NULL) {
5394 xmlGenericError(xmlGenericErrorContext,
5395 "xmlReconciliateNs : memory pbm\n");
5396 xmlFree(newNs);
5397 return(-1);
5398 }
5399 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5400 sizeof(xmlNsPtr));
5401 if (newNs == NULL) {
5402 xmlGenericError(xmlGenericErrorContext,
5403 "xmlReconciliateNs : memory pbm\n");
5404 xmlFree(oldNs);
5405 return(-1);
5406 }
5407 }
5408 newNs[nbCache] = n;
5409 oldNs[nbCache++] = node->ns;
5410 node->ns = n;
5411 }
5412 }
5413 }
5414 /*
5415 * now check for namespace hold by attributes on the node.
5416 */
5417 attr = node->properties;
5418 while (attr != NULL) {
5419 if (attr->ns != NULL) {
5420 /*
5421 * initialize the cache if needed
5422 */
5423 if (sizeCache == 0) {
5424 sizeCache = 10;
5425 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5426 sizeof(xmlNsPtr));
5427 if (oldNs == NULL) {
5428 xmlGenericError(xmlGenericErrorContext,
5429 "xmlReconciliateNs : memory pbm\n");
5430 return(-1);
5431 }
5432 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5433 sizeof(xmlNsPtr));
5434 if (newNs == NULL) {
5435 xmlGenericError(xmlGenericErrorContext,
5436 "xmlReconciliateNs : memory pbm\n");
5437 xmlFree(oldNs);
5438 return(-1);
5439 }
5440 }
5441 for (i = 0;i < nbCache;i++) {
5442 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005443 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005444 break;
5445 }
5446 }
5447 if (i == nbCache) {
5448 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005449 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005450 */
5451 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5452 if (n != NULL) { /* :-( what if else ??? */
5453 /*
5454 * check if we need to grow the cache buffers.
5455 */
5456 if (sizeCache <= nbCache) {
5457 sizeCache *= 2;
5458 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5459 sizeof(xmlNsPtr));
5460 if (oldNs == NULL) {
5461 xmlGenericError(xmlGenericErrorContext,
5462 "xmlReconciliateNs : memory pbm\n");
5463 xmlFree(newNs);
5464 return(-1);
5465 }
5466 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5467 sizeof(xmlNsPtr));
5468 if (newNs == NULL) {
5469 xmlGenericError(xmlGenericErrorContext,
5470 "xmlReconciliateNs : memory pbm\n");
5471 xmlFree(oldNs);
5472 return(-1);
5473 }
5474 }
5475 newNs[nbCache] = n;
5476 oldNs[nbCache++] = attr->ns;
5477 attr->ns = n;
5478 }
5479 }
5480 }
5481 attr = attr->next;
5482 }
5483
5484 /*
5485 * Browse the full subtree, deep first
5486 */
5487 if (node->children != NULL) {
5488 /* deep first */
5489 node = node->children;
5490 } else if ((node != tree) && (node->next != NULL)) {
5491 /* then siblings */
5492 node = node->next;
5493 } else if (node != tree) {
5494 /* go up to parents->next if needed */
5495 while (node != tree) {
5496 if (node->parent != NULL)
5497 node = node->parent;
5498 if ((node != tree) && (node->next != NULL)) {
5499 node = node->next;
5500 break;
5501 }
5502 if (node->parent == NULL) {
5503 node = NULL;
5504 break;
5505 }
5506 }
5507 /* exit condition */
5508 if (node == tree)
5509 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005510 } else
5511 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005512 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005513 if (oldNs != NULL)
5514 xmlFree(oldNs);
5515 if (newNs != NULL)
5516 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005517 return(ret);
5518}
5519
5520/**
5521 * xmlHasProp:
5522 * @node: the node
5523 * @name: the attribute name
5524 *
5525 * Search an attribute associated to a node
5526 * This function also looks in DTD attribute declaration for #FIXED or
5527 * default declaration values unless DTD use has been turned off.
5528 *
5529 * Returns the attribute or the attribute declaration or NULL if
5530 * neither was found.
5531 */
5532xmlAttrPtr
5533xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5534 xmlAttrPtr prop;
5535 xmlDocPtr doc;
5536
5537 if ((node == NULL) || (name == NULL)) return(NULL);
5538 /*
5539 * Check on the properties attached to the node
5540 */
5541 prop = node->properties;
5542 while (prop != NULL) {
5543 if (xmlStrEqual(prop->name, name)) {
5544 return(prop);
5545 }
5546 prop = prop->next;
5547 }
5548 if (!xmlCheckDTD) return(NULL);
5549
5550 /*
5551 * Check if there is a default declaration in the internal
5552 * or external subsets
5553 */
5554 doc = node->doc;
5555 if (doc != NULL) {
5556 xmlAttributePtr attrDecl;
5557 if (doc->intSubset != NULL) {
5558 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5559 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5560 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5561 if (attrDecl != NULL)
5562 return((xmlAttrPtr) attrDecl);
5563 }
5564 }
5565 return(NULL);
5566}
5567
5568/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005569 * xmlHasNsProp:
5570 * @node: the node
5571 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005572 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005573 *
5574 * Search for an attribute associated to a node
5575 * This attribute has to be anchored in the namespace specified.
5576 * This does the entity substitution.
5577 * This function looks in DTD attribute declaration for #FIXED or
5578 * default declaration values unless DTD use has been turned off.
5579 *
5580 * Returns the attribute or the attribute declaration or NULL
5581 * if neither was found.
5582 */
5583xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005584xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005585 xmlAttrPtr prop;
5586 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005587
5588 if (node == NULL)
5589 return(NULL);
5590
5591 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005592 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005593 return(xmlHasProp(node, name));
5594 while (prop != NULL) {
5595 /*
5596 * One need to have
5597 * - same attribute names
5598 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005599 */
5600 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005601 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5602 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005603 }
5604 prop = prop->next;
5605 }
5606 if (!xmlCheckDTD) return(NULL);
5607
5608 /*
5609 * Check if there is a default declaration in the internal
5610 * or external subsets
5611 */
5612 doc = node->doc;
5613 if (doc != NULL) {
5614 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005615 xmlAttributePtr attrDecl = NULL;
5616 xmlNsPtr *nsList, *cur;
5617 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005618
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005619 nsList = xmlGetNsList(node->doc, node);
5620 if (nsList == NULL)
5621 return(NULL);
5622 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5623 ename = xmlStrdup(node->ns->prefix);
5624 ename = xmlStrcat(ename, BAD_CAST ":");
5625 ename = xmlStrcat(ename, node->name);
5626 } else {
5627 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005628 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005629 if (ename == NULL) {
5630 xmlFree(nsList);
5631 return(NULL);
5632 }
5633
5634 cur = nsList;
5635 while (*cur != NULL) {
5636 if (xmlStrEqual((*cur)->href, nameSpace)) {
5637 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5638 name, (*cur)->prefix);
5639 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5640 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5641 name, (*cur)->prefix);
5642 }
5643 cur++;
5644 }
5645 xmlFree(nsList);
5646 xmlFree(ename);
5647 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005648 }
5649 }
5650 return(NULL);
5651}
5652
5653/**
Owen Taylor3473f882001-02-23 17:55:21 +00005654 * xmlGetProp:
5655 * @node: the node
5656 * @name: the attribute name
5657 *
5658 * Search and get the value of an attribute associated to a node
5659 * This does the entity substitution.
5660 * This function looks in DTD attribute declaration for #FIXED or
5661 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00005662 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00005663 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
5664 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00005665 *
5666 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005667 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005668 */
5669xmlChar *
5670xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5671 xmlAttrPtr prop;
5672 xmlDocPtr doc;
5673
5674 if ((node == NULL) || (name == NULL)) return(NULL);
5675 /*
5676 * Check on the properties attached to the node
5677 */
5678 prop = node->properties;
5679 while (prop != NULL) {
5680 if (xmlStrEqual(prop->name, name)) {
5681 xmlChar *ret;
5682
5683 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5684 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5685 return(ret);
5686 }
5687 prop = prop->next;
5688 }
5689 if (!xmlCheckDTD) return(NULL);
5690
5691 /*
5692 * Check if there is a default declaration in the internal
5693 * or external subsets
5694 */
5695 doc = node->doc;
5696 if (doc != NULL) {
5697 xmlAttributePtr attrDecl;
5698 if (doc->intSubset != NULL) {
5699 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5700 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5701 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5702 if (attrDecl != NULL)
5703 return(xmlStrdup(attrDecl->defaultValue));
5704 }
5705 }
5706 return(NULL);
5707}
5708
5709/**
Daniel Veillard71531f32003-02-05 13:19:53 +00005710 * xmlGetNoNsProp:
5711 * @node: the node
5712 * @name: the attribute name
5713 *
5714 * Search and get the value of an attribute associated to a node
5715 * This does the entity substitution.
5716 * This function looks in DTD attribute declaration for #FIXED or
5717 * default declaration values unless DTD use has been turned off.
5718 * This function is similar to xmlGetProp except it will accept only
5719 * an attribute in no namespace.
5720 *
5721 * Returns the attribute value or NULL if not found.
5722 * It's up to the caller to free the memory with xmlFree().
5723 */
5724xmlChar *
5725xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
5726 xmlAttrPtr prop;
5727 xmlDocPtr doc;
5728
5729 if ((node == NULL) || (name == NULL)) return(NULL);
5730 /*
5731 * Check on the properties attached to the node
5732 */
5733 prop = node->properties;
5734 while (prop != NULL) {
5735 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
5736 xmlChar *ret;
5737
5738 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5739 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5740 return(ret);
5741 }
5742 prop = prop->next;
5743 }
5744 if (!xmlCheckDTD) return(NULL);
5745
5746 /*
5747 * Check if there is a default declaration in the internal
5748 * or external subsets
5749 */
5750 doc = node->doc;
5751 if (doc != NULL) {
5752 xmlAttributePtr attrDecl;
5753 if (doc->intSubset != NULL) {
5754 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5755 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5756 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5757 if (attrDecl != NULL)
5758 return(xmlStrdup(attrDecl->defaultValue));
5759 }
5760 }
5761 return(NULL);
5762}
5763
5764/**
Owen Taylor3473f882001-02-23 17:55:21 +00005765 * xmlGetNsProp:
5766 * @node: the node
5767 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005768 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005769 *
5770 * Search and get the value of an attribute associated to a node
5771 * This attribute has to be anchored in the namespace specified.
5772 * This does the entity substitution.
5773 * This function looks in DTD attribute declaration for #FIXED or
5774 * default declaration values unless DTD use has been turned off.
5775 *
5776 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005777 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005778 */
5779xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00005780xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00005781 xmlAttrPtr prop;
5782 xmlDocPtr doc;
5783 xmlNsPtr ns;
5784
5785 if (node == NULL)
5786 return(NULL);
5787
5788 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005789 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00005790 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00005791 while (prop != NULL) {
5792 /*
5793 * One need to have
5794 * - same attribute names
5795 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005796 */
5797 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00005798 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00005799 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005800 xmlChar *ret;
5801
5802 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5803 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5804 return(ret);
5805 }
5806 prop = prop->next;
5807 }
5808 if (!xmlCheckDTD) return(NULL);
5809
5810 /*
5811 * Check if there is a default declaration in the internal
5812 * or external subsets
5813 */
5814 doc = node->doc;
5815 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005816 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00005817 xmlAttributePtr attrDecl;
5818
Owen Taylor3473f882001-02-23 17:55:21 +00005819 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5820 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5821 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5822
5823 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
5824 /*
5825 * The DTD declaration only allows a prefix search
5826 */
5827 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00005828 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00005829 return(xmlStrdup(attrDecl->defaultValue));
5830 }
5831 }
5832 }
5833 return(NULL);
5834}
5835
5836/**
5837 * xmlSetProp:
5838 * @node: the node
5839 * @name: the attribute name
5840 * @value: the attribute value
5841 *
5842 * Set (or reset) an attribute carried by a node.
5843 * Returns the attribute pointer.
5844 */
5845xmlAttrPtr
5846xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005847 xmlAttrPtr prop;
5848 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00005849
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00005850 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00005851 return(NULL);
5852 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005853 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00005854 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005855 if ((xmlStrEqual(prop->name, name)) &&
5856 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005857 xmlNodePtr oldprop = prop->children;
5858
Owen Taylor3473f882001-02-23 17:55:21 +00005859 prop->children = NULL;
5860 prop->last = NULL;
5861 if (value != NULL) {
5862 xmlChar *buffer;
5863 xmlNodePtr tmp;
5864
5865 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5866 prop->children = xmlStringGetNodeList(node->doc, buffer);
5867 prop->last = NULL;
5868 prop->doc = doc;
5869 tmp = prop->children;
5870 while (tmp != NULL) {
5871 tmp->parent = (xmlNodePtr) prop;
5872 tmp->doc = doc;
5873 if (tmp->next == NULL)
5874 prop->last = tmp;
5875 tmp = tmp->next;
5876 }
5877 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00005878 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005879 if (oldprop != NULL)
5880 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00005881 return(prop);
5882 }
5883 prop = prop->next;
5884 }
5885 prop = xmlNewProp(node, name, value);
5886 return(prop);
5887}
5888
5889/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005890 * xmlUnsetProp:
5891 * @node: the node
5892 * @name: the attribute name
5893 *
5894 * Remove an attribute carried by a node.
5895 * Returns 0 if successful, -1 if not found
5896 */
5897int
5898xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Daniel Veillard814a76d2003-01-23 18:24:20 +00005899 xmlAttrPtr prop, prev = NULL;;
Daniel Veillard75bea542001-05-11 17:41:21 +00005900
5901 if ((node == NULL) || (name == NULL))
5902 return(-1);
Daniel Veillard814a76d2003-01-23 18:24:20 +00005903 prop = node->properties;
Daniel Veillard75bea542001-05-11 17:41:21 +00005904 while (prop != NULL) {
5905 if ((xmlStrEqual(prop->name, name)) &&
5906 (prop->ns == NULL)) {
5907 if (prev == NULL)
5908 node->properties = prop->next;
5909 else
5910 prev->next = prop->next;
5911 xmlFreeProp(prop);
5912 return(0);
5913 }
5914 prev = prop;
5915 prop = prop->next;
5916 }
5917 return(-1);
5918}
5919
5920/**
Owen Taylor3473f882001-02-23 17:55:21 +00005921 * xmlSetNsProp:
5922 * @node: the node
5923 * @ns: the namespace definition
5924 * @name: the attribute name
5925 * @value: the attribute value
5926 *
5927 * Set (or reset) an attribute carried by a node.
5928 * The ns structure must be in scope, this is not checked.
5929 *
5930 * Returns the attribute pointer.
5931 */
5932xmlAttrPtr
5933xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
5934 const xmlChar *value) {
5935 xmlAttrPtr prop;
5936
5937 if ((node == NULL) || (name == NULL))
5938 return(NULL);
5939
5940 if (ns == NULL)
5941 return(xmlSetProp(node, name, value));
5942 if (ns->href == NULL)
5943 return(NULL);
5944 prop = node->properties;
5945
5946 while (prop != NULL) {
5947 /*
5948 * One need to have
5949 * - same attribute names
5950 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005951 */
5952 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00005953 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005954 if (prop->children != NULL)
5955 xmlFreeNodeList(prop->children);
5956 prop->children = NULL;
5957 prop->last = NULL;
5958 prop->ns = ns;
5959 if (value != NULL) {
5960 xmlChar *buffer;
5961 xmlNodePtr tmp;
5962
5963 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5964 prop->children = xmlStringGetNodeList(node->doc, buffer);
5965 prop->last = NULL;
5966 tmp = prop->children;
5967 while (tmp != NULL) {
5968 tmp->parent = (xmlNodePtr) prop;
5969 if (tmp->next == NULL)
5970 prop->last = tmp;
5971 tmp = tmp->next;
5972 }
5973 xmlFree(buffer);
5974 }
5975 return(prop);
5976 }
5977 prop = prop->next;
5978 }
5979 prop = xmlNewNsProp(node, ns, name, value);
5980 return(prop);
5981}
5982
5983/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005984 * xmlUnsetNsProp:
5985 * @node: the node
5986 * @ns: the namespace definition
5987 * @name: the attribute name
5988 *
5989 * Remove an attribute carried by a node.
5990 * Returns 0 if successful, -1 if not found
5991 */
5992int
5993xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
5994 xmlAttrPtr prop = node->properties, prev = NULL;;
5995
5996 if ((node == NULL) || (name == NULL))
5997 return(-1);
5998 if (ns == NULL)
5999 return(xmlUnsetProp(node, name));
6000 if (ns->href == NULL)
6001 return(-1);
6002 while (prop != NULL) {
6003 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00006004 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006005 if (prev == NULL)
6006 node->properties = prop->next;
6007 else
6008 prev->next = prop->next;
6009 xmlFreeProp(prop);
6010 return(0);
6011 }
6012 prev = prop;
6013 prop = prop->next;
6014 }
6015 return(-1);
6016}
6017
6018/**
Owen Taylor3473f882001-02-23 17:55:21 +00006019 * xmlNodeIsText:
6020 * @node: the node
6021 *
6022 * Is this node a Text node ?
6023 * Returns 1 yes, 0 no
6024 */
6025int
6026xmlNodeIsText(xmlNodePtr node) {
6027 if (node == NULL) return(0);
6028
6029 if (node->type == XML_TEXT_NODE) return(1);
6030 return(0);
6031}
6032
6033/**
6034 * xmlIsBlankNode:
6035 * @node: the node
6036 *
6037 * Checks whether this node is an empty or whitespace only
6038 * (and possibly ignorable) text-node.
6039 *
6040 * Returns 1 yes, 0 no
6041 */
6042int
6043xmlIsBlankNode(xmlNodePtr node) {
6044 const xmlChar *cur;
6045 if (node == NULL) return(0);
6046
Daniel Veillard7db37732001-07-12 01:20:08 +00006047 if ((node->type != XML_TEXT_NODE) &&
6048 (node->type != XML_CDATA_SECTION_NODE))
6049 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006050 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006051 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006052 while (*cur != 0) {
6053 if (!IS_BLANK(*cur)) return(0);
6054 cur++;
6055 }
6056
6057 return(1);
6058}
6059
6060/**
6061 * xmlTextConcat:
6062 * @node: the node
6063 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006064 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006065 *
6066 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006067 *
6068 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006069 */
6070
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006071int
Owen Taylor3473f882001-02-23 17:55:21 +00006072xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006073 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006074
6075 if ((node->type != XML_TEXT_NODE) &&
6076 (node->type != XML_CDATA_SECTION_NODE)) {
6077#ifdef DEBUG_TREE
6078 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006079 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006080#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006081 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006082 }
Owen Taylor3473f882001-02-23 17:55:21 +00006083 node->content = xmlStrncat(node->content, content, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006084 if (node->content == NULL)
6085 return(-1);
6086 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006087}
6088
6089/************************************************************************
6090 * *
6091 * Output : to a FILE or in memory *
6092 * *
6093 ************************************************************************/
6094
Owen Taylor3473f882001-02-23 17:55:21 +00006095/**
6096 * xmlBufferCreate:
6097 *
6098 * routine to create an XML buffer.
6099 * returns the new structure.
6100 */
6101xmlBufferPtr
6102xmlBufferCreate(void) {
6103 xmlBufferPtr ret;
6104
6105 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6106 if (ret == NULL) {
6107 xmlGenericError(xmlGenericErrorContext,
6108 "xmlBufferCreate : out of memory!\n");
6109 return(NULL);
6110 }
6111 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006112 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006113 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006114 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006115 if (ret->content == NULL) {
6116 xmlGenericError(xmlGenericErrorContext,
6117 "xmlBufferCreate : out of memory!\n");
6118 xmlFree(ret);
6119 return(NULL);
6120 }
6121 ret->content[0] = 0;
6122 return(ret);
6123}
6124
6125/**
6126 * xmlBufferCreateSize:
6127 * @size: initial size of buffer
6128 *
6129 * routine to create an XML buffer.
6130 * returns the new structure.
6131 */
6132xmlBufferPtr
6133xmlBufferCreateSize(size_t size) {
6134 xmlBufferPtr ret;
6135
6136 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6137 if (ret == NULL) {
6138 xmlGenericError(xmlGenericErrorContext,
6139 "xmlBufferCreate : out of memory!\n");
6140 return(NULL);
6141 }
6142 ret->use = 0;
6143 ret->alloc = xmlBufferAllocScheme;
6144 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6145 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006146 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006147 if (ret->content == NULL) {
6148 xmlGenericError(xmlGenericErrorContext,
6149 "xmlBufferCreate : out of memory!\n");
6150 xmlFree(ret);
6151 return(NULL);
6152 }
6153 ret->content[0] = 0;
6154 } else
6155 ret->content = NULL;
6156 return(ret);
6157}
6158
6159/**
6160 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006161 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006162 * @scheme: allocation scheme to use
6163 *
6164 * Sets the allocation scheme for this buffer
6165 */
6166void
6167xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6168 xmlBufferAllocationScheme scheme) {
6169 if (buf == NULL) {
6170#ifdef DEBUG_BUFFER
6171 xmlGenericError(xmlGenericErrorContext,
6172 "xmlBufferSetAllocationScheme: buf == NULL\n");
6173#endif
6174 return;
6175 }
6176
6177 buf->alloc = scheme;
6178}
6179
6180/**
6181 * xmlBufferFree:
6182 * @buf: the buffer to free
6183 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006184 * Frees an XML buffer. It frees both the content and the structure which
6185 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006186 */
6187void
6188xmlBufferFree(xmlBufferPtr buf) {
6189 if (buf == NULL) {
6190#ifdef DEBUG_BUFFER
6191 xmlGenericError(xmlGenericErrorContext,
6192 "xmlBufferFree: buf == NULL\n");
6193#endif
6194 return;
6195 }
Daniel Veillard561b7f82002-03-20 21:55:57 +00006196 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006197 xmlFree(buf->content);
6198 }
Owen Taylor3473f882001-02-23 17:55:21 +00006199 xmlFree(buf);
6200}
6201
6202/**
6203 * xmlBufferEmpty:
6204 * @buf: the buffer
6205 *
6206 * empty a buffer.
6207 */
6208void
6209xmlBufferEmpty(xmlBufferPtr buf) {
6210 if (buf->content == NULL) return;
6211 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006212 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00006213}
6214
6215/**
6216 * xmlBufferShrink:
6217 * @buf: the buffer to dump
6218 * @len: the number of xmlChar to remove
6219 *
6220 * Remove the beginning of an XML buffer.
6221 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006222 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006223 */
6224int
6225xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
6226 if (len == 0) return(0);
6227 if (len > buf->use) return(-1);
6228
6229 buf->use -= len;
6230 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6231
6232 buf->content[buf->use] = 0;
6233 return(len);
6234}
6235
6236/**
6237 * xmlBufferGrow:
6238 * @buf: the buffer
6239 * @len: the minimum free size to allocate
6240 *
6241 * Grow the available space of an XML buffer.
6242 *
6243 * Returns the new available space or -1 in case of error
6244 */
6245int
6246xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6247 int size;
6248 xmlChar *newbuf;
6249
6250 if (len + buf->use < buf->size) return(0);
6251
6252 size = buf->use + len + 100;
6253
6254 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
6255 if (newbuf == NULL) return(-1);
6256 buf->content = newbuf;
6257 buf->size = size;
6258 return(buf->size - buf->use);
6259}
6260
6261/**
6262 * xmlBufferDump:
6263 * @file: the file output
6264 * @buf: the buffer to dump
6265 *
6266 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006267 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006268 */
6269int
6270xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6271 int ret;
6272
6273 if (buf == NULL) {
6274#ifdef DEBUG_BUFFER
6275 xmlGenericError(xmlGenericErrorContext,
6276 "xmlBufferDump: buf == NULL\n");
6277#endif
6278 return(0);
6279 }
6280 if (buf->content == NULL) {
6281#ifdef DEBUG_BUFFER
6282 xmlGenericError(xmlGenericErrorContext,
6283 "xmlBufferDump: buf->content == NULL\n");
6284#endif
6285 return(0);
6286 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006287 if (file == NULL)
6288 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006289 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6290 return(ret);
6291}
6292
6293/**
6294 * xmlBufferContent:
6295 * @buf: the buffer
6296 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006297 * Function to extract the content of a buffer
6298 *
Owen Taylor3473f882001-02-23 17:55:21 +00006299 * Returns the internal content
6300 */
6301
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006302const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006303xmlBufferContent(const xmlBufferPtr buf)
6304{
6305 if(!buf)
6306 return NULL;
6307
6308 return buf->content;
6309}
6310
6311/**
6312 * xmlBufferLength:
6313 * @buf: the buffer
6314 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006315 * Function to get the length of a buffer
6316 *
Owen Taylor3473f882001-02-23 17:55:21 +00006317 * Returns the length of data in the internal content
6318 */
6319
6320int
6321xmlBufferLength(const xmlBufferPtr buf)
6322{
6323 if(!buf)
6324 return 0;
6325
6326 return buf->use;
6327}
6328
6329/**
6330 * xmlBufferResize:
6331 * @buf: the buffer to resize
6332 * @size: the desired size
6333 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006334 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006335 *
6336 * Returns 0 in case of problems, 1 otherwise
6337 */
6338int
6339xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6340{
6341 unsigned int newSize;
6342 xmlChar* rebuf = NULL;
6343
6344 /*take care of empty case*/
6345 newSize = (buf->size ? buf->size*2 : size);
6346
6347 /* Don't resize if we don't have to */
6348 if (size < buf->size)
6349 return 1;
6350
6351 /* figure out new size */
6352 switch (buf->alloc){
6353 case XML_BUFFER_ALLOC_DOUBLEIT:
6354 while (size > newSize) newSize *= 2;
6355 break;
6356 case XML_BUFFER_ALLOC_EXACT:
6357 newSize = size+10;
6358 break;
6359 default:
6360 newSize = size+10;
6361 break;
6362 }
6363
6364 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006365 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006366 else
6367 rebuf = (xmlChar *) xmlRealloc(buf->content,
6368 newSize * sizeof(xmlChar));
6369 if (rebuf == NULL) {
6370 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006371 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006372 return 0;
6373 }
6374 buf->content = rebuf;
6375 buf->size = newSize;
6376
6377 return 1;
6378}
6379
6380/**
6381 * xmlBufferAdd:
6382 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006383 * @str: the #xmlChar string
6384 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006385 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006386 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006387 * str is recomputed.
6388 */
6389void
6390xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6391 unsigned int needSize;
6392
6393 if (str == NULL) {
6394#ifdef DEBUG_BUFFER
6395 xmlGenericError(xmlGenericErrorContext,
6396 "xmlBufferAdd: str == NULL\n");
6397#endif
6398 return;
6399 }
6400 if (len < -1) {
6401#ifdef DEBUG_BUFFER
6402 xmlGenericError(xmlGenericErrorContext,
6403 "xmlBufferAdd: len < 0\n");
6404#endif
6405 return;
6406 }
6407 if (len == 0) return;
6408
6409 if (len < 0)
6410 len = xmlStrlen(str);
6411
6412 if (len <= 0) return;
6413
6414 needSize = buf->use + len + 2;
6415 if (needSize > buf->size){
6416 if (!xmlBufferResize(buf, needSize)){
6417 xmlGenericError(xmlGenericErrorContext,
6418 "xmlBufferAdd : out of memory!\n");
6419 return;
6420 }
6421 }
6422
6423 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6424 buf->use += len;
6425 buf->content[buf->use] = 0;
6426}
6427
6428/**
6429 * xmlBufferAddHead:
6430 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006431 * @str: the #xmlChar string
6432 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006433 *
6434 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006435 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00006436 */
6437void
6438xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6439 unsigned int needSize;
6440
6441 if (str == NULL) {
6442#ifdef DEBUG_BUFFER
6443 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006444 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006445#endif
6446 return;
6447 }
6448 if (len < -1) {
6449#ifdef DEBUG_BUFFER
6450 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006451 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006452#endif
6453 return;
6454 }
6455 if (len == 0) return;
6456
6457 if (len < 0)
6458 len = xmlStrlen(str);
6459
6460 if (len <= 0) return;
6461
6462 needSize = buf->use + len + 2;
6463 if (needSize > buf->size){
6464 if (!xmlBufferResize(buf, needSize)){
6465 xmlGenericError(xmlGenericErrorContext,
6466 "xmlBufferAddHead : out of memory!\n");
6467 return;
6468 }
6469 }
6470
6471 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6472 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6473 buf->use += len;
6474 buf->content[buf->use] = 0;
6475}
6476
6477/**
6478 * xmlBufferCat:
6479 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006480 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006481 *
6482 * Append a zero terminated string to an XML buffer.
6483 */
6484void
6485xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
6486 if (str != NULL)
6487 xmlBufferAdd(buf, str, -1);
6488}
6489
6490/**
6491 * xmlBufferCCat:
6492 * @buf: the buffer to dump
6493 * @str: the C char string
6494 *
6495 * Append a zero terminated C string to an XML buffer.
6496 */
6497void
6498xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6499 const char *cur;
6500
6501 if (str == NULL) {
6502#ifdef DEBUG_BUFFER
6503 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006504 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006505#endif
6506 return;
6507 }
6508 for (cur = str;*cur != 0;cur++) {
6509 if (buf->use + 10 >= buf->size) {
6510 if (!xmlBufferResize(buf, buf->use+10)){
6511 xmlGenericError(xmlGenericErrorContext,
6512 "xmlBufferCCat : out of memory!\n");
6513 return;
6514 }
6515 }
6516 buf->content[buf->use++] = *cur;
6517 }
6518 buf->content[buf->use] = 0;
6519}
6520
6521/**
6522 * xmlBufferWriteCHAR:
6523 * @buf: the XML buffer
6524 * @string: the string to add
6525 *
6526 * routine which manages and grows an output buffer. This one adds
6527 * xmlChars at the end of the buffer.
6528 */
6529void
Owen Taylor3473f882001-02-23 17:55:21 +00006530xmlBufferWriteCHAR
Owen Taylor3473f882001-02-23 17:55:21 +00006531(xmlBufferPtr buf, const xmlChar *string) {
6532 xmlBufferCat(buf, string);
6533}
6534
6535/**
6536 * xmlBufferWriteChar:
6537 * @buf: the XML buffer output
6538 * @string: the string to add
6539 *
6540 * routine which manage and grows an output buffer. This one add
6541 * C chars at the end of the array.
6542 */
6543void
6544xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
6545 xmlBufferCCat(buf, string);
6546}
6547
6548
6549/**
6550 * xmlBufferWriteQuotedString:
6551 * @buf: the XML buffer output
6552 * @string: the string to add
6553 *
6554 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00006555 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00006556 * quote or double-quotes internally
6557 */
6558void
6559xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
6560 if (xmlStrchr(string, '"')) {
6561 if (xmlStrchr(string, '\'')) {
6562#ifdef DEBUG_BUFFER
6563 xmlGenericError(xmlGenericErrorContext,
6564 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
6565#endif
6566 }
6567 xmlBufferCCat(buf, "'");
6568 xmlBufferCat(buf, string);
6569 xmlBufferCCat(buf, "'");
6570 } else {
6571 xmlBufferCCat(buf, "\"");
6572 xmlBufferCat(buf, string);
6573 xmlBufferCCat(buf, "\"");
6574 }
6575}
6576
6577
6578/************************************************************************
6579 * *
6580 * Dumping XML tree content to a simple buffer *
6581 * *
6582 ************************************************************************/
6583
Owen Taylor3473f882001-02-23 17:55:21 +00006584/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00006585 * xmlAttrSerializeContent:
6586 * @buf: the XML buffer output
6587 * @doc: the document
6588 * @attr: the attribute pointer
6589 *
6590 * Serialize the attribute in the buffer
6591 */
6592static void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006593xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr)
6594{
Daniel Veillarda6d05382002-02-13 13:07:41 +00006595 const xmlChar *cur, *base;
6596 xmlNodePtr children;
6597
6598 children = attr->children;
6599 while (children != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006600 switch (children->type) {
6601 case XML_TEXT_NODE:
6602 base = cur = children->content;
6603 while (*cur != 0) {
6604 if (*cur == '\n') {
6605 if (base != cur)
6606 xmlBufferAdd(buf, base, cur - base);
6607 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
6608 cur++;
6609 base = cur;
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006610 } else if (*cur == '\r') {
6611 if (base != cur)
6612 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006613 xmlBufferAdd(buf, BAD_CAST "&#13;", 5);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006614 cur++;
6615 base = cur;
6616 } else if (*cur == '\t') {
6617 if (base != cur)
6618 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006619 xmlBufferAdd(buf, BAD_CAST "&#9;", 4);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006620 cur++;
6621 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006622#if 0
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006623 } else if (*cur == '\'') {
6624 if (base != cur)
6625 xmlBufferAdd(buf, base, cur - base);
6626 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
6627 cur++;
6628 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006629#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006630 } else if (*cur == '"') {
6631 if (base != cur)
6632 xmlBufferAdd(buf, base, cur - base);
6633 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6634 cur++;
6635 base = cur;
6636 } else if (*cur == '<') {
6637 if (base != cur)
6638 xmlBufferAdd(buf, base, cur - base);
6639 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
6640 cur++;
6641 base = cur;
6642 } else if (*cur == '>') {
6643 if (base != cur)
6644 xmlBufferAdd(buf, base, cur - base);
6645 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
6646 cur++;
6647 base = cur;
6648 } else if (*cur == '&') {
6649 if (base != cur)
6650 xmlBufferAdd(buf, base, cur - base);
6651 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
6652 cur++;
6653 base = cur;
6654 } else if ((*cur >= 0x80) && ((doc == NULL) ||
6655 (doc->encoding ==
6656 NULL))) {
6657 /*
6658 * We assume we have UTF-8 content.
6659 */
6660 char tmp[10];
6661 int val = 0, l = 1;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006662
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006663 if (base != cur)
6664 xmlBufferAdd(buf, base, cur - base);
6665 if (*cur < 0xC0) {
6666 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6d05382002-02-13 13:07:41 +00006667 "xmlAttrSerializeContent : input not UTF-8\n");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006668 if (doc != NULL)
6669 doc->encoding =
6670 xmlStrdup(BAD_CAST "ISO-8859-1");
6671 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6672 tmp[sizeof(tmp) - 1] = 0;
6673 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6674 cur++;
6675 base = cur;
6676 continue;
6677 } else if (*cur < 0xE0) {
6678 val = (cur[0]) & 0x1F;
6679 val <<= 6;
6680 val |= (cur[1]) & 0x3F;
6681 l = 2;
6682 } else if (*cur < 0xF0) {
6683 val = (cur[0]) & 0x0F;
6684 val <<= 6;
6685 val |= (cur[1]) & 0x3F;
6686 val <<= 6;
6687 val |= (cur[2]) & 0x3F;
6688 l = 3;
6689 } else if (*cur < 0xF8) {
6690 val = (cur[0]) & 0x07;
6691 val <<= 6;
6692 val |= (cur[1]) & 0x3F;
6693 val <<= 6;
6694 val |= (cur[2]) & 0x3F;
6695 val <<= 6;
6696 val |= (cur[3]) & 0x3F;
6697 l = 4;
6698 }
6699 if ((l == 1) || (!IS_CHAR(val))) {
6700 xmlGenericError(xmlGenericErrorContext,
6701 "xmlAttrSerializeContent : char out of range\n");
6702 if (doc != NULL)
6703 doc->encoding =
6704 xmlStrdup(BAD_CAST "ISO-8859-1");
6705 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6706 tmp[sizeof(tmp) - 1] = 0;
6707 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6708 cur++;
6709 base = cur;
6710 continue;
6711 }
6712 /*
6713 * We could do multiple things here. Just save
6714 * as a char ref
6715 */
6716 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
6717 tmp[sizeof(tmp) - 1] = 0;
6718 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6719 cur += l;
6720 base = cur;
6721 } else {
6722 cur++;
6723 }
6724 }
6725 if (base != cur)
6726 xmlBufferAdd(buf, base, cur - base);
6727 break;
6728 case XML_ENTITY_REF_NODE:
6729 xmlBufferAdd(buf, BAD_CAST "&", 1);
6730 xmlBufferAdd(buf, children->name,
6731 xmlStrlen(children->name));
6732 xmlBufferAdd(buf, BAD_CAST ";", 1);
6733 break;
6734 default:
6735 /* should not happen unless we have a badly built tree */
6736 break;
6737 }
6738 children = children->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006739 }
6740}
6741
6742/**
6743 * xmlNodeDump:
6744 * @buf: the XML buffer output
6745 * @doc: the document
6746 * @cur: the current node
6747 * @level: the imbrication level for indenting
6748 * @format: is formatting allowed
6749 *
6750 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00006751 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006752 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006753 *
6754 * Returns the number of bytes written to the buffer or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00006755 */
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006756int
Owen Taylor3473f882001-02-23 17:55:21 +00006757xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006758 int format)
6759{
6760 unsigned int use;
6761 int ret;
6762 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006763
6764 if (cur == NULL) {
6765#ifdef DEBUG_TREE
6766 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006767 "xmlNodeDump : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006768#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006769 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006770 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006771 if (buf == NULL) {
6772#ifdef DEBUG_TREE
6773 xmlGenericError(xmlGenericErrorContext,
6774 "xmlNodeDump : buf == NULL\n");
6775#endif
6776 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006777 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006778 outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
6779 if (outbuf == NULL) {
6780 xmlGenericError(xmlGenericErrorContext,
6781 "xmlNodeDump: out of memory!\n");
6782 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006783 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006784 memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
6785 outbuf->buffer = buf;
6786 outbuf->encoder = NULL;
6787 outbuf->writecallback = NULL;
6788 outbuf->closecallback = NULL;
6789 outbuf->context = NULL;
6790 outbuf->written = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006791
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006792 use = buf->use;
6793 xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
6794 xmlFree(outbuf);
6795 ret = buf->use - use;
6796 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006797}
6798
6799/**
6800 * xmlElemDump:
6801 * @f: the FILE * for the output
6802 * @doc: the document
6803 * @cur: the current node
6804 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006805 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006806 */
6807void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006808xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur)
6809{
6810 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006811
6812 if (cur == NULL) {
6813#ifdef DEBUG_TREE
6814 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006815 "xmlElemDump : cur == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006816#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006817 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006818 }
Owen Taylor3473f882001-02-23 17:55:21 +00006819#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006820 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006821 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006822 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006823 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006824#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006825
6826 outbuf = xmlOutputBufferCreateFile(f, NULL);
6827 if (outbuf == NULL)
6828 return;
6829 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006830#ifdef LIBXML_HTML_ENABLED
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006831 htmlNodeDumpOutput(outbuf, doc, cur, NULL);
6832#else
6833 xmlGenericError(xmlGenericErrorContext,
6834 "HTML support not compiled in\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006835#endif /* LIBXML_HTML_ENABLED */
6836 } else
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006837 xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL);
6838 xmlOutputBufferClose(outbuf);
Owen Taylor3473f882001-02-23 17:55:21 +00006839}
6840
6841/************************************************************************
6842 * *
6843 * Dumping XML tree content to an I/O output buffer *
6844 * *
6845 ************************************************************************/
6846
Owen Taylor3473f882001-02-23 17:55:21 +00006847static void
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006848xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6849 int level, int format, const char *encoding);
6850static void
Owen Taylor3473f882001-02-23 17:55:21 +00006851xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6852 int level, int format, const char *encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006853static void
6854xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
6855 xmlNodePtr cur, int level, int format, const char *encoding);
6856
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00006857void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
6858
Owen Taylor3473f882001-02-23 17:55:21 +00006859/**
6860 * xmlNsDumpOutput:
6861 * @buf: the XML buffer output
6862 * @cur: a namespace
6863 *
6864 * Dump a local Namespace definition.
6865 * Should be called in the context of attributes dumps.
6866 */
6867static void
6868xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6869 if (cur == NULL) {
6870#ifdef DEBUG_TREE
6871 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006872 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006873#endif
6874 return;
6875 }
6876 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00006877 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
6878 return;
6879
Owen Taylor3473f882001-02-23 17:55:21 +00006880 /* Within the context of an element attributes */
6881 if (cur->prefix != NULL) {
6882 xmlOutputBufferWriteString(buf, " xmlns:");
6883 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6884 } else
6885 xmlOutputBufferWriteString(buf, " xmlns");
6886 xmlOutputBufferWriteString(buf, "=");
6887 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6888 }
6889}
6890
6891/**
6892 * xmlNsListDumpOutput:
6893 * @buf: the XML buffer output
6894 * @cur: the first namespace
6895 *
6896 * Dump a list of local Namespace definitions.
6897 * Should be called in the context of attributes dumps.
6898 */
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00006899void
Owen Taylor3473f882001-02-23 17:55:21 +00006900xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6901 while (cur != NULL) {
6902 xmlNsDumpOutput(buf, cur);
6903 cur = cur->next;
6904 }
6905}
6906
6907/**
6908 * xmlDtdDumpOutput:
6909 * @buf: the XML buffer output
6910 * @doc: the document
6911 * @encoding: an optional encoding string
6912 *
6913 * Dump the XML document DTD, if any.
6914 */
6915static void
6916xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6917 if (dtd == NULL) {
6918#ifdef DEBUG_TREE
6919 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006920 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006921#endif
6922 return;
6923 }
6924 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6925 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6926 if (dtd->ExternalID != NULL) {
6927 xmlOutputBufferWriteString(buf, " PUBLIC ");
6928 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6929 xmlOutputBufferWriteString(buf, " ");
6930 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6931 } else if (dtd->SystemID != NULL) {
6932 xmlOutputBufferWriteString(buf, " SYSTEM ");
6933 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6934 }
6935 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6936 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6937 xmlOutputBufferWriteString(buf, ">");
6938 return;
6939 }
6940 xmlOutputBufferWriteString(buf, " [\n");
6941 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6942 xmlOutputBufferWriteString(buf, "]>");
6943}
6944
6945/**
6946 * xmlAttrDumpOutput:
6947 * @buf: the XML buffer output
6948 * @doc: the document
6949 * @cur: the attribute pointer
6950 * @encoding: an optional encoding string
6951 *
6952 * Dump an XML attribute
6953 */
6954static void
6955xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006956 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006957 if (cur == NULL) {
6958#ifdef DEBUG_TREE
6959 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006960 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006961#endif
6962 return;
6963 }
6964 xmlOutputBufferWriteString(buf, " ");
6965 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6966 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6967 xmlOutputBufferWriteString(buf, ":");
6968 }
6969 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006970 xmlOutputBufferWriteString(buf, "=\"");
6971 xmlAttrSerializeContent(buf->buffer, doc, cur);
6972 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006973}
6974
6975/**
6976 * xmlAttrListDumpOutput:
6977 * @buf: the XML buffer output
6978 * @doc: the document
6979 * @cur: the first attribute pointer
6980 * @encoding: an optional encoding string
6981 *
6982 * Dump a list of XML attributes
6983 */
6984static void
6985xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6986 xmlAttrPtr cur, const char *encoding) {
6987 if (cur == NULL) {
6988#ifdef DEBUG_TREE
6989 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006990 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006991#endif
6992 return;
6993 }
6994 while (cur != NULL) {
6995 xmlAttrDumpOutput(buf, doc, cur, encoding);
6996 cur = cur->next;
6997 }
6998}
6999
7000
7001
7002/**
7003 * xmlNodeListDumpOutput:
7004 * @buf: the XML buffer output
7005 * @doc: the document
7006 * @cur: the first node
7007 * @level: the imbrication level for indenting
7008 * @format: is formatting allowed
7009 * @encoding: an optional encoding string
7010 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007011 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007012 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007013 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007014 */
7015static void
7016xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7017 xmlNodePtr cur, int level, int format, const char *encoding) {
7018 int i;
7019
7020 if (cur == NULL) {
7021#ifdef DEBUG_TREE
7022 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007023 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007024#endif
7025 return;
7026 }
7027 while (cur != NULL) {
7028 if ((format) && (xmlIndentTreeOutput) &&
7029 (cur->type == XML_ELEMENT_NODE))
7030 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007031 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007032 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007033 if (format) {
7034 xmlOutputBufferWriteString(buf, "\n");
7035 }
7036 cur = cur->next;
7037 }
7038}
7039
7040/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007041 * xmlNodeDumpOutputInternal:
Owen Taylor3473f882001-02-23 17:55:21 +00007042 * @buf: the XML buffer output
7043 * @doc: the document
7044 * @cur: the current node
7045 * @level: the imbrication level for indenting
7046 * @format: is formatting allowed
7047 * @encoding: an optional encoding string
7048 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007049 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007050 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007051 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007052 */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007053static void
7054xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
7055 xmlNodePtr cur, int level, int format, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007056 int i;
7057 xmlNodePtr tmp;
7058
7059 if (cur == NULL) {
7060#ifdef DEBUG_TREE
7061 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007062 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007063#endif
7064 return;
7065 }
7066 if (cur->type == XML_XINCLUDE_START)
7067 return;
7068 if (cur->type == XML_XINCLUDE_END)
7069 return;
7070 if (cur->type == XML_DTD_NODE) {
7071 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7072 return;
7073 }
7074 if (cur->type == XML_ELEMENT_DECL) {
7075 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7076 return;
7077 }
7078 if (cur->type == XML_ATTRIBUTE_DECL) {
7079 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7080 return;
7081 }
7082 if (cur->type == XML_ENTITY_DECL) {
7083 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7084 return;
7085 }
7086 if (cur->type == XML_TEXT_NODE) {
7087 if (cur->content != NULL) {
7088 if ((cur->name == xmlStringText) ||
7089 (cur->name != xmlStringTextNoenc)) {
7090 xmlChar *buffer;
7091
Owen Taylor3473f882001-02-23 17:55:21 +00007092 if (encoding == NULL)
7093 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7094 else
7095 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007096 if (buffer != NULL) {
7097 xmlOutputBufferWriteString(buf, (const char *)buffer);
7098 xmlFree(buffer);
7099 }
7100 } else {
7101 /*
7102 * Disable escaping, needed for XSLT
7103 */
Owen Taylor3473f882001-02-23 17:55:21 +00007104 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007105 }
7106 }
7107
7108 return;
7109 }
7110 if (cur->type == XML_PI_NODE) {
7111 if (cur->content != NULL) {
7112 xmlOutputBufferWriteString(buf, "<?");
7113 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7114 if (cur->content != NULL) {
7115 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00007116 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007117 }
7118 xmlOutputBufferWriteString(buf, "?>");
7119 } else {
7120 xmlOutputBufferWriteString(buf, "<?");
7121 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7122 xmlOutputBufferWriteString(buf, "?>");
7123 }
7124 return;
7125 }
7126 if (cur->type == XML_COMMENT_NODE) {
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 xmlOutputBufferWriteString(buf, "-->");
7131 }
7132 return;
7133 }
7134 if (cur->type == XML_ENTITY_REF_NODE) {
7135 xmlOutputBufferWriteString(buf, "&");
7136 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7137 xmlOutputBufferWriteString(buf, ";");
7138 return;
7139 }
7140 if (cur->type == XML_CDATA_SECTION_NODE) {
7141 xmlOutputBufferWriteString(buf, "<![CDATA[");
7142 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007143 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007144 xmlOutputBufferWriteString(buf, "]]>");
7145 return;
7146 }
Daniel Veillard7b72ee52003-02-27 23:24:53 +00007147 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillarda1a9d042003-03-18 16:53:17 +00007148 xmlAttrDumpOutput(buf,doc, (xmlAttrPtr) cur,encoding);
Daniel Veillard7b72ee52003-02-27 23:24:53 +00007149 return;
7150 }
Daniel Veillard6aa2f602003-02-10 00:01:56 +00007151 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007152 xmlNsDumpOutput(buf, (xmlNsPtr) cur);
Daniel Veillard6aa2f602003-02-10 00:01:56 +00007153 return;
7154 }
Owen Taylor3473f882001-02-23 17:55:21 +00007155
7156 if (format == 1) {
7157 tmp = cur->children;
7158 while (tmp != NULL) {
7159 if ((tmp->type == XML_TEXT_NODE) ||
7160 (tmp->type == XML_ENTITY_REF_NODE)) {
7161 format = 0;
7162 break;
7163 }
7164 tmp = tmp->next;
7165 }
7166 }
7167 xmlOutputBufferWriteString(buf, "<");
7168 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7169 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7170 xmlOutputBufferWriteString(buf, ":");
7171 }
7172
7173 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7174 if (cur->nsDef)
7175 xmlNsListDumpOutput(buf, cur->nsDef);
7176 if (cur->properties != NULL)
7177 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7178
Daniel Veillard7db37732001-07-12 01:20:08 +00007179 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
7180 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007181 xmlOutputBufferWriteString(buf, "/>");
7182 return;
7183 }
7184 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00007185 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007186 xmlChar *buffer;
7187
Owen Taylor3473f882001-02-23 17:55:21 +00007188 if (encoding == NULL)
7189 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7190 else
7191 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007192 if (buffer != NULL) {
7193 xmlOutputBufferWriteString(buf, (const char *)buffer);
7194 xmlFree(buffer);
7195 }
7196 }
7197 if (cur->children != NULL) {
7198 if (format) xmlOutputBufferWriteString(buf, "\n");
7199 xmlNodeListDumpOutput(buf, doc, cur->children,
7200 (level >= 0?level+1:-1), format, encoding);
7201 if ((xmlIndentTreeOutput) && (format))
7202 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007203 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00007204 }
7205 xmlOutputBufferWriteString(buf, "</");
7206 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7207 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7208 xmlOutputBufferWriteString(buf, ":");
7209 }
7210
7211 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7212 xmlOutputBufferWriteString(buf, ">");
7213}
7214
7215/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007216 * xmlNodeDumpOutput:
7217 * @buf: the XML buffer output
7218 * @doc: the document
7219 * @cur: the current node
7220 * @level: the imbrication level for indenting
7221 * @format: is formatting allowed
7222 * @encoding: an optional encoding string
7223 *
7224 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007225 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007226 * or xmlKeepBlanksDefault(0) was called
7227 */
7228void
7229xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007230 int level, int format, const char *encoding)
7231{
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007232#ifdef LIBXML_HTML_ENABLED
7233 xmlDtdPtr dtd;
7234 int is_xhtml = 0;
7235
7236 dtd = xmlGetIntSubset(doc);
7237 if (dtd != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007238 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7239 if (is_xhtml < 0)
7240 is_xhtml = 0;
7241 if ((is_xhtml) && (cur->parent == (xmlNodePtr) doc) &&
7242 (cur->type == XML_ELEMENT_NODE) &&
7243 (xmlStrEqual(cur->name, BAD_CAST "html"))) {
7244 if (encoding != NULL)
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007245 htmlSetMetaEncoding((htmlDocPtr) doc,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007246 (const xmlChar *) encoding);
7247 else
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007248 htmlSetMetaEncoding((htmlDocPtr) doc, BAD_CAST "UTF-8");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007249 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007250 }
7251
7252 if (is_xhtml)
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007253 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007254 else
7255#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007256 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007257}
7258
7259/**
Owen Taylor3473f882001-02-23 17:55:21 +00007260 * xmlDocContentDumpOutput:
7261 * @buf: the XML buffer output
7262 * @cur: the document
7263 * @encoding: an optional encoding string
7264 * @format: should formatting spaces been added
7265 *
7266 * Dump an XML document.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007267 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007268 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007269 */
7270static void
7271xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
7272 const char *encoding, int format) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007273#ifdef LIBXML_HTML_ENABLED
7274 xmlDtdPtr dtd;
7275 int is_xhtml = 0;
7276#endif
7277
Owen Taylor3473f882001-02-23 17:55:21 +00007278 xmlOutputBufferWriteString(buf, "<?xml version=");
7279 if (cur->version != NULL)
7280 xmlBufferWriteQuotedString(buf->buffer, cur->version);
7281 else
7282 xmlOutputBufferWriteString(buf, "\"1.0\"");
7283 if (encoding == NULL) {
7284 if (cur->encoding != NULL)
7285 encoding = (const char *) cur->encoding;
7286 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
7287 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
7288 }
7289 if (encoding != NULL) {
7290 xmlOutputBufferWriteString(buf, " encoding=");
7291 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
7292 }
7293 switch (cur->standalone) {
7294 case 0:
7295 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
7296 break;
7297 case 1:
7298 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
7299 break;
7300 }
7301 xmlOutputBufferWriteString(buf, "?>\n");
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007302
7303#ifdef LIBXML_HTML_ENABLED
7304 dtd = xmlGetIntSubset(cur);
7305 if (dtd != NULL) {
7306 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7307 if (is_xhtml < 0) is_xhtml = 0;
7308 }
7309 if (is_xhtml) {
7310 if (encoding != NULL)
7311 htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
7312 else
7313 htmlSetMetaEncoding(cur, BAD_CAST "UTF-8");
7314 }
7315#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007316 if (cur->children != NULL) {
7317 xmlNodePtr child = cur->children;
7318
7319 while (child != NULL) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007320#ifdef LIBXML_HTML_ENABLED
7321 if (is_xhtml)
7322 xhtmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
7323 else
7324#endif
7325 xmlNodeDumpOutputInternal(buf, cur, child, 0, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007326 xmlOutputBufferWriteString(buf, "\n");
7327 child = child->next;
7328 }
7329 }
7330}
7331
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007332#ifdef LIBXML_HTML_ENABLED
7333/************************************************************************
7334 * *
7335 * Functions specific to XHTML serialization *
7336 * *
7337 ************************************************************************/
7338
7339#define XHTML_STRICT_PUBLIC_ID BAD_CAST \
7340 "-//W3C//DTD XHTML 1.0 Strict//EN"
7341#define XHTML_STRICT_SYSTEM_ID BAD_CAST \
7342 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
7343#define XHTML_FRAME_PUBLIC_ID BAD_CAST \
7344 "-//W3C//DTD XHTML 1.0 Frameset//EN"
7345#define XHTML_FRAME_SYSTEM_ID BAD_CAST \
7346 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
7347#define XHTML_TRANS_PUBLIC_ID BAD_CAST \
7348 "-//W3C//DTD XHTML 1.0 Transitional//EN"
7349#define XHTML_TRANS_SYSTEM_ID BAD_CAST \
7350 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
7351
7352#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
7353/**
7354 * xmlIsXHTML:
7355 * @systemID: the system identifier
7356 * @publicID: the public identifier
7357 *
7358 * Try to find if the document correspond to an XHTML DTD
7359 *
7360 * Returns 1 if true, 0 if not and -1 in case of error
7361 */
7362int
7363xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) {
7364 if ((systemID == NULL) && (publicID == NULL))
7365 return(-1);
7366 if (publicID != NULL) {
7367 if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1);
7368 if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1);
7369 if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1);
7370 }
7371 if (systemID != NULL) {
7372 if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1);
7373 if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1);
7374 if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1);
7375 }
7376 return(0);
7377}
7378
7379/**
7380 * xhtmlIsEmpty:
7381 * @node: the node
7382 *
7383 * Check if a node is an empty xhtml node
7384 *
7385 * Returns 1 if the node is an empty node, 0 if not and -1 in case of error
7386 */
7387static int
7388xhtmlIsEmpty(xmlNodePtr node) {
7389 if (node == NULL)
7390 return(-1);
7391 if (node->type != XML_ELEMENT_NODE)
7392 return(0);
7393 if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME)))
7394 return(0);
7395 if (node->children != NULL)
7396 return(0);
7397 switch (node->name[0]) {
7398 case 'a':
7399 if (xmlStrEqual(node->name, BAD_CAST "area"))
7400 return(1);
7401 return(0);
7402 case 'b':
7403 if (xmlStrEqual(node->name, BAD_CAST "br"))
7404 return(1);
7405 if (xmlStrEqual(node->name, BAD_CAST "base"))
7406 return(1);
7407 if (xmlStrEqual(node->name, BAD_CAST "basefont"))
7408 return(1);
7409 return(0);
7410 case 'c':
7411 if (xmlStrEqual(node->name, BAD_CAST "col"))
7412 return(1);
7413 return(0);
7414 case 'f':
7415 if (xmlStrEqual(node->name, BAD_CAST "frame"))
7416 return(1);
7417 return(0);
7418 case 'h':
7419 if (xmlStrEqual(node->name, BAD_CAST "hr"))
7420 return(1);
7421 return(0);
7422 case 'i':
7423 if (xmlStrEqual(node->name, BAD_CAST "img"))
7424 return(1);
7425 if (xmlStrEqual(node->name, BAD_CAST "input"))
7426 return(1);
7427 if (xmlStrEqual(node->name, BAD_CAST "isindex"))
7428 return(1);
7429 return(0);
7430 case 'l':
7431 if (xmlStrEqual(node->name, BAD_CAST "link"))
7432 return(1);
7433 return(0);
7434 case 'm':
7435 if (xmlStrEqual(node->name, BAD_CAST "meta"))
7436 return(1);
7437 return(0);
7438 case 'p':
7439 if (xmlStrEqual(node->name, BAD_CAST "param"))
7440 return(1);
7441 return(0);
7442 }
7443 return(0);
7444}
7445
7446/**
7447 * xhtmlAttrListDumpOutput:
7448 * @buf: the XML buffer output
7449 * @doc: the document
7450 * @cur: the first attribute pointer
7451 * @encoding: an optional encoding string
7452 *
7453 * Dump a list of XML attributes
7454 */
7455static void
7456xhtmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7457 xmlAttrPtr cur, const char *encoding) {
7458 xmlAttrPtr xml_lang = NULL;
7459 xmlAttrPtr lang = NULL;
7460 xmlAttrPtr name = NULL;
7461 xmlAttrPtr id = NULL;
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007462 xmlNodePtr parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007463
7464 if (cur == NULL) {
7465#ifdef DEBUG_TREE
7466 xmlGenericError(xmlGenericErrorContext,
7467 "xmlAttrListDumpOutput : property == NULL\n");
7468#endif
7469 return;
7470 }
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007471 parent = cur->parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007472 while (cur != NULL) {
7473 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id")))
7474 id = cur;
7475 else
7476 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name")))
7477 name = cur;
7478 else
7479 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")))
7480 lang = cur;
7481 else
7482 if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) &&
7483 (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml")))
7484 xml_lang = cur;
7485 else if ((cur->ns == NULL) &&
7486 ((cur->children == NULL) ||
7487 (cur->children->content == NULL) ||
7488 (cur->children->content[0] == 0)) &&
7489 (htmlIsBooleanAttr(cur->name))) {
7490 if (cur->children != NULL)
7491 xmlFreeNode(cur->children);
7492 cur->children = xmlNewText(cur->name);
7493 if (cur->children != NULL)
7494 cur->children->parent = (xmlNodePtr) cur;
7495 }
7496 xmlAttrDumpOutput(buf, doc, cur, encoding);
7497 cur = cur->next;
7498 }
7499 /*
7500 * C.8
7501 */
7502 if ((name != NULL) && (id == NULL)) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007503 if ((parent != NULL) && (parent->name != NULL) &&
7504 ((xmlStrEqual(parent->name, BAD_CAST "a")) ||
7505 (xmlStrEqual(parent->name, BAD_CAST "p")) ||
7506 (xmlStrEqual(parent->name, BAD_CAST "div")) ||
7507 (xmlStrEqual(parent->name, BAD_CAST "img")) ||
7508 (xmlStrEqual(parent->name, BAD_CAST "map")) ||
7509 (xmlStrEqual(parent->name, BAD_CAST "applet")) ||
7510 (xmlStrEqual(parent->name, BAD_CAST "form")) ||
7511 (xmlStrEqual(parent->name, BAD_CAST "frame")) ||
7512 (xmlStrEqual(parent->name, BAD_CAST "iframe")))) {
7513 xmlOutputBufferWriteString(buf, " id=\"");
7514 xmlAttrSerializeContent(buf->buffer, doc, name);
7515 xmlOutputBufferWriteString(buf, "\"");
7516 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007517 }
7518 /*
7519 * C.7.
7520 */
7521 if ((lang != NULL) && (xml_lang == NULL)) {
7522 xmlOutputBufferWriteString(buf, " xml:lang=\"");
7523 xmlAttrSerializeContent(buf->buffer, doc, lang);
7524 xmlOutputBufferWriteString(buf, "\"");
7525 } else
7526 if ((xml_lang != NULL) && (lang == NULL)) {
7527 xmlOutputBufferWriteString(buf, " lang=\"");
7528 xmlAttrSerializeContent(buf->buffer, doc, xml_lang);
7529 xmlOutputBufferWriteString(buf, "\"");
7530 }
7531}
7532
7533/**
7534 * xhtmlNodeListDumpOutput:
7535 * @buf: the XML buffer output
7536 * @doc: the XHTML document
7537 * @cur: the first node
7538 * @level: the imbrication level for indenting
7539 * @format: is formatting allowed
7540 * @encoding: an optional encoding string
7541 *
7542 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007543 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007544 * or xmlKeepBlanksDefault(0) was called
7545 */
7546static void
7547xhtmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7548 xmlNodePtr cur, int level, int format, const char *encoding) {
7549 int i;
7550
7551 if (cur == NULL) {
7552#ifdef DEBUG_TREE
7553 xmlGenericError(xmlGenericErrorContext,
7554 "xhtmlNodeListDumpOutput : node == NULL\n");
7555#endif
7556 return;
7557 }
7558 while (cur != NULL) {
7559 if ((format) && (xmlIndentTreeOutput) &&
7560 (cur->type == XML_ELEMENT_NODE))
7561 for (i = 0;i < level;i++)
7562 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7563 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
7564 if (format) {
7565 xmlOutputBufferWriteString(buf, "\n");
7566 }
7567 cur = cur->next;
7568 }
7569}
7570
7571/**
7572 * xhtmlNodeDumpOutput:
7573 * @buf: the XML buffer output
7574 * @doc: the XHTML document
7575 * @cur: the current node
7576 * @level: the imbrication level for indenting
7577 * @format: is formatting allowed
7578 * @encoding: an optional encoding string
7579 *
7580 * Dump an XHTML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007581 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007582 * or xmlKeepBlanksDefault(0) was called
7583 */
7584static void
7585xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7586 int level, int format, const char *encoding) {
7587 int i;
7588 xmlNodePtr tmp;
7589
7590 if (cur == NULL) {
7591#ifdef DEBUG_TREE
7592 xmlGenericError(xmlGenericErrorContext,
7593 "xmlNodeDumpOutput : node == NULL\n");
7594#endif
7595 return;
7596 }
7597 if (cur->type == XML_XINCLUDE_START)
7598 return;
7599 if (cur->type == XML_XINCLUDE_END)
7600 return;
7601 if (cur->type == XML_DTD_NODE) {
7602 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7603 return;
7604 }
7605 if (cur->type == XML_ELEMENT_DECL) {
7606 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7607 return;
7608 }
7609 if (cur->type == XML_ATTRIBUTE_DECL) {
7610 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7611 return;
7612 }
7613 if (cur->type == XML_ENTITY_DECL) {
7614 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7615 return;
7616 }
7617 if (cur->type == XML_TEXT_NODE) {
7618 if (cur->content != NULL) {
7619 if ((cur->name == xmlStringText) ||
7620 (cur->name != xmlStringTextNoenc)) {
7621 xmlChar *buffer;
7622
7623 if (encoding == NULL)
7624 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7625 else
7626 buffer = xmlEncodeSpecialChars(doc, cur->content);
7627 if (buffer != NULL) {
7628 xmlOutputBufferWriteString(buf, (const char *)buffer);
7629 xmlFree(buffer);
7630 }
7631 } else {
7632 /*
7633 * Disable escaping, needed for XSLT
7634 */
7635 xmlOutputBufferWriteString(buf, (const char *) cur->content);
7636 }
7637 }
7638
7639 return;
7640 }
7641 if (cur->type == XML_PI_NODE) {
7642 if (cur->content != NULL) {
7643 xmlOutputBufferWriteString(buf, "<?");
7644 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7645 if (cur->content != NULL) {
7646 xmlOutputBufferWriteString(buf, " ");
7647 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7648 }
7649 xmlOutputBufferWriteString(buf, "?>");
7650 } else {
7651 xmlOutputBufferWriteString(buf, "<?");
7652 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7653 xmlOutputBufferWriteString(buf, "?>");
7654 }
7655 return;
7656 }
7657 if (cur->type == XML_COMMENT_NODE) {
7658 if (cur->content != NULL) {
7659 xmlOutputBufferWriteString(buf, "<!--");
7660 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7661 xmlOutputBufferWriteString(buf, "-->");
7662 }
7663 return;
7664 }
7665 if (cur->type == XML_ENTITY_REF_NODE) {
7666 xmlOutputBufferWriteString(buf, "&");
7667 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7668 xmlOutputBufferWriteString(buf, ";");
7669 return;
7670 }
7671 if (cur->type == XML_CDATA_SECTION_NODE) {
7672 xmlOutputBufferWriteString(buf, "<![CDATA[");
7673 if (cur->content != NULL)
7674 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7675 xmlOutputBufferWriteString(buf, "]]>");
7676 return;
7677 }
7678
7679 if (format == 1) {
7680 tmp = cur->children;
7681 while (tmp != NULL) {
7682 if ((tmp->type == XML_TEXT_NODE) ||
7683 (tmp->type == XML_ENTITY_REF_NODE)) {
7684 format = 0;
7685 break;
7686 }
7687 tmp = tmp->next;
7688 }
7689 }
7690 xmlOutputBufferWriteString(buf, "<");
7691 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7692 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7693 xmlOutputBufferWriteString(buf, ":");
7694 }
7695
7696 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7697 if (cur->nsDef)
7698 xmlNsListDumpOutput(buf, cur->nsDef);
7699 if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
7700 (cur->ns == NULL) && (cur->nsDef == NULL))) {
7701 /*
7702 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
7703 */
7704 xmlOutputBufferWriteString(buf,
7705 " xmlns=\"http://www.w3.org/1999/xhtml\"");
7706 }
7707 if (cur->properties != NULL)
7708 xhtmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7709
7710 if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) {
7711 if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
7712 (xhtmlIsEmpty(cur) == 1)) {
7713 /*
7714 * C.2. Empty Elements
7715 */
7716 xmlOutputBufferWriteString(buf, " />");
7717 } else {
7718 /*
7719 * C.3. Element Minimization and Empty Element Content
7720 */
7721 xmlOutputBufferWriteString(buf, "></");
7722 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7723 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7724 xmlOutputBufferWriteString(buf, ":");
7725 }
7726 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7727 xmlOutputBufferWriteString(buf, ">");
7728 }
7729 return;
7730 }
7731 xmlOutputBufferWriteString(buf, ">");
7732 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
7733 xmlChar *buffer;
7734
7735 if (encoding == NULL)
7736 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7737 else
7738 buffer = xmlEncodeSpecialChars(doc, cur->content);
7739 if (buffer != NULL) {
7740 xmlOutputBufferWriteString(buf, (const char *)buffer);
7741 xmlFree(buffer);
7742 }
7743 }
7744
7745 /*
7746 * 4.8. Script and Style elements
7747 */
7748 if ((cur->type == XML_ELEMENT_NODE) &&
7749 ((xmlStrEqual(cur->name, BAD_CAST "script")) ||
7750 (xmlStrEqual(cur->name, BAD_CAST "style"))) &&
7751 ((cur->ns == NULL) ||
7752 (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) {
7753 xmlNodePtr child = cur->children;
7754
7755 while (child != NULL) {
7756 if ((child->type == XML_TEXT_NODE) ||
7757 (child->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard64b35282002-12-04 15:10:40 +00007758 /*
7759 * Apparently CDATA escaping for style just break on IE,
7760 * mozilla and galeon, so ...
7761 */
7762 if (xmlStrEqual(cur->name, BAD_CAST "style") &&
7763 (xmlStrchr(child->content, '<') == NULL) &&
7764 (xmlStrchr(child->content, '>') == NULL) &&
7765 (xmlStrchr(child->content, '&') == NULL)) {
7766 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7767 } else {
7768 xmlOutputBufferWriteString(buf, "<![CDATA[");
7769 if (child->content != NULL)
7770 xmlOutputBufferWriteString(buf,
7771 (const char *)child->content);
7772 xmlOutputBufferWriteString(buf, "]]>");
7773 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007774 } else {
7775 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7776 }
7777 child = child->next;
7778 }
7779 } else if (cur->children != NULL) {
7780 if (format) xmlOutputBufferWriteString(buf, "\n");
7781 xhtmlNodeListDumpOutput(buf, doc, cur->children,
7782 (level >= 0?level+1:-1), format, encoding);
7783 if ((xmlIndentTreeOutput) && (format))
7784 for (i = 0;i < level;i++)
7785 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7786 }
7787 xmlOutputBufferWriteString(buf, "</");
7788 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7789 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7790 xmlOutputBufferWriteString(buf, ":");
7791 }
7792
7793 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7794 xmlOutputBufferWriteString(buf, ">");
7795}
7796#endif
7797
Owen Taylor3473f882001-02-23 17:55:21 +00007798/************************************************************************
7799 * *
7800 * Saving functions front-ends *
7801 * *
7802 ************************************************************************/
7803
7804/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00007805 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00007806 * @out_doc: Document to generate XML text from
7807 * @doc_txt_ptr: Memory pointer for allocated XML text
7808 * @doc_txt_len: Length of the generated XML text
7809 * @txt_encoding: Character encoding to use when generating XML text
7810 * @format: should formatting spaces been added
7811 *
7812 * Dump the current DOM tree into memory using the character encoding specified
7813 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007814 * allocated memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00007815 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007816 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007817 */
7818
7819void
7820xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007821 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007822 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007823 int dummy = 0;
7824
7825 xmlCharEncoding doc_charset;
7826 xmlOutputBufferPtr out_buff = NULL;
7827 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
7828
7829 if (doc_txt_len == NULL) {
7830 doc_txt_len = &dummy; /* Continue, caller just won't get length */
7831 }
7832
7833 if (doc_txt_ptr == NULL) {
7834 *doc_txt_len = 0;
7835 xmlGenericError(xmlGenericErrorContext,
7836 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
7837 return;
7838 }
7839
7840 *doc_txt_ptr = NULL;
7841 *doc_txt_len = 0;
7842
7843 if (out_doc == NULL) {
7844 /* No document, no output */
7845 xmlGenericError(xmlGenericErrorContext,
7846 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
7847 return;
7848 }
7849
7850 /*
7851 * Validate the encoding value, if provided.
7852 * This logic is copied from xmlSaveFileEnc.
7853 */
7854
7855 if (txt_encoding == NULL)
7856 txt_encoding = (const char *) out_doc->encoding;
7857 if (txt_encoding != NULL) {
7858 doc_charset = xmlParseCharEncoding(txt_encoding);
7859
7860 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
7861 xmlGenericError(xmlGenericErrorContext,
7862 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
7863 return;
7864
7865 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
7866 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
7867 if ( conv_hdlr == NULL ) {
7868 xmlGenericError(xmlGenericErrorContext,
7869 "%s: %s %s '%s'\n",
7870 "xmlDocDumpFormatMemoryEnc",
7871 "Failed to identify encoding handler for",
7872 "character set",
7873 txt_encoding);
7874 return;
7875 }
7876 }
7877 }
7878
7879 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
7880 xmlGenericError(xmlGenericErrorContext,
7881 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
7882 return;
7883 }
7884
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007885 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007886 xmlOutputBufferFlush(out_buff);
7887 if (out_buff->conv != NULL) {
7888 *doc_txt_len = out_buff->conv->use;
7889 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
7890 } else {
7891 *doc_txt_len = out_buff->buffer->use;
7892 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
7893 }
7894 (void)xmlOutputBufferClose(out_buff);
7895
7896 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
7897 *doc_txt_len = 0;
7898 xmlGenericError(xmlGenericErrorContext,
7899 "xmlDocDumpFormatMemoryEnc: %s\n",
7900 "Failed to allocate memory for document text representation.");
7901 }
7902
7903 return;
7904}
7905
7906/**
7907 * xmlDocDumpMemory:
7908 * @cur: the document
7909 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007910 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007911 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007912 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007913 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007914 */
7915void
7916xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
7917 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
7918}
7919
7920/**
7921 * xmlDocDumpFormatMemory:
7922 * @cur: the document
7923 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007924 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007925 * @format: should formatting spaces been added
7926 *
7927 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007928 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007929 * It's up to the caller to free the memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00007930 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007931 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007932 */
7933void
7934xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
7935 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
7936}
7937
7938/**
7939 * xmlDocDumpMemoryEnc:
7940 * @out_doc: Document to generate XML text from
7941 * @doc_txt_ptr: Memory pointer for allocated XML text
7942 * @doc_txt_len: Length of the generated XML text
7943 * @txt_encoding: Character encoding to use when generating XML text
7944 *
7945 * Dump the current DOM tree into memory using the character encoding specified
7946 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007947 * allocated memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007948 */
7949
7950void
7951xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
7952 int * doc_txt_len, const char * txt_encoding) {
7953 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007954 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007955}
7956
7957/**
7958 * xmlGetDocCompressMode:
7959 * @doc: the document
7960 *
7961 * get the compression ratio for a document, ZLIB based
7962 * Returns 0 (uncompressed) to 9 (max compression)
7963 */
7964int
7965xmlGetDocCompressMode (xmlDocPtr doc) {
7966 if (doc == NULL) return(-1);
7967 return(doc->compression);
7968}
7969
7970/**
7971 * xmlSetDocCompressMode:
7972 * @doc: the document
7973 * @mode: the compression ratio
7974 *
7975 * set the compression ratio for a document, ZLIB based
7976 * Correct values: 0 (uncompressed) to 9 (max compression)
7977 */
7978void
7979xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7980 if (doc == NULL) return;
7981 if (mode < 0) doc->compression = 0;
7982 else if (mode > 9) doc->compression = 9;
7983 else doc->compression = mode;
7984}
7985
7986/**
7987 * xmlGetCompressMode:
7988 *
7989 * get the default compression mode used, ZLIB based.
7990 * Returns 0 (uncompressed) to 9 (max compression)
7991 */
7992int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007993xmlGetCompressMode(void)
7994{
7995 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00007996}
7997
7998/**
7999 * xmlSetCompressMode:
8000 * @mode: the compression ratio
8001 *
8002 * set the default compression mode used, ZLIB based
8003 * Correct values: 0 (uncompressed) to 9 (max compression)
8004 */
8005void
8006xmlSetCompressMode(int mode) {
8007 if (mode < 0) xmlCompressMode = 0;
8008 else if (mode > 9) xmlCompressMode = 9;
8009 else xmlCompressMode = mode;
8010}
8011
8012/**
Daniel Veillard9e412302002-06-10 15:59:44 +00008013 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00008014 * @f: the FILE*
8015 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00008016 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00008017 *
8018 * Dump an XML document to an open FILE.
8019 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008020 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008021 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8022 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008023 */
8024int
Daniel Veillard9e412302002-06-10 15:59:44 +00008025xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00008026 xmlOutputBufferPtr buf;
8027 const char * encoding;
8028 xmlCharEncodingHandlerPtr handler = NULL;
8029 int ret;
8030
8031 if (cur == NULL) {
8032#ifdef DEBUG_TREE
8033 xmlGenericError(xmlGenericErrorContext,
8034 "xmlDocDump : document == NULL\n");
8035#endif
8036 return(-1);
8037 }
8038 encoding = (const char *) cur->encoding;
8039
8040 if (encoding != NULL) {
8041 xmlCharEncoding enc;
8042
8043 enc = xmlParseCharEncoding(encoding);
8044
8045 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
8046 xmlGenericError(xmlGenericErrorContext,
8047 "xmlDocDump: document not in UTF8\n");
8048 return(-1);
8049 }
8050 if (enc != XML_CHAR_ENCODING_UTF8) {
8051 handler = xmlFindCharEncodingHandler(encoding);
8052 if (handler == NULL) {
8053 xmlFree((char *) cur->encoding);
8054 cur->encoding = NULL;
8055 }
8056 }
8057 }
8058 buf = xmlOutputBufferCreateFile(f, handler);
8059 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00008060 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008061
8062 ret = xmlOutputBufferClose(buf);
8063 return(ret);
8064}
8065
8066/**
Daniel Veillard9e412302002-06-10 15:59:44 +00008067 * xmlDocDump:
8068 * @f: the FILE*
8069 * @cur: the document
8070 *
8071 * Dump an XML document to an open FILE.
8072 *
8073 * returns: the number of bytes written or -1 in case of failure.
8074 */
8075int
8076xmlDocDump(FILE *f, xmlDocPtr cur) {
8077 return(xmlDocFormatDump (f, cur, 0));
8078}
8079
8080/**
Owen Taylor3473f882001-02-23 17:55:21 +00008081 * xmlSaveFileTo:
8082 * @buf: an output I/O buffer
8083 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00008084 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00008085 *
8086 * Dump an XML document to an I/O buffer.
8087 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008088 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008089 */
8090int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00008091xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00008092 int ret;
8093
8094 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008095 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008096 ret = xmlOutputBufferClose(buf);
8097 return(ret);
8098}
8099
8100/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00008101 * xmlSaveFormatFileTo:
8102 * @buf: an output I/O buffer
8103 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00008104 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00008105 * @format: should formatting spaces been added
8106 *
8107 * Dump an XML document to an I/O buffer.
8108 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008109 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008110 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8111 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardeefd4492001-04-28 16:55:50 +00008112 */
8113int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00008114xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00008115 int ret;
8116
8117 if (buf == NULL) return(0);
8118 xmlDocContentDumpOutput(buf, cur, encoding, format);
8119 ret = xmlOutputBufferClose(buf);
8120 return(ret);
8121}
8122
8123/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00008124 * xmlSaveFormatFileEnc:
Daniel Veillardf012a642001-07-23 19:10:52 +00008125 * @filename: the filename or URL to output
8126 * @cur: the document being saved
8127 * @encoding: the name of the encoding to use or NULL.
8128 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00008129 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00008130 * Dump an XML document to a file or an URL.
8131 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008132 * Returns the number of bytes written or -1 in case of error.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008133 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8134 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008135 */
8136int
Daniel Veillardf012a642001-07-23 19:10:52 +00008137xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
8138 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00008139 xmlOutputBufferPtr buf;
8140 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00008141 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00008142 int ret;
8143
Daniel Veillard4dbe77a2003-01-14 00:17:42 +00008144 if (cur == NULL)
8145 return(-1);
8146
Daniel Veillardfb25a512002-01-13 20:32:08 +00008147 if (encoding == NULL)
8148 encoding = (const char *) cur->encoding;
8149
Owen Taylor3473f882001-02-23 17:55:21 +00008150 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00008151
8152 enc = xmlParseCharEncoding(encoding);
8153 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
8154 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00008155 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00008156 return(-1);
8157 }
8158 if (enc != XML_CHAR_ENCODING_UTF8) {
8159 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00008160 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00008161 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00008162 }
8163 }
8164
Daniel Veillardf012a642001-07-23 19:10:52 +00008165#ifdef HAVE_ZLIB_H
8166 if (cur->compression < 0) cur->compression = xmlCompressMode;
8167#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008168 /*
8169 * save the content to a temp buffer.
8170 */
Daniel Veillardf012a642001-07-23 19:10:52 +00008171 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00008172 if (buf == NULL) return(-1);
8173
Daniel Veillardf012a642001-07-23 19:10:52 +00008174 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008175
8176 ret = xmlOutputBufferClose(buf);
8177 return(ret);
8178}
8179
Daniel Veillardf012a642001-07-23 19:10:52 +00008180
8181/**
8182 * xmlSaveFileEnc:
8183 * @filename: the filename (or URL)
8184 * @cur: the document
8185 * @encoding: the name of an encoding (or NULL)
8186 *
8187 * Dump an XML document, converting it to the given encoding
8188 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008189 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00008190 */
8191int
8192xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
8193 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
8194}
8195
Owen Taylor3473f882001-02-23 17:55:21 +00008196/**
Daniel Veillard67fee942001-04-26 18:59:03 +00008197 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00008198 * @filename: the filename (or URL)
8199 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00008200 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00008201 *
8202 * Dump an XML document to a file. Will use compression if
8203 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00008204 * used. If @format is set then the document will be indented on output.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008205 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8206 * or xmlKeepBlanksDefault(0) was called
Daniel Veillard67fee942001-04-26 18:59:03 +00008207 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008208 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008209 */
8210int
Daniel Veillard67fee942001-04-26 18:59:03 +00008211xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008212 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00008213}
8214
Daniel Veillard67fee942001-04-26 18:59:03 +00008215/**
8216 * xmlSaveFile:
8217 * @filename: the filename (or URL)
8218 * @cur: the document
8219 *
8220 * Dump an XML document to a file. Will use compression if
8221 * compiled in and enabled. If @filename is "-" the stdout file is
8222 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00008223 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00008224 */
8225int
8226xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008227 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00008228}
8229