blob: 867f074a73cf16c4abaa7e976ce3b0868156b8ba [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;
196
197#ifndef XML_XML_NAMESPACE
198 /* xml: prefix is not really a namespace */
199 if ((name[0] == 'x') && (name[1] == 'm') &&
200 (name[2] == 'l') && (name[3] == ':'))
201 return(NULL);
202#endif
203
204 /* nasty but valid */
205 if (name[0] == ':')
206 return(NULL);
207
208 /*
209 * we are not trying to validate but just to cut, and yes it will
210 * work even if this is as set of UTF-8 encoded chars
211 */
212 while ((name[len] != 0) && (name[len] != ':'))
213 len++;
214
215 if (name[len] == 0)
216 return(NULL);
217
218 *prefix = xmlStrndup(name, len);
219 ret = xmlStrdup(&name[len + 1]);
220
221 return(ret);
222}
223
224/************************************************************************
225 * *
Daniel Veillardd2298792003-02-14 16:54:11 +0000226 * Check Name, NCName and QName strings *
227 * *
228 ************************************************************************/
229
230#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
231
232/**
233 * xmlValidateNCName:
234 * @value: the value to check
235 * @space: allow spaces in front and end of the string
236 *
237 * Check that a value conforms to the lexical space of NCName
238 *
239 * Returns 0 if this validates, a positive error code number otherwise
240 * and -1 in case of internal or API error.
241 */
242int
243xmlValidateNCName(const xmlChar *value, int space) {
244 const xmlChar *cur = value;
245 int c,l;
246
247 /*
248 * First quick algorithm for ASCII range
249 */
250 if (space)
251 while (IS_BLANK(*cur)) cur++;
252 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
253 (*cur == '_'))
254 cur++;
255 else
256 goto try_complex;
257 while (((*cur >= 'a') && (*cur <= 'z')) ||
258 ((*cur >= 'A') && (*cur <= 'Z')) ||
259 ((*cur >= '0') && (*cur <= '9')) ||
260 (*cur == '_') || (*cur == '-') || (*cur == '.'))
261 cur++;
262 if (space)
263 while (IS_BLANK(*cur)) cur++;
264 if (*cur == 0)
265 return(0);
266
267try_complex:
268 /*
269 * Second check for chars outside the ASCII range
270 */
271 cur = value;
272 c = CUR_SCHAR(cur, l);
273 if (space) {
274 while (IS_BLANK(c)) {
275 cur += l;
276 c = CUR_SCHAR(cur, l);
277 }
278 }
279 if ((!xmlIsLetter(c)) && (c != '_'))
280 return(1);
281 cur += l;
282 c = CUR_SCHAR(cur, l);
283 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') ||
284 (c == '-') || (c == '_') || xmlIsCombining(c) ||
285 xmlIsExtender(c)) {
286 cur += l;
287 c = CUR_SCHAR(cur, l);
288 }
289 if (space) {
290 while (IS_BLANK(c)) {
291 cur += l;
292 c = CUR_SCHAR(cur, l);
293 }
294 }
295 if (c != 0)
296 return(1);
297
298 return(0);
299}
300
301/**
302 * xmlValidateQName:
303 * @value: the value to check
304 * @space: allow spaces in front and end of the string
305 *
306 * Check that a value conforms to the lexical space of QName
307 *
308 * Returns 0 if this validates, a positive error code number otherwise
309 * and -1 in case of internal or API error.
310 */
311int
312xmlValidateQName(const xmlChar *value, int space) {
313 const xmlChar *cur = value;
314 int c,l;
315
316 /*
317 * First quick algorithm for ASCII range
318 */
319 if (space)
320 while (IS_BLANK(*cur)) cur++;
321 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
322 (*cur == '_'))
323 cur++;
324 else
325 goto try_complex;
326 while (((*cur >= 'a') && (*cur <= 'z')) ||
327 ((*cur >= 'A') && (*cur <= 'Z')) ||
328 ((*cur >= '0') && (*cur <= '9')) ||
329 (*cur == '_') || (*cur == '-') || (*cur == '.'))
330 cur++;
331 if (*cur == ':') {
332 cur++;
333 if (((*cur >= 'a') && (*cur <= 'z')) ||
334 ((*cur >= 'A') && (*cur <= 'Z')) ||
335 (*cur == '_'))
336 cur++;
337 else
338 goto try_complex;
339 while (((*cur >= 'a') && (*cur <= 'z')) ||
340 ((*cur >= 'A') && (*cur <= 'Z')) ||
341 ((*cur >= '0') && (*cur <= '9')) ||
342 (*cur == '_') || (*cur == '-') || (*cur == '.'))
343 cur++;
344 }
345 if (space)
346 while (IS_BLANK(*cur)) cur++;
347 if (*cur == 0)
348 return(0);
349
350try_complex:
351 /*
352 * Second check for chars outside the ASCII range
353 */
354 cur = value;
355 c = CUR_SCHAR(cur, l);
356 if (space) {
357 while (IS_BLANK(c)) {
358 cur += l;
359 c = CUR_SCHAR(cur, l);
360 }
361 }
362 if ((!xmlIsLetter(c)) && (c != '_'))
363 return(1);
364 cur += l;
365 c = CUR_SCHAR(cur, l);
366 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') ||
367 (c == '-') || (c == '_') || xmlIsCombining(c) ||
368 xmlIsExtender(c)) {
369 cur += l;
370 c = CUR_SCHAR(cur, l);
371 }
372 if (c == ':') {
373 cur += l;
374 c = CUR_SCHAR(cur, l);
375 if ((!xmlIsLetter(c)) && (c != '_'))
376 return(1);
377 cur += l;
378 c = CUR_SCHAR(cur, l);
379 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') ||
380 (c == '-') || (c == '_') || xmlIsCombining(c) ||
381 xmlIsExtender(c)) {
382 cur += l;
383 c = CUR_SCHAR(cur, l);
384 }
385 }
386 if (space) {
387 while (IS_BLANK(c)) {
388 cur += l;
389 c = CUR_SCHAR(cur, l);
390 }
391 }
392 if (c != 0)
393 return(1);
394 return(0);
395}
396
397/**
398 * xmlValidateName:
399 * @value: the value to check
400 * @space: allow spaces in front and end of the string
401 *
402 * Check that a value conforms to the lexical space of Name
403 *
404 * Returns 0 if this validates, a positive error code number otherwise
405 * and -1 in case of internal or API error.
406 */
407int
408xmlValidateName(const xmlChar *value, int space) {
409 const xmlChar *cur = value;
410 int c,l;
411
412 /*
413 * First quick algorithm for ASCII range
414 */
415 if (space)
416 while (IS_BLANK(*cur)) cur++;
417 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
418 (*cur == '_') || (*cur == ':'))
419 cur++;
420 else
421 goto try_complex;
422 while (((*cur >= 'a') && (*cur <= 'z')) ||
423 ((*cur >= 'A') && (*cur <= 'Z')) ||
424 ((*cur >= '0') && (*cur <= '9')) ||
425 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
426 cur++;
427 if (space)
428 while (IS_BLANK(*cur)) cur++;
429 if (*cur == 0)
430 return(0);
431
432try_complex:
433 /*
434 * Second check for chars outside the ASCII range
435 */
436 cur = value;
437 c = CUR_SCHAR(cur, l);
438 if (space) {
439 while (IS_BLANK(c)) {
440 cur += l;
441 c = CUR_SCHAR(cur, l);
442 }
443 }
444 if ((!xmlIsLetter(c)) && (c != '_') && (c != ':'))
445 return(1);
446 cur += l;
447 c = CUR_SCHAR(cur, l);
448 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') || (c == ':') ||
449 (c == '-') || (c == '_') || xmlIsCombining(c) || xmlIsExtender(c)) {
450 cur += l;
451 c = CUR_SCHAR(cur, l);
452 }
453 if (space) {
454 while (IS_BLANK(c)) {
455 cur += l;
456 c = CUR_SCHAR(cur, l);
457 }
458 }
459 if (c != 0)
460 return(1);
461 return(0);
462}
463
Daniel Veillardd4310742003-02-18 21:12:46 +0000464/**
465 * xmlValidateNMToken:
466 * @value: the value to check
467 * @space: allow spaces in front and end of the string
468 *
469 * Check that a value conforms to the lexical space of NMToken
470 *
471 * Returns 0 if this validates, a positive error code number otherwise
472 * and -1 in case of internal or API error.
473 */
474int
475xmlValidateNMToken(const xmlChar *value, int space) {
476 const xmlChar *cur = value;
477 int c,l;
478
479 /*
480 * First quick algorithm for ASCII range
481 */
482 if (space)
483 while (IS_BLANK(*cur)) cur++;
484 if (((*cur >= 'a') && (*cur <= 'z')) ||
485 ((*cur >= 'A') && (*cur <= 'Z')) ||
486 ((*cur >= '0') && (*cur <= '9')) ||
487 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
488 cur++;
489 else
490 goto try_complex;
491 while (((*cur >= 'a') && (*cur <= 'z')) ||
492 ((*cur >= 'A') && (*cur <= 'Z')) ||
493 ((*cur >= '0') && (*cur <= '9')) ||
494 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
495 cur++;
496 if (space)
497 while (IS_BLANK(*cur)) cur++;
498 if (*cur == 0)
499 return(0);
500
501try_complex:
502 /*
503 * Second check for chars outside the ASCII range
504 */
505 cur = value;
506 c = CUR_SCHAR(cur, l);
507 if (space) {
508 while (IS_BLANK(c)) {
509 cur += l;
510 c = CUR_SCHAR(cur, l);
511 }
512 }
513 if (!(xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') || (c == ':') ||
514 (c == '-') || (c == '_') || xmlIsCombining(c) || xmlIsExtender(c)))
515 return(1);
516 cur += l;
517 c = CUR_SCHAR(cur, l);
518 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') || (c == ':') ||
519 (c == '-') || (c == '_') || xmlIsCombining(c) || xmlIsExtender(c)) {
520 cur += l;
521 c = CUR_SCHAR(cur, l);
522 }
523 if (space) {
524 while (IS_BLANK(c)) {
525 cur += l;
526 c = CUR_SCHAR(cur, l);
527 }
528 }
529 if (c != 0)
530 return(1);
531 return(0);
532}
533
Daniel Veillardd2298792003-02-14 16:54:11 +0000534/************************************************************************
535 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000536 * Allocation and deallocation of basic structures *
537 * *
538 ************************************************************************/
539
540/**
541 * xmlSetBufferAllocationScheme:
542 * @scheme: allocation method to use
543 *
544 * Set the buffer allocation method. Types are
545 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
546 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
547 * improves performance
548 */
549void
550xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
551 xmlBufferAllocScheme = scheme;
552}
553
554/**
555 * xmlGetBufferAllocationScheme:
556 *
557 * Types are
558 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
559 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
560 * improves performance
561 *
562 * Returns the current allocation scheme
563 */
564xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000565xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000566 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000567}
568
569/**
570 * xmlNewNs:
571 * @node: the element carrying the namespace
572 * @href: the URI associated
573 * @prefix: the prefix for the namespace
574 *
575 * Creation of a new Namespace. This function will refuse to create
576 * a namespace with a similar prefix than an existing one present on this
577 * node.
578 * We use href==NULL in the case of an element creation where the namespace
579 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000580 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000581 */
582xmlNsPtr
583xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
584 xmlNsPtr cur;
585
586 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
587 return(NULL);
588
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000589 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
590 return(NULL);
591
Owen Taylor3473f882001-02-23 17:55:21 +0000592 /*
593 * Allocate a new Namespace and fill the fields.
594 */
595 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
596 if (cur == NULL) {
597 xmlGenericError(xmlGenericErrorContext,
598 "xmlNewNs : malloc failed\n");
599 return(NULL);
600 }
601 memset(cur, 0, sizeof(xmlNs));
602 cur->type = XML_LOCAL_NAMESPACE;
603
604 if (href != NULL)
605 cur->href = xmlStrdup(href);
606 if (prefix != NULL)
607 cur->prefix = xmlStrdup(prefix);
608
609 /*
610 * Add it at the end to preserve parsing order ...
611 * and checks for existing use of the prefix
612 */
613 if (node != NULL) {
614 if (node->nsDef == NULL) {
615 node->nsDef = cur;
616 } else {
617 xmlNsPtr prev = node->nsDef;
618
619 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
620 (xmlStrEqual(prev->prefix, cur->prefix))) {
621 xmlFreeNs(cur);
622 return(NULL);
623 }
624 while (prev->next != NULL) {
625 prev = prev->next;
626 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
627 (xmlStrEqual(prev->prefix, cur->prefix))) {
628 xmlFreeNs(cur);
629 return(NULL);
630 }
631 }
632 prev->next = cur;
633 }
634 }
635 return(cur);
636}
637
638/**
639 * xmlSetNs:
640 * @node: a node in the document
641 * @ns: a namespace pointer
642 *
643 * Associate a namespace to a node, a posteriori.
644 */
645void
646xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
647 if (node == NULL) {
648#ifdef DEBUG_TREE
649 xmlGenericError(xmlGenericErrorContext,
650 "xmlSetNs: node == NULL\n");
651#endif
652 return;
653 }
654 node->ns = ns;
655}
656
657/**
658 * xmlFreeNs:
659 * @cur: the namespace pointer
660 *
661 * Free up the structures associated to a namespace
662 */
663void
664xmlFreeNs(xmlNsPtr cur) {
665 if (cur == NULL) {
666#ifdef DEBUG_TREE
667 xmlGenericError(xmlGenericErrorContext,
668 "xmlFreeNs : ns == NULL\n");
669#endif
670 return;
671 }
672 if (cur->href != NULL) xmlFree((char *) cur->href);
673 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000674 xmlFree(cur);
675}
676
677/**
678 * xmlFreeNsList:
679 * @cur: the first namespace pointer
680 *
681 * Free up all the structures associated to the chained namespaces.
682 */
683void
684xmlFreeNsList(xmlNsPtr cur) {
685 xmlNsPtr next;
686 if (cur == NULL) {
687#ifdef DEBUG_TREE
688 xmlGenericError(xmlGenericErrorContext,
689 "xmlFreeNsList : ns == NULL\n");
690#endif
691 return;
692 }
693 while (cur != NULL) {
694 next = cur->next;
695 xmlFreeNs(cur);
696 cur = next;
697 }
698}
699
700/**
701 * xmlNewDtd:
702 * @doc: the document pointer
703 * @name: the DTD name
704 * @ExternalID: the external ID
705 * @SystemID: the system ID
706 *
707 * Creation of a new DTD for the external subset. To create an
708 * internal subset, use xmlCreateIntSubset().
709 *
710 * Returns a pointer to the new DTD structure
711 */
712xmlDtdPtr
713xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
714 const xmlChar *ExternalID, const xmlChar *SystemID) {
715 xmlDtdPtr cur;
716
717 if ((doc != NULL) && (doc->extSubset != NULL)) {
718#ifdef DEBUG_TREE
719 xmlGenericError(xmlGenericErrorContext,
720 "xmlNewDtd(%s): document %s already have a DTD %s\n",
721 /* !!! */ (char *) name, doc->name,
722 /* !!! */ (char *)doc->extSubset->name);
723#endif
724 return(NULL);
725 }
726
727 /*
728 * Allocate a new DTD and fill the fields.
729 */
730 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
731 if (cur == NULL) {
732 xmlGenericError(xmlGenericErrorContext,
733 "xmlNewDtd : malloc failed\n");
734 return(NULL);
735 }
736 memset(cur, 0 , sizeof(xmlDtd));
737 cur->type = XML_DTD_NODE;
738
739 if (name != NULL)
740 cur->name = xmlStrdup(name);
741 if (ExternalID != NULL)
742 cur->ExternalID = xmlStrdup(ExternalID);
743 if (SystemID != NULL)
744 cur->SystemID = xmlStrdup(SystemID);
745 if (doc != NULL)
746 doc->extSubset = cur;
747 cur->doc = doc;
748
Daniel Veillarda880b122003-04-21 21:36:41 +0000749 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000750 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000751 return(cur);
752}
753
754/**
755 * xmlGetIntSubset:
756 * @doc: the document pointer
757 *
758 * Get the internal subset of a document
759 * Returns a pointer to the DTD structure or NULL if not found
760 */
761
762xmlDtdPtr
763xmlGetIntSubset(xmlDocPtr doc) {
764 xmlNodePtr cur;
765
766 if (doc == NULL)
767 return(NULL);
768 cur = doc->children;
769 while (cur != NULL) {
770 if (cur->type == XML_DTD_NODE)
771 return((xmlDtdPtr) cur);
772 cur = cur->next;
773 }
774 return((xmlDtdPtr) doc->intSubset);
775}
776
777/**
778 * xmlCreateIntSubset:
779 * @doc: the document pointer
780 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000781 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000782 * @SystemID: the system ID
783 *
784 * Create the internal subset of a document
785 * Returns a pointer to the new DTD structure
786 */
787xmlDtdPtr
788xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
789 const xmlChar *ExternalID, const xmlChar *SystemID) {
790 xmlDtdPtr cur;
791
792 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
793#ifdef DEBUG_TREE
794 xmlGenericError(xmlGenericErrorContext,
795
796 "xmlCreateIntSubset(): document %s already have an internal subset\n",
797 doc->name);
798#endif
799 return(NULL);
800 }
801
802 /*
803 * Allocate a new DTD and fill the fields.
804 */
805 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
806 if (cur == NULL) {
807 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000808 "xmlCreateIntSubset : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000809 return(NULL);
810 }
811 memset(cur, 0, sizeof(xmlDtd));
812 cur->type = XML_DTD_NODE;
813
814 if (name != NULL)
815 cur->name = xmlStrdup(name);
816 if (ExternalID != NULL)
817 cur->ExternalID = xmlStrdup(ExternalID);
818 if (SystemID != NULL)
819 cur->SystemID = xmlStrdup(SystemID);
820 if (doc != NULL) {
821 doc->intSubset = cur;
822 cur->parent = doc;
823 cur->doc = doc;
824 if (doc->children == NULL) {
825 doc->children = (xmlNodePtr) cur;
826 doc->last = (xmlNodePtr) cur;
827 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000828 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000829 xmlNodePtr prev;
830
Owen Taylor3473f882001-02-23 17:55:21 +0000831 prev = doc->children;
832 prev->prev = (xmlNodePtr) cur;
833 cur->next = prev;
834 doc->children = (xmlNodePtr) cur;
835 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000836 xmlNodePtr next;
837
838 next = doc->children;
839 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
840 next = next->next;
841 if (next == NULL) {
842 cur->prev = doc->last;
843 cur->prev->next = (xmlNodePtr) cur;
844 cur->next = NULL;
845 doc->last = (xmlNodePtr) cur;
846 } else {
847 cur->next = next;
848 cur->prev = next->prev;
849 if (cur->prev == NULL)
850 doc->children = (xmlNodePtr) cur;
851 else
852 cur->prev->next = (xmlNodePtr) cur;
853 next->prev = (xmlNodePtr) cur;
854 }
Owen Taylor3473f882001-02-23 17:55:21 +0000855 }
856 }
857 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000858
Daniel Veillarda880b122003-04-21 21:36:41 +0000859 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000860 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000861 return(cur);
862}
863
864/**
865 * xmlFreeDtd:
866 * @cur: the DTD structure to free up
867 *
868 * Free a DTD structure.
869 */
870void
871xmlFreeDtd(xmlDtdPtr cur) {
872 if (cur == NULL) {
873#ifdef DEBUG_TREE
874 xmlGenericError(xmlGenericErrorContext,
875 "xmlFreeDtd : DTD == NULL\n");
876#endif
877 return;
878 }
Daniel Veillard5335dc52003-01-01 20:59:38 +0000879
Daniel Veillarda880b122003-04-21 21:36:41 +0000880 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000881 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
882
Owen Taylor3473f882001-02-23 17:55:21 +0000883 if (cur->children != NULL) {
884 xmlNodePtr next, c = cur->children;
885
886 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000887 * Cleanup all the DTD comments they are not in the DTD
Owen Taylor3473f882001-02-23 17:55:21 +0000888 * indexes.
889 */
890 while (c != NULL) {
891 next = c->next;
892 if (c->type == XML_COMMENT_NODE) {
893 xmlUnlinkNode(c);
894 xmlFreeNode(c);
895 }
896 c = next;
897 }
898 }
899 if (cur->name != NULL) xmlFree((char *) cur->name);
900 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
901 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
902 /* TODO !!! */
903 if (cur->notations != NULL)
904 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
905
906 if (cur->elements != NULL)
907 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
908 if (cur->attributes != NULL)
909 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
910 if (cur->entities != NULL)
911 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
912 if (cur->pentities != NULL)
913 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
914
Owen Taylor3473f882001-02-23 17:55:21 +0000915 xmlFree(cur);
916}
917
918/**
919 * xmlNewDoc:
920 * @version: xmlChar string giving the version of XML "1.0"
921 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000922 * Creates a new XML document
923 *
Owen Taylor3473f882001-02-23 17:55:21 +0000924 * Returns a new document
925 */
926xmlDocPtr
927xmlNewDoc(const xmlChar *version) {
928 xmlDocPtr cur;
929
930 if (version == NULL)
931 version = (const xmlChar *) "1.0";
932
933 /*
934 * Allocate a new document and fill the fields.
935 */
936 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
937 if (cur == NULL) {
938 xmlGenericError(xmlGenericErrorContext,
939 "xmlNewDoc : malloc failed\n");
940 return(NULL);
941 }
942 memset(cur, 0, sizeof(xmlDoc));
943 cur->type = XML_DOCUMENT_NODE;
944
945 cur->version = xmlStrdup(version);
946 cur->standalone = -1;
947 cur->compression = -1; /* not initialized */
948 cur->doc = cur;
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000949 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +0000950
Daniel Veillarda880b122003-04-21 21:36:41 +0000951 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000952 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000953 return(cur);
954}
955
956/**
957 * xmlFreeDoc:
958 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +0000959 *
960 * Free up all the structures used by a document, tree included.
961 */
962void
963xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +0000964 xmlDtdPtr extSubset, intSubset;
965
Owen Taylor3473f882001-02-23 17:55:21 +0000966 if (cur == NULL) {
967#ifdef DEBUG_TREE
968 xmlGenericError(xmlGenericErrorContext,
969 "xmlFreeDoc : document == NULL\n");
970#endif
971 return;
972 }
Daniel Veillard5335dc52003-01-01 20:59:38 +0000973
Daniel Veillarda880b122003-04-21 21:36:41 +0000974 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000975 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
976
Daniel Veillard76d66f42001-05-16 21:05:17 +0000977 /*
978 * Do this before freeing the children list to avoid ID lookups
979 */
980 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
981 cur->ids = NULL;
982 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
983 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000984 extSubset = cur->extSubset;
985 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +0000986 if (intSubset == extSubset)
987 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000988 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000989 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000990 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000991 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000992 }
Daniel Veillarda9142e72001-06-19 11:07:54 +0000993 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000994 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000995 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000996 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000997 }
998
999 if (cur->children != NULL) xmlFreeNodeList(cur->children);
1000
Owen Taylor3473f882001-02-23 17:55:21 +00001001 if (cur->version != NULL) xmlFree((char *) cur->version);
1002 if (cur->name != NULL) xmlFree((char *) cur->name);
1003 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00001004 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00001005 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Owen Taylor3473f882001-02-23 17:55:21 +00001006 xmlFree(cur);
1007}
1008
1009/**
1010 * xmlStringLenGetNodeList:
1011 * @doc: the document
1012 * @value: the value of the text
1013 * @len: the length of the string value
1014 *
1015 * Parse the value string and build the node list associated. Should
1016 * produce a flat tree with only TEXTs and ENTITY_REFs.
1017 * Returns a pointer to the first child
1018 */
1019xmlNodePtr
1020xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1021 xmlNodePtr ret = NULL, last = NULL;
1022 xmlNodePtr node;
1023 xmlChar *val;
1024 const xmlChar *cur = value;
1025 const xmlChar *q;
1026 xmlEntityPtr ent;
1027
1028 if (value == NULL) return(NULL);
1029
1030 q = cur;
1031 while ((*cur != 0) && (cur - value < len)) {
1032 if (*cur == '&') {
1033 /*
1034 * Save the current text.
1035 */
1036 if (cur != q) {
1037 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1038 xmlNodeAddContentLen(last, q, cur - q);
1039 } else {
1040 node = xmlNewDocTextLen(doc, q, cur - q);
1041 if (node == NULL) return(ret);
1042 if (last == NULL)
1043 last = ret = node;
1044 else {
1045 last->next = node;
1046 node->prev = last;
1047 last = node;
1048 }
1049 }
1050 }
1051 /*
1052 * Read the entity string
1053 */
1054 cur++;
1055 q = cur;
1056 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
1057 if ((*cur == 0) || (cur - value >= len)) {
1058#ifdef DEBUG_TREE
1059 xmlGenericError(xmlGenericErrorContext,
1060 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
1061#endif
1062 return(ret);
1063 }
1064 if (cur != q) {
1065 /*
1066 * Predefined entities don't generate nodes
1067 */
1068 val = xmlStrndup(q, cur - q);
1069 ent = xmlGetDocEntity(doc, val);
1070 if ((ent != NULL) &&
1071 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1072 if (last == NULL) {
1073 node = xmlNewDocText(doc, ent->content);
1074 last = ret = node;
1075 } else
1076 xmlNodeAddContent(last, ent->content);
1077
1078 } else {
1079 /*
1080 * Create a new REFERENCE_REF node
1081 */
1082 node = xmlNewReference(doc, val);
1083 if (node == NULL) {
1084 if (val != NULL) xmlFree(val);
1085 return(ret);
1086 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001087 else if ((ent != NULL) && (ent->children == NULL)) {
1088 xmlNodePtr tmp;
1089
1090 ent->children =
1091 xmlStringGetNodeList(doc, (const xmlChar*)node->content);
1092 tmp = ent->children;
1093 while (tmp) {
1094 tmp->parent = (xmlNodePtr)ent;
1095 tmp = tmp->next;
1096 }
1097 }
Owen Taylor3473f882001-02-23 17:55:21 +00001098 if (last == NULL)
1099 last = ret = node;
1100 else {
1101 last->next = node;
1102 node->prev = last;
1103 last = node;
1104 }
1105 }
1106 xmlFree(val);
1107 }
1108 cur++;
1109 q = cur;
1110 } else
1111 cur++;
1112 }
1113 if (cur != q) {
1114 /*
1115 * Handle the last piece of text.
1116 */
1117 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1118 xmlNodeAddContentLen(last, q, cur - q);
1119 } else {
1120 node = xmlNewDocTextLen(doc, q, cur - q);
1121 if (node == NULL) return(ret);
1122 if (last == NULL)
1123 last = ret = node;
1124 else {
1125 last->next = node;
1126 node->prev = last;
1127 last = node;
1128 }
1129 }
1130 }
1131 return(ret);
1132}
1133
1134/**
1135 * xmlStringGetNodeList:
1136 * @doc: the document
1137 * @value: the value of the attribute
1138 *
1139 * Parse the value string and build the node list associated. Should
1140 * produce a flat tree with only TEXTs and ENTITY_REFs.
1141 * Returns a pointer to the first child
1142 */
1143xmlNodePtr
1144xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1145 xmlNodePtr ret = NULL, last = NULL;
1146 xmlNodePtr node;
1147 xmlChar *val;
1148 const xmlChar *cur = value;
1149 const xmlChar *q;
1150 xmlEntityPtr ent;
1151
1152 if (value == NULL) return(NULL);
1153
1154 q = cur;
1155 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001156 if (cur[0] == '&') {
1157 int charval = 0;
1158 xmlChar tmp;
1159
Owen Taylor3473f882001-02-23 17:55:21 +00001160 /*
1161 * Save the current text.
1162 */
1163 if (cur != q) {
1164 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1165 xmlNodeAddContentLen(last, q, cur - q);
1166 } else {
1167 node = xmlNewDocTextLen(doc, q, cur - q);
1168 if (node == NULL) return(ret);
1169 if (last == NULL)
1170 last = ret = node;
1171 else {
1172 last->next = node;
1173 node->prev = last;
1174 last = node;
1175 }
1176 }
1177 }
Owen Taylor3473f882001-02-23 17:55:21 +00001178 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001179 if ((cur[1] == '#') && (cur[2] == 'x')) {
1180 cur += 3;
1181 tmp = *cur;
1182 while (tmp != ';') { /* Non input consuming loop */
1183 if ((tmp >= '0') && (tmp <= '9'))
1184 charval = charval * 16 + (tmp - '0');
1185 else if ((tmp >= 'a') && (tmp <= 'f'))
1186 charval = charval * 16 + (tmp - 'a') + 10;
1187 else if ((tmp >= 'A') && (tmp <= 'F'))
1188 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001189 else {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001190 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001191 "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001192 charval = 0;
1193 break;
1194 }
1195 cur++;
1196 tmp = *cur;
1197 }
1198 if (tmp == ';')
1199 cur++;
1200 q = cur;
1201 } else if (cur[1] == '#') {
1202 cur += 2;
1203 tmp = *cur;
1204 while (tmp != ';') { /* Non input consuming loops */
1205 if ((tmp >= '0') && (tmp <= '9'))
1206 charval = charval * 10 + (tmp - '0');
1207 else {
1208 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001209 "xmlStringGetNodeList: invalid decimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001210 charval = 0;
1211 break;
1212 }
1213 cur++;
1214 tmp = *cur;
1215 }
1216 if (tmp == ';')
1217 cur++;
1218 q = cur;
1219 } else {
1220 /*
1221 * Read the entity string
1222 */
1223 cur++;
1224 q = cur;
1225 while ((*cur != 0) && (*cur != ';')) cur++;
1226 if (*cur == 0) {
1227#ifdef DEBUG_TREE
1228 xmlGenericError(xmlGenericErrorContext,
1229 "xmlStringGetNodeList: unterminated entity %30s\n", q);
1230#endif
1231 return(ret);
1232 }
1233 if (cur != q) {
1234 /*
1235 * Predefined entities don't generate nodes
1236 */
1237 val = xmlStrndup(q, cur - q);
1238 ent = xmlGetDocEntity(doc, val);
1239 if ((ent != NULL) &&
1240 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1241 if (last == NULL) {
1242 node = xmlNewDocText(doc, ent->content);
1243 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001244 } else if (last->type != XML_TEXT_NODE) {
1245 node = xmlNewDocText(doc, ent->content);
1246 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001247 } else
1248 xmlNodeAddContent(last, ent->content);
1249
1250 } else {
1251 /*
1252 * Create a new REFERENCE_REF node
1253 */
1254 node = xmlNewReference(doc, val);
1255 if (node == NULL) {
1256 if (val != NULL) xmlFree(val);
1257 return(ret);
1258 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001259 else if ((ent != NULL) && (ent->children == NULL)) {
1260 xmlNodePtr temp;
1261
1262 ent->children = xmlStringGetNodeList(doc,
1263 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001264 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001265 temp = ent->children;
1266 while (temp) {
1267 temp->parent = (xmlNodePtr)ent;
1268 temp = temp->next;
1269 }
1270 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001271 if (last == NULL) {
1272 last = ret = node;
1273 } else {
1274 last = xmlAddNextSibling(last, node);
1275 }
1276 }
1277 xmlFree(val);
1278 }
1279 cur++;
1280 q = cur;
1281 }
1282 if (charval != 0) {
1283 xmlChar buf[10];
1284 int len;
1285
1286 len = xmlCopyCharMultiByte(buf, charval);
1287 buf[len] = 0;
1288 node = xmlNewDocText(doc, buf);
1289 if (node != NULL) {
1290 if (last == NULL) {
1291 last = ret = node;
1292 } else {
1293 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001294 }
1295 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001296
1297 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001298 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001299 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001300 cur++;
1301 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001302 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001303 /*
1304 * Handle the last piece of text.
1305 */
1306 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1307 xmlNodeAddContentLen(last, q, cur - q);
1308 } else {
1309 node = xmlNewDocTextLen(doc, q, cur - q);
1310 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001311 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001312 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001313 } else {
1314 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001315 }
1316 }
1317 }
1318 return(ret);
1319}
1320
1321/**
1322 * xmlNodeListGetString:
1323 * @doc: the document
1324 * @list: a Node list
1325 * @inLine: should we replace entity contents or show their external form
1326 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001327 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001328 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001329 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001330 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001331 */
1332xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001333xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1334{
Owen Taylor3473f882001-02-23 17:55:21 +00001335 xmlNodePtr node = list;
1336 xmlChar *ret = NULL;
1337 xmlEntityPtr ent;
1338
Daniel Veillard7646b182002-04-20 06:41:40 +00001339 if (list == NULL)
1340 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001341
1342 while (node != NULL) {
1343 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001344 (node->type == XML_CDATA_SECTION_NODE)) {
1345 if (inLine) {
1346 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001347 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001348 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001349
Daniel Veillard7646b182002-04-20 06:41:40 +00001350 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1351 if (buffer != NULL) {
1352 ret = xmlStrcat(ret, buffer);
1353 xmlFree(buffer);
1354 }
1355 }
1356 } else if (node->type == XML_ENTITY_REF_NODE) {
1357 if (inLine) {
1358 ent = xmlGetDocEntity(doc, node->name);
1359 if (ent != NULL) {
1360 xmlChar *buffer;
1361
1362 /* an entity content can be any "well balanced chunk",
1363 * i.e. the result of the content [43] production:
1364 * http://www.w3.org/TR/REC-xml#NT-content.
1365 * So it can contain text, CDATA section or nested
1366 * entity reference nodes (among others).
1367 * -> we recursive call xmlNodeListGetString()
1368 * which handles these types */
1369 buffer = xmlNodeListGetString(doc, ent->children, 1);
1370 if (buffer != NULL) {
1371 ret = xmlStrcat(ret, buffer);
1372 xmlFree(buffer);
1373 }
1374 } else {
1375 ret = xmlStrcat(ret, node->content);
1376 }
1377 } else {
1378 xmlChar buf[2];
1379
1380 buf[0] = '&';
1381 buf[1] = 0;
1382 ret = xmlStrncat(ret, buf, 1);
1383 ret = xmlStrcat(ret, node->name);
1384 buf[0] = ';';
1385 buf[1] = 0;
1386 ret = xmlStrncat(ret, buf, 1);
1387 }
1388 }
1389#if 0
1390 else {
1391 xmlGenericError(xmlGenericErrorContext,
1392 "xmlGetNodeListString : invalid node type %d\n",
1393 node->type);
1394 }
1395#endif
1396 node = node->next;
1397 }
1398 return (ret);
1399}
Owen Taylor3473f882001-02-23 17:55:21 +00001400/**
1401 * xmlNodeListGetRawString:
1402 * @doc: the document
1403 * @list: a Node list
1404 * @inLine: should we replace entity contents or show their external form
1405 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001406 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001407 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1408 * this function doesn't do any character encoding handling.
1409 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001410 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001411 */
1412xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001413xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1414{
Owen Taylor3473f882001-02-23 17:55:21 +00001415 xmlNodePtr node = list;
1416 xmlChar *ret = NULL;
1417 xmlEntityPtr ent;
1418
Daniel Veillard7646b182002-04-20 06:41:40 +00001419 if (list == NULL)
1420 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001421
1422 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001423 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001424 (node->type == XML_CDATA_SECTION_NODE)) {
1425 if (inLine) {
1426 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001427 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001428 xmlChar *buffer;
1429
1430 buffer = xmlEncodeSpecialChars(doc, node->content);
1431 if (buffer != NULL) {
1432 ret = xmlStrcat(ret, buffer);
1433 xmlFree(buffer);
1434 }
1435 }
1436 } else if (node->type == XML_ENTITY_REF_NODE) {
1437 if (inLine) {
1438 ent = xmlGetDocEntity(doc, node->name);
1439 if (ent != NULL) {
1440 xmlChar *buffer;
1441
1442 /* an entity content can be any "well balanced chunk",
1443 * i.e. the result of the content [43] production:
1444 * http://www.w3.org/TR/REC-xml#NT-content.
1445 * So it can contain text, CDATA section or nested
1446 * entity reference nodes (among others).
1447 * -> we recursive call xmlNodeListGetRawString()
1448 * which handles these types */
1449 buffer =
1450 xmlNodeListGetRawString(doc, ent->children, 1);
1451 if (buffer != NULL) {
1452 ret = xmlStrcat(ret, buffer);
1453 xmlFree(buffer);
1454 }
1455 } else {
1456 ret = xmlStrcat(ret, node->content);
1457 }
1458 } else {
1459 xmlChar buf[2];
1460
1461 buf[0] = '&';
1462 buf[1] = 0;
1463 ret = xmlStrncat(ret, buf, 1);
1464 ret = xmlStrcat(ret, node->name);
1465 buf[0] = ';';
1466 buf[1] = 0;
1467 ret = xmlStrncat(ret, buf, 1);
1468 }
1469 }
Owen Taylor3473f882001-02-23 17:55:21 +00001470#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001471 else {
1472 xmlGenericError(xmlGenericErrorContext,
1473 "xmlGetNodeListString : invalid node type %d\n",
1474 node->type);
1475 }
Owen Taylor3473f882001-02-23 17:55:21 +00001476#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001477 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001478 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001479 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001480}
1481
1482/**
1483 * xmlNewProp:
1484 * @node: the holding node
1485 * @name: the name of the attribute
1486 * @value: the value of the attribute
1487 *
1488 * Create a new property carried by a node.
1489 * Returns a pointer to the attribute
1490 */
1491xmlAttrPtr
1492xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1493 xmlAttrPtr cur;
1494 xmlDocPtr doc = NULL;
1495
1496 if (name == NULL) {
1497#ifdef DEBUG_TREE
1498 xmlGenericError(xmlGenericErrorContext,
1499 "xmlNewProp : name == NULL\n");
1500#endif
1501 return(NULL);
1502 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00001503 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
1504 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001505
1506 /*
1507 * Allocate a new property and fill the fields.
1508 */
1509 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1510 if (cur == NULL) {
1511 xmlGenericError(xmlGenericErrorContext,
1512 "xmlNewProp : malloc failed\n");
1513 return(NULL);
1514 }
1515 memset(cur, 0, sizeof(xmlAttr));
1516 cur->type = XML_ATTRIBUTE_NODE;
1517
1518 cur->parent = node;
1519 if (node != NULL) {
1520 doc = node->doc;
1521 cur->doc = doc;
1522 }
1523 cur->name = xmlStrdup(name);
1524 if (value != NULL) {
1525 xmlChar *buffer;
1526 xmlNodePtr tmp;
1527
1528 buffer = xmlEncodeEntitiesReentrant(doc, value);
1529 cur->children = xmlStringGetNodeList(doc, buffer);
1530 cur->last = NULL;
1531 tmp = cur->children;
1532 while (tmp != NULL) {
1533 tmp->parent = (xmlNodePtr) cur;
1534 tmp->doc = doc;
1535 if (tmp->next == NULL)
1536 cur->last = tmp;
1537 tmp = tmp->next;
1538 }
1539 xmlFree(buffer);
1540 }
1541
1542 /*
1543 * Add it at the end to preserve parsing order ...
1544 */
1545 if (node != NULL) {
1546 if (node->properties == NULL) {
1547 node->properties = cur;
1548 } else {
1549 xmlAttrPtr prev = node->properties;
1550
1551 while (prev->next != NULL) prev = prev->next;
1552 prev->next = cur;
1553 cur->prev = prev;
1554 }
1555 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001556
Daniel Veillarda880b122003-04-21 21:36:41 +00001557 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001558 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001559 return(cur);
1560}
1561
1562/**
1563 * xmlNewNsProp:
1564 * @node: the holding node
1565 * @ns: the namespace
1566 * @name: the name of the attribute
1567 * @value: the value of the attribute
1568 *
1569 * Create a new property tagged with a namespace and carried by a node.
1570 * Returns a pointer to the attribute
1571 */
1572xmlAttrPtr
1573xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1574 const xmlChar *value) {
1575 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001576 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001577
1578 if (name == NULL) {
1579#ifdef DEBUG_TREE
1580 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001581 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001582#endif
1583 return(NULL);
1584 }
1585
1586 /*
1587 * Allocate a new property and fill the fields.
1588 */
1589 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1590 if (cur == NULL) {
1591 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001592 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001593 return(NULL);
1594 }
1595 memset(cur, 0, sizeof(xmlAttr));
1596 cur->type = XML_ATTRIBUTE_NODE;
1597
1598 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001599 if (node != NULL) {
1600 doc = node->doc;
1601 cur->doc = doc;
1602 }
Owen Taylor3473f882001-02-23 17:55:21 +00001603 cur->ns = ns;
1604 cur->name = xmlStrdup(name);
1605 if (value != NULL) {
1606 xmlChar *buffer;
1607 xmlNodePtr tmp;
1608
Daniel Veillarda682b212001-06-07 19:59:42 +00001609 buffer = xmlEncodeEntitiesReentrant(doc, value);
1610 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001611 cur->last = NULL;
1612 tmp = cur->children;
1613 while (tmp != NULL) {
1614 tmp->parent = (xmlNodePtr) cur;
1615 if (tmp->next == NULL)
1616 cur->last = tmp;
1617 tmp = tmp->next;
1618 }
1619 xmlFree(buffer);
1620 }
1621
1622 /*
1623 * Add it at the end to preserve parsing order ...
1624 */
1625 if (node != NULL) {
1626 if (node->properties == NULL) {
1627 node->properties = cur;
1628 } else {
1629 xmlAttrPtr prev = node->properties;
1630
1631 while (prev->next != NULL) prev = prev->next;
1632 prev->next = cur;
1633 cur->prev = prev;
1634 }
1635 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001636
Daniel Veillarda880b122003-04-21 21:36:41 +00001637 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001638 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001639 return(cur);
1640}
1641
1642/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001643 * xmlNewNsPropEatName:
1644 * @node: the holding node
1645 * @ns: the namespace
1646 * @name: the name of the attribute
1647 * @value: the value of the attribute
1648 *
1649 * Create a new property tagged with a namespace and carried by a node.
1650 * Returns a pointer to the attribute
1651 */
1652xmlAttrPtr
1653xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1654 const xmlChar *value) {
1655 xmlAttrPtr cur;
1656 xmlDocPtr doc = NULL;
1657
1658 if (name == NULL) {
1659#ifdef DEBUG_TREE
1660 xmlGenericError(xmlGenericErrorContext,
1661 "xmlNewNsPropEatName : name == NULL\n");
1662#endif
1663 return(NULL);
1664 }
1665
1666 /*
1667 * Allocate a new property and fill the fields.
1668 */
1669 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1670 if (cur == NULL) {
1671 xmlGenericError(xmlGenericErrorContext,
1672 "xmlNewNsPropEatName : malloc failed\n");
1673 return(NULL);
1674 }
1675 memset(cur, 0, sizeof(xmlAttr));
1676 cur->type = XML_ATTRIBUTE_NODE;
1677
1678 cur->parent = node;
1679 if (node != NULL) {
1680 doc = node->doc;
1681 cur->doc = doc;
1682 }
1683 cur->ns = ns;
1684 cur->name = name;
1685 if (value != NULL) {
1686 xmlChar *buffer;
1687 xmlNodePtr tmp;
1688
1689 buffer = xmlEncodeEntitiesReentrant(doc, value);
1690 cur->children = xmlStringGetNodeList(doc, buffer);
1691 cur->last = NULL;
1692 tmp = cur->children;
1693 while (tmp != NULL) {
1694 tmp->parent = (xmlNodePtr) cur;
1695 if (tmp->next == NULL)
1696 cur->last = tmp;
1697 tmp = tmp->next;
1698 }
1699 xmlFree(buffer);
1700 }
1701
1702 /*
1703 * Add it at the end to preserve parsing order ...
1704 */
1705 if (node != NULL) {
1706 if (node->properties == NULL) {
1707 node->properties = cur;
1708 } else {
1709 xmlAttrPtr prev = node->properties;
1710
1711 while (prev->next != NULL) prev = prev->next;
1712 prev->next = cur;
1713 cur->prev = prev;
1714 }
1715 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001716
Daniel Veillarda880b122003-04-21 21:36:41 +00001717 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001718 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001719 return(cur);
1720}
1721
1722/**
Owen Taylor3473f882001-02-23 17:55:21 +00001723 * xmlNewDocProp:
1724 * @doc: the document
1725 * @name: the name of the attribute
1726 * @value: the value of the attribute
1727 *
1728 * Create a new property carried by a document.
1729 * Returns a pointer to the attribute
1730 */
1731xmlAttrPtr
1732xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1733 xmlAttrPtr cur;
1734
1735 if (name == NULL) {
1736#ifdef DEBUG_TREE
1737 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001738 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001739#endif
1740 return(NULL);
1741 }
1742
1743 /*
1744 * Allocate a new property and fill the fields.
1745 */
1746 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1747 if (cur == NULL) {
1748 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001749 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001750 return(NULL);
1751 }
1752 memset(cur, 0, sizeof(xmlAttr));
1753 cur->type = XML_ATTRIBUTE_NODE;
1754
1755 cur->name = xmlStrdup(name);
1756 cur->doc = doc;
1757 if (value != NULL) {
1758 xmlNodePtr tmp;
1759
1760 cur->children = xmlStringGetNodeList(doc, value);
1761 cur->last = NULL;
1762
1763 tmp = cur->children;
1764 while (tmp != NULL) {
1765 tmp->parent = (xmlNodePtr) cur;
1766 if (tmp->next == NULL)
1767 cur->last = tmp;
1768 tmp = tmp->next;
1769 }
1770 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001771
Daniel Veillarda880b122003-04-21 21:36:41 +00001772 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001773 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001774 return(cur);
1775}
1776
1777/**
1778 * xmlFreePropList:
1779 * @cur: the first property in the list
1780 *
1781 * Free a property and all its siblings, all the children are freed too.
1782 */
1783void
1784xmlFreePropList(xmlAttrPtr cur) {
1785 xmlAttrPtr next;
1786 if (cur == NULL) {
1787#ifdef DEBUG_TREE
1788 xmlGenericError(xmlGenericErrorContext,
1789 "xmlFreePropList : property == NULL\n");
1790#endif
1791 return;
1792 }
1793 while (cur != NULL) {
1794 next = cur->next;
1795 xmlFreeProp(cur);
1796 cur = next;
1797 }
1798}
1799
1800/**
1801 * xmlFreeProp:
1802 * @cur: an attribute
1803 *
1804 * Free one attribute, all the content is freed too
1805 */
1806void
1807xmlFreeProp(xmlAttrPtr cur) {
1808 if (cur == NULL) {
1809#ifdef DEBUG_TREE
1810 xmlGenericError(xmlGenericErrorContext,
1811 "xmlFreeProp : property == NULL\n");
1812#endif
1813 return;
1814 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001815
Daniel Veillarda880b122003-04-21 21:36:41 +00001816 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001817 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1818
Owen Taylor3473f882001-02-23 17:55:21 +00001819 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001820 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1821 ((cur->parent->doc->intSubset != NULL) ||
1822 (cur->parent->doc->extSubset != NULL))) {
1823 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1824 xmlRemoveID(cur->parent->doc, cur);
1825 }
Owen Taylor3473f882001-02-23 17:55:21 +00001826 if (cur->name != NULL) xmlFree((char *) cur->name);
1827 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001828 xmlFree(cur);
1829}
1830
1831/**
1832 * xmlRemoveProp:
1833 * @cur: an attribute
1834 *
1835 * Unlink and free one attribute, all the content is freed too
1836 * Note this doesn't work for namespace definition attributes
1837 *
1838 * Returns 0 if success and -1 in case of error.
1839 */
1840int
1841xmlRemoveProp(xmlAttrPtr cur) {
1842 xmlAttrPtr tmp;
1843 if (cur == NULL) {
1844#ifdef DEBUG_TREE
1845 xmlGenericError(xmlGenericErrorContext,
1846 "xmlRemoveProp : cur == NULL\n");
1847#endif
1848 return(-1);
1849 }
1850 if (cur->parent == NULL) {
1851#ifdef DEBUG_TREE
1852 xmlGenericError(xmlGenericErrorContext,
1853 "xmlRemoveProp : cur->parent == NULL\n");
1854#endif
1855 return(-1);
1856 }
1857 tmp = cur->parent->properties;
1858 if (tmp == cur) {
1859 cur->parent->properties = cur->next;
1860 xmlFreeProp(cur);
1861 return(0);
1862 }
1863 while (tmp != NULL) {
1864 if (tmp->next == cur) {
1865 tmp->next = cur->next;
1866 if (tmp->next != NULL)
1867 tmp->next->prev = tmp;
1868 xmlFreeProp(cur);
1869 return(0);
1870 }
1871 tmp = tmp->next;
1872 }
1873#ifdef DEBUG_TREE
1874 xmlGenericError(xmlGenericErrorContext,
1875 "xmlRemoveProp : attribute not owned by its node\n");
1876#endif
1877 return(-1);
1878}
1879
1880/**
1881 * xmlNewPI:
1882 * @name: the processing instruction name
1883 * @content: the PI content
1884 *
1885 * Creation of a processing instruction element.
1886 * Returns a pointer to the new node object.
1887 */
1888xmlNodePtr
1889xmlNewPI(const xmlChar *name, const xmlChar *content) {
1890 xmlNodePtr cur;
1891
1892 if (name == NULL) {
1893#ifdef DEBUG_TREE
1894 xmlGenericError(xmlGenericErrorContext,
1895 "xmlNewPI : name == NULL\n");
1896#endif
1897 return(NULL);
1898 }
1899
1900 /*
1901 * Allocate a new node and fill the fields.
1902 */
1903 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1904 if (cur == NULL) {
1905 xmlGenericError(xmlGenericErrorContext,
1906 "xmlNewPI : malloc failed\n");
1907 return(NULL);
1908 }
1909 memset(cur, 0, sizeof(xmlNode));
1910 cur->type = XML_PI_NODE;
1911
1912 cur->name = xmlStrdup(name);
1913 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001914 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001915 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001916
Daniel Veillarda880b122003-04-21 21:36:41 +00001917 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001918 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001919 return(cur);
1920}
1921
1922/**
1923 * xmlNewNode:
1924 * @ns: namespace if any
1925 * @name: the node name
1926 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001927 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001928 *
1929 * Returns a pointer to the new node object.
1930 */
1931xmlNodePtr
1932xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1933 xmlNodePtr cur;
1934
1935 if (name == NULL) {
1936#ifdef DEBUG_TREE
1937 xmlGenericError(xmlGenericErrorContext,
1938 "xmlNewNode : name == NULL\n");
1939#endif
1940 return(NULL);
1941 }
1942
1943 /*
1944 * Allocate a new node and fill the fields.
1945 */
1946 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1947 if (cur == NULL) {
1948 xmlGenericError(xmlGenericErrorContext,
1949 "xmlNewNode : malloc failed\n");
1950 return(NULL);
1951 }
1952 memset(cur, 0, sizeof(xmlNode));
1953 cur->type = XML_ELEMENT_NODE;
1954
1955 cur->name = xmlStrdup(name);
1956 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001957
Daniel Veillarda880b122003-04-21 21:36:41 +00001958 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001959 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001960 return(cur);
1961}
1962
1963/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001964 * xmlNewNodeEatName:
1965 * @ns: namespace if any
1966 * @name: the node name
1967 *
1968 * Creation of a new node element. @ns is optional (NULL).
1969 *
1970 * Returns a pointer to the new node object.
1971 */
1972xmlNodePtr
1973xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
1974 xmlNodePtr cur;
1975
1976 if (name == NULL) {
1977#ifdef DEBUG_TREE
1978 xmlGenericError(xmlGenericErrorContext,
1979 "xmlNewNode : name == NULL\n");
1980#endif
1981 return(NULL);
1982 }
1983
1984 /*
1985 * Allocate a new node and fill the fields.
1986 */
1987 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1988 if (cur == NULL) {
1989 xmlGenericError(xmlGenericErrorContext,
1990 "xmlNewNode : malloc failed\n");
1991 return(NULL);
1992 }
1993 memset(cur, 0, sizeof(xmlNode));
1994 cur->type = XML_ELEMENT_NODE;
1995
1996 cur->name = name;
1997 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001998
Daniel Veillarda880b122003-04-21 21:36:41 +00001999 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002000 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002001 return(cur);
2002}
2003
2004/**
Owen Taylor3473f882001-02-23 17:55:21 +00002005 * xmlNewDocNode:
2006 * @doc: the document
2007 * @ns: namespace if any
2008 * @name: the node name
2009 * @content: the XML text content if any
2010 *
2011 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002012 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002013 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2014 * references, but XML special chars need to be escaped first by using
2015 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2016 * need entities support.
2017 *
2018 * Returns a pointer to the new node object.
2019 */
2020xmlNodePtr
2021xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2022 const xmlChar *name, const xmlChar *content) {
2023 xmlNodePtr cur;
2024
2025 cur = xmlNewNode(ns, name);
2026 if (cur != NULL) {
2027 cur->doc = doc;
2028 if (content != NULL) {
2029 cur->children = xmlStringGetNodeList(doc, content);
2030 UPDATE_LAST_CHILD_AND_PARENT(cur)
2031 }
2032 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002033
Owen Taylor3473f882001-02-23 17:55:21 +00002034 return(cur);
2035}
2036
Daniel Veillard46de64e2002-05-29 08:21:33 +00002037/**
2038 * xmlNewDocNodeEatName:
2039 * @doc: the document
2040 * @ns: namespace if any
2041 * @name: the node name
2042 * @content: the XML text content if any
2043 *
2044 * Creation of a new node element within a document. @ns and @content
2045 * are optional (NULL).
2046 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2047 * references, but XML special chars need to be escaped first by using
2048 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2049 * need entities support.
2050 *
2051 * Returns a pointer to the new node object.
2052 */
2053xmlNodePtr
2054xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2055 xmlChar *name, const xmlChar *content) {
2056 xmlNodePtr cur;
2057
2058 cur = xmlNewNodeEatName(ns, name);
2059 if (cur != NULL) {
2060 cur->doc = doc;
2061 if (content != NULL) {
2062 cur->children = xmlStringGetNodeList(doc, content);
2063 UPDATE_LAST_CHILD_AND_PARENT(cur)
2064 }
2065 }
2066 return(cur);
2067}
2068
Owen Taylor3473f882001-02-23 17:55:21 +00002069
2070/**
2071 * xmlNewDocRawNode:
2072 * @doc: the document
2073 * @ns: namespace if any
2074 * @name: the node name
2075 * @content: the text content if any
2076 *
2077 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002078 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002079 *
2080 * Returns a pointer to the new node object.
2081 */
2082xmlNodePtr
2083xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2084 const xmlChar *name, const xmlChar *content) {
2085 xmlNodePtr cur;
2086
2087 cur = xmlNewNode(ns, name);
2088 if (cur != NULL) {
2089 cur->doc = doc;
2090 if (content != NULL) {
2091 cur->children = xmlNewDocText(doc, content);
2092 UPDATE_LAST_CHILD_AND_PARENT(cur)
2093 }
2094 }
2095 return(cur);
2096}
2097
2098/**
2099 * xmlNewDocFragment:
2100 * @doc: the document owning the fragment
2101 *
2102 * Creation of a new Fragment node.
2103 * Returns a pointer to the new node object.
2104 */
2105xmlNodePtr
2106xmlNewDocFragment(xmlDocPtr doc) {
2107 xmlNodePtr cur;
2108
2109 /*
2110 * Allocate a new DocumentFragment node and fill the fields.
2111 */
2112 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2113 if (cur == NULL) {
2114 xmlGenericError(xmlGenericErrorContext,
2115 "xmlNewDocFragment : malloc failed\n");
2116 return(NULL);
2117 }
2118 memset(cur, 0, sizeof(xmlNode));
2119 cur->type = XML_DOCUMENT_FRAG_NODE;
2120
2121 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002122
Daniel Veillarda880b122003-04-21 21:36:41 +00002123 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002124 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002125 return(cur);
2126}
2127
2128/**
2129 * xmlNewText:
2130 * @content: the text content
2131 *
2132 * Creation of a new text node.
2133 * Returns a pointer to the new node object.
2134 */
2135xmlNodePtr
2136xmlNewText(const xmlChar *content) {
2137 xmlNodePtr cur;
2138
2139 /*
2140 * Allocate a new node and fill the fields.
2141 */
2142 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2143 if (cur == NULL) {
2144 xmlGenericError(xmlGenericErrorContext,
2145 "xmlNewText : malloc failed\n");
2146 return(NULL);
2147 }
2148 memset(cur, 0, sizeof(xmlNode));
2149 cur->type = XML_TEXT_NODE;
2150
2151 cur->name = xmlStringText;
2152 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002153 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002154 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002155
Daniel Veillarda880b122003-04-21 21:36:41 +00002156 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002157 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002158 return(cur);
2159}
2160
2161/**
2162 * xmlNewTextChild:
2163 * @parent: the parent node
2164 * @ns: a namespace if any
2165 * @name: the name of the child
2166 * @content: the text content of the child if any.
2167 *
2168 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002169 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002170 * a child TEXT node will be created containing the string content.
2171 *
2172 * Returns a pointer to the new node object.
2173 */
2174xmlNodePtr
2175xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2176 const xmlChar *name, const xmlChar *content) {
2177 xmlNodePtr cur, prev;
2178
2179 if (parent == NULL) {
2180#ifdef DEBUG_TREE
2181 xmlGenericError(xmlGenericErrorContext,
2182 "xmlNewTextChild : parent == NULL\n");
2183#endif
2184 return(NULL);
2185 }
2186
2187 if (name == NULL) {
2188#ifdef DEBUG_TREE
2189 xmlGenericError(xmlGenericErrorContext,
2190 "xmlNewTextChild : name == NULL\n");
2191#endif
2192 return(NULL);
2193 }
2194
2195 /*
2196 * Allocate a new node
2197 */
2198 if (ns == NULL)
2199 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2200 else
2201 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2202 if (cur == NULL) return(NULL);
2203
2204 /*
2205 * add the new element at the end of the children list.
2206 */
2207 cur->type = XML_ELEMENT_NODE;
2208 cur->parent = parent;
2209 cur->doc = parent->doc;
2210 if (parent->children == NULL) {
2211 parent->children = cur;
2212 parent->last = cur;
2213 } else {
2214 prev = parent->last;
2215 prev->next = cur;
2216 cur->prev = prev;
2217 parent->last = cur;
2218 }
2219
2220 return(cur);
2221}
2222
2223/**
2224 * xmlNewCharRef:
2225 * @doc: the document
2226 * @name: the char ref string, starting with # or "&# ... ;"
2227 *
2228 * Creation of a new character reference node.
2229 * Returns a pointer to the new node object.
2230 */
2231xmlNodePtr
2232xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2233 xmlNodePtr cur;
2234
2235 /*
2236 * Allocate a new node and fill the fields.
2237 */
2238 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2239 if (cur == NULL) {
2240 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002241 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002242 return(NULL);
2243 }
2244 memset(cur, 0, sizeof(xmlNode));
2245 cur->type = XML_ENTITY_REF_NODE;
2246
2247 cur->doc = doc;
2248 if (name[0] == '&') {
2249 int len;
2250 name++;
2251 len = xmlStrlen(name);
2252 if (name[len - 1] == ';')
2253 cur->name = xmlStrndup(name, len - 1);
2254 else
2255 cur->name = xmlStrndup(name, len);
2256 } else
2257 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002258
Daniel Veillarda880b122003-04-21 21:36:41 +00002259 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002260 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002261 return(cur);
2262}
2263
2264/**
2265 * xmlNewReference:
2266 * @doc: the document
2267 * @name: the reference name, or the reference string with & and ;
2268 *
2269 * Creation of a new reference node.
2270 * Returns a pointer to the new node object.
2271 */
2272xmlNodePtr
2273xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2274 xmlNodePtr cur;
2275 xmlEntityPtr ent;
2276
2277 /*
2278 * Allocate a new node and fill the fields.
2279 */
2280 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2281 if (cur == NULL) {
2282 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002283 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002284 return(NULL);
2285 }
2286 memset(cur, 0, sizeof(xmlNode));
2287 cur->type = XML_ENTITY_REF_NODE;
2288
2289 cur->doc = doc;
2290 if (name[0] == '&') {
2291 int len;
2292 name++;
2293 len = xmlStrlen(name);
2294 if (name[len - 1] == ';')
2295 cur->name = xmlStrndup(name, len - 1);
2296 else
2297 cur->name = xmlStrndup(name, len);
2298 } else
2299 cur->name = xmlStrdup(name);
2300
2301 ent = xmlGetDocEntity(doc, cur->name);
2302 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002303 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002304 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002305 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002306 * updated. Not sure if this is 100% correct.
2307 * -George
2308 */
2309 cur->children = (xmlNodePtr) ent;
2310 cur->last = (xmlNodePtr) ent;
2311 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002312
Daniel Veillarda880b122003-04-21 21:36:41 +00002313 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002314 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002315 return(cur);
2316}
2317
2318/**
2319 * xmlNewDocText:
2320 * @doc: the document
2321 * @content: the text content
2322 *
2323 * Creation of a new text node within a document.
2324 * Returns a pointer to the new node object.
2325 */
2326xmlNodePtr
2327xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2328 xmlNodePtr cur;
2329
2330 cur = xmlNewText(content);
2331 if (cur != NULL) cur->doc = doc;
2332 return(cur);
2333}
2334
2335/**
2336 * xmlNewTextLen:
2337 * @content: the text content
2338 * @len: the text len.
2339 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002340 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002341 * Returns a pointer to the new node object.
2342 */
2343xmlNodePtr
2344xmlNewTextLen(const xmlChar *content, int len) {
2345 xmlNodePtr cur;
2346
2347 /*
2348 * Allocate a new node and fill the fields.
2349 */
2350 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2351 if (cur == NULL) {
2352 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002353 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002354 return(NULL);
2355 }
2356 memset(cur, 0, sizeof(xmlNode));
2357 cur->type = XML_TEXT_NODE;
2358
2359 cur->name = xmlStringText;
2360 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002361 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002362 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002363
Daniel Veillarda880b122003-04-21 21:36:41 +00002364 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002365 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002366 return(cur);
2367}
2368
2369/**
2370 * xmlNewDocTextLen:
2371 * @doc: the document
2372 * @content: the text content
2373 * @len: the text len.
2374 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002375 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002376 * text node pertain to a given document.
2377 * Returns a pointer to the new node object.
2378 */
2379xmlNodePtr
2380xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2381 xmlNodePtr cur;
2382
2383 cur = xmlNewTextLen(content, len);
2384 if (cur != NULL) cur->doc = doc;
2385 return(cur);
2386}
2387
2388/**
2389 * xmlNewComment:
2390 * @content: the comment content
2391 *
2392 * Creation of a new node containing a comment.
2393 * Returns a pointer to the new node object.
2394 */
2395xmlNodePtr
2396xmlNewComment(const xmlChar *content) {
2397 xmlNodePtr cur;
2398
2399 /*
2400 * Allocate a new node and fill the fields.
2401 */
2402 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2403 if (cur == NULL) {
2404 xmlGenericError(xmlGenericErrorContext,
2405 "xmlNewComment : malloc failed\n");
2406 return(NULL);
2407 }
2408 memset(cur, 0, sizeof(xmlNode));
2409 cur->type = XML_COMMENT_NODE;
2410
2411 cur->name = xmlStringComment;
2412 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002413 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002414 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002415
Daniel Veillarda880b122003-04-21 21:36:41 +00002416 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002417 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002418 return(cur);
2419}
2420
2421/**
2422 * xmlNewCDataBlock:
2423 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002424 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002425 * @len: the length of the block
2426 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002427 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002428 * Returns a pointer to the new node object.
2429 */
2430xmlNodePtr
2431xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2432 xmlNodePtr cur;
2433
2434 /*
2435 * Allocate a new node and fill the fields.
2436 */
2437 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2438 if (cur == NULL) {
2439 xmlGenericError(xmlGenericErrorContext,
2440 "xmlNewCDataBlock : malloc failed\n");
2441 return(NULL);
2442 }
2443 memset(cur, 0, sizeof(xmlNode));
2444 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002445 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002446
2447 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002448 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002449 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002450
Daniel Veillarda880b122003-04-21 21:36:41 +00002451 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002452 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002453 return(cur);
2454}
2455
2456/**
2457 * xmlNewDocComment:
2458 * @doc: the document
2459 * @content: the comment content
2460 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002461 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002462 * Returns a pointer to the new node object.
2463 */
2464xmlNodePtr
2465xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2466 xmlNodePtr cur;
2467
2468 cur = xmlNewComment(content);
2469 if (cur != NULL) cur->doc = doc;
2470 return(cur);
2471}
2472
2473/**
2474 * xmlSetTreeDoc:
2475 * @tree: the top element
2476 * @doc: the document
2477 *
2478 * update all nodes under the tree to point to the right document
2479 */
2480void
2481xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002482 xmlAttrPtr prop;
2483
Owen Taylor3473f882001-02-23 17:55:21 +00002484 if (tree == NULL)
2485 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002486 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002487 if(tree->type == XML_ELEMENT_NODE) {
2488 prop = tree->properties;
2489 while (prop != NULL) {
2490 prop->doc = doc;
2491 xmlSetListDoc(prop->children, doc);
2492 prop = prop->next;
2493 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002494 }
Owen Taylor3473f882001-02-23 17:55:21 +00002495 if (tree->children != NULL)
2496 xmlSetListDoc(tree->children, doc);
2497 tree->doc = doc;
2498 }
2499}
2500
2501/**
2502 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002503 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002504 * @doc: the document
2505 *
2506 * update all nodes in the list to point to the right document
2507 */
2508void
2509xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2510 xmlNodePtr cur;
2511
2512 if (list == NULL)
2513 return;
2514 cur = list;
2515 while (cur != NULL) {
2516 if (cur->doc != doc)
2517 xmlSetTreeDoc(cur, doc);
2518 cur = cur->next;
2519 }
2520}
2521
2522
2523/**
2524 * xmlNewChild:
2525 * @parent: the parent node
2526 * @ns: a namespace if any
2527 * @name: the name of the child
2528 * @content: the XML content of the child if any.
2529 *
2530 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002531 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002532 * a child list containing the TEXTs and ENTITY_REFs node will be created.
2533 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2534 * references, but XML special chars need to be escaped first by using
2535 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
2536 * support is not needed.
2537 *
2538 * Returns a pointer to the new node object.
2539 */
2540xmlNodePtr
2541xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2542 const xmlChar *name, const xmlChar *content) {
2543 xmlNodePtr cur, prev;
2544
2545 if (parent == NULL) {
2546#ifdef DEBUG_TREE
2547 xmlGenericError(xmlGenericErrorContext,
2548 "xmlNewChild : parent == NULL\n");
2549#endif
2550 return(NULL);
2551 }
2552
2553 if (name == NULL) {
2554#ifdef DEBUG_TREE
2555 xmlGenericError(xmlGenericErrorContext,
2556 "xmlNewChild : name == NULL\n");
2557#endif
2558 return(NULL);
2559 }
2560
2561 /*
2562 * Allocate a new node
2563 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002564 if (parent->type == XML_ELEMENT_NODE) {
2565 if (ns == NULL)
2566 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2567 else
2568 cur = xmlNewDocNode(parent->doc, ns, name, content);
2569 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2570 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2571 if (ns == NULL)
2572 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2573 else
2574 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002575 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2576 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002577 } else {
2578 return(NULL);
2579 }
Owen Taylor3473f882001-02-23 17:55:21 +00002580 if (cur == NULL) return(NULL);
2581
2582 /*
2583 * add the new element at the end of the children list.
2584 */
2585 cur->type = XML_ELEMENT_NODE;
2586 cur->parent = parent;
2587 cur->doc = parent->doc;
2588 if (parent->children == NULL) {
2589 parent->children = cur;
2590 parent->last = cur;
2591 } else {
2592 prev = parent->last;
2593 prev->next = cur;
2594 cur->prev = prev;
2595 parent->last = cur;
2596 }
2597
2598 return(cur);
2599}
2600
2601/**
2602 * xmlAddNextSibling:
2603 * @cur: the child node
2604 * @elem: the new node
2605 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002606 * Add a new node @elem as the next sibling of @cur
2607 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002608 * first unlinked from its existing context.
2609 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002610 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2611 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002612 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002613 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002614 */
2615xmlNodePtr
2616xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2617 if (cur == NULL) {
2618#ifdef DEBUG_TREE
2619 xmlGenericError(xmlGenericErrorContext,
2620 "xmlAddNextSibling : cur == NULL\n");
2621#endif
2622 return(NULL);
2623 }
2624 if (elem == NULL) {
2625#ifdef DEBUG_TREE
2626 xmlGenericError(xmlGenericErrorContext,
2627 "xmlAddNextSibling : elem == NULL\n");
2628#endif
2629 return(NULL);
2630 }
2631
2632 xmlUnlinkNode(elem);
2633
2634 if (elem->type == XML_TEXT_NODE) {
2635 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002636 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002637 xmlFreeNode(elem);
2638 return(cur);
2639 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002640 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2641 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002642 xmlChar *tmp;
2643
2644 tmp = xmlStrdup(elem->content);
2645 tmp = xmlStrcat(tmp, cur->next->content);
2646 xmlNodeSetContent(cur->next, tmp);
2647 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002648 xmlFreeNode(elem);
2649 return(cur->next);
2650 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002651 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2652 /* check if an attribute with the same name exists */
2653 xmlAttrPtr attr;
2654
2655 if (elem->ns == NULL)
2656 attr = xmlHasProp(cur->parent, elem->name);
2657 else
2658 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2659 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2660 /* different instance, destroy it (attributes must be unique) */
2661 xmlFreeProp(attr);
2662 }
Owen Taylor3473f882001-02-23 17:55:21 +00002663 }
2664
2665 if (elem->doc != cur->doc) {
2666 xmlSetTreeDoc(elem, cur->doc);
2667 }
2668 elem->parent = cur->parent;
2669 elem->prev = cur;
2670 elem->next = cur->next;
2671 cur->next = elem;
2672 if (elem->next != NULL)
2673 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002674 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002675 elem->parent->last = elem;
2676 return(elem);
2677}
2678
2679/**
2680 * xmlAddPrevSibling:
2681 * @cur: the child node
2682 * @elem: the new node
2683 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002684 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002685 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002686 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002687 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002688 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2689 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002690 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002691 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002692 */
2693xmlNodePtr
2694xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2695 if (cur == NULL) {
2696#ifdef DEBUG_TREE
2697 xmlGenericError(xmlGenericErrorContext,
2698 "xmlAddPrevSibling : cur == NULL\n");
2699#endif
2700 return(NULL);
2701 }
2702 if (elem == NULL) {
2703#ifdef DEBUG_TREE
2704 xmlGenericError(xmlGenericErrorContext,
2705 "xmlAddPrevSibling : elem == NULL\n");
2706#endif
2707 return(NULL);
2708 }
2709
2710 xmlUnlinkNode(elem);
2711
2712 if (elem->type == XML_TEXT_NODE) {
2713 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002714 xmlChar *tmp;
2715
2716 tmp = xmlStrdup(elem->content);
2717 tmp = xmlStrcat(tmp, cur->content);
2718 xmlNodeSetContent(cur, tmp);
2719 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002720 xmlFreeNode(elem);
2721 return(cur);
2722 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002723 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2724 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002725 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002726 xmlFreeNode(elem);
2727 return(cur->prev);
2728 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002729 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2730 /* check if an attribute with the same name exists */
2731 xmlAttrPtr attr;
2732
2733 if (elem->ns == NULL)
2734 attr = xmlHasProp(cur->parent, elem->name);
2735 else
2736 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2737 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2738 /* different instance, destroy it (attributes must be unique) */
2739 xmlFreeProp(attr);
2740 }
Owen Taylor3473f882001-02-23 17:55:21 +00002741 }
2742
2743 if (elem->doc != cur->doc) {
2744 xmlSetTreeDoc(elem, cur->doc);
2745 }
2746 elem->parent = cur->parent;
2747 elem->next = cur;
2748 elem->prev = cur->prev;
2749 cur->prev = elem;
2750 if (elem->prev != NULL)
2751 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002752 if (elem->parent != NULL) {
2753 if (elem->type == XML_ATTRIBUTE_NODE) {
2754 if (elem->parent->properties == (xmlAttrPtr) cur) {
2755 elem->parent->properties = (xmlAttrPtr) elem;
2756 }
2757 } else {
2758 if (elem->parent->children == cur) {
2759 elem->parent->children = elem;
2760 }
2761 }
2762 }
Owen Taylor3473f882001-02-23 17:55:21 +00002763 return(elem);
2764}
2765
2766/**
2767 * xmlAddSibling:
2768 * @cur: the child node
2769 * @elem: the new node
2770 *
2771 * Add a new element @elem to the list of siblings of @cur
2772 * merging adjacent TEXT nodes (@elem may be freed)
2773 * If the new element was already inserted in a document it is
2774 * first unlinked from its existing context.
2775 *
2776 * Returns the new element or NULL in case of error.
2777 */
2778xmlNodePtr
2779xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2780 xmlNodePtr parent;
2781
2782 if (cur == NULL) {
2783#ifdef DEBUG_TREE
2784 xmlGenericError(xmlGenericErrorContext,
2785 "xmlAddSibling : cur == NULL\n");
2786#endif
2787 return(NULL);
2788 }
2789
2790 if (elem == NULL) {
2791#ifdef DEBUG_TREE
2792 xmlGenericError(xmlGenericErrorContext,
2793 "xmlAddSibling : elem == NULL\n");
2794#endif
2795 return(NULL);
2796 }
2797
2798 /*
2799 * Constant time is we can rely on the ->parent->last to find
2800 * the last sibling.
2801 */
2802 if ((cur->parent != NULL) &&
2803 (cur->parent->children != NULL) &&
2804 (cur->parent->last != NULL) &&
2805 (cur->parent->last->next == NULL)) {
2806 cur = cur->parent->last;
2807 } else {
2808 while (cur->next != NULL) cur = cur->next;
2809 }
2810
2811 xmlUnlinkNode(elem);
2812
2813 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002814 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002815 xmlFreeNode(elem);
2816 return(cur);
2817 }
2818
2819 if (elem->doc != cur->doc) {
2820 xmlSetTreeDoc(elem, cur->doc);
2821 }
2822 parent = cur->parent;
2823 elem->prev = cur;
2824 elem->next = NULL;
2825 elem->parent = parent;
2826 cur->next = elem;
2827 if (parent != NULL)
2828 parent->last = elem;
2829
2830 return(elem);
2831}
2832
2833/**
2834 * xmlAddChildList:
2835 * @parent: the parent node
2836 * @cur: the first node in the list
2837 *
2838 * Add a list of node at the end of the child list of the parent
2839 * merging adjacent TEXT nodes (@cur may be freed)
2840 *
2841 * Returns the last child or NULL in case of error.
2842 */
2843xmlNodePtr
2844xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2845 xmlNodePtr prev;
2846
2847 if (parent == NULL) {
2848#ifdef DEBUG_TREE
2849 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002850 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002851#endif
2852 return(NULL);
2853 }
2854
2855 if (cur == NULL) {
2856#ifdef DEBUG_TREE
2857 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002858 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002859#endif
2860 return(NULL);
2861 }
2862
2863 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2864 (cur->doc != parent->doc)) {
2865#ifdef DEBUG_TREE
2866 xmlGenericError(xmlGenericErrorContext,
2867 "Elements moved to a different document\n");
2868#endif
2869 }
2870
2871 /*
2872 * add the first element at the end of the children list.
2873 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00002874
Owen Taylor3473f882001-02-23 17:55:21 +00002875 if (parent->children == NULL) {
2876 parent->children = cur;
2877 } else {
2878 /*
2879 * If cur and parent->last both are TEXT nodes, then merge them.
2880 */
2881 if ((cur->type == XML_TEXT_NODE) &&
2882 (parent->last->type == XML_TEXT_NODE) &&
2883 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00002884 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002885 /*
2886 * if it's the only child, nothing more to be done.
2887 */
2888 if (cur->next == NULL) {
2889 xmlFreeNode(cur);
2890 return(parent->last);
2891 }
2892 prev = cur;
2893 cur = cur->next;
2894 xmlFreeNode(prev);
2895 }
2896 prev = parent->last;
2897 prev->next = cur;
2898 cur->prev = prev;
2899 }
2900 while (cur->next != NULL) {
2901 cur->parent = parent;
2902 if (cur->doc != parent->doc) {
2903 xmlSetTreeDoc(cur, parent->doc);
2904 }
2905 cur = cur->next;
2906 }
2907 cur->parent = parent;
2908 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2909 parent->last = cur;
2910
2911 return(cur);
2912}
2913
2914/**
2915 * xmlAddChild:
2916 * @parent: the parent node
2917 * @cur: the child node
2918 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002919 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00002920 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002921 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2922 * If there is an attribute with equal name, it is first destroyed.
2923 *
Owen Taylor3473f882001-02-23 17:55:21 +00002924 * Returns the child or NULL in case of error.
2925 */
2926xmlNodePtr
2927xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2928 xmlNodePtr prev;
2929
2930 if (parent == NULL) {
2931#ifdef DEBUG_TREE
2932 xmlGenericError(xmlGenericErrorContext,
2933 "xmlAddChild : parent == NULL\n");
2934#endif
2935 return(NULL);
2936 }
2937
2938 if (cur == NULL) {
2939#ifdef DEBUG_TREE
2940 xmlGenericError(xmlGenericErrorContext,
2941 "xmlAddChild : child == NULL\n");
2942#endif
2943 return(NULL);
2944 }
2945
Owen Taylor3473f882001-02-23 17:55:21 +00002946 /*
2947 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002948 * cur is then freed.
2949 */
2950 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002951 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002952 (parent->content != NULL) &&
2953 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002954 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002955 xmlFreeNode(cur);
2956 return(parent);
2957 }
2958 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002959 (parent->last->name == cur->name) &&
2960 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002961 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002962 xmlFreeNode(cur);
2963 return(parent->last);
2964 }
2965 }
2966
2967 /*
2968 * add the new element at the end of the children list.
2969 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00002970 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00002971 cur->parent = parent;
2972 if (cur->doc != parent->doc) {
2973 xmlSetTreeDoc(cur, parent->doc);
2974 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002975 /* this check prevents a loop on tree-traversions if a developer
2976 * tries to add a node to its parent multiple times
2977 */
2978 if (prev == parent)
2979 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002980
2981 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002982 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002983 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002984 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002985 (parent->content != NULL) &&
2986 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002987 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002988 xmlFreeNode(cur);
2989 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002990 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002991 if (cur->type == XML_ATTRIBUTE_NODE) {
2992 if (parent->properties == NULL) {
2993 parent->properties = (xmlAttrPtr) cur;
2994 } else {
2995 /* check if an attribute with the same name exists */
2996 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00002997
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002998 if (cur->ns == NULL)
2999 lastattr = xmlHasProp(parent, cur->name);
3000 else
3001 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3002 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
3003 /* different instance, destroy it (attributes must be unique) */
3004 xmlFreeProp(lastattr);
3005 }
3006 /* find the end */
3007 lastattr = parent->properties;
3008 while (lastattr->next != NULL) {
3009 lastattr = lastattr->next;
3010 }
3011 lastattr->next = (xmlAttrPtr) cur;
3012 ((xmlAttrPtr) cur)->prev = lastattr;
3013 }
3014 } else {
3015 if (parent->children == NULL) {
3016 parent->children = cur;
3017 parent->last = cur;
3018 } else {
3019 prev = parent->last;
3020 prev->next = cur;
3021 cur->prev = prev;
3022 parent->last = cur;
3023 }
3024 }
Owen Taylor3473f882001-02-23 17:55:21 +00003025 return(cur);
3026}
3027
3028/**
3029 * xmlGetLastChild:
3030 * @parent: the parent node
3031 *
3032 * Search the last child of a node.
3033 * Returns the last child or NULL if none.
3034 */
3035xmlNodePtr
3036xmlGetLastChild(xmlNodePtr parent) {
3037 if (parent == NULL) {
3038#ifdef DEBUG_TREE
3039 xmlGenericError(xmlGenericErrorContext,
3040 "xmlGetLastChild : parent == NULL\n");
3041#endif
3042 return(NULL);
3043 }
3044 return(parent->last);
3045}
3046
3047/**
3048 * xmlFreeNodeList:
3049 * @cur: the first node in the list
3050 *
3051 * Free a node and all its siblings, this is a recursive behaviour, all
3052 * the children are freed too.
3053 */
3054void
3055xmlFreeNodeList(xmlNodePtr cur) {
3056 xmlNodePtr next;
3057 if (cur == NULL) {
3058#ifdef DEBUG_TREE
3059 xmlGenericError(xmlGenericErrorContext,
3060 "xmlFreeNodeList : node == NULL\n");
3061#endif
3062 return;
3063 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00003064 if (cur->type == XML_NAMESPACE_DECL) {
3065 xmlFreeNsList((xmlNsPtr) cur);
3066 return;
3067 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003068 if ((cur->type == XML_DOCUMENT_NODE) ||
3069#ifdef LIBXML_DOCB_ENABLED
3070 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003071#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003072 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003073 xmlFreeDoc((xmlDocPtr) cur);
3074 return;
3075 }
Owen Taylor3473f882001-02-23 17:55:21 +00003076 while (cur != NULL) {
3077 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003078 /* unroll to speed up freeing the document */
3079 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003080
Daniel Veillarda880b122003-04-21 21:36:41 +00003081 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003082 xmlDeregisterNodeDefaultValue(cur);
3083
Daniel Veillard02141ea2001-04-30 11:46:40 +00003084 if ((cur->children != NULL) &&
3085 (cur->type != XML_ENTITY_REF_NODE))
3086 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003087 if (((cur->type == XML_ELEMENT_NODE) ||
3088 (cur->type == XML_XINCLUDE_START) ||
3089 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003090 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003091 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003092 if ((cur->type != XML_ELEMENT_NODE) &&
3093 (cur->type != XML_XINCLUDE_START) &&
3094 (cur->type != XML_XINCLUDE_END) &&
3095 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00003096 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003097 }
3098 if (((cur->type == XML_ELEMENT_NODE) ||
3099 (cur->type == XML_XINCLUDE_START) ||
3100 (cur->type == XML_XINCLUDE_END)) &&
3101 (cur->nsDef != NULL))
3102 xmlFreeNsList(cur->nsDef);
3103
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003104 /*
3105 * When a node is a text node or a comment, it uses a global static
3106 * variable for the name of the node.
3107 *
3108 * The xmlStrEqual comparisons need to be done when (happened with
3109 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003110 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00003111 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003112 * the string addresses compare are not sufficient.
3113 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003114 if ((cur->name != NULL) &&
3115 (cur->name != xmlStringText) &&
3116 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003117 (cur->name != xmlStringComment)) {
3118 if (cur->type == XML_TEXT_NODE) {
3119 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
3120 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
3121 xmlFree((char *) cur->name);
3122 } else if (cur->type == XML_COMMENT_NODE) {
3123 if (!xmlStrEqual(cur->name, xmlStringComment))
3124 xmlFree((char *) cur->name);
3125 } else
3126 xmlFree((char *) cur->name);
3127 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00003128 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003129 xmlFree(cur);
3130 }
Owen Taylor3473f882001-02-23 17:55:21 +00003131 cur = next;
3132 }
3133}
3134
3135/**
3136 * xmlFreeNode:
3137 * @cur: the node
3138 *
3139 * Free a node, this is a recursive behaviour, all the children are freed too.
3140 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3141 */
3142void
3143xmlFreeNode(xmlNodePtr cur) {
3144 if (cur == NULL) {
3145#ifdef DEBUG_TREE
3146 xmlGenericError(xmlGenericErrorContext,
3147 "xmlFreeNode : node == NULL\n");
3148#endif
3149 return;
3150 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003151
Daniel Veillard02141ea2001-04-30 11:46:40 +00003152 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003153 if (cur->type == XML_DTD_NODE) {
3154 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003155 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003156 }
3157 if (cur->type == XML_NAMESPACE_DECL) {
3158 xmlFreeNs((xmlNsPtr) cur);
3159 return;
3160 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003161 if (cur->type == XML_ATTRIBUTE_NODE) {
3162 xmlFreeProp((xmlAttrPtr) cur);
3163 return;
3164 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003165
Daniel Veillarda880b122003-04-21 21:36:41 +00003166 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003167 xmlDeregisterNodeDefaultValue(cur);
3168
Owen Taylor3473f882001-02-23 17:55:21 +00003169 if ((cur->children != NULL) &&
3170 (cur->type != XML_ENTITY_REF_NODE))
3171 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003172 if (((cur->type == XML_ELEMENT_NODE) ||
3173 (cur->type == XML_XINCLUDE_START) ||
3174 (cur->type == XML_XINCLUDE_END)) &&
3175 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003176 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003177 if ((cur->type != XML_ELEMENT_NODE) &&
3178 (cur->content != NULL) &&
3179 (cur->type != XML_ENTITY_REF_NODE) &&
3180 (cur->type != XML_XINCLUDE_END) &&
3181 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003182 xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003183 }
3184
Daniel Veillardacd370f2001-06-09 17:17:51 +00003185 /*
3186 * When a node is a text node or a comment, it uses a global static
3187 * variable for the name of the node.
3188 *
3189 * The xmlStrEqual comparisons need to be done when (happened with
3190 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003191 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00003192 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00003193 * are not sufficient.
3194 */
Owen Taylor3473f882001-02-23 17:55:21 +00003195 if ((cur->name != NULL) &&
3196 (cur->name != xmlStringText) &&
3197 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00003198 (cur->name != xmlStringComment)) {
3199 if (cur->type == XML_TEXT_NODE) {
3200 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
3201 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
3202 xmlFree((char *) cur->name);
3203 } else if (cur->type == XML_COMMENT_NODE) {
3204 if (!xmlStrEqual(cur->name, xmlStringComment))
3205 xmlFree((char *) cur->name);
3206 } else
3207 xmlFree((char *) cur->name);
3208 }
3209
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003210 if (((cur->type == XML_ELEMENT_NODE) ||
3211 (cur->type == XML_XINCLUDE_START) ||
3212 (cur->type == XML_XINCLUDE_END)) &&
3213 (cur->nsDef != NULL))
3214 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003215 xmlFree(cur);
3216}
3217
3218/**
3219 * xmlUnlinkNode:
3220 * @cur: the node
3221 *
3222 * Unlink a node from it's current context, the node is not freed
3223 */
3224void
3225xmlUnlinkNode(xmlNodePtr cur) {
3226 if (cur == NULL) {
3227#ifdef DEBUG_TREE
3228 xmlGenericError(xmlGenericErrorContext,
3229 "xmlUnlinkNode : node == NULL\n");
3230#endif
3231 return;
3232 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003233 if (cur->type == XML_DTD_NODE) {
3234 xmlDocPtr doc;
3235 doc = cur->doc;
3236 if (doc->intSubset == (xmlDtdPtr) cur)
3237 doc->intSubset = NULL;
3238 if (doc->extSubset == (xmlDtdPtr) cur)
3239 doc->extSubset = NULL;
3240 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003241 if (cur->parent != NULL) {
3242 xmlNodePtr parent;
3243 parent = cur->parent;
3244 if (cur->type == XML_ATTRIBUTE_NODE) {
3245 if (parent->properties == (xmlAttrPtr) cur)
3246 parent->properties = ((xmlAttrPtr) cur)->next;
3247 } else {
3248 if (parent->children == cur)
3249 parent->children = cur->next;
3250 if (parent->last == cur)
3251 parent->last = cur->prev;
3252 }
3253 cur->parent = NULL;
3254 }
Owen Taylor3473f882001-02-23 17:55:21 +00003255 if (cur->next != NULL)
3256 cur->next->prev = cur->prev;
3257 if (cur->prev != NULL)
3258 cur->prev->next = cur->next;
3259 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003260}
3261
3262/**
3263 * xmlReplaceNode:
3264 * @old: the old node
3265 * @cur: the node
3266 *
3267 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003268 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003269 * first unlinked from its existing context.
3270 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003271 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003272 */
3273xmlNodePtr
3274xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3275 if (old == NULL) {
3276#ifdef DEBUG_TREE
3277 xmlGenericError(xmlGenericErrorContext,
3278 "xmlReplaceNode : old == NULL\n");
3279#endif
3280 return(NULL);
3281 }
3282 if (cur == NULL) {
3283 xmlUnlinkNode(old);
3284 return(old);
3285 }
3286 if (cur == old) {
3287 return(old);
3288 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003289 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3290#ifdef DEBUG_TREE
3291 xmlGenericError(xmlGenericErrorContext,
3292 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3293#endif
3294 return(old);
3295 }
3296 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3297#ifdef DEBUG_TREE
3298 xmlGenericError(xmlGenericErrorContext,
3299 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3300#endif
3301 return(old);
3302 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003303 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3304#ifdef DEBUG_TREE
3305 xmlGenericError(xmlGenericErrorContext,
3306 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3307#endif
3308 return(old);
3309 }
3310 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3311#ifdef DEBUG_TREE
3312 xmlGenericError(xmlGenericErrorContext,
3313 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3314#endif
3315 return(old);
3316 }
Owen Taylor3473f882001-02-23 17:55:21 +00003317 xmlUnlinkNode(cur);
3318 cur->doc = old->doc;
3319 cur->parent = old->parent;
3320 cur->next = old->next;
3321 if (cur->next != NULL)
3322 cur->next->prev = cur;
3323 cur->prev = old->prev;
3324 if (cur->prev != NULL)
3325 cur->prev->next = cur;
3326 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003327 if (cur->type == XML_ATTRIBUTE_NODE) {
3328 if (cur->parent->properties == (xmlAttrPtr)old)
3329 cur->parent->properties = ((xmlAttrPtr) cur);
3330 } else {
3331 if (cur->parent->children == old)
3332 cur->parent->children = cur;
3333 if (cur->parent->last == old)
3334 cur->parent->last = cur;
3335 }
Owen Taylor3473f882001-02-23 17:55:21 +00003336 }
3337 old->next = old->prev = NULL;
3338 old->parent = NULL;
3339 return(old);
3340}
3341
3342/************************************************************************
3343 * *
3344 * Copy operations *
3345 * *
3346 ************************************************************************/
3347
3348/**
3349 * xmlCopyNamespace:
3350 * @cur: the namespace
3351 *
3352 * Do a copy of the namespace.
3353 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003354 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003355 */
3356xmlNsPtr
3357xmlCopyNamespace(xmlNsPtr cur) {
3358 xmlNsPtr ret;
3359
3360 if (cur == NULL) return(NULL);
3361 switch (cur->type) {
3362 case XML_LOCAL_NAMESPACE:
3363 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3364 break;
3365 default:
3366#ifdef DEBUG_TREE
3367 xmlGenericError(xmlGenericErrorContext,
3368 "xmlCopyNamespace: invalid type %d\n", cur->type);
3369#endif
3370 return(NULL);
3371 }
3372 return(ret);
3373}
3374
3375/**
3376 * xmlCopyNamespaceList:
3377 * @cur: the first namespace
3378 *
3379 * Do a copy of an namespace list.
3380 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003381 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003382 */
3383xmlNsPtr
3384xmlCopyNamespaceList(xmlNsPtr cur) {
3385 xmlNsPtr ret = NULL;
3386 xmlNsPtr p = NULL,q;
3387
3388 while (cur != NULL) {
3389 q = xmlCopyNamespace(cur);
3390 if (p == NULL) {
3391 ret = p = q;
3392 } else {
3393 p->next = q;
3394 p = q;
3395 }
3396 cur = cur->next;
3397 }
3398 return(ret);
3399}
3400
3401static xmlNodePtr
3402xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3403/**
3404 * xmlCopyProp:
3405 * @target: the element where the attribute will be grafted
3406 * @cur: the attribute
3407 *
3408 * Do a copy of the attribute.
3409 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003410 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003411 */
3412xmlAttrPtr
3413xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3414 xmlAttrPtr ret;
3415
3416 if (cur == NULL) return(NULL);
3417 if (target != NULL)
3418 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3419 else if (cur->parent != NULL)
3420 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3421 else if (cur->children != NULL)
3422 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3423 else
3424 ret = xmlNewDocProp(NULL, cur->name, NULL);
3425 if (ret == NULL) return(NULL);
3426 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003427
Owen Taylor3473f882001-02-23 17:55:21 +00003428 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003429 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003430/*
3431 * if (target->doc)
3432 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3433 * else if (cur->doc) / * target may not yet have a doc : KPI * /
3434 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
3435 * else
3436 * ns = NULL;
3437 * ret->ns = ns;
3438 */
3439 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3440 if (ns == NULL) {
3441 /*
3442 * Humm, we are copying an element whose namespace is defined
3443 * out of the new tree scope. Search it in the original tree
3444 * and add it at the top of the new tree
3445 */
3446 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3447 if (ns != NULL) {
3448 xmlNodePtr root = target;
3449 xmlNodePtr pred = NULL;
3450
3451 while (root->parent != NULL) {
3452 pred = root;
3453 root = root->parent;
3454 }
3455 if (root == (xmlNodePtr) target->doc) {
3456 /* correct possibly cycling above the document elt */
3457 root = pred;
3458 }
3459 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3460 }
3461 } else {
3462 /*
3463 * we have to find something appropriate here since
3464 * we cant be sure, that the namespce we found is identified
3465 * by the prefix
3466 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003467 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003468 /* this is the nice case */
3469 ret->ns = ns;
3470 } else {
3471 /*
3472 * we are in trouble: we need a new reconcilied namespace.
3473 * This is expensive
3474 */
3475 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3476 }
3477 }
3478
Owen Taylor3473f882001-02-23 17:55:21 +00003479 } else
3480 ret->ns = NULL;
3481
3482 if (cur->children != NULL) {
3483 xmlNodePtr tmp;
3484
3485 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3486 ret->last = NULL;
3487 tmp = ret->children;
3488 while (tmp != NULL) {
3489 /* tmp->parent = (xmlNodePtr)ret; */
3490 if (tmp->next == NULL)
3491 ret->last = tmp;
3492 tmp = tmp->next;
3493 }
3494 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003495 /*
3496 * Try to handle IDs
3497 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003498 if ((target!= NULL) && (cur!= NULL) &&
3499 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003500 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3501 if (xmlIsID(cur->doc, cur->parent, cur)) {
3502 xmlChar *id;
3503
3504 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3505 if (id != NULL) {
3506 xmlAddID(NULL, target->doc, id, ret);
3507 xmlFree(id);
3508 }
3509 }
3510 }
Owen Taylor3473f882001-02-23 17:55:21 +00003511 return(ret);
3512}
3513
3514/**
3515 * xmlCopyPropList:
3516 * @target: the element where the attributes will be grafted
3517 * @cur: the first attribute
3518 *
3519 * Do a copy of an attribute list.
3520 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003521 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003522 */
3523xmlAttrPtr
3524xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3525 xmlAttrPtr ret = NULL;
3526 xmlAttrPtr p = NULL,q;
3527
3528 while (cur != NULL) {
3529 q = xmlCopyProp(target, cur);
3530 if (p == NULL) {
3531 ret = p = q;
3532 } else {
3533 p->next = q;
3534 q->prev = p;
3535 p = q;
3536 }
3537 cur = cur->next;
3538 }
3539 return(ret);
3540}
3541
3542/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003543 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003544 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003545 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003546 * tricky reason: namespaces. Doing a direct copy of a node
3547 * say RPM:Copyright without changing the namespace pointer to
3548 * something else can produce stale links. One way to do it is
3549 * to keep a reference counter but this doesn't work as soon
3550 * as one move the element or the subtree out of the scope of
3551 * the existing namespace. The actual solution seems to add
3552 * a copy of the namespace at the top of the copied tree if
3553 * not available in the subtree.
3554 * Hence two functions, the public front-end call the inner ones
3555 */
3556
3557static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003558xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003559 int recursive) {
3560 xmlNodePtr ret;
3561
3562 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003563 switch (node->type) {
3564 case XML_TEXT_NODE:
3565 case XML_CDATA_SECTION_NODE:
3566 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003567 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003568 case XML_ENTITY_REF_NODE:
3569 case XML_ENTITY_NODE:
3570 case XML_PI_NODE:
3571 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003572 case XML_XINCLUDE_START:
3573 case XML_XINCLUDE_END:
3574 break;
3575 case XML_ATTRIBUTE_NODE:
3576 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3577 case XML_NAMESPACE_DECL:
3578 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3579
Daniel Veillard39196eb2001-06-19 18:09:42 +00003580 case XML_DOCUMENT_NODE:
3581 case XML_HTML_DOCUMENT_NODE:
3582#ifdef LIBXML_DOCB_ENABLED
3583 case XML_DOCB_DOCUMENT_NODE:
3584#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003585 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00003586 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003587 case XML_NOTATION_NODE:
3588 case XML_DTD_NODE:
3589 case XML_ELEMENT_DECL:
3590 case XML_ATTRIBUTE_DECL:
3591 case XML_ENTITY_DECL:
3592 return(NULL);
3593 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003594
Owen Taylor3473f882001-02-23 17:55:21 +00003595 /*
3596 * Allocate a new node and fill the fields.
3597 */
3598 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3599 if (ret == NULL) {
3600 xmlGenericError(xmlGenericErrorContext,
3601 "xmlStaticCopyNode : malloc failed\n");
3602 return(NULL);
3603 }
3604 memset(ret, 0, sizeof(xmlNode));
3605 ret->type = node->type;
3606
3607 ret->doc = doc;
3608 ret->parent = parent;
3609 if (node->name == xmlStringText)
3610 ret->name = xmlStringText;
3611 else if (node->name == xmlStringTextNoenc)
3612 ret->name = xmlStringTextNoenc;
3613 else if (node->name == xmlStringComment)
3614 ret->name = xmlStringComment;
3615 else if (node->name != NULL)
3616 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003617 if ((node->type != XML_ELEMENT_NODE) &&
3618 (node->content != NULL) &&
3619 (node->type != XML_ENTITY_REF_NODE) &&
3620 (node->type != XML_XINCLUDE_END) &&
3621 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003622 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003623 }else{
3624 if (node->type == XML_ELEMENT_NODE)
3625 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00003626 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003627 if (parent != NULL) {
3628 xmlNodePtr tmp;
3629
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003630 /*
3631 * this is a tricky part for the node register thing:
3632 * in case ret does get coalesced in xmlAddChild
3633 * the deregister-node callback is called; so we register ret now already
3634 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003635 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003636 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3637
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003638 tmp = xmlAddChild(parent, ret);
3639 /* node could have coalesced */
3640 if (tmp != ret)
3641 return(tmp);
3642 }
Owen Taylor3473f882001-02-23 17:55:21 +00003643
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003644 if (!recursive)
3645 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003646 if (node->nsDef != NULL)
3647 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3648
3649 if (node->ns != NULL) {
3650 xmlNsPtr ns;
3651
3652 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3653 if (ns == NULL) {
3654 /*
3655 * Humm, we are copying an element whose namespace is defined
3656 * out of the new tree scope. Search it in the original tree
3657 * and add it at the top of the new tree
3658 */
3659 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3660 if (ns != NULL) {
3661 xmlNodePtr root = ret;
3662
3663 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003664 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003665 }
3666 } else {
3667 /*
3668 * reference the existing namespace definition in our own tree.
3669 */
3670 ret->ns = ns;
3671 }
3672 }
3673 if (node->properties != NULL)
3674 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003675 if (node->type == XML_ENTITY_REF_NODE) {
3676 if ((doc == NULL) || (node->doc != doc)) {
3677 /*
3678 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003679 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003680 * we cannot keep the reference. Try to find it in the
3681 * target document.
3682 */
3683 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3684 } else {
3685 ret->children = node->children;
3686 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003687 ret->last = ret->children;
3688 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003689 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003690 UPDATE_LAST_CHILD_AND_PARENT(ret)
3691 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003692
3693out:
3694 /* if parent != NULL we already registered the node above */
3695 if (parent == NULL && xmlRegisterNodeDefaultValue)
3696 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003697 return(ret);
3698}
3699
3700static xmlNodePtr
3701xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3702 xmlNodePtr ret = NULL;
3703 xmlNodePtr p = NULL,q;
3704
3705 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003706 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003707 if (doc == NULL) {
3708 node = node->next;
3709 continue;
3710 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003711 if (doc->intSubset == NULL) {
3712 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3713 q->doc = doc;
3714 q->parent = parent;
3715 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003716 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003717 } else {
3718 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003719 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003720 }
3721 } else
3722 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003723 if (ret == NULL) {
3724 q->prev = NULL;
3725 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003726 } else if (p != q) {
3727 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003728 p->next = q;
3729 q->prev = p;
3730 p = q;
3731 }
3732 node = node->next;
3733 }
3734 return(ret);
3735}
3736
3737/**
3738 * xmlCopyNode:
3739 * @node: the node
3740 * @recursive: if 1 do a recursive copy.
3741 *
3742 * Do a copy of the node.
3743 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003744 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003745 */
3746xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003747xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003748 xmlNodePtr ret;
3749
3750 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3751 return(ret);
3752}
3753
3754/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003755 * xmlDocCopyNode:
3756 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003757 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003758 * @recursive: if 1 do a recursive copy.
3759 *
3760 * Do a copy of the node to a given document.
3761 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003762 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003763 */
3764xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003765xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003766 xmlNodePtr ret;
3767
3768 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3769 return(ret);
3770}
3771
3772/**
Owen Taylor3473f882001-02-23 17:55:21 +00003773 * xmlCopyNodeList:
3774 * @node: the first node in the list.
3775 *
3776 * Do a recursive copy of the node list.
3777 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003778 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003779 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003780xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003781 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3782 return(ret);
3783}
3784
3785/**
Owen Taylor3473f882001-02-23 17:55:21 +00003786 * xmlCopyDtd:
3787 * @dtd: the dtd
3788 *
3789 * Do a copy of the dtd.
3790 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003791 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003792 */
3793xmlDtdPtr
3794xmlCopyDtd(xmlDtdPtr dtd) {
3795 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003796 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003797
3798 if (dtd == NULL) return(NULL);
3799 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3800 if (ret == NULL) return(NULL);
3801 if (dtd->entities != NULL)
3802 ret->entities = (void *) xmlCopyEntitiesTable(
3803 (xmlEntitiesTablePtr) dtd->entities);
3804 if (dtd->notations != NULL)
3805 ret->notations = (void *) xmlCopyNotationTable(
3806 (xmlNotationTablePtr) dtd->notations);
3807 if (dtd->elements != NULL)
3808 ret->elements = (void *) xmlCopyElementTable(
3809 (xmlElementTablePtr) dtd->elements);
3810 if (dtd->attributes != NULL)
3811 ret->attributes = (void *) xmlCopyAttributeTable(
3812 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003813 if (dtd->pentities != NULL)
3814 ret->pentities = (void *) xmlCopyEntitiesTable(
3815 (xmlEntitiesTablePtr) dtd->pentities);
3816
3817 cur = dtd->children;
3818 while (cur != NULL) {
3819 q = NULL;
3820
3821 if (cur->type == XML_ENTITY_DECL) {
3822 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3823 switch (tmp->etype) {
3824 case XML_INTERNAL_GENERAL_ENTITY:
3825 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3826 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3827 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3828 break;
3829 case XML_INTERNAL_PARAMETER_ENTITY:
3830 case XML_EXTERNAL_PARAMETER_ENTITY:
3831 q = (xmlNodePtr)
3832 xmlGetParameterEntityFromDtd(ret, tmp->name);
3833 break;
3834 case XML_INTERNAL_PREDEFINED_ENTITY:
3835 break;
3836 }
3837 } else if (cur->type == XML_ELEMENT_DECL) {
3838 xmlElementPtr tmp = (xmlElementPtr) cur;
3839 q = (xmlNodePtr)
3840 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3841 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3842 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3843 q = (xmlNodePtr)
3844 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3845 } else if (cur->type == XML_COMMENT_NODE) {
3846 q = xmlCopyNode(cur, 0);
3847 }
3848
3849 if (q == NULL) {
3850 cur = cur->next;
3851 continue;
3852 }
3853
3854 if (p == NULL)
3855 ret->children = q;
3856 else
3857 p->next = q;
3858
3859 q->prev = p;
3860 q->parent = (xmlNodePtr) ret;
3861 q->next = NULL;
3862 ret->last = q;
3863 p = q;
3864 cur = cur->next;
3865 }
3866
Owen Taylor3473f882001-02-23 17:55:21 +00003867 return(ret);
3868}
3869
3870/**
3871 * xmlCopyDoc:
3872 * @doc: the document
3873 * @recursive: if 1 do a recursive copy.
3874 *
3875 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003876 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003877 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003878 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003879 */
3880xmlDocPtr
3881xmlCopyDoc(xmlDocPtr doc, int recursive) {
3882 xmlDocPtr ret;
3883
3884 if (doc == NULL) return(NULL);
3885 ret = xmlNewDoc(doc->version);
3886 if (ret == NULL) return(NULL);
3887 if (doc->name != NULL)
3888 ret->name = xmlMemStrdup(doc->name);
3889 if (doc->encoding != NULL)
3890 ret->encoding = xmlStrdup(doc->encoding);
3891 ret->charset = doc->charset;
3892 ret->compression = doc->compression;
3893 ret->standalone = doc->standalone;
3894 if (!recursive) return(ret);
3895
Daniel Veillardb33c2012001-04-25 12:59:04 +00003896 ret->last = NULL;
3897 ret->children = NULL;
3898 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003899 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003900 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003901 ret->intSubset->parent = ret;
3902 }
Owen Taylor3473f882001-02-23 17:55:21 +00003903 if (doc->oldNs != NULL)
3904 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3905 if (doc->children != NULL) {
3906 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003907
3908 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3909 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003910 ret->last = NULL;
3911 tmp = ret->children;
3912 while (tmp != NULL) {
3913 if (tmp->next == NULL)
3914 ret->last = tmp;
3915 tmp = tmp->next;
3916 }
3917 }
3918 return(ret);
3919}
3920
3921/************************************************************************
3922 * *
3923 * Content access functions *
3924 * *
3925 ************************************************************************/
3926
3927/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003928 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003929 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00003930 *
3931 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003932 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003933 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003934 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003935 */
3936long
3937xmlGetLineNo(xmlNodePtr node)
3938{
3939 long result = -1;
3940
3941 if (!node)
3942 return result;
3943 if (node->type == XML_ELEMENT_NODE)
3944 result = (long) node->content;
3945 else if ((node->prev != NULL) &&
3946 ((node->prev->type == XML_ELEMENT_NODE) ||
3947 (node->prev->type == XML_TEXT_NODE)))
3948 result = xmlGetLineNo(node->prev);
3949 else if ((node->parent != NULL) &&
3950 ((node->parent->type == XML_ELEMENT_NODE) ||
3951 (node->parent->type == XML_TEXT_NODE)))
3952 result = xmlGetLineNo(node->parent);
3953
3954 return result;
3955}
3956
3957/**
3958 * xmlGetNodePath:
3959 * @node: a node
3960 *
3961 * Build a structure based Path for the given node
3962 *
3963 * Returns the new path or NULL in case of error. The caller must free
3964 * the returned string
3965 */
3966xmlChar *
3967xmlGetNodePath(xmlNodePtr node)
3968{
3969 xmlNodePtr cur, tmp, next;
3970 xmlChar *buffer = NULL, *temp;
3971 size_t buf_len;
3972 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00003973 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00003974 const char *name;
3975 char nametemp[100];
3976 int occur = 0;
3977
3978 if (node == NULL)
3979 return (NULL);
3980
3981 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00003982 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00003983 if (buffer == NULL)
3984 return (NULL);
Daniel Veillard3c908dc2003-04-19 00:07:51 +00003985 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00003986 if (buf == NULL) {
3987 xmlFree(buffer);
3988 return (NULL);
3989 }
3990
3991 buffer[0] = 0;
3992 cur = node;
3993 do {
3994 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003995 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003996 occur = 0;
3997 if ((cur->type == XML_DOCUMENT_NODE) ||
3998 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3999 if (buffer[0] == '/')
4000 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004001 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004002 next = NULL;
4003 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004004 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004005 name = (const char *) cur->name;
4006 if (cur->ns) {
4007 snprintf(nametemp, sizeof(nametemp) - 1,
4008 "%s:%s", cur->ns->prefix, cur->name);
4009 nametemp[sizeof(nametemp) - 1] = 0;
4010 name = nametemp;
4011 }
4012 next = cur->parent;
4013
4014 /*
4015 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004016 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004017 */
4018 tmp = cur->prev;
4019 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004020 if ((tmp->type == XML_ELEMENT_NODE) &&
4021 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004022 occur++;
4023 tmp = tmp->prev;
4024 }
4025 if (occur == 0) {
4026 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004027 while (tmp != NULL && occur == 0) {
4028 if ((tmp->type == XML_ELEMENT_NODE) &&
4029 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004030 occur++;
4031 tmp = tmp->next;
4032 }
4033 if (occur != 0)
4034 occur = 1;
4035 } else
4036 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004037 } else if (cur->type == XML_COMMENT_NODE) {
4038 sep = "/";
4039 name = "comment()";
4040 next = cur->parent;
4041
4042 /*
4043 * Thumbler index computation
4044 */
4045 tmp = cur->prev;
4046 while (tmp != NULL) {
4047 if (tmp->type == XML_COMMENT_NODE)
4048 occur++;
4049 tmp = tmp->prev;
4050 }
4051 if (occur == 0) {
4052 tmp = cur->next;
4053 while (tmp != NULL && occur == 0) {
4054 if (tmp->type == XML_COMMENT_NODE)
4055 occur++;
4056 tmp = tmp->next;
4057 }
4058 if (occur != 0)
4059 occur = 1;
4060 } else
4061 occur++;
4062 } else if ((cur->type == XML_TEXT_NODE) ||
4063 (cur->type == XML_CDATA_SECTION_NODE)) {
4064 sep = "/";
4065 name = "text()";
4066 next = cur->parent;
4067
4068 /*
4069 * Thumbler index computation
4070 */
4071 tmp = cur->prev;
4072 while (tmp != NULL) {
4073 if ((cur->type == XML_TEXT_NODE) ||
4074 (cur->type == XML_CDATA_SECTION_NODE))
4075 occur++;
4076 tmp = tmp->prev;
4077 }
4078 if (occur == 0) {
4079 tmp = cur->next;
4080 while (tmp != NULL && occur == 0) {
4081 if ((cur->type == XML_TEXT_NODE) ||
4082 (cur->type == XML_CDATA_SECTION_NODE))
4083 occur++;
4084 tmp = tmp->next;
4085 }
4086 if (occur != 0)
4087 occur = 1;
4088 } else
4089 occur++;
4090 } else if (cur->type == XML_PI_NODE) {
4091 sep = "/";
4092 snprintf(nametemp, sizeof(nametemp) - 1,
4093 "processing-instruction('%s')", cur->name);
4094 nametemp[sizeof(nametemp) - 1] = 0;
4095 name = nametemp;
4096
4097 next = cur->parent;
4098
4099 /*
4100 * Thumbler index computation
4101 */
4102 tmp = cur->prev;
4103 while (tmp != NULL) {
4104 if ((tmp->type == XML_PI_NODE) &&
4105 (xmlStrEqual(cur->name, tmp->name)))
4106 occur++;
4107 tmp = tmp->prev;
4108 }
4109 if (occur == 0) {
4110 tmp = cur->next;
4111 while (tmp != NULL && occur == 0) {
4112 if ((tmp->type == XML_PI_NODE) &&
4113 (xmlStrEqual(cur->name, tmp->name)))
4114 occur++;
4115 tmp = tmp->next;
4116 }
4117 if (occur != 0)
4118 occur = 1;
4119 } else
4120 occur++;
4121
Daniel Veillard8faa7832001-11-26 15:58:08 +00004122 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004123 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004124 name = (const char *) (((xmlAttrPtr) cur)->name);
4125 next = ((xmlAttrPtr) cur)->parent;
4126 } else {
4127 next = cur->parent;
4128 }
4129
4130 /*
4131 * Make sure there is enough room
4132 */
4133 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4134 buf_len =
4135 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4136 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4137 if (temp == NULL) {
4138 xmlFree(buf);
4139 xmlFree(buffer);
4140 return (NULL);
4141 }
4142 buffer = temp;
4143 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4144 if (temp == NULL) {
4145 xmlFree(buf);
4146 xmlFree(buffer);
4147 return (NULL);
4148 }
4149 buf = temp;
4150 }
4151 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004152 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004153 sep, name, (char *) buffer);
4154 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004155 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004156 sep, name, occur, (char *) buffer);
4157 snprintf((char *) buffer, buf_len, "%s", buf);
4158 cur = next;
4159 } while (cur != NULL);
4160 xmlFree(buf);
4161 return (buffer);
4162}
4163
4164/**
Owen Taylor3473f882001-02-23 17:55:21 +00004165 * xmlDocGetRootElement:
4166 * @doc: the document
4167 *
4168 * Get the root element of the document (doc->children is a list
4169 * containing possibly comments, PIs, etc ...).
4170 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004171 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004172 */
4173xmlNodePtr
4174xmlDocGetRootElement(xmlDocPtr doc) {
4175 xmlNodePtr ret;
4176
4177 if (doc == NULL) return(NULL);
4178 ret = doc->children;
4179 while (ret != NULL) {
4180 if (ret->type == XML_ELEMENT_NODE)
4181 return(ret);
4182 ret = ret->next;
4183 }
4184 return(ret);
4185}
4186
4187/**
4188 * xmlDocSetRootElement:
4189 * @doc: the document
4190 * @root: the new document root element
4191 *
4192 * Set the root element of the document (doc->children is a list
4193 * containing possibly comments, PIs, etc ...).
4194 *
4195 * Returns the old root element if any was found
4196 */
4197xmlNodePtr
4198xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4199 xmlNodePtr old = NULL;
4200
4201 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004202 if (root == NULL)
4203 return(NULL);
4204 xmlUnlinkNode(root);
4205 root->doc = doc;
4206 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004207 old = doc->children;
4208 while (old != NULL) {
4209 if (old->type == XML_ELEMENT_NODE)
4210 break;
4211 old = old->next;
4212 }
4213 if (old == NULL) {
4214 if (doc->children == NULL) {
4215 doc->children = root;
4216 doc->last = root;
4217 } else {
4218 xmlAddSibling(doc->children, root);
4219 }
4220 } else {
4221 xmlReplaceNode(old, root);
4222 }
4223 return(old);
4224}
4225
4226/**
4227 * xmlNodeSetLang:
4228 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004229 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004230 *
4231 * Set the language of a node, i.e. the values of the xml:lang
4232 * attribute.
4233 */
4234void
4235xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004236 xmlNsPtr ns;
4237
Owen Taylor3473f882001-02-23 17:55:21 +00004238 if (cur == NULL) return;
4239 switch(cur->type) {
4240 case XML_TEXT_NODE:
4241 case XML_CDATA_SECTION_NODE:
4242 case XML_COMMENT_NODE:
4243 case XML_DOCUMENT_NODE:
4244 case XML_DOCUMENT_TYPE_NODE:
4245 case XML_DOCUMENT_FRAG_NODE:
4246 case XML_NOTATION_NODE:
4247 case XML_HTML_DOCUMENT_NODE:
4248 case XML_DTD_NODE:
4249 case XML_ELEMENT_DECL:
4250 case XML_ATTRIBUTE_DECL:
4251 case XML_ENTITY_DECL:
4252 case XML_PI_NODE:
4253 case XML_ENTITY_REF_NODE:
4254 case XML_ENTITY_NODE:
4255 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004256#ifdef LIBXML_DOCB_ENABLED
4257 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004258#endif
4259 case XML_XINCLUDE_START:
4260 case XML_XINCLUDE_END:
4261 return;
4262 case XML_ELEMENT_NODE:
4263 case XML_ATTRIBUTE_NODE:
4264 break;
4265 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004266 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4267 if (ns == NULL)
4268 return;
4269 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004270}
4271
4272/**
4273 * xmlNodeGetLang:
4274 * @cur: the node being checked
4275 *
4276 * Searches the language of a node, i.e. the values of the xml:lang
4277 * attribute or the one carried by the nearest ancestor.
4278 *
4279 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004280 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004281 */
4282xmlChar *
4283xmlNodeGetLang(xmlNodePtr cur) {
4284 xmlChar *lang;
4285
4286 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004287 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004288 if (lang != NULL)
4289 return(lang);
4290 cur = cur->parent;
4291 }
4292 return(NULL);
4293}
4294
4295
4296/**
4297 * xmlNodeSetSpacePreserve:
4298 * @cur: the node being changed
4299 * @val: the xml:space value ("0": default, 1: "preserve")
4300 *
4301 * Set (or reset) the space preserving behaviour of a node, i.e. the
4302 * value of the xml:space attribute.
4303 */
4304void
4305xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004306 xmlNsPtr ns;
4307
Owen Taylor3473f882001-02-23 17:55:21 +00004308 if (cur == NULL) return;
4309 switch(cur->type) {
4310 case XML_TEXT_NODE:
4311 case XML_CDATA_SECTION_NODE:
4312 case XML_COMMENT_NODE:
4313 case XML_DOCUMENT_NODE:
4314 case XML_DOCUMENT_TYPE_NODE:
4315 case XML_DOCUMENT_FRAG_NODE:
4316 case XML_NOTATION_NODE:
4317 case XML_HTML_DOCUMENT_NODE:
4318 case XML_DTD_NODE:
4319 case XML_ELEMENT_DECL:
4320 case XML_ATTRIBUTE_DECL:
4321 case XML_ENTITY_DECL:
4322 case XML_PI_NODE:
4323 case XML_ENTITY_REF_NODE:
4324 case XML_ENTITY_NODE:
4325 case XML_NAMESPACE_DECL:
4326 case XML_XINCLUDE_START:
4327 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004328#ifdef LIBXML_DOCB_ENABLED
4329 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004330#endif
4331 return;
4332 case XML_ELEMENT_NODE:
4333 case XML_ATTRIBUTE_NODE:
4334 break;
4335 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004336 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4337 if (ns == NULL)
4338 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004339 switch (val) {
4340 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004341 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004342 break;
4343 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004344 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004345 break;
4346 }
4347}
4348
4349/**
4350 * xmlNodeGetSpacePreserve:
4351 * @cur: the node being checked
4352 *
4353 * Searches the space preserving behaviour of a node, i.e. the values
4354 * of the xml:space attribute or the one carried by the nearest
4355 * ancestor.
4356 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004357 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004358 */
4359int
4360xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4361 xmlChar *space;
4362
4363 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004364 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004365 if (space != NULL) {
4366 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4367 xmlFree(space);
4368 return(1);
4369 }
4370 if (xmlStrEqual(space, BAD_CAST "default")) {
4371 xmlFree(space);
4372 return(0);
4373 }
4374 xmlFree(space);
4375 }
4376 cur = cur->parent;
4377 }
4378 return(-1);
4379}
4380
4381/**
4382 * xmlNodeSetName:
4383 * @cur: the node being changed
4384 * @name: the new tag name
4385 *
4386 * Set (or reset) the name of a node.
4387 */
4388void
4389xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
4390 if (cur == NULL) return;
4391 if (name == NULL) return;
4392 switch(cur->type) {
4393 case XML_TEXT_NODE:
4394 case XML_CDATA_SECTION_NODE:
4395 case XML_COMMENT_NODE:
4396 case XML_DOCUMENT_TYPE_NODE:
4397 case XML_DOCUMENT_FRAG_NODE:
4398 case XML_NOTATION_NODE:
4399 case XML_HTML_DOCUMENT_NODE:
4400 case XML_NAMESPACE_DECL:
4401 case XML_XINCLUDE_START:
4402 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004403#ifdef LIBXML_DOCB_ENABLED
4404 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004405#endif
4406 return;
4407 case XML_ELEMENT_NODE:
4408 case XML_ATTRIBUTE_NODE:
4409 case XML_PI_NODE:
4410 case XML_ENTITY_REF_NODE:
4411 case XML_ENTITY_NODE:
4412 case XML_DTD_NODE:
4413 case XML_DOCUMENT_NODE:
4414 case XML_ELEMENT_DECL:
4415 case XML_ATTRIBUTE_DECL:
4416 case XML_ENTITY_DECL:
4417 break;
4418 }
4419 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4420 cur->name = xmlStrdup(name);
4421}
4422
4423/**
4424 * xmlNodeSetBase:
4425 * @cur: the node being changed
4426 * @uri: the new base URI
4427 *
4428 * Set (or reset) the base URI of a node, i.e. the value of the
4429 * xml:base attribute.
4430 */
4431void
4432xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004433 xmlNsPtr ns;
4434
Owen Taylor3473f882001-02-23 17:55:21 +00004435 if (cur == NULL) return;
4436 switch(cur->type) {
4437 case XML_TEXT_NODE:
4438 case XML_CDATA_SECTION_NODE:
4439 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004440 case XML_DOCUMENT_TYPE_NODE:
4441 case XML_DOCUMENT_FRAG_NODE:
4442 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004443 case XML_DTD_NODE:
4444 case XML_ELEMENT_DECL:
4445 case XML_ATTRIBUTE_DECL:
4446 case XML_ENTITY_DECL:
4447 case XML_PI_NODE:
4448 case XML_ENTITY_REF_NODE:
4449 case XML_ENTITY_NODE:
4450 case XML_NAMESPACE_DECL:
4451 case XML_XINCLUDE_START:
4452 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004453 return;
4454 case XML_ELEMENT_NODE:
4455 case XML_ATTRIBUTE_NODE:
4456 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004457 case XML_DOCUMENT_NODE:
4458#ifdef LIBXML_DOCB_ENABLED
4459 case XML_DOCB_DOCUMENT_NODE:
4460#endif
4461 case XML_HTML_DOCUMENT_NODE: {
4462 xmlDocPtr doc = (xmlDocPtr) cur;
4463
4464 if (doc->URL != NULL)
4465 xmlFree((xmlChar *) doc->URL);
4466 if (uri == NULL)
4467 doc->URL = NULL;
4468 else
4469 doc->URL = xmlStrdup(uri);
4470 return;
4471 }
Owen Taylor3473f882001-02-23 17:55:21 +00004472 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004473
4474 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4475 if (ns == NULL)
4476 return;
4477 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004478}
4479
4480/**
Owen Taylor3473f882001-02-23 17:55:21 +00004481 * xmlNodeGetBase:
4482 * @doc: the document the node pertains to
4483 * @cur: the node being checked
4484 *
4485 * Searches for the BASE URL. The code should work on both XML
4486 * and HTML document even if base mechanisms are completely different.
4487 * It returns the base as defined in RFC 2396 sections
4488 * 5.1.1. Base URI within Document Content
4489 * and
4490 * 5.1.2. Base URI from the Encapsulating Entity
4491 * However it does not return the document base (5.1.3), use
4492 * xmlDocumentGetBase() for this
4493 *
4494 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004495 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004496 */
4497xmlChar *
4498xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004499 xmlChar *oldbase = NULL;
4500 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004501
4502 if ((cur == NULL) && (doc == NULL))
4503 return(NULL);
4504 if (doc == NULL) doc = cur->doc;
4505 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4506 cur = doc->children;
4507 while ((cur != NULL) && (cur->name != NULL)) {
4508 if (cur->type != XML_ELEMENT_NODE) {
4509 cur = cur->next;
4510 continue;
4511 }
4512 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4513 cur = cur->children;
4514 continue;
4515 }
4516 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4517 cur = cur->children;
4518 continue;
4519 }
4520 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4521 return(xmlGetProp(cur, BAD_CAST "href"));
4522 }
4523 cur = cur->next;
4524 }
4525 return(NULL);
4526 }
4527 while (cur != NULL) {
4528 if (cur->type == XML_ENTITY_DECL) {
4529 xmlEntityPtr ent = (xmlEntityPtr) cur;
4530 return(xmlStrdup(ent->URI));
4531 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004532 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004533 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004534 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004535 if (oldbase != NULL) {
4536 newbase = xmlBuildURI(oldbase, base);
4537 if (newbase != NULL) {
4538 xmlFree(oldbase);
4539 xmlFree(base);
4540 oldbase = newbase;
4541 } else {
4542 xmlFree(oldbase);
4543 xmlFree(base);
4544 return(NULL);
4545 }
4546 } else {
4547 oldbase = base;
4548 }
4549 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4550 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4551 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4552 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004553 }
4554 }
Owen Taylor3473f882001-02-23 17:55:21 +00004555 cur = cur->parent;
4556 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004557 if ((doc != NULL) && (doc->URL != NULL)) {
4558 if (oldbase == NULL)
4559 return(xmlStrdup(doc->URL));
4560 newbase = xmlBuildURI(oldbase, doc->URL);
4561 xmlFree(oldbase);
4562 return(newbase);
4563 }
4564 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004565}
4566
4567/**
4568 * xmlNodeGetContent:
4569 * @cur: the node being read
4570 *
4571 * Read the value of a node, this can be either the text carried
4572 * directly by this node if it's a TEXT node or the aggregate string
4573 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004574 * Entity references are substituted.
4575 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004576 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004577 */
4578xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004579xmlNodeGetContent(xmlNodePtr cur)
4580{
4581 if (cur == NULL)
4582 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004583 switch (cur->type) {
4584 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004585 case XML_ELEMENT_NODE:{
4586 xmlNodePtr tmp = cur;
4587 xmlBufferPtr buffer;
4588 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004589
Daniel Veillard814a76d2003-01-23 18:24:20 +00004590 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004591 if (buffer == NULL)
4592 return (NULL);
4593 while (tmp != NULL) {
4594 switch (tmp->type) {
4595 case XML_CDATA_SECTION_NODE:
4596 case XML_TEXT_NODE:
4597 if (tmp->content != NULL)
4598 xmlBufferCat(buffer, tmp->content);
4599 break;
4600 case XML_ENTITY_REF_NODE:{
4601 /* recursive substitution of entity references */
4602 xmlChar *cont = xmlNodeGetContent(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00004603
Daniel Veillard7646b182002-04-20 06:41:40 +00004604 if (cont) {
4605 xmlBufferCat(buffer,
4606 (const xmlChar *) cont);
4607 xmlFree(cont);
4608 }
4609 break;
4610 }
4611 default:
4612 break;
4613 }
4614 /*
4615 * Skip to next node
4616 */
4617 if (tmp->children != NULL) {
4618 if (tmp->children->type != XML_ENTITY_DECL) {
4619 tmp = tmp->children;
4620 continue;
4621 }
4622 }
4623 if (tmp == cur)
4624 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00004625
Daniel Veillard7646b182002-04-20 06:41:40 +00004626 if (tmp->next != NULL) {
4627 tmp = tmp->next;
4628 continue;
4629 }
4630
4631 do {
4632 tmp = tmp->parent;
4633 if (tmp == NULL)
4634 break;
4635 if (tmp == cur) {
4636 tmp = NULL;
4637 break;
4638 }
4639 if (tmp->next != NULL) {
4640 tmp = tmp->next;
4641 break;
4642 }
4643 } while (tmp != NULL);
4644 }
4645 ret = buffer->content;
4646 buffer->content = NULL;
4647 xmlBufferFree(buffer);
4648 return (ret);
4649 }
4650 case XML_ATTRIBUTE_NODE:{
4651 xmlAttrPtr attr = (xmlAttrPtr) cur;
4652
4653 if (attr->parent != NULL)
4654 return (xmlNodeListGetString
4655 (attr->parent->doc, attr->children, 1));
4656 else
4657 return (xmlNodeListGetString(NULL, attr->children, 1));
4658 break;
4659 }
Owen Taylor3473f882001-02-23 17:55:21 +00004660 case XML_COMMENT_NODE:
4661 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004662 if (cur->content != NULL)
4663 return (xmlStrdup(cur->content));
4664 return (NULL);
4665 case XML_ENTITY_REF_NODE:{
4666 xmlEntityPtr ent;
4667 xmlNodePtr tmp;
4668 xmlBufferPtr buffer;
4669 xmlChar *ret;
4670
4671 /* lookup entity declaration */
4672 ent = xmlGetDocEntity(cur->doc, cur->name);
4673 if (ent == NULL)
4674 return (NULL);
4675
4676 buffer = xmlBufferCreate();
4677 if (buffer == NULL)
4678 return (NULL);
4679
4680 /* an entity content can be any "well balanced chunk",
4681 * i.e. the result of the content [43] production:
4682 * http://www.w3.org/TR/REC-xml#NT-content
4683 * -> we iterate through child nodes and recursive call
4684 * xmlNodeGetContent() which handles all possible node types */
4685 tmp = ent->children;
4686 while (tmp) {
4687 xmlChar *cont = xmlNodeGetContent(tmp);
4688
4689 if (cont) {
4690 xmlBufferCat(buffer, (const xmlChar *) cont);
4691 xmlFree(cont);
4692 }
4693 tmp = tmp->next;
4694 }
4695
4696 ret = buffer->content;
4697 buffer->content = NULL;
4698 xmlBufferFree(buffer);
4699 return (ret);
4700 }
Owen Taylor3473f882001-02-23 17:55:21 +00004701 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004702 case XML_DOCUMENT_TYPE_NODE:
4703 case XML_NOTATION_NODE:
4704 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004705 case XML_XINCLUDE_START:
4706 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00004707 return (NULL);
4708 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004709#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004710 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004711#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00004712 case XML_HTML_DOCUMENT_NODE: {
4713 xmlChar *tmp;
4714 xmlChar *res = NULL;
4715
4716 cur = cur->children;
4717 while (cur!= NULL) {
4718 if ((cur->type == XML_ELEMENT_NODE) ||
4719 (cur->type == XML_TEXT_NODE) ||
4720 (cur->type == XML_CDATA_SECTION_NODE)) {
4721 tmp = xmlNodeGetContent(cur);
4722 if (tmp != NULL) {
4723 if (res == NULL)
4724 res = tmp;
4725 else {
4726 res = xmlStrcat(res, tmp);
4727 xmlFree(tmp);
4728 }
4729 }
4730 }
4731 cur = cur->next;
4732 }
4733 return(res);
4734 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004735 case XML_NAMESPACE_DECL: {
4736 xmlChar *tmp;
4737
4738 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4739 return (tmp);
4740 }
Owen Taylor3473f882001-02-23 17:55:21 +00004741 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004742 /* TODO !!! */
4743 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004744 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004745 /* TODO !!! */
4746 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004747 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004748 /* TODO !!! */
4749 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004750 case XML_CDATA_SECTION_NODE:
4751 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004752 if (cur->content != NULL)
4753 return (xmlStrdup(cur->content));
4754 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004755 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004756 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004757}
Owen Taylor3473f882001-02-23 17:55:21 +00004758/**
4759 * xmlNodeSetContent:
4760 * @cur: the node being modified
4761 * @content: the new value of the content
4762 *
4763 * Replace the content of a node.
4764 */
4765void
4766xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4767 if (cur == NULL) {
4768#ifdef DEBUG_TREE
4769 xmlGenericError(xmlGenericErrorContext,
4770 "xmlNodeSetContent : node == NULL\n");
4771#endif
4772 return;
4773 }
4774 switch (cur->type) {
4775 case XML_DOCUMENT_FRAG_NODE:
4776 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004777 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004778 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4779 cur->children = xmlStringGetNodeList(cur->doc, content);
4780 UPDATE_LAST_CHILD_AND_PARENT(cur)
4781 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004782 case XML_TEXT_NODE:
4783 case XML_CDATA_SECTION_NODE:
4784 case XML_ENTITY_REF_NODE:
4785 case XML_ENTITY_NODE:
4786 case XML_PI_NODE:
4787 case XML_COMMENT_NODE:
4788 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004789 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004790 }
4791 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4792 cur->last = cur->children = NULL;
4793 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004794 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00004795 } else
4796 cur->content = NULL;
4797 break;
4798 case XML_DOCUMENT_NODE:
4799 case XML_HTML_DOCUMENT_NODE:
4800 case XML_DOCUMENT_TYPE_NODE:
4801 case XML_XINCLUDE_START:
4802 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004803#ifdef LIBXML_DOCB_ENABLED
4804 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004805#endif
4806 break;
4807 case XML_NOTATION_NODE:
4808 break;
4809 case XML_DTD_NODE:
4810 break;
4811 case XML_NAMESPACE_DECL:
4812 break;
4813 case XML_ELEMENT_DECL:
4814 /* TODO !!! */
4815 break;
4816 case XML_ATTRIBUTE_DECL:
4817 /* TODO !!! */
4818 break;
4819 case XML_ENTITY_DECL:
4820 /* TODO !!! */
4821 break;
4822 }
4823}
4824
4825/**
4826 * xmlNodeSetContentLen:
4827 * @cur: the node being modified
4828 * @content: the new value of the content
4829 * @len: the size of @content
4830 *
4831 * Replace the content of a node.
4832 */
4833void
4834xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4835 if (cur == NULL) {
4836#ifdef DEBUG_TREE
4837 xmlGenericError(xmlGenericErrorContext,
4838 "xmlNodeSetContentLen : node == NULL\n");
4839#endif
4840 return;
4841 }
4842 switch (cur->type) {
4843 case XML_DOCUMENT_FRAG_NODE:
4844 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004845 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004846 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4847 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
4848 UPDATE_LAST_CHILD_AND_PARENT(cur)
4849 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004850 case XML_TEXT_NODE:
4851 case XML_CDATA_SECTION_NODE:
4852 case XML_ENTITY_REF_NODE:
4853 case XML_ENTITY_NODE:
4854 case XML_PI_NODE:
4855 case XML_COMMENT_NODE:
4856 case XML_NOTATION_NODE:
4857 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004858 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004859 }
4860 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4861 cur->children = cur->last = NULL;
4862 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004863 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004864 } else
4865 cur->content = NULL;
4866 break;
4867 case XML_DOCUMENT_NODE:
4868 case XML_DTD_NODE:
4869 case XML_HTML_DOCUMENT_NODE:
4870 case XML_DOCUMENT_TYPE_NODE:
4871 case XML_NAMESPACE_DECL:
4872 case XML_XINCLUDE_START:
4873 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004874#ifdef LIBXML_DOCB_ENABLED
4875 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004876#endif
4877 break;
4878 case XML_ELEMENT_DECL:
4879 /* TODO !!! */
4880 break;
4881 case XML_ATTRIBUTE_DECL:
4882 /* TODO !!! */
4883 break;
4884 case XML_ENTITY_DECL:
4885 /* TODO !!! */
4886 break;
4887 }
4888}
4889
4890/**
4891 * xmlNodeAddContentLen:
4892 * @cur: the node being modified
4893 * @content: extra content
4894 * @len: the size of @content
4895 *
4896 * Append the extra substring to the node content.
4897 */
4898void
4899xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4900 if (cur == NULL) {
4901#ifdef DEBUG_TREE
4902 xmlGenericError(xmlGenericErrorContext,
4903 "xmlNodeAddContentLen : node == NULL\n");
4904#endif
4905 return;
4906 }
4907 if (len <= 0) return;
4908 switch (cur->type) {
4909 case XML_DOCUMENT_FRAG_NODE:
4910 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004911 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004912
Daniel Veillard7db37732001-07-12 01:20:08 +00004913 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004914 newNode = xmlNewTextLen(content, len);
4915 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004916 tmp = xmlAddChild(cur, newNode);
4917 if (tmp != newNode)
4918 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004919 if ((last != NULL) && (last->next == newNode)) {
4920 xmlTextMerge(last, newNode);
4921 }
4922 }
4923 break;
4924 }
4925 case XML_ATTRIBUTE_NODE:
4926 break;
4927 case XML_TEXT_NODE:
4928 case XML_CDATA_SECTION_NODE:
4929 case XML_ENTITY_REF_NODE:
4930 case XML_ENTITY_NODE:
4931 case XML_PI_NODE:
4932 case XML_COMMENT_NODE:
4933 case XML_NOTATION_NODE:
4934 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004935 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004936 }
4937 case XML_DOCUMENT_NODE:
4938 case XML_DTD_NODE:
4939 case XML_HTML_DOCUMENT_NODE:
4940 case XML_DOCUMENT_TYPE_NODE:
4941 case XML_NAMESPACE_DECL:
4942 case XML_XINCLUDE_START:
4943 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004944#ifdef LIBXML_DOCB_ENABLED
4945 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004946#endif
4947 break;
4948 case XML_ELEMENT_DECL:
4949 case XML_ATTRIBUTE_DECL:
4950 case XML_ENTITY_DECL:
4951 break;
4952 }
4953}
4954
4955/**
4956 * xmlNodeAddContent:
4957 * @cur: the node being modified
4958 * @content: extra content
4959 *
4960 * Append the extra substring to the node content.
4961 */
4962void
4963xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
4964 int len;
4965
4966 if (cur == NULL) {
4967#ifdef DEBUG_TREE
4968 xmlGenericError(xmlGenericErrorContext,
4969 "xmlNodeAddContent : node == NULL\n");
4970#endif
4971 return;
4972 }
4973 if (content == NULL) return;
4974 len = xmlStrlen(content);
4975 xmlNodeAddContentLen(cur, content, len);
4976}
4977
4978/**
4979 * xmlTextMerge:
4980 * @first: the first text node
4981 * @second: the second text node being merged
4982 *
4983 * Merge two text nodes into one
4984 * Returns the first text node augmented
4985 */
4986xmlNodePtr
4987xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
4988 if (first == NULL) return(second);
4989 if (second == NULL) return(first);
4990 if (first->type != XML_TEXT_NODE) return(first);
4991 if (second->type != XML_TEXT_NODE) return(first);
4992 if (second->name != first->name)
4993 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00004994 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004995 xmlUnlinkNode(second);
4996 xmlFreeNode(second);
4997 return(first);
4998}
4999
5000/**
5001 * xmlGetNsList:
5002 * @doc: the document
5003 * @node: the current node
5004 *
5005 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005006 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005007 * that need to be freed by the caller or NULL if no
5008 * namespace if defined
5009 */
5010xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005011xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5012{
Owen Taylor3473f882001-02-23 17:55:21 +00005013 xmlNsPtr cur;
5014 xmlNsPtr *ret = NULL;
5015 int nbns = 0;
5016 int maxns = 10;
5017 int i;
5018
5019 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005020 if (node->type == XML_ELEMENT_NODE) {
5021 cur = node->nsDef;
5022 while (cur != NULL) {
5023 if (ret == NULL) {
5024 ret =
5025 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5026 sizeof(xmlNsPtr));
5027 if (ret == NULL) {
5028 xmlGenericError(xmlGenericErrorContext,
5029 "xmlGetNsList : out of memory!\n");
5030 return (NULL);
5031 }
5032 ret[nbns] = NULL;
5033 }
5034 for (i = 0; i < nbns; i++) {
5035 if ((cur->prefix == ret[i]->prefix) ||
5036 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5037 break;
5038 }
5039 if (i >= nbns) {
5040 if (nbns >= maxns) {
5041 maxns *= 2;
5042 ret = (xmlNsPtr *) xmlRealloc(ret,
5043 (maxns +
5044 1) *
5045 sizeof(xmlNsPtr));
5046 if (ret == NULL) {
5047 xmlGenericError(xmlGenericErrorContext,
5048 "xmlGetNsList : realloc failed!\n");
5049 return (NULL);
5050 }
5051 }
5052 ret[nbns++] = cur;
5053 ret[nbns] = NULL;
5054 }
Owen Taylor3473f882001-02-23 17:55:21 +00005055
Daniel Veillard77044732001-06-29 21:31:07 +00005056 cur = cur->next;
5057 }
5058 }
5059 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005060 }
Daniel Veillard77044732001-06-29 21:31:07 +00005061 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005062}
5063
5064/**
5065 * xmlSearchNs:
5066 * @doc: the document
5067 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005068 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005069 *
5070 * Search a Ns registered under a given name space for a document.
5071 * recurse on the parents until it finds the defined namespace
5072 * or return NULL otherwise.
5073 * @nameSpace can be NULL, this is a search for the default namespace.
5074 * We don't allow to cross entities boundaries. If you don't declare
5075 * the namespace within those you will be in troubles !!! A warning
5076 * is generated to cover this case.
5077 *
5078 * Returns the namespace pointer or NULL.
5079 */
5080xmlNsPtr
5081xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
5082 xmlNsPtr cur;
5083
5084 if (node == NULL) return(NULL);
5085 if ((nameSpace != NULL) &&
5086 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005087 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5088 /*
5089 * The XML-1.0 namespace is normally held on the root
5090 * element. In this case exceptionally create it on the
5091 * node element.
5092 */
5093 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5094 if (cur == NULL) {
5095 xmlGenericError(xmlGenericErrorContext,
5096 "xmlSearchNs : malloc failed\n");
5097 return(NULL);
5098 }
5099 memset(cur, 0, sizeof(xmlNs));
5100 cur->type = XML_LOCAL_NAMESPACE;
5101 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5102 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5103 cur->next = node->nsDef;
5104 node->nsDef = cur;
5105 return(cur);
5106 }
Owen Taylor3473f882001-02-23 17:55:21 +00005107 if (doc->oldNs == NULL) {
5108 /*
5109 * Allocate a new Namespace and fill the fields.
5110 */
5111 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5112 if (doc->oldNs == NULL) {
5113 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005114 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005115 return(NULL);
5116 }
5117 memset(doc->oldNs, 0, sizeof(xmlNs));
5118 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5119
5120 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5121 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5122 }
5123 return(doc->oldNs);
5124 }
5125 while (node != NULL) {
5126 if ((node->type == XML_ENTITY_REF_NODE) ||
5127 (node->type == XML_ENTITY_NODE) ||
5128 (node->type == XML_ENTITY_DECL))
5129 return(NULL);
5130 if (node->type == XML_ELEMENT_NODE) {
5131 cur = node->nsDef;
5132 while (cur != NULL) {
5133 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5134 (cur->href != NULL))
5135 return(cur);
5136 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5137 (cur->href != NULL) &&
5138 (xmlStrEqual(cur->prefix, nameSpace)))
5139 return(cur);
5140 cur = cur->next;
5141 }
5142 }
5143 node = node->parent;
5144 }
5145 return(NULL);
5146}
5147
5148/**
5149 * xmlSearchNsByHref:
5150 * @doc: the document
5151 * @node: the current node
5152 * @href: the namespace value
5153 *
5154 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5155 * the defined namespace or return NULL otherwise.
5156 * Returns the namespace pointer or NULL.
5157 */
5158xmlNsPtr
5159xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
5160 xmlNsPtr cur;
5161 xmlNodePtr orig = node;
5162
5163 if ((node == NULL) || (href == NULL)) return(NULL);
5164 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00005165 /*
5166 * Only the document can hold the XML spec namespace.
5167 */
Daniel Veillardc1a0da32002-08-14 08:32:18 +00005168 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5169 /*
5170 * The XML-1.0 namespace is normally held on the root
5171 * element. In this case exceptionally create it on the
5172 * node element.
5173 */
5174 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5175 if (cur == NULL) {
5176 xmlGenericError(xmlGenericErrorContext,
5177 "xmlSearchNs : malloc failed\n");
5178 return(NULL);
5179 }
5180 memset(cur, 0, sizeof(xmlNs));
5181 cur->type = XML_LOCAL_NAMESPACE;
5182 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5183 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5184 cur->next = node->nsDef;
5185 node->nsDef = cur;
5186 return(cur);
5187 }
Owen Taylor3473f882001-02-23 17:55:21 +00005188 if (doc->oldNs == NULL) {
5189 /*
5190 * Allocate a new Namespace and fill the fields.
5191 */
5192 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5193 if (doc->oldNs == NULL) {
5194 xmlGenericError(xmlGenericErrorContext,
5195 "xmlSearchNsByHref : malloc failed\n");
5196 return(NULL);
5197 }
5198 memset(doc->oldNs, 0, sizeof(xmlNs));
5199 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5200
5201 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5202 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5203 }
5204 return(doc->oldNs);
5205 }
5206 while (node != NULL) {
5207 cur = node->nsDef;
5208 while (cur != NULL) {
5209 if ((cur->href != NULL) && (href != NULL) &&
5210 (xmlStrEqual(cur->href, href))) {
5211 /*
5212 * Check that the prefix is not shadowed between orig and node
5213 */
5214 xmlNodePtr check = orig;
5215 xmlNsPtr tst;
5216
5217 while (check != node) {
5218 tst = check->nsDef;
5219 while (tst != NULL) {
5220 if ((tst->prefix == NULL) && (cur->prefix == NULL))
5221 goto shadowed;
5222 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
5223 (xmlStrEqual(tst->prefix, cur->prefix)))
5224 goto shadowed;
5225 tst = tst->next;
5226 }
5227 check = check->parent;
5228 }
5229 return(cur);
5230 }
5231shadowed:
5232 cur = cur->next;
5233 }
5234 node = node->parent;
5235 }
5236 return(NULL);
5237}
5238
5239/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005240 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005241 * @doc: the document
5242 * @tree: a node expected to hold the new namespace
5243 * @ns: the original namespace
5244 *
5245 * This function tries to locate a namespace definition in a tree
5246 * ancestors, or create a new namespace definition node similar to
5247 * @ns trying to reuse the same prefix. However if the given prefix is
5248 * null (default namespace) or reused within the subtree defined by
5249 * @tree or on one of its ancestors then a new prefix is generated.
5250 * Returns the (new) namespace definition or NULL in case of error
5251 */
5252xmlNsPtr
5253xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5254 xmlNsPtr def;
5255 xmlChar prefix[50];
5256 int counter = 1;
5257
5258 if (tree == NULL) {
5259#ifdef DEBUG_TREE
5260 xmlGenericError(xmlGenericErrorContext,
5261 "xmlNewReconciliedNs : tree == NULL\n");
5262#endif
5263 return(NULL);
5264 }
5265 if (ns == NULL) {
5266#ifdef DEBUG_TREE
5267 xmlGenericError(xmlGenericErrorContext,
5268 "xmlNewReconciliedNs : ns == NULL\n");
5269#endif
5270 return(NULL);
5271 }
5272 /*
5273 * Search an existing namespace definition inherited.
5274 */
5275 def = xmlSearchNsByHref(doc, tree, ns->href);
5276 if (def != NULL)
5277 return(def);
5278
5279 /*
5280 * Find a close prefix which is not already in use.
5281 * Let's strip namespace prefixes longer than 20 chars !
5282 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005283 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005284 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005285 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005286 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005287
Owen Taylor3473f882001-02-23 17:55:21 +00005288 def = xmlSearchNs(doc, tree, prefix);
5289 while (def != NULL) {
5290 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005291 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005292 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005293 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005294 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005295 def = xmlSearchNs(doc, tree, prefix);
5296 }
5297
5298 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005299 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005300 */
5301 def = xmlNewNs(tree, ns->href, prefix);
5302 return(def);
5303}
5304
5305/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005306 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005307 * @doc: the document
5308 * @tree: a node defining the subtree to reconciliate
5309 *
5310 * This function checks that all the namespaces declared within the given
5311 * tree are properly declared. This is needed for example after Copy or Cut
5312 * and then paste operations. The subtree may still hold pointers to
5313 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005314 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005315 * the new environment. If not possible the new namespaces are redeclared
5316 * on @tree at the top of the given subtree.
5317 * Returns the number of namespace declarations created or -1 in case of error.
5318 */
5319int
5320xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5321 xmlNsPtr *oldNs = NULL;
5322 xmlNsPtr *newNs = NULL;
5323 int sizeCache = 0;
5324 int nbCache = 0;
5325
5326 xmlNsPtr n;
5327 xmlNodePtr node = tree;
5328 xmlAttrPtr attr;
5329 int ret = 0, i;
5330
5331 while (node != NULL) {
5332 /*
5333 * Reconciliate the node namespace
5334 */
5335 if (node->ns != NULL) {
5336 /*
5337 * initialize the cache if needed
5338 */
5339 if (sizeCache == 0) {
5340 sizeCache = 10;
5341 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5342 sizeof(xmlNsPtr));
5343 if (oldNs == NULL) {
5344 xmlGenericError(xmlGenericErrorContext,
5345 "xmlReconciliateNs : memory pbm\n");
5346 return(-1);
5347 }
5348 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5349 sizeof(xmlNsPtr));
5350 if (newNs == NULL) {
5351 xmlGenericError(xmlGenericErrorContext,
5352 "xmlReconciliateNs : memory pbm\n");
5353 xmlFree(oldNs);
5354 return(-1);
5355 }
5356 }
5357 for (i = 0;i < nbCache;i++) {
5358 if (oldNs[i] == node->ns) {
5359 node->ns = newNs[i];
5360 break;
5361 }
5362 }
5363 if (i == nbCache) {
5364 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005365 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005366 */
5367 n = xmlNewReconciliedNs(doc, tree, node->ns);
5368 if (n != NULL) { /* :-( what if else ??? */
5369 /*
5370 * check if we need to grow the cache buffers.
5371 */
5372 if (sizeCache <= nbCache) {
5373 sizeCache *= 2;
5374 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5375 sizeof(xmlNsPtr));
5376 if (oldNs == NULL) {
5377 xmlGenericError(xmlGenericErrorContext,
5378 "xmlReconciliateNs : memory pbm\n");
5379 xmlFree(newNs);
5380 return(-1);
5381 }
5382 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5383 sizeof(xmlNsPtr));
5384 if (newNs == NULL) {
5385 xmlGenericError(xmlGenericErrorContext,
5386 "xmlReconciliateNs : memory pbm\n");
5387 xmlFree(oldNs);
5388 return(-1);
5389 }
5390 }
5391 newNs[nbCache] = n;
5392 oldNs[nbCache++] = node->ns;
5393 node->ns = n;
5394 }
5395 }
5396 }
5397 /*
5398 * now check for namespace hold by attributes on the node.
5399 */
5400 attr = node->properties;
5401 while (attr != NULL) {
5402 if (attr->ns != NULL) {
5403 /*
5404 * initialize the cache if needed
5405 */
5406 if (sizeCache == 0) {
5407 sizeCache = 10;
5408 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5409 sizeof(xmlNsPtr));
5410 if (oldNs == NULL) {
5411 xmlGenericError(xmlGenericErrorContext,
5412 "xmlReconciliateNs : memory pbm\n");
5413 return(-1);
5414 }
5415 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5416 sizeof(xmlNsPtr));
5417 if (newNs == NULL) {
5418 xmlGenericError(xmlGenericErrorContext,
5419 "xmlReconciliateNs : memory pbm\n");
5420 xmlFree(oldNs);
5421 return(-1);
5422 }
5423 }
5424 for (i = 0;i < nbCache;i++) {
5425 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005426 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005427 break;
5428 }
5429 }
5430 if (i == nbCache) {
5431 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005432 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005433 */
5434 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5435 if (n != NULL) { /* :-( what if else ??? */
5436 /*
5437 * check if we need to grow the cache buffers.
5438 */
5439 if (sizeCache <= nbCache) {
5440 sizeCache *= 2;
5441 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5442 sizeof(xmlNsPtr));
5443 if (oldNs == NULL) {
5444 xmlGenericError(xmlGenericErrorContext,
5445 "xmlReconciliateNs : memory pbm\n");
5446 xmlFree(newNs);
5447 return(-1);
5448 }
5449 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5450 sizeof(xmlNsPtr));
5451 if (newNs == NULL) {
5452 xmlGenericError(xmlGenericErrorContext,
5453 "xmlReconciliateNs : memory pbm\n");
5454 xmlFree(oldNs);
5455 return(-1);
5456 }
5457 }
5458 newNs[nbCache] = n;
5459 oldNs[nbCache++] = attr->ns;
5460 attr->ns = n;
5461 }
5462 }
5463 }
5464 attr = attr->next;
5465 }
5466
5467 /*
5468 * Browse the full subtree, deep first
5469 */
5470 if (node->children != NULL) {
5471 /* deep first */
5472 node = node->children;
5473 } else if ((node != tree) && (node->next != NULL)) {
5474 /* then siblings */
5475 node = node->next;
5476 } else if (node != tree) {
5477 /* go up to parents->next if needed */
5478 while (node != tree) {
5479 if (node->parent != NULL)
5480 node = node->parent;
5481 if ((node != tree) && (node->next != NULL)) {
5482 node = node->next;
5483 break;
5484 }
5485 if (node->parent == NULL) {
5486 node = NULL;
5487 break;
5488 }
5489 }
5490 /* exit condition */
5491 if (node == tree)
5492 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005493 } else
5494 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005495 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005496 if (oldNs != NULL)
5497 xmlFree(oldNs);
5498 if (newNs != NULL)
5499 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005500 return(ret);
5501}
5502
5503/**
5504 * xmlHasProp:
5505 * @node: the node
5506 * @name: the attribute name
5507 *
5508 * Search an attribute associated to a node
5509 * This function also looks in DTD attribute declaration for #FIXED or
5510 * default declaration values unless DTD use has been turned off.
5511 *
5512 * Returns the attribute or the attribute declaration or NULL if
5513 * neither was found.
5514 */
5515xmlAttrPtr
5516xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5517 xmlAttrPtr prop;
5518 xmlDocPtr doc;
5519
5520 if ((node == NULL) || (name == NULL)) return(NULL);
5521 /*
5522 * Check on the properties attached to the node
5523 */
5524 prop = node->properties;
5525 while (prop != NULL) {
5526 if (xmlStrEqual(prop->name, name)) {
5527 return(prop);
5528 }
5529 prop = prop->next;
5530 }
5531 if (!xmlCheckDTD) return(NULL);
5532
5533 /*
5534 * Check if there is a default declaration in the internal
5535 * or external subsets
5536 */
5537 doc = node->doc;
5538 if (doc != NULL) {
5539 xmlAttributePtr attrDecl;
5540 if (doc->intSubset != NULL) {
5541 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5542 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5543 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5544 if (attrDecl != NULL)
5545 return((xmlAttrPtr) attrDecl);
5546 }
5547 }
5548 return(NULL);
5549}
5550
5551/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005552 * xmlHasNsProp:
5553 * @node: the node
5554 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005555 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005556 *
5557 * Search for an attribute associated to a node
5558 * This attribute has to be anchored in the namespace specified.
5559 * This does the entity substitution.
5560 * This function looks in DTD attribute declaration for #FIXED or
5561 * default declaration values unless DTD use has been turned off.
5562 *
5563 * Returns the attribute or the attribute declaration or NULL
5564 * if neither was found.
5565 */
5566xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005567xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005568 xmlAttrPtr prop;
5569 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005570
5571 if (node == NULL)
5572 return(NULL);
5573
5574 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005575 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005576 return(xmlHasProp(node, name));
5577 while (prop != NULL) {
5578 /*
5579 * One need to have
5580 * - same attribute names
5581 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005582 */
5583 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005584 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5585 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005586 }
5587 prop = prop->next;
5588 }
5589 if (!xmlCheckDTD) return(NULL);
5590
5591 /*
5592 * Check if there is a default declaration in the internal
5593 * or external subsets
5594 */
5595 doc = node->doc;
5596 if (doc != NULL) {
5597 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005598 xmlAttributePtr attrDecl = NULL;
5599 xmlNsPtr *nsList, *cur;
5600 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005601
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005602 nsList = xmlGetNsList(node->doc, node);
5603 if (nsList == NULL)
5604 return(NULL);
5605 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5606 ename = xmlStrdup(node->ns->prefix);
5607 ename = xmlStrcat(ename, BAD_CAST ":");
5608 ename = xmlStrcat(ename, node->name);
5609 } else {
5610 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005611 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005612 if (ename == NULL) {
5613 xmlFree(nsList);
5614 return(NULL);
5615 }
5616
5617 cur = nsList;
5618 while (*cur != NULL) {
5619 if (xmlStrEqual((*cur)->href, nameSpace)) {
5620 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5621 name, (*cur)->prefix);
5622 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5623 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5624 name, (*cur)->prefix);
5625 }
5626 cur++;
5627 }
5628 xmlFree(nsList);
5629 xmlFree(ename);
5630 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005631 }
5632 }
5633 return(NULL);
5634}
5635
5636/**
Owen Taylor3473f882001-02-23 17:55:21 +00005637 * xmlGetProp:
5638 * @node: the node
5639 * @name: the attribute name
5640 *
5641 * Search and get the value of an attribute associated to a node
5642 * This does the entity substitution.
5643 * This function looks in DTD attribute declaration for #FIXED or
5644 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00005645 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00005646 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
5647 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00005648 *
5649 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005650 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005651 */
5652xmlChar *
5653xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5654 xmlAttrPtr prop;
5655 xmlDocPtr doc;
5656
5657 if ((node == NULL) || (name == NULL)) return(NULL);
5658 /*
5659 * Check on the properties attached to the node
5660 */
5661 prop = node->properties;
5662 while (prop != NULL) {
5663 if (xmlStrEqual(prop->name, name)) {
5664 xmlChar *ret;
5665
5666 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5667 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5668 return(ret);
5669 }
5670 prop = prop->next;
5671 }
5672 if (!xmlCheckDTD) return(NULL);
5673
5674 /*
5675 * Check if there is a default declaration in the internal
5676 * or external subsets
5677 */
5678 doc = node->doc;
5679 if (doc != NULL) {
5680 xmlAttributePtr attrDecl;
5681 if (doc->intSubset != NULL) {
5682 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5683 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5684 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5685 if (attrDecl != NULL)
5686 return(xmlStrdup(attrDecl->defaultValue));
5687 }
5688 }
5689 return(NULL);
5690}
5691
5692/**
Daniel Veillard71531f32003-02-05 13:19:53 +00005693 * xmlGetNoNsProp:
5694 * @node: the node
5695 * @name: the attribute name
5696 *
5697 * Search and get the value of an attribute associated to a node
5698 * This does the entity substitution.
5699 * This function looks in DTD attribute declaration for #FIXED or
5700 * default declaration values unless DTD use has been turned off.
5701 * This function is similar to xmlGetProp except it will accept only
5702 * an attribute in no namespace.
5703 *
5704 * Returns the attribute value or NULL if not found.
5705 * It's up to the caller to free the memory with xmlFree().
5706 */
5707xmlChar *
5708xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
5709 xmlAttrPtr prop;
5710 xmlDocPtr doc;
5711
5712 if ((node == NULL) || (name == NULL)) return(NULL);
5713 /*
5714 * Check on the properties attached to the node
5715 */
5716 prop = node->properties;
5717 while (prop != NULL) {
5718 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
5719 xmlChar *ret;
5720
5721 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5722 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5723 return(ret);
5724 }
5725 prop = prop->next;
5726 }
5727 if (!xmlCheckDTD) return(NULL);
5728
5729 /*
5730 * Check if there is a default declaration in the internal
5731 * or external subsets
5732 */
5733 doc = node->doc;
5734 if (doc != NULL) {
5735 xmlAttributePtr attrDecl;
5736 if (doc->intSubset != NULL) {
5737 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5738 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5739 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5740 if (attrDecl != NULL)
5741 return(xmlStrdup(attrDecl->defaultValue));
5742 }
5743 }
5744 return(NULL);
5745}
5746
5747/**
Owen Taylor3473f882001-02-23 17:55:21 +00005748 * xmlGetNsProp:
5749 * @node: the node
5750 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005751 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005752 *
5753 * Search and get the value of an attribute associated to a node
5754 * This attribute has to be anchored in the namespace specified.
5755 * This does the entity substitution.
5756 * This function looks in DTD attribute declaration for #FIXED or
5757 * default declaration values unless DTD use has been turned off.
5758 *
5759 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005760 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005761 */
5762xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00005763xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00005764 xmlAttrPtr prop;
5765 xmlDocPtr doc;
5766 xmlNsPtr ns;
5767
5768 if (node == NULL)
5769 return(NULL);
5770
5771 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005772 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00005773 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00005774 while (prop != NULL) {
5775 /*
5776 * One need to have
5777 * - same attribute names
5778 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005779 */
5780 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00005781 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00005782 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005783 xmlChar *ret;
5784
5785 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5786 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5787 return(ret);
5788 }
5789 prop = prop->next;
5790 }
5791 if (!xmlCheckDTD) return(NULL);
5792
5793 /*
5794 * Check if there is a default declaration in the internal
5795 * or external subsets
5796 */
5797 doc = node->doc;
5798 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005799 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00005800 xmlAttributePtr attrDecl;
5801
Owen Taylor3473f882001-02-23 17:55:21 +00005802 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5803 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5804 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5805
5806 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
5807 /*
5808 * The DTD declaration only allows a prefix search
5809 */
5810 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00005811 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00005812 return(xmlStrdup(attrDecl->defaultValue));
5813 }
5814 }
5815 }
5816 return(NULL);
5817}
5818
5819/**
5820 * xmlSetProp:
5821 * @node: the node
5822 * @name: the attribute name
5823 * @value: the attribute value
5824 *
5825 * Set (or reset) an attribute carried by a node.
5826 * Returns the attribute pointer.
5827 */
5828xmlAttrPtr
5829xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005830 xmlAttrPtr prop;
5831 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00005832
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00005833 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00005834 return(NULL);
5835 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005836 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00005837 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005838 if ((xmlStrEqual(prop->name, name)) &&
5839 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005840 xmlNodePtr oldprop = prop->children;
5841
Owen Taylor3473f882001-02-23 17:55:21 +00005842 prop->children = NULL;
5843 prop->last = NULL;
5844 if (value != NULL) {
5845 xmlChar *buffer;
5846 xmlNodePtr tmp;
5847
5848 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5849 prop->children = xmlStringGetNodeList(node->doc, buffer);
5850 prop->last = NULL;
5851 prop->doc = doc;
5852 tmp = prop->children;
5853 while (tmp != NULL) {
5854 tmp->parent = (xmlNodePtr) prop;
5855 tmp->doc = doc;
5856 if (tmp->next == NULL)
5857 prop->last = tmp;
5858 tmp = tmp->next;
5859 }
5860 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00005861 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005862 if (oldprop != NULL)
5863 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00005864 return(prop);
5865 }
5866 prop = prop->next;
5867 }
5868 prop = xmlNewProp(node, name, value);
5869 return(prop);
5870}
5871
5872/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005873 * xmlUnsetProp:
5874 * @node: the node
5875 * @name: the attribute name
5876 *
5877 * Remove an attribute carried by a node.
5878 * Returns 0 if successful, -1 if not found
5879 */
5880int
5881xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Daniel Veillard814a76d2003-01-23 18:24:20 +00005882 xmlAttrPtr prop, prev = NULL;;
Daniel Veillard75bea542001-05-11 17:41:21 +00005883
5884 if ((node == NULL) || (name == NULL))
5885 return(-1);
Daniel Veillard814a76d2003-01-23 18:24:20 +00005886 prop = node->properties;
Daniel Veillard75bea542001-05-11 17:41:21 +00005887 while (prop != NULL) {
5888 if ((xmlStrEqual(prop->name, name)) &&
5889 (prop->ns == NULL)) {
5890 if (prev == NULL)
5891 node->properties = prop->next;
5892 else
5893 prev->next = prop->next;
5894 xmlFreeProp(prop);
5895 return(0);
5896 }
5897 prev = prop;
5898 prop = prop->next;
5899 }
5900 return(-1);
5901}
5902
5903/**
Owen Taylor3473f882001-02-23 17:55:21 +00005904 * xmlSetNsProp:
5905 * @node: the node
5906 * @ns: the namespace definition
5907 * @name: the attribute name
5908 * @value: the attribute value
5909 *
5910 * Set (or reset) an attribute carried by a node.
5911 * The ns structure must be in scope, this is not checked.
5912 *
5913 * Returns the attribute pointer.
5914 */
5915xmlAttrPtr
5916xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
5917 const xmlChar *value) {
5918 xmlAttrPtr prop;
5919
5920 if ((node == NULL) || (name == NULL))
5921 return(NULL);
5922
5923 if (ns == NULL)
5924 return(xmlSetProp(node, name, value));
5925 if (ns->href == NULL)
5926 return(NULL);
5927 prop = node->properties;
5928
5929 while (prop != NULL) {
5930 /*
5931 * One need to have
5932 * - same attribute names
5933 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005934 */
5935 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00005936 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005937 if (prop->children != NULL)
5938 xmlFreeNodeList(prop->children);
5939 prop->children = NULL;
5940 prop->last = NULL;
5941 prop->ns = ns;
5942 if (value != NULL) {
5943 xmlChar *buffer;
5944 xmlNodePtr tmp;
5945
5946 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5947 prop->children = xmlStringGetNodeList(node->doc, buffer);
5948 prop->last = NULL;
5949 tmp = prop->children;
5950 while (tmp != NULL) {
5951 tmp->parent = (xmlNodePtr) prop;
5952 if (tmp->next == NULL)
5953 prop->last = tmp;
5954 tmp = tmp->next;
5955 }
5956 xmlFree(buffer);
5957 }
5958 return(prop);
5959 }
5960 prop = prop->next;
5961 }
5962 prop = xmlNewNsProp(node, ns, name, value);
5963 return(prop);
5964}
5965
5966/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005967 * xmlUnsetNsProp:
5968 * @node: the node
5969 * @ns: the namespace definition
5970 * @name: the attribute name
5971 *
5972 * Remove an attribute carried by a node.
5973 * Returns 0 if successful, -1 if not found
5974 */
5975int
5976xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
5977 xmlAttrPtr prop = node->properties, prev = NULL;;
5978
5979 if ((node == NULL) || (name == NULL))
5980 return(-1);
5981 if (ns == NULL)
5982 return(xmlUnsetProp(node, name));
5983 if (ns->href == NULL)
5984 return(-1);
5985 while (prop != NULL) {
5986 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00005987 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005988 if (prev == NULL)
5989 node->properties = prop->next;
5990 else
5991 prev->next = prop->next;
5992 xmlFreeProp(prop);
5993 return(0);
5994 }
5995 prev = prop;
5996 prop = prop->next;
5997 }
5998 return(-1);
5999}
6000
6001/**
Owen Taylor3473f882001-02-23 17:55:21 +00006002 * xmlNodeIsText:
6003 * @node: the node
6004 *
6005 * Is this node a Text node ?
6006 * Returns 1 yes, 0 no
6007 */
6008int
6009xmlNodeIsText(xmlNodePtr node) {
6010 if (node == NULL) return(0);
6011
6012 if (node->type == XML_TEXT_NODE) return(1);
6013 return(0);
6014}
6015
6016/**
6017 * xmlIsBlankNode:
6018 * @node: the node
6019 *
6020 * Checks whether this node is an empty or whitespace only
6021 * (and possibly ignorable) text-node.
6022 *
6023 * Returns 1 yes, 0 no
6024 */
6025int
6026xmlIsBlankNode(xmlNodePtr node) {
6027 const xmlChar *cur;
6028 if (node == NULL) return(0);
6029
Daniel Veillard7db37732001-07-12 01:20:08 +00006030 if ((node->type != XML_TEXT_NODE) &&
6031 (node->type != XML_CDATA_SECTION_NODE))
6032 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006033 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006034 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006035 while (*cur != 0) {
6036 if (!IS_BLANK(*cur)) return(0);
6037 cur++;
6038 }
6039
6040 return(1);
6041}
6042
6043/**
6044 * xmlTextConcat:
6045 * @node: the node
6046 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006047 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006048 *
6049 * Concat the given string at the end of the existing node content
6050 */
6051
6052void
6053xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
6054 if (node == NULL) return;
6055
6056 if ((node->type != XML_TEXT_NODE) &&
6057 (node->type != XML_CDATA_SECTION_NODE)) {
6058#ifdef DEBUG_TREE
6059 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006060 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006061#endif
6062 return;
6063 }
Owen Taylor3473f882001-02-23 17:55:21 +00006064 node->content = xmlStrncat(node->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00006065}
6066
6067/************************************************************************
6068 * *
6069 * Output : to a FILE or in memory *
6070 * *
6071 ************************************************************************/
6072
Owen Taylor3473f882001-02-23 17:55:21 +00006073/**
6074 * xmlBufferCreate:
6075 *
6076 * routine to create an XML buffer.
6077 * returns the new structure.
6078 */
6079xmlBufferPtr
6080xmlBufferCreate(void) {
6081 xmlBufferPtr ret;
6082
6083 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6084 if (ret == NULL) {
6085 xmlGenericError(xmlGenericErrorContext,
6086 "xmlBufferCreate : out of memory!\n");
6087 return(NULL);
6088 }
6089 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006090 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006091 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006092 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006093 if (ret->content == NULL) {
6094 xmlGenericError(xmlGenericErrorContext,
6095 "xmlBufferCreate : out of memory!\n");
6096 xmlFree(ret);
6097 return(NULL);
6098 }
6099 ret->content[0] = 0;
6100 return(ret);
6101}
6102
6103/**
6104 * xmlBufferCreateSize:
6105 * @size: initial size of buffer
6106 *
6107 * routine to create an XML buffer.
6108 * returns the new structure.
6109 */
6110xmlBufferPtr
6111xmlBufferCreateSize(size_t size) {
6112 xmlBufferPtr ret;
6113
6114 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6115 if (ret == NULL) {
6116 xmlGenericError(xmlGenericErrorContext,
6117 "xmlBufferCreate : out of memory!\n");
6118 return(NULL);
6119 }
6120 ret->use = 0;
6121 ret->alloc = xmlBufferAllocScheme;
6122 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6123 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006124 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006125 if (ret->content == NULL) {
6126 xmlGenericError(xmlGenericErrorContext,
6127 "xmlBufferCreate : out of memory!\n");
6128 xmlFree(ret);
6129 return(NULL);
6130 }
6131 ret->content[0] = 0;
6132 } else
6133 ret->content = NULL;
6134 return(ret);
6135}
6136
6137/**
6138 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006139 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006140 * @scheme: allocation scheme to use
6141 *
6142 * Sets the allocation scheme for this buffer
6143 */
6144void
6145xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6146 xmlBufferAllocationScheme scheme) {
6147 if (buf == NULL) {
6148#ifdef DEBUG_BUFFER
6149 xmlGenericError(xmlGenericErrorContext,
6150 "xmlBufferSetAllocationScheme: buf == NULL\n");
6151#endif
6152 return;
6153 }
6154
6155 buf->alloc = scheme;
6156}
6157
6158/**
6159 * xmlBufferFree:
6160 * @buf: the buffer to free
6161 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006162 * Frees an XML buffer. It frees both the content and the structure which
6163 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006164 */
6165void
6166xmlBufferFree(xmlBufferPtr buf) {
6167 if (buf == NULL) {
6168#ifdef DEBUG_BUFFER
6169 xmlGenericError(xmlGenericErrorContext,
6170 "xmlBufferFree: buf == NULL\n");
6171#endif
6172 return;
6173 }
Daniel Veillard561b7f82002-03-20 21:55:57 +00006174 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006175 xmlFree(buf->content);
6176 }
Owen Taylor3473f882001-02-23 17:55:21 +00006177 xmlFree(buf);
6178}
6179
6180/**
6181 * xmlBufferEmpty:
6182 * @buf: the buffer
6183 *
6184 * empty a buffer.
6185 */
6186void
6187xmlBufferEmpty(xmlBufferPtr buf) {
6188 if (buf->content == NULL) return;
6189 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006190 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00006191}
6192
6193/**
6194 * xmlBufferShrink:
6195 * @buf: the buffer to dump
6196 * @len: the number of xmlChar to remove
6197 *
6198 * Remove the beginning of an XML buffer.
6199 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006200 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006201 */
6202int
6203xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
6204 if (len == 0) return(0);
6205 if (len > buf->use) return(-1);
6206
6207 buf->use -= len;
6208 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6209
6210 buf->content[buf->use] = 0;
6211 return(len);
6212}
6213
6214/**
6215 * xmlBufferGrow:
6216 * @buf: the buffer
6217 * @len: the minimum free size to allocate
6218 *
6219 * Grow the available space of an XML buffer.
6220 *
6221 * Returns the new available space or -1 in case of error
6222 */
6223int
6224xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6225 int size;
6226 xmlChar *newbuf;
6227
6228 if (len + buf->use < buf->size) return(0);
6229
6230 size = buf->use + len + 100;
6231
6232 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
6233 if (newbuf == NULL) return(-1);
6234 buf->content = newbuf;
6235 buf->size = size;
6236 return(buf->size - buf->use);
6237}
6238
6239/**
6240 * xmlBufferDump:
6241 * @file: the file output
6242 * @buf: the buffer to dump
6243 *
6244 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006245 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006246 */
6247int
6248xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6249 int ret;
6250
6251 if (buf == NULL) {
6252#ifdef DEBUG_BUFFER
6253 xmlGenericError(xmlGenericErrorContext,
6254 "xmlBufferDump: buf == NULL\n");
6255#endif
6256 return(0);
6257 }
6258 if (buf->content == NULL) {
6259#ifdef DEBUG_BUFFER
6260 xmlGenericError(xmlGenericErrorContext,
6261 "xmlBufferDump: buf->content == NULL\n");
6262#endif
6263 return(0);
6264 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006265 if (file == NULL)
6266 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006267 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6268 return(ret);
6269}
6270
6271/**
6272 * xmlBufferContent:
6273 * @buf: the buffer
6274 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006275 * Function to extract the content of a buffer
6276 *
Owen Taylor3473f882001-02-23 17:55:21 +00006277 * Returns the internal content
6278 */
6279
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006280const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006281xmlBufferContent(const xmlBufferPtr buf)
6282{
6283 if(!buf)
6284 return NULL;
6285
6286 return buf->content;
6287}
6288
6289/**
6290 * xmlBufferLength:
6291 * @buf: the buffer
6292 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006293 * Function to get the length of a buffer
6294 *
Owen Taylor3473f882001-02-23 17:55:21 +00006295 * Returns the length of data in the internal content
6296 */
6297
6298int
6299xmlBufferLength(const xmlBufferPtr buf)
6300{
6301 if(!buf)
6302 return 0;
6303
6304 return buf->use;
6305}
6306
6307/**
6308 * xmlBufferResize:
6309 * @buf: the buffer to resize
6310 * @size: the desired size
6311 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006312 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006313 *
6314 * Returns 0 in case of problems, 1 otherwise
6315 */
6316int
6317xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6318{
6319 unsigned int newSize;
6320 xmlChar* rebuf = NULL;
6321
6322 /*take care of empty case*/
6323 newSize = (buf->size ? buf->size*2 : size);
6324
6325 /* Don't resize if we don't have to */
6326 if (size < buf->size)
6327 return 1;
6328
6329 /* figure out new size */
6330 switch (buf->alloc){
6331 case XML_BUFFER_ALLOC_DOUBLEIT:
6332 while (size > newSize) newSize *= 2;
6333 break;
6334 case XML_BUFFER_ALLOC_EXACT:
6335 newSize = size+10;
6336 break;
6337 default:
6338 newSize = size+10;
6339 break;
6340 }
6341
6342 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006343 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006344 else
6345 rebuf = (xmlChar *) xmlRealloc(buf->content,
6346 newSize * sizeof(xmlChar));
6347 if (rebuf == NULL) {
6348 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006349 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006350 return 0;
6351 }
6352 buf->content = rebuf;
6353 buf->size = newSize;
6354
6355 return 1;
6356}
6357
6358/**
6359 * xmlBufferAdd:
6360 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006361 * @str: the #xmlChar string
6362 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006363 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006364 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006365 * str is recomputed.
6366 */
6367void
6368xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6369 unsigned int needSize;
6370
6371 if (str == NULL) {
6372#ifdef DEBUG_BUFFER
6373 xmlGenericError(xmlGenericErrorContext,
6374 "xmlBufferAdd: str == NULL\n");
6375#endif
6376 return;
6377 }
6378 if (len < -1) {
6379#ifdef DEBUG_BUFFER
6380 xmlGenericError(xmlGenericErrorContext,
6381 "xmlBufferAdd: len < 0\n");
6382#endif
6383 return;
6384 }
6385 if (len == 0) return;
6386
6387 if (len < 0)
6388 len = xmlStrlen(str);
6389
6390 if (len <= 0) return;
6391
6392 needSize = buf->use + len + 2;
6393 if (needSize > buf->size){
6394 if (!xmlBufferResize(buf, needSize)){
6395 xmlGenericError(xmlGenericErrorContext,
6396 "xmlBufferAdd : out of memory!\n");
6397 return;
6398 }
6399 }
6400
6401 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6402 buf->use += len;
6403 buf->content[buf->use] = 0;
6404}
6405
6406/**
6407 * xmlBufferAddHead:
6408 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006409 * @str: the #xmlChar string
6410 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006411 *
6412 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006413 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00006414 */
6415void
6416xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6417 unsigned int needSize;
6418
6419 if (str == NULL) {
6420#ifdef DEBUG_BUFFER
6421 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006422 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006423#endif
6424 return;
6425 }
6426 if (len < -1) {
6427#ifdef DEBUG_BUFFER
6428 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006429 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006430#endif
6431 return;
6432 }
6433 if (len == 0) return;
6434
6435 if (len < 0)
6436 len = xmlStrlen(str);
6437
6438 if (len <= 0) return;
6439
6440 needSize = buf->use + len + 2;
6441 if (needSize > buf->size){
6442 if (!xmlBufferResize(buf, needSize)){
6443 xmlGenericError(xmlGenericErrorContext,
6444 "xmlBufferAddHead : out of memory!\n");
6445 return;
6446 }
6447 }
6448
6449 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6450 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6451 buf->use += len;
6452 buf->content[buf->use] = 0;
6453}
6454
6455/**
6456 * xmlBufferCat:
6457 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006458 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006459 *
6460 * Append a zero terminated string to an XML buffer.
6461 */
6462void
6463xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
6464 if (str != NULL)
6465 xmlBufferAdd(buf, str, -1);
6466}
6467
6468/**
6469 * xmlBufferCCat:
6470 * @buf: the buffer to dump
6471 * @str: the C char string
6472 *
6473 * Append a zero terminated C string to an XML buffer.
6474 */
6475void
6476xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6477 const char *cur;
6478
6479 if (str == NULL) {
6480#ifdef DEBUG_BUFFER
6481 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006482 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006483#endif
6484 return;
6485 }
6486 for (cur = str;*cur != 0;cur++) {
6487 if (buf->use + 10 >= buf->size) {
6488 if (!xmlBufferResize(buf, buf->use+10)){
6489 xmlGenericError(xmlGenericErrorContext,
6490 "xmlBufferCCat : out of memory!\n");
6491 return;
6492 }
6493 }
6494 buf->content[buf->use++] = *cur;
6495 }
6496 buf->content[buf->use] = 0;
6497}
6498
6499/**
6500 * xmlBufferWriteCHAR:
6501 * @buf: the XML buffer
6502 * @string: the string to add
6503 *
6504 * routine which manages and grows an output buffer. This one adds
6505 * xmlChars at the end of the buffer.
6506 */
6507void
Owen Taylor3473f882001-02-23 17:55:21 +00006508xmlBufferWriteCHAR
Owen Taylor3473f882001-02-23 17:55:21 +00006509(xmlBufferPtr buf, const xmlChar *string) {
6510 xmlBufferCat(buf, string);
6511}
6512
6513/**
6514 * xmlBufferWriteChar:
6515 * @buf: the XML buffer output
6516 * @string: the string to add
6517 *
6518 * routine which manage and grows an output buffer. This one add
6519 * C chars at the end of the array.
6520 */
6521void
6522xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
6523 xmlBufferCCat(buf, string);
6524}
6525
6526
6527/**
6528 * xmlBufferWriteQuotedString:
6529 * @buf: the XML buffer output
6530 * @string: the string to add
6531 *
6532 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00006533 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00006534 * quote or double-quotes internally
6535 */
6536void
6537xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
6538 if (xmlStrchr(string, '"')) {
6539 if (xmlStrchr(string, '\'')) {
6540#ifdef DEBUG_BUFFER
6541 xmlGenericError(xmlGenericErrorContext,
6542 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
6543#endif
6544 }
6545 xmlBufferCCat(buf, "'");
6546 xmlBufferCat(buf, string);
6547 xmlBufferCCat(buf, "'");
6548 } else {
6549 xmlBufferCCat(buf, "\"");
6550 xmlBufferCat(buf, string);
6551 xmlBufferCCat(buf, "\"");
6552 }
6553}
6554
6555
6556/************************************************************************
6557 * *
6558 * Dumping XML tree content to a simple buffer *
6559 * *
6560 ************************************************************************/
6561
Owen Taylor3473f882001-02-23 17:55:21 +00006562/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00006563 * xmlAttrSerializeContent:
6564 * @buf: the XML buffer output
6565 * @doc: the document
6566 * @attr: the attribute pointer
6567 *
6568 * Serialize the attribute in the buffer
6569 */
6570static void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006571xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr)
6572{
Daniel Veillarda6d05382002-02-13 13:07:41 +00006573 const xmlChar *cur, *base;
6574 xmlNodePtr children;
6575
6576 children = attr->children;
6577 while (children != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006578 switch (children->type) {
6579 case XML_TEXT_NODE:
6580 base = cur = children->content;
6581 while (*cur != 0) {
6582 if (*cur == '\n') {
6583 if (base != cur)
6584 xmlBufferAdd(buf, base, cur - base);
6585 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
6586 cur++;
6587 base = cur;
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006588 } else if (*cur == '\r') {
6589 if (base != cur)
6590 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006591 xmlBufferAdd(buf, BAD_CAST "&#13;", 5);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006592 cur++;
6593 base = cur;
6594 } else if (*cur == '\t') {
6595 if (base != cur)
6596 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006597 xmlBufferAdd(buf, BAD_CAST "&#9;", 4);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006598 cur++;
6599 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006600#if 0
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006601 } else if (*cur == '\'') {
6602 if (base != cur)
6603 xmlBufferAdd(buf, base, cur - base);
6604 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
6605 cur++;
6606 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006607#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006608 } else if (*cur == '"') {
6609 if (base != cur)
6610 xmlBufferAdd(buf, base, cur - base);
6611 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6612 cur++;
6613 base = cur;
6614 } else if (*cur == '<') {
6615 if (base != cur)
6616 xmlBufferAdd(buf, base, cur - base);
6617 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
6618 cur++;
6619 base = cur;
6620 } else if (*cur == '>') {
6621 if (base != cur)
6622 xmlBufferAdd(buf, base, cur - base);
6623 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
6624 cur++;
6625 base = cur;
6626 } else if (*cur == '&') {
6627 if (base != cur)
6628 xmlBufferAdd(buf, base, cur - base);
6629 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
6630 cur++;
6631 base = cur;
6632 } else if ((*cur >= 0x80) && ((doc == NULL) ||
6633 (doc->encoding ==
6634 NULL))) {
6635 /*
6636 * We assume we have UTF-8 content.
6637 */
6638 char tmp[10];
6639 int val = 0, l = 1;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006640
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006641 if (base != cur)
6642 xmlBufferAdd(buf, base, cur - base);
6643 if (*cur < 0xC0) {
6644 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6d05382002-02-13 13:07:41 +00006645 "xmlAttrSerializeContent : input not UTF-8\n");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006646 if (doc != NULL)
6647 doc->encoding =
6648 xmlStrdup(BAD_CAST "ISO-8859-1");
6649 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6650 tmp[sizeof(tmp) - 1] = 0;
6651 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6652 cur++;
6653 base = cur;
6654 continue;
6655 } else if (*cur < 0xE0) {
6656 val = (cur[0]) & 0x1F;
6657 val <<= 6;
6658 val |= (cur[1]) & 0x3F;
6659 l = 2;
6660 } else if (*cur < 0xF0) {
6661 val = (cur[0]) & 0x0F;
6662 val <<= 6;
6663 val |= (cur[1]) & 0x3F;
6664 val <<= 6;
6665 val |= (cur[2]) & 0x3F;
6666 l = 3;
6667 } else if (*cur < 0xF8) {
6668 val = (cur[0]) & 0x07;
6669 val <<= 6;
6670 val |= (cur[1]) & 0x3F;
6671 val <<= 6;
6672 val |= (cur[2]) & 0x3F;
6673 val <<= 6;
6674 val |= (cur[3]) & 0x3F;
6675 l = 4;
6676 }
6677 if ((l == 1) || (!IS_CHAR(val))) {
6678 xmlGenericError(xmlGenericErrorContext,
6679 "xmlAttrSerializeContent : char out of range\n");
6680 if (doc != NULL)
6681 doc->encoding =
6682 xmlStrdup(BAD_CAST "ISO-8859-1");
6683 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6684 tmp[sizeof(tmp) - 1] = 0;
6685 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6686 cur++;
6687 base = cur;
6688 continue;
6689 }
6690 /*
6691 * We could do multiple things here. Just save
6692 * as a char ref
6693 */
6694 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
6695 tmp[sizeof(tmp) - 1] = 0;
6696 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6697 cur += l;
6698 base = cur;
6699 } else {
6700 cur++;
6701 }
6702 }
6703 if (base != cur)
6704 xmlBufferAdd(buf, base, cur - base);
6705 break;
6706 case XML_ENTITY_REF_NODE:
6707 xmlBufferAdd(buf, BAD_CAST "&", 1);
6708 xmlBufferAdd(buf, children->name,
6709 xmlStrlen(children->name));
6710 xmlBufferAdd(buf, BAD_CAST ";", 1);
6711 break;
6712 default:
6713 /* should not happen unless we have a badly built tree */
6714 break;
6715 }
6716 children = children->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006717 }
6718}
6719
6720/**
6721 * xmlNodeDump:
6722 * @buf: the XML buffer output
6723 * @doc: the document
6724 * @cur: the current node
6725 * @level: the imbrication level for indenting
6726 * @format: is formatting allowed
6727 *
6728 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00006729 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006730 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006731 *
6732 * Returns the number of bytes written to the buffer or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00006733 */
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006734int
Owen Taylor3473f882001-02-23 17:55:21 +00006735xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006736 int format)
6737{
6738 unsigned int use;
6739 int ret;
6740 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006741
6742 if (cur == NULL) {
6743#ifdef DEBUG_TREE
6744 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006745 "xmlNodeDump : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006746#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006747 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006748 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006749 if (buf == NULL) {
6750#ifdef DEBUG_TREE
6751 xmlGenericError(xmlGenericErrorContext,
6752 "xmlNodeDump : buf == NULL\n");
6753#endif
6754 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006755 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006756 outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
6757 if (outbuf == NULL) {
6758 xmlGenericError(xmlGenericErrorContext,
6759 "xmlNodeDump: out of memory!\n");
6760 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006761 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006762 memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
6763 outbuf->buffer = buf;
6764 outbuf->encoder = NULL;
6765 outbuf->writecallback = NULL;
6766 outbuf->closecallback = NULL;
6767 outbuf->context = NULL;
6768 outbuf->written = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006769
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006770 use = buf->use;
6771 xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
6772 xmlFree(outbuf);
6773 ret = buf->use - use;
6774 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006775}
6776
6777/**
6778 * xmlElemDump:
6779 * @f: the FILE * for the output
6780 * @doc: the document
6781 * @cur: the current node
6782 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006783 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006784 */
6785void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006786xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur)
6787{
6788 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006789
6790 if (cur == NULL) {
6791#ifdef DEBUG_TREE
6792 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006793 "xmlElemDump : cur == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006794#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006795 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006796 }
Owen Taylor3473f882001-02-23 17:55:21 +00006797#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006798 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006799 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006800 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006801 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006802#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006803
6804 outbuf = xmlOutputBufferCreateFile(f, NULL);
6805 if (outbuf == NULL)
6806 return;
6807 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006808#ifdef LIBXML_HTML_ENABLED
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006809 htmlNodeDumpOutput(outbuf, doc, cur, NULL);
6810#else
6811 xmlGenericError(xmlGenericErrorContext,
6812 "HTML support not compiled in\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006813#endif /* LIBXML_HTML_ENABLED */
6814 } else
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006815 xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL);
6816 xmlOutputBufferClose(outbuf);
Owen Taylor3473f882001-02-23 17:55:21 +00006817}
6818
6819/************************************************************************
6820 * *
6821 * Dumping XML tree content to an I/O output buffer *
6822 * *
6823 ************************************************************************/
6824
Owen Taylor3473f882001-02-23 17:55:21 +00006825static void
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006826xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6827 int level, int format, const char *encoding);
6828static void
Owen Taylor3473f882001-02-23 17:55:21 +00006829xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6830 int level, int format, const char *encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006831static void
6832xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
6833 xmlNodePtr cur, int level, int format, const char *encoding);
6834
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00006835void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
6836
Owen Taylor3473f882001-02-23 17:55:21 +00006837/**
6838 * xmlNsDumpOutput:
6839 * @buf: the XML buffer output
6840 * @cur: a namespace
6841 *
6842 * Dump a local Namespace definition.
6843 * Should be called in the context of attributes dumps.
6844 */
6845static void
6846xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6847 if (cur == NULL) {
6848#ifdef DEBUG_TREE
6849 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006850 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006851#endif
6852 return;
6853 }
6854 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00006855 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
6856 return;
6857
Owen Taylor3473f882001-02-23 17:55:21 +00006858 /* Within the context of an element attributes */
6859 if (cur->prefix != NULL) {
6860 xmlOutputBufferWriteString(buf, " xmlns:");
6861 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6862 } else
6863 xmlOutputBufferWriteString(buf, " xmlns");
6864 xmlOutputBufferWriteString(buf, "=");
6865 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6866 }
6867}
6868
6869/**
6870 * xmlNsListDumpOutput:
6871 * @buf: the XML buffer output
6872 * @cur: the first namespace
6873 *
6874 * Dump a list of local Namespace definitions.
6875 * Should be called in the context of attributes dumps.
6876 */
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00006877void
Owen Taylor3473f882001-02-23 17:55:21 +00006878xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6879 while (cur != NULL) {
6880 xmlNsDumpOutput(buf, cur);
6881 cur = cur->next;
6882 }
6883}
6884
6885/**
6886 * xmlDtdDumpOutput:
6887 * @buf: the XML buffer output
6888 * @doc: the document
6889 * @encoding: an optional encoding string
6890 *
6891 * Dump the XML document DTD, if any.
6892 */
6893static void
6894xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6895 if (dtd == NULL) {
6896#ifdef DEBUG_TREE
6897 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006898 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006899#endif
6900 return;
6901 }
6902 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6903 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6904 if (dtd->ExternalID != NULL) {
6905 xmlOutputBufferWriteString(buf, " PUBLIC ");
6906 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6907 xmlOutputBufferWriteString(buf, " ");
6908 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6909 } else if (dtd->SystemID != NULL) {
6910 xmlOutputBufferWriteString(buf, " SYSTEM ");
6911 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6912 }
6913 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6914 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6915 xmlOutputBufferWriteString(buf, ">");
6916 return;
6917 }
6918 xmlOutputBufferWriteString(buf, " [\n");
6919 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6920 xmlOutputBufferWriteString(buf, "]>");
6921}
6922
6923/**
6924 * xmlAttrDumpOutput:
6925 * @buf: the XML buffer output
6926 * @doc: the document
6927 * @cur: the attribute pointer
6928 * @encoding: an optional encoding string
6929 *
6930 * Dump an XML attribute
6931 */
6932static void
6933xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006934 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006935 if (cur == NULL) {
6936#ifdef DEBUG_TREE
6937 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006938 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006939#endif
6940 return;
6941 }
6942 xmlOutputBufferWriteString(buf, " ");
6943 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6944 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6945 xmlOutputBufferWriteString(buf, ":");
6946 }
6947 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006948 xmlOutputBufferWriteString(buf, "=\"");
6949 xmlAttrSerializeContent(buf->buffer, doc, cur);
6950 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006951}
6952
6953/**
6954 * xmlAttrListDumpOutput:
6955 * @buf: the XML buffer output
6956 * @doc: the document
6957 * @cur: the first attribute pointer
6958 * @encoding: an optional encoding string
6959 *
6960 * Dump a list of XML attributes
6961 */
6962static void
6963xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6964 xmlAttrPtr cur, const char *encoding) {
6965 if (cur == NULL) {
6966#ifdef DEBUG_TREE
6967 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006968 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006969#endif
6970 return;
6971 }
6972 while (cur != NULL) {
6973 xmlAttrDumpOutput(buf, doc, cur, encoding);
6974 cur = cur->next;
6975 }
6976}
6977
6978
6979
6980/**
6981 * xmlNodeListDumpOutput:
6982 * @buf: the XML buffer output
6983 * @doc: the document
6984 * @cur: the first node
6985 * @level: the imbrication level for indenting
6986 * @format: is formatting allowed
6987 * @encoding: an optional encoding string
6988 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006989 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00006990 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006991 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006992 */
6993static void
6994xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6995 xmlNodePtr cur, int level, int format, const char *encoding) {
6996 int i;
6997
6998 if (cur == NULL) {
6999#ifdef DEBUG_TREE
7000 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007001 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007002#endif
7003 return;
7004 }
7005 while (cur != NULL) {
7006 if ((format) && (xmlIndentTreeOutput) &&
7007 (cur->type == XML_ELEMENT_NODE))
7008 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007009 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007010 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007011 if (format) {
7012 xmlOutputBufferWriteString(buf, "\n");
7013 }
7014 cur = cur->next;
7015 }
7016}
7017
7018/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007019 * xmlNodeDumpOutputInternal:
Owen Taylor3473f882001-02-23 17:55:21 +00007020 * @buf: the XML buffer output
7021 * @doc: the document
7022 * @cur: the current node
7023 * @level: the imbrication level for indenting
7024 * @format: is formatting allowed
7025 * @encoding: an optional encoding string
7026 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007027 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007028 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007029 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007030 */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007031static void
7032xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
7033 xmlNodePtr cur, int level, int format, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007034 int i;
7035 xmlNodePtr tmp;
7036
7037 if (cur == NULL) {
7038#ifdef DEBUG_TREE
7039 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007040 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007041#endif
7042 return;
7043 }
7044 if (cur->type == XML_XINCLUDE_START)
7045 return;
7046 if (cur->type == XML_XINCLUDE_END)
7047 return;
7048 if (cur->type == XML_DTD_NODE) {
7049 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7050 return;
7051 }
7052 if (cur->type == XML_ELEMENT_DECL) {
7053 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7054 return;
7055 }
7056 if (cur->type == XML_ATTRIBUTE_DECL) {
7057 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7058 return;
7059 }
7060 if (cur->type == XML_ENTITY_DECL) {
7061 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7062 return;
7063 }
7064 if (cur->type == XML_TEXT_NODE) {
7065 if (cur->content != NULL) {
7066 if ((cur->name == xmlStringText) ||
7067 (cur->name != xmlStringTextNoenc)) {
7068 xmlChar *buffer;
7069
Owen Taylor3473f882001-02-23 17:55:21 +00007070 if (encoding == NULL)
7071 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7072 else
7073 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007074 if (buffer != NULL) {
7075 xmlOutputBufferWriteString(buf, (const char *)buffer);
7076 xmlFree(buffer);
7077 }
7078 } else {
7079 /*
7080 * Disable escaping, needed for XSLT
7081 */
Owen Taylor3473f882001-02-23 17:55:21 +00007082 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007083 }
7084 }
7085
7086 return;
7087 }
7088 if (cur->type == XML_PI_NODE) {
7089 if (cur->content != NULL) {
7090 xmlOutputBufferWriteString(buf, "<?");
7091 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7092 if (cur->content != NULL) {
7093 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00007094 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007095 }
7096 xmlOutputBufferWriteString(buf, "?>");
7097 } else {
7098 xmlOutputBufferWriteString(buf, "<?");
7099 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7100 xmlOutputBufferWriteString(buf, "?>");
7101 }
7102 return;
7103 }
7104 if (cur->type == XML_COMMENT_NODE) {
7105 if (cur->content != NULL) {
7106 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00007107 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007108 xmlOutputBufferWriteString(buf, "-->");
7109 }
7110 return;
7111 }
7112 if (cur->type == XML_ENTITY_REF_NODE) {
7113 xmlOutputBufferWriteString(buf, "&");
7114 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7115 xmlOutputBufferWriteString(buf, ";");
7116 return;
7117 }
7118 if (cur->type == XML_CDATA_SECTION_NODE) {
7119 xmlOutputBufferWriteString(buf, "<![CDATA[");
7120 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007121 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007122 xmlOutputBufferWriteString(buf, "]]>");
7123 return;
7124 }
Daniel Veillard7b72ee52003-02-27 23:24:53 +00007125 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillarda1a9d042003-03-18 16:53:17 +00007126 xmlAttrDumpOutput(buf,doc, (xmlAttrPtr) cur,encoding);
Daniel Veillard7b72ee52003-02-27 23:24:53 +00007127 return;
7128 }
Daniel Veillard6aa2f602003-02-10 00:01:56 +00007129 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007130 xmlNsDumpOutput(buf, (xmlNsPtr) cur);
Daniel Veillard6aa2f602003-02-10 00:01:56 +00007131 return;
7132 }
Owen Taylor3473f882001-02-23 17:55:21 +00007133
7134 if (format == 1) {
7135 tmp = cur->children;
7136 while (tmp != NULL) {
7137 if ((tmp->type == XML_TEXT_NODE) ||
7138 (tmp->type == XML_ENTITY_REF_NODE)) {
7139 format = 0;
7140 break;
7141 }
7142 tmp = tmp->next;
7143 }
7144 }
7145 xmlOutputBufferWriteString(buf, "<");
7146 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7147 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7148 xmlOutputBufferWriteString(buf, ":");
7149 }
7150
7151 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7152 if (cur->nsDef)
7153 xmlNsListDumpOutput(buf, cur->nsDef);
7154 if (cur->properties != NULL)
7155 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7156
Daniel Veillard7db37732001-07-12 01:20:08 +00007157 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
7158 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007159 xmlOutputBufferWriteString(buf, "/>");
7160 return;
7161 }
7162 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00007163 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007164 xmlChar *buffer;
7165
Owen Taylor3473f882001-02-23 17:55:21 +00007166 if (encoding == NULL)
7167 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7168 else
7169 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007170 if (buffer != NULL) {
7171 xmlOutputBufferWriteString(buf, (const char *)buffer);
7172 xmlFree(buffer);
7173 }
7174 }
7175 if (cur->children != NULL) {
7176 if (format) xmlOutputBufferWriteString(buf, "\n");
7177 xmlNodeListDumpOutput(buf, doc, cur->children,
7178 (level >= 0?level+1:-1), format, encoding);
7179 if ((xmlIndentTreeOutput) && (format))
7180 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007181 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00007182 }
7183 xmlOutputBufferWriteString(buf, "</");
7184 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7185 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7186 xmlOutputBufferWriteString(buf, ":");
7187 }
7188
7189 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7190 xmlOutputBufferWriteString(buf, ">");
7191}
7192
7193/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007194 * xmlNodeDumpOutput:
7195 * @buf: the XML buffer output
7196 * @doc: the document
7197 * @cur: the current node
7198 * @level: the imbrication level for indenting
7199 * @format: is formatting allowed
7200 * @encoding: an optional encoding string
7201 *
7202 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007203 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007204 * or xmlKeepBlanksDefault(0) was called
7205 */
7206void
7207xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007208 int level, int format, const char *encoding)
7209{
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007210#ifdef LIBXML_HTML_ENABLED
7211 xmlDtdPtr dtd;
7212 int is_xhtml = 0;
7213
7214 dtd = xmlGetIntSubset(doc);
7215 if (dtd != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007216 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7217 if (is_xhtml < 0)
7218 is_xhtml = 0;
7219 if ((is_xhtml) && (cur->parent == (xmlNodePtr) doc) &&
7220 (cur->type == XML_ELEMENT_NODE) &&
7221 (xmlStrEqual(cur->name, BAD_CAST "html"))) {
7222 if (encoding != NULL)
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007223 htmlSetMetaEncoding((htmlDocPtr) doc,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007224 (const xmlChar *) encoding);
7225 else
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007226 htmlSetMetaEncoding((htmlDocPtr) doc, BAD_CAST "UTF-8");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007227 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007228 }
7229
7230 if (is_xhtml)
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007231 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007232 else
7233#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007234 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007235}
7236
7237/**
Owen Taylor3473f882001-02-23 17:55:21 +00007238 * xmlDocContentDumpOutput:
7239 * @buf: the XML buffer output
7240 * @cur: the document
7241 * @encoding: an optional encoding string
7242 * @format: should formatting spaces been added
7243 *
7244 * Dump an XML document.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007245 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007246 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007247 */
7248static void
7249xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
7250 const char *encoding, int format) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007251#ifdef LIBXML_HTML_ENABLED
7252 xmlDtdPtr dtd;
7253 int is_xhtml = 0;
7254#endif
7255
Owen Taylor3473f882001-02-23 17:55:21 +00007256 xmlOutputBufferWriteString(buf, "<?xml version=");
7257 if (cur->version != NULL)
7258 xmlBufferWriteQuotedString(buf->buffer, cur->version);
7259 else
7260 xmlOutputBufferWriteString(buf, "\"1.0\"");
7261 if (encoding == NULL) {
7262 if (cur->encoding != NULL)
7263 encoding = (const char *) cur->encoding;
7264 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
7265 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
7266 }
7267 if (encoding != NULL) {
7268 xmlOutputBufferWriteString(buf, " encoding=");
7269 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
7270 }
7271 switch (cur->standalone) {
7272 case 0:
7273 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
7274 break;
7275 case 1:
7276 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
7277 break;
7278 }
7279 xmlOutputBufferWriteString(buf, "?>\n");
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007280
7281#ifdef LIBXML_HTML_ENABLED
7282 dtd = xmlGetIntSubset(cur);
7283 if (dtd != NULL) {
7284 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7285 if (is_xhtml < 0) is_xhtml = 0;
7286 }
7287 if (is_xhtml) {
7288 if (encoding != NULL)
7289 htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
7290 else
7291 htmlSetMetaEncoding(cur, BAD_CAST "UTF-8");
7292 }
7293#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007294 if (cur->children != NULL) {
7295 xmlNodePtr child = cur->children;
7296
7297 while (child != NULL) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007298#ifdef LIBXML_HTML_ENABLED
7299 if (is_xhtml)
7300 xhtmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
7301 else
7302#endif
7303 xmlNodeDumpOutputInternal(buf, cur, child, 0, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007304 xmlOutputBufferWriteString(buf, "\n");
7305 child = child->next;
7306 }
7307 }
7308}
7309
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007310#ifdef LIBXML_HTML_ENABLED
7311/************************************************************************
7312 * *
7313 * Functions specific to XHTML serialization *
7314 * *
7315 ************************************************************************/
7316
7317#define XHTML_STRICT_PUBLIC_ID BAD_CAST \
7318 "-//W3C//DTD XHTML 1.0 Strict//EN"
7319#define XHTML_STRICT_SYSTEM_ID BAD_CAST \
7320 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
7321#define XHTML_FRAME_PUBLIC_ID BAD_CAST \
7322 "-//W3C//DTD XHTML 1.0 Frameset//EN"
7323#define XHTML_FRAME_SYSTEM_ID BAD_CAST \
7324 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
7325#define XHTML_TRANS_PUBLIC_ID BAD_CAST \
7326 "-//W3C//DTD XHTML 1.0 Transitional//EN"
7327#define XHTML_TRANS_SYSTEM_ID BAD_CAST \
7328 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
7329
7330#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
7331/**
7332 * xmlIsXHTML:
7333 * @systemID: the system identifier
7334 * @publicID: the public identifier
7335 *
7336 * Try to find if the document correspond to an XHTML DTD
7337 *
7338 * Returns 1 if true, 0 if not and -1 in case of error
7339 */
7340int
7341xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) {
7342 if ((systemID == NULL) && (publicID == NULL))
7343 return(-1);
7344 if (publicID != NULL) {
7345 if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1);
7346 if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1);
7347 if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1);
7348 }
7349 if (systemID != NULL) {
7350 if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1);
7351 if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1);
7352 if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1);
7353 }
7354 return(0);
7355}
7356
7357/**
7358 * xhtmlIsEmpty:
7359 * @node: the node
7360 *
7361 * Check if a node is an empty xhtml node
7362 *
7363 * Returns 1 if the node is an empty node, 0 if not and -1 in case of error
7364 */
7365static int
7366xhtmlIsEmpty(xmlNodePtr node) {
7367 if (node == NULL)
7368 return(-1);
7369 if (node->type != XML_ELEMENT_NODE)
7370 return(0);
7371 if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME)))
7372 return(0);
7373 if (node->children != NULL)
7374 return(0);
7375 switch (node->name[0]) {
7376 case 'a':
7377 if (xmlStrEqual(node->name, BAD_CAST "area"))
7378 return(1);
7379 return(0);
7380 case 'b':
7381 if (xmlStrEqual(node->name, BAD_CAST "br"))
7382 return(1);
7383 if (xmlStrEqual(node->name, BAD_CAST "base"))
7384 return(1);
7385 if (xmlStrEqual(node->name, BAD_CAST "basefont"))
7386 return(1);
7387 return(0);
7388 case 'c':
7389 if (xmlStrEqual(node->name, BAD_CAST "col"))
7390 return(1);
7391 return(0);
7392 case 'f':
7393 if (xmlStrEqual(node->name, BAD_CAST "frame"))
7394 return(1);
7395 return(0);
7396 case 'h':
7397 if (xmlStrEqual(node->name, BAD_CAST "hr"))
7398 return(1);
7399 return(0);
7400 case 'i':
7401 if (xmlStrEqual(node->name, BAD_CAST "img"))
7402 return(1);
7403 if (xmlStrEqual(node->name, BAD_CAST "input"))
7404 return(1);
7405 if (xmlStrEqual(node->name, BAD_CAST "isindex"))
7406 return(1);
7407 return(0);
7408 case 'l':
7409 if (xmlStrEqual(node->name, BAD_CAST "link"))
7410 return(1);
7411 return(0);
7412 case 'm':
7413 if (xmlStrEqual(node->name, BAD_CAST "meta"))
7414 return(1);
7415 return(0);
7416 case 'p':
7417 if (xmlStrEqual(node->name, BAD_CAST "param"))
7418 return(1);
7419 return(0);
7420 }
7421 return(0);
7422}
7423
7424/**
7425 * xhtmlAttrListDumpOutput:
7426 * @buf: the XML buffer output
7427 * @doc: the document
7428 * @cur: the first attribute pointer
7429 * @encoding: an optional encoding string
7430 *
7431 * Dump a list of XML attributes
7432 */
7433static void
7434xhtmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7435 xmlAttrPtr cur, const char *encoding) {
7436 xmlAttrPtr xml_lang = NULL;
7437 xmlAttrPtr lang = NULL;
7438 xmlAttrPtr name = NULL;
7439 xmlAttrPtr id = NULL;
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007440 xmlNodePtr parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007441
7442 if (cur == NULL) {
7443#ifdef DEBUG_TREE
7444 xmlGenericError(xmlGenericErrorContext,
7445 "xmlAttrListDumpOutput : property == NULL\n");
7446#endif
7447 return;
7448 }
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007449 parent = cur->parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007450 while (cur != NULL) {
7451 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id")))
7452 id = cur;
7453 else
7454 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name")))
7455 name = cur;
7456 else
7457 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")))
7458 lang = cur;
7459 else
7460 if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) &&
7461 (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml")))
7462 xml_lang = cur;
7463 else if ((cur->ns == NULL) &&
7464 ((cur->children == NULL) ||
7465 (cur->children->content == NULL) ||
7466 (cur->children->content[0] == 0)) &&
7467 (htmlIsBooleanAttr(cur->name))) {
7468 if (cur->children != NULL)
7469 xmlFreeNode(cur->children);
7470 cur->children = xmlNewText(cur->name);
7471 if (cur->children != NULL)
7472 cur->children->parent = (xmlNodePtr) cur;
7473 }
7474 xmlAttrDumpOutput(buf, doc, cur, encoding);
7475 cur = cur->next;
7476 }
7477 /*
7478 * C.8
7479 */
7480 if ((name != NULL) && (id == NULL)) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007481 if ((parent != NULL) && (parent->name != NULL) &&
7482 ((xmlStrEqual(parent->name, BAD_CAST "a")) ||
7483 (xmlStrEqual(parent->name, BAD_CAST "p")) ||
7484 (xmlStrEqual(parent->name, BAD_CAST "div")) ||
7485 (xmlStrEqual(parent->name, BAD_CAST "img")) ||
7486 (xmlStrEqual(parent->name, BAD_CAST "map")) ||
7487 (xmlStrEqual(parent->name, BAD_CAST "applet")) ||
7488 (xmlStrEqual(parent->name, BAD_CAST "form")) ||
7489 (xmlStrEqual(parent->name, BAD_CAST "frame")) ||
7490 (xmlStrEqual(parent->name, BAD_CAST "iframe")))) {
7491 xmlOutputBufferWriteString(buf, " id=\"");
7492 xmlAttrSerializeContent(buf->buffer, doc, name);
7493 xmlOutputBufferWriteString(buf, "\"");
7494 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007495 }
7496 /*
7497 * C.7.
7498 */
7499 if ((lang != NULL) && (xml_lang == NULL)) {
7500 xmlOutputBufferWriteString(buf, " xml:lang=\"");
7501 xmlAttrSerializeContent(buf->buffer, doc, lang);
7502 xmlOutputBufferWriteString(buf, "\"");
7503 } else
7504 if ((xml_lang != NULL) && (lang == NULL)) {
7505 xmlOutputBufferWriteString(buf, " lang=\"");
7506 xmlAttrSerializeContent(buf->buffer, doc, xml_lang);
7507 xmlOutputBufferWriteString(buf, "\"");
7508 }
7509}
7510
7511/**
7512 * xhtmlNodeListDumpOutput:
7513 * @buf: the XML buffer output
7514 * @doc: the XHTML document
7515 * @cur: the first node
7516 * @level: the imbrication level for indenting
7517 * @format: is formatting allowed
7518 * @encoding: an optional encoding string
7519 *
7520 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007521 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007522 * or xmlKeepBlanksDefault(0) was called
7523 */
7524static void
7525xhtmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7526 xmlNodePtr cur, int level, int format, const char *encoding) {
7527 int i;
7528
7529 if (cur == NULL) {
7530#ifdef DEBUG_TREE
7531 xmlGenericError(xmlGenericErrorContext,
7532 "xhtmlNodeListDumpOutput : node == NULL\n");
7533#endif
7534 return;
7535 }
7536 while (cur != NULL) {
7537 if ((format) && (xmlIndentTreeOutput) &&
7538 (cur->type == XML_ELEMENT_NODE))
7539 for (i = 0;i < level;i++)
7540 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7541 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
7542 if (format) {
7543 xmlOutputBufferWriteString(buf, "\n");
7544 }
7545 cur = cur->next;
7546 }
7547}
7548
7549/**
7550 * xhtmlNodeDumpOutput:
7551 * @buf: the XML buffer output
7552 * @doc: the XHTML document
7553 * @cur: the current node
7554 * @level: the imbrication level for indenting
7555 * @format: is formatting allowed
7556 * @encoding: an optional encoding string
7557 *
7558 * Dump an XHTML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007559 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007560 * or xmlKeepBlanksDefault(0) was called
7561 */
7562static void
7563xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7564 int level, int format, const char *encoding) {
7565 int i;
7566 xmlNodePtr tmp;
7567
7568 if (cur == NULL) {
7569#ifdef DEBUG_TREE
7570 xmlGenericError(xmlGenericErrorContext,
7571 "xmlNodeDumpOutput : node == NULL\n");
7572#endif
7573 return;
7574 }
7575 if (cur->type == XML_XINCLUDE_START)
7576 return;
7577 if (cur->type == XML_XINCLUDE_END)
7578 return;
7579 if (cur->type == XML_DTD_NODE) {
7580 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7581 return;
7582 }
7583 if (cur->type == XML_ELEMENT_DECL) {
7584 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7585 return;
7586 }
7587 if (cur->type == XML_ATTRIBUTE_DECL) {
7588 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7589 return;
7590 }
7591 if (cur->type == XML_ENTITY_DECL) {
7592 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7593 return;
7594 }
7595 if (cur->type == XML_TEXT_NODE) {
7596 if (cur->content != NULL) {
7597 if ((cur->name == xmlStringText) ||
7598 (cur->name != xmlStringTextNoenc)) {
7599 xmlChar *buffer;
7600
7601 if (encoding == NULL)
7602 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7603 else
7604 buffer = xmlEncodeSpecialChars(doc, cur->content);
7605 if (buffer != NULL) {
7606 xmlOutputBufferWriteString(buf, (const char *)buffer);
7607 xmlFree(buffer);
7608 }
7609 } else {
7610 /*
7611 * Disable escaping, needed for XSLT
7612 */
7613 xmlOutputBufferWriteString(buf, (const char *) cur->content);
7614 }
7615 }
7616
7617 return;
7618 }
7619 if (cur->type == XML_PI_NODE) {
7620 if (cur->content != NULL) {
7621 xmlOutputBufferWriteString(buf, "<?");
7622 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7623 if (cur->content != NULL) {
7624 xmlOutputBufferWriteString(buf, " ");
7625 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7626 }
7627 xmlOutputBufferWriteString(buf, "?>");
7628 } else {
7629 xmlOutputBufferWriteString(buf, "<?");
7630 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7631 xmlOutputBufferWriteString(buf, "?>");
7632 }
7633 return;
7634 }
7635 if (cur->type == XML_COMMENT_NODE) {
7636 if (cur->content != NULL) {
7637 xmlOutputBufferWriteString(buf, "<!--");
7638 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7639 xmlOutputBufferWriteString(buf, "-->");
7640 }
7641 return;
7642 }
7643 if (cur->type == XML_ENTITY_REF_NODE) {
7644 xmlOutputBufferWriteString(buf, "&");
7645 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7646 xmlOutputBufferWriteString(buf, ";");
7647 return;
7648 }
7649 if (cur->type == XML_CDATA_SECTION_NODE) {
7650 xmlOutputBufferWriteString(buf, "<![CDATA[");
7651 if (cur->content != NULL)
7652 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7653 xmlOutputBufferWriteString(buf, "]]>");
7654 return;
7655 }
7656
7657 if (format == 1) {
7658 tmp = cur->children;
7659 while (tmp != NULL) {
7660 if ((tmp->type == XML_TEXT_NODE) ||
7661 (tmp->type == XML_ENTITY_REF_NODE)) {
7662 format = 0;
7663 break;
7664 }
7665 tmp = tmp->next;
7666 }
7667 }
7668 xmlOutputBufferWriteString(buf, "<");
7669 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7670 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7671 xmlOutputBufferWriteString(buf, ":");
7672 }
7673
7674 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7675 if (cur->nsDef)
7676 xmlNsListDumpOutput(buf, cur->nsDef);
7677 if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
7678 (cur->ns == NULL) && (cur->nsDef == NULL))) {
7679 /*
7680 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
7681 */
7682 xmlOutputBufferWriteString(buf,
7683 " xmlns=\"http://www.w3.org/1999/xhtml\"");
7684 }
7685 if (cur->properties != NULL)
7686 xhtmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7687
7688 if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) {
7689 if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
7690 (xhtmlIsEmpty(cur) == 1)) {
7691 /*
7692 * C.2. Empty Elements
7693 */
7694 xmlOutputBufferWriteString(buf, " />");
7695 } else {
7696 /*
7697 * C.3. Element Minimization and Empty Element Content
7698 */
7699 xmlOutputBufferWriteString(buf, "></");
7700 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7701 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7702 xmlOutputBufferWriteString(buf, ":");
7703 }
7704 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7705 xmlOutputBufferWriteString(buf, ">");
7706 }
7707 return;
7708 }
7709 xmlOutputBufferWriteString(buf, ">");
7710 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
7711 xmlChar *buffer;
7712
7713 if (encoding == NULL)
7714 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7715 else
7716 buffer = xmlEncodeSpecialChars(doc, cur->content);
7717 if (buffer != NULL) {
7718 xmlOutputBufferWriteString(buf, (const char *)buffer);
7719 xmlFree(buffer);
7720 }
7721 }
7722
7723 /*
7724 * 4.8. Script and Style elements
7725 */
7726 if ((cur->type == XML_ELEMENT_NODE) &&
7727 ((xmlStrEqual(cur->name, BAD_CAST "script")) ||
7728 (xmlStrEqual(cur->name, BAD_CAST "style"))) &&
7729 ((cur->ns == NULL) ||
7730 (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) {
7731 xmlNodePtr child = cur->children;
7732
7733 while (child != NULL) {
7734 if ((child->type == XML_TEXT_NODE) ||
7735 (child->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard64b35282002-12-04 15:10:40 +00007736 /*
7737 * Apparently CDATA escaping for style just break on IE,
7738 * mozilla and galeon, so ...
7739 */
7740 if (xmlStrEqual(cur->name, BAD_CAST "style") &&
7741 (xmlStrchr(child->content, '<') == NULL) &&
7742 (xmlStrchr(child->content, '>') == NULL) &&
7743 (xmlStrchr(child->content, '&') == NULL)) {
7744 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7745 } else {
7746 xmlOutputBufferWriteString(buf, "<![CDATA[");
7747 if (child->content != NULL)
7748 xmlOutputBufferWriteString(buf,
7749 (const char *)child->content);
7750 xmlOutputBufferWriteString(buf, "]]>");
7751 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007752 } else {
7753 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7754 }
7755 child = child->next;
7756 }
7757 } else if (cur->children != NULL) {
7758 if (format) xmlOutputBufferWriteString(buf, "\n");
7759 xhtmlNodeListDumpOutput(buf, doc, cur->children,
7760 (level >= 0?level+1:-1), format, encoding);
7761 if ((xmlIndentTreeOutput) && (format))
7762 for (i = 0;i < level;i++)
7763 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7764 }
7765 xmlOutputBufferWriteString(buf, "</");
7766 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7767 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7768 xmlOutputBufferWriteString(buf, ":");
7769 }
7770
7771 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7772 xmlOutputBufferWriteString(buf, ">");
7773}
7774#endif
7775
Owen Taylor3473f882001-02-23 17:55:21 +00007776/************************************************************************
7777 * *
7778 * Saving functions front-ends *
7779 * *
7780 ************************************************************************/
7781
7782/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00007783 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00007784 * @out_doc: Document to generate XML text from
7785 * @doc_txt_ptr: Memory pointer for allocated XML text
7786 * @doc_txt_len: Length of the generated XML text
7787 * @txt_encoding: Character encoding to use when generating XML text
7788 * @format: should formatting spaces been added
7789 *
7790 * Dump the current DOM tree into memory using the character encoding specified
7791 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007792 * allocated memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00007793 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007794 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007795 */
7796
7797void
7798xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007799 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007800 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007801 int dummy = 0;
7802
7803 xmlCharEncoding doc_charset;
7804 xmlOutputBufferPtr out_buff = NULL;
7805 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
7806
7807 if (doc_txt_len == NULL) {
7808 doc_txt_len = &dummy; /* Continue, caller just won't get length */
7809 }
7810
7811 if (doc_txt_ptr == NULL) {
7812 *doc_txt_len = 0;
7813 xmlGenericError(xmlGenericErrorContext,
7814 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
7815 return;
7816 }
7817
7818 *doc_txt_ptr = NULL;
7819 *doc_txt_len = 0;
7820
7821 if (out_doc == NULL) {
7822 /* No document, no output */
7823 xmlGenericError(xmlGenericErrorContext,
7824 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
7825 return;
7826 }
7827
7828 /*
7829 * Validate the encoding value, if provided.
7830 * This logic is copied from xmlSaveFileEnc.
7831 */
7832
7833 if (txt_encoding == NULL)
7834 txt_encoding = (const char *) out_doc->encoding;
7835 if (txt_encoding != NULL) {
7836 doc_charset = xmlParseCharEncoding(txt_encoding);
7837
7838 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
7839 xmlGenericError(xmlGenericErrorContext,
7840 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
7841 return;
7842
7843 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
7844 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
7845 if ( conv_hdlr == NULL ) {
7846 xmlGenericError(xmlGenericErrorContext,
7847 "%s: %s %s '%s'\n",
7848 "xmlDocDumpFormatMemoryEnc",
7849 "Failed to identify encoding handler for",
7850 "character set",
7851 txt_encoding);
7852 return;
7853 }
7854 }
7855 }
7856
7857 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
7858 xmlGenericError(xmlGenericErrorContext,
7859 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
7860 return;
7861 }
7862
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007863 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007864 xmlOutputBufferFlush(out_buff);
7865 if (out_buff->conv != NULL) {
7866 *doc_txt_len = out_buff->conv->use;
7867 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
7868 } else {
7869 *doc_txt_len = out_buff->buffer->use;
7870 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
7871 }
7872 (void)xmlOutputBufferClose(out_buff);
7873
7874 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
7875 *doc_txt_len = 0;
7876 xmlGenericError(xmlGenericErrorContext,
7877 "xmlDocDumpFormatMemoryEnc: %s\n",
7878 "Failed to allocate memory for document text representation.");
7879 }
7880
7881 return;
7882}
7883
7884/**
7885 * xmlDocDumpMemory:
7886 * @cur: the document
7887 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007888 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007889 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007890 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007891 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007892 */
7893void
7894xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
7895 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
7896}
7897
7898/**
7899 * xmlDocDumpFormatMemory:
7900 * @cur: the document
7901 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007902 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007903 * @format: should formatting spaces been added
7904 *
7905 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007906 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007907 * It's up to the caller to free the memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00007908 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007909 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007910 */
7911void
7912xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
7913 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
7914}
7915
7916/**
7917 * xmlDocDumpMemoryEnc:
7918 * @out_doc: Document to generate XML text from
7919 * @doc_txt_ptr: Memory pointer for allocated XML text
7920 * @doc_txt_len: Length of the generated XML text
7921 * @txt_encoding: Character encoding to use when generating XML text
7922 *
7923 * Dump the current DOM tree into memory using the character encoding specified
7924 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007925 * allocated memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007926 */
7927
7928void
7929xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
7930 int * doc_txt_len, const char * txt_encoding) {
7931 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007932 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007933}
7934
7935/**
7936 * xmlGetDocCompressMode:
7937 * @doc: the document
7938 *
7939 * get the compression ratio for a document, ZLIB based
7940 * Returns 0 (uncompressed) to 9 (max compression)
7941 */
7942int
7943xmlGetDocCompressMode (xmlDocPtr doc) {
7944 if (doc == NULL) return(-1);
7945 return(doc->compression);
7946}
7947
7948/**
7949 * xmlSetDocCompressMode:
7950 * @doc: the document
7951 * @mode: the compression ratio
7952 *
7953 * set the compression ratio for a document, ZLIB based
7954 * Correct values: 0 (uncompressed) to 9 (max compression)
7955 */
7956void
7957xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7958 if (doc == NULL) return;
7959 if (mode < 0) doc->compression = 0;
7960 else if (mode > 9) doc->compression = 9;
7961 else doc->compression = mode;
7962}
7963
7964/**
7965 * xmlGetCompressMode:
7966 *
7967 * get the default compression mode used, ZLIB based.
7968 * Returns 0 (uncompressed) to 9 (max compression)
7969 */
7970int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007971xmlGetCompressMode(void)
7972{
7973 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00007974}
7975
7976/**
7977 * xmlSetCompressMode:
7978 * @mode: the compression ratio
7979 *
7980 * set the default compression mode used, ZLIB based
7981 * Correct values: 0 (uncompressed) to 9 (max compression)
7982 */
7983void
7984xmlSetCompressMode(int mode) {
7985 if (mode < 0) xmlCompressMode = 0;
7986 else if (mode > 9) xmlCompressMode = 9;
7987 else xmlCompressMode = mode;
7988}
7989
7990/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007991 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00007992 * @f: the FILE*
7993 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00007994 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007995 *
7996 * Dump an XML document to an open FILE.
7997 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007998 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007999 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8000 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008001 */
8002int
Daniel Veillard9e412302002-06-10 15:59:44 +00008003xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00008004 xmlOutputBufferPtr buf;
8005 const char * encoding;
8006 xmlCharEncodingHandlerPtr handler = NULL;
8007 int ret;
8008
8009 if (cur == NULL) {
8010#ifdef DEBUG_TREE
8011 xmlGenericError(xmlGenericErrorContext,
8012 "xmlDocDump : document == NULL\n");
8013#endif
8014 return(-1);
8015 }
8016 encoding = (const char *) cur->encoding;
8017
8018 if (encoding != NULL) {
8019 xmlCharEncoding enc;
8020
8021 enc = xmlParseCharEncoding(encoding);
8022
8023 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
8024 xmlGenericError(xmlGenericErrorContext,
8025 "xmlDocDump: document not in UTF8\n");
8026 return(-1);
8027 }
8028 if (enc != XML_CHAR_ENCODING_UTF8) {
8029 handler = xmlFindCharEncodingHandler(encoding);
8030 if (handler == NULL) {
8031 xmlFree((char *) cur->encoding);
8032 cur->encoding = NULL;
8033 }
8034 }
8035 }
8036 buf = xmlOutputBufferCreateFile(f, handler);
8037 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00008038 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008039
8040 ret = xmlOutputBufferClose(buf);
8041 return(ret);
8042}
8043
8044/**
Daniel Veillard9e412302002-06-10 15:59:44 +00008045 * xmlDocDump:
8046 * @f: the FILE*
8047 * @cur: the document
8048 *
8049 * Dump an XML document to an open FILE.
8050 *
8051 * returns: the number of bytes written or -1 in case of failure.
8052 */
8053int
8054xmlDocDump(FILE *f, xmlDocPtr cur) {
8055 return(xmlDocFormatDump (f, cur, 0));
8056}
8057
8058/**
Owen Taylor3473f882001-02-23 17:55:21 +00008059 * xmlSaveFileTo:
8060 * @buf: an output I/O buffer
8061 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00008062 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00008063 *
8064 * Dump an XML document to an I/O buffer.
8065 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008066 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008067 */
8068int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00008069xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00008070 int ret;
8071
8072 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008073 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008074 ret = xmlOutputBufferClose(buf);
8075 return(ret);
8076}
8077
8078/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00008079 * xmlSaveFormatFileTo:
8080 * @buf: an output I/O buffer
8081 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00008082 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00008083 * @format: should formatting spaces been added
8084 *
8085 * Dump an XML document to an I/O buffer.
8086 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008087 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008088 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8089 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardeefd4492001-04-28 16:55:50 +00008090 */
8091int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00008092xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00008093 int ret;
8094
8095 if (buf == NULL) return(0);
8096 xmlDocContentDumpOutput(buf, cur, encoding, format);
8097 ret = xmlOutputBufferClose(buf);
8098 return(ret);
8099}
8100
8101/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00008102 * xmlSaveFormatFileEnc:
Daniel Veillardf012a642001-07-23 19:10:52 +00008103 * @filename: the filename or URL to output
8104 * @cur: the document being saved
8105 * @encoding: the name of the encoding to use or NULL.
8106 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00008107 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00008108 * Dump an XML document to a file or an URL.
8109 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008110 * Returns the number of bytes written or -1 in case of error.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008111 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8112 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008113 */
8114int
Daniel Veillardf012a642001-07-23 19:10:52 +00008115xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
8116 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00008117 xmlOutputBufferPtr buf;
8118 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00008119 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00008120 int ret;
8121
Daniel Veillard4dbe77a2003-01-14 00:17:42 +00008122 if (cur == NULL)
8123 return(-1);
8124
Daniel Veillardfb25a512002-01-13 20:32:08 +00008125 if (encoding == NULL)
8126 encoding = (const char *) cur->encoding;
8127
Owen Taylor3473f882001-02-23 17:55:21 +00008128 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00008129
8130 enc = xmlParseCharEncoding(encoding);
8131 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
8132 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00008133 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00008134 return(-1);
8135 }
8136 if (enc != XML_CHAR_ENCODING_UTF8) {
8137 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00008138 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00008139 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00008140 }
8141 }
8142
Daniel Veillardf012a642001-07-23 19:10:52 +00008143#ifdef HAVE_ZLIB_H
8144 if (cur->compression < 0) cur->compression = xmlCompressMode;
8145#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008146 /*
8147 * save the content to a temp buffer.
8148 */
Daniel Veillardf012a642001-07-23 19:10:52 +00008149 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00008150 if (buf == NULL) return(-1);
8151
Daniel Veillardf012a642001-07-23 19:10:52 +00008152 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008153
8154 ret = xmlOutputBufferClose(buf);
8155 return(ret);
8156}
8157
Daniel Veillardf012a642001-07-23 19:10:52 +00008158
8159/**
8160 * xmlSaveFileEnc:
8161 * @filename: the filename (or URL)
8162 * @cur: the document
8163 * @encoding: the name of an encoding (or NULL)
8164 *
8165 * Dump an XML document, converting it to the given encoding
8166 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008167 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00008168 */
8169int
8170xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
8171 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
8172}
8173
Owen Taylor3473f882001-02-23 17:55:21 +00008174/**
Daniel Veillard67fee942001-04-26 18:59:03 +00008175 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00008176 * @filename: the filename (or URL)
8177 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00008178 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00008179 *
8180 * Dump an XML document to a file. Will use compression if
8181 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00008182 * used. If @format is set then the document will be indented on output.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008183 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8184 * or xmlKeepBlanksDefault(0) was called
Daniel Veillard67fee942001-04-26 18:59:03 +00008185 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008186 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008187 */
8188int
Daniel Veillard67fee942001-04-26 18:59:03 +00008189xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008190 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00008191}
8192
Daniel Veillard67fee942001-04-26 18:59:03 +00008193/**
8194 * xmlSaveFile:
8195 * @filename: the filename (or URL)
8196 * @cur: the document
8197 *
8198 * Dump an XML document to a file. Will use compression if
8199 * compiled in and enabled. If @filename is "-" the stdout file is
8200 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00008201 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00008202 */
8203int
8204xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008205 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00008206}
8207