blob: 1a03a5abcce1c9ece763409a98d0ea4de6d147da [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002 * tree.c : implementation of access function for an XML tree.
Owen Taylor3473f882001-02-23 17:55:21 +00003 *
Daniel Veillardd5c2f922002-11-21 14:10:52 +00004 * References:
5 * XHTML 1.0 W3C REC: http://www.w3.org/TR/2002/REC-xhtml1-20020801/
6 *
Owen Taylor3473f882001-02-23 17:55:21 +00007 * See Copyright for the status of this software.
8 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00009 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000010 *
Owen Taylor3473f882001-02-23 17:55:21 +000011 */
12
Daniel Veillard34ce8be2002-03-18 19:37:11 +000013#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000014#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000015
Owen Taylor3473f882001-02-23 17:55:21 +000016#include <string.h> /* for memset() only ! */
17
18#ifdef HAVE_CTYPE_H
19#include <ctype.h>
20#endif
21#ifdef HAVE_STDLIB_H
22#include <stdlib.h>
23#endif
24#ifdef HAVE_ZLIB_H
25#include <zlib.h>
26#endif
27
28#include <libxml/xmlmemory.h>
29#include <libxml/tree.h>
30#include <libxml/parser.h>
Daniel Veillardb8c9be92001-07-09 16:01:19 +000031#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000032#include <libxml/entities.h>
33#include <libxml/valid.h>
34#include <libxml/xmlerror.h>
Daniel Veillardbdb9ba72001-04-11 11:28:06 +000035#include <libxml/parserInternals.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000036#include <libxml/globals.h>
Daniel Veillardd5c2f922002-11-21 14:10:52 +000037#ifdef LIBXML_HTML_ENABLED
38#include <libxml/HTMLtree.h>
39#endif
Owen Taylor3473f882001-02-23 17:55:21 +000040
Daniel Veillard56a4cb82001-03-24 17:00:36 +000041xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
42
43/************************************************************************
44 * *
45 * A few static variables and macros *
46 * *
47 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +000048/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +000049const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000050/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +000051const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +000052 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000053/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +000054const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
55
Owen Taylor3473f882001-02-23 17:55:21 +000056static int xmlCompressMode = 0;
57static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000058
Owen Taylor3473f882001-02-23 17:55:21 +000059#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
60 xmlNodePtr ulccur = (n)->children; \
61 if (ulccur == NULL) { \
62 (n)->last = NULL; \
63 } else { \
64 while (ulccur->next != NULL) { \
65 ulccur->parent = (n); \
66 ulccur = ulccur->next; \
67 } \
68 ulccur->parent = (n); \
69 (n)->last = ulccur; \
70}}
71
72/* #define DEBUG_BUFFER */
73/* #define DEBUG_TREE */
74
75/************************************************************************
76 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +000077 * Functions to move to entities.c once the *
78 * API freeze is smoothen and they can be made public. *
79 * *
80 ************************************************************************/
81#include <libxml/hash.h>
82
83/**
84 * xmlGetEntityFromDtd:
85 * @dtd: A pointer to the DTD to search
86 * @name: The entity name
87 *
88 * Do an entity lookup in the DTD entity hash table and
89 * return the corresponding entity, if found.
90 *
91 * Returns A pointer to the entity structure or NULL if not found.
92 */
93static xmlEntityPtr
94xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
95 xmlEntitiesTablePtr table;
96
97 if((dtd != NULL) && (dtd->entities != NULL)) {
98 table = (xmlEntitiesTablePtr) dtd->entities;
99 return((xmlEntityPtr) xmlHashLookup(table, name));
100 /* return(xmlGetEntityFromTable(table, name)); */
101 }
102 return(NULL);
103}
104/**
105 * xmlGetParameterEntityFromDtd:
106 * @dtd: A pointer to the DTD to search
107 * @name: The entity name
108 *
109 * Do an entity lookup in the DTD pararmeter entity hash table and
110 * return the corresponding entity, if found.
111 *
112 * Returns A pointer to the entity structure or NULL if not found.
113 */
114static xmlEntityPtr
115xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
116 xmlEntitiesTablePtr table;
117
118 if ((dtd != NULL) && (dtd->pentities != NULL)) {
119 table = (xmlEntitiesTablePtr) dtd->pentities;
120 return((xmlEntityPtr) xmlHashLookup(table, name));
121 /* return(xmlGetEntityFromTable(table, name)); */
122 }
123 return(NULL);
124}
125
126/************************************************************************
127 * *
Daniel Veillardd2298792003-02-14 16:54:11 +0000128 * Check Name, NCName and QName strings *
129 * *
130 ************************************************************************/
131
132#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
133
134/**
135 * xmlValidateNCName:
136 * @value: the value to check
137 * @space: allow spaces in front and end of the string
138 *
139 * Check that a value conforms to the lexical space of NCName
140 *
141 * Returns 0 if this validates, a positive error code number otherwise
142 * and -1 in case of internal or API error.
143 */
144int
145xmlValidateNCName(const xmlChar *value, int space) {
146 const xmlChar *cur = value;
147 int c,l;
148
149 /*
150 * First quick algorithm for ASCII range
151 */
152 if (space)
153 while (IS_BLANK(*cur)) cur++;
154 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
155 (*cur == '_'))
156 cur++;
157 else
158 goto try_complex;
159 while (((*cur >= 'a') && (*cur <= 'z')) ||
160 ((*cur >= 'A') && (*cur <= 'Z')) ||
161 ((*cur >= '0') && (*cur <= '9')) ||
162 (*cur == '_') || (*cur == '-') || (*cur == '.'))
163 cur++;
164 if (space)
165 while (IS_BLANK(*cur)) cur++;
166 if (*cur == 0)
167 return(0);
168
169try_complex:
170 /*
171 * Second check for chars outside the ASCII range
172 */
173 cur = value;
174 c = CUR_SCHAR(cur, l);
175 if (space) {
176 while (IS_BLANK(c)) {
177 cur += l;
178 c = CUR_SCHAR(cur, l);
179 }
180 }
181 if ((!xmlIsLetter(c)) && (c != '_'))
182 return(1);
183 cur += l;
184 c = CUR_SCHAR(cur, l);
185 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') ||
186 (c == '-') || (c == '_') || xmlIsCombining(c) ||
187 xmlIsExtender(c)) {
188 cur += l;
189 c = CUR_SCHAR(cur, l);
190 }
191 if (space) {
192 while (IS_BLANK(c)) {
193 cur += l;
194 c = CUR_SCHAR(cur, l);
195 }
196 }
197 if (c != 0)
198 return(1);
199
200 return(0);
201}
202
203/**
204 * xmlValidateQName:
205 * @value: the value to check
206 * @space: allow spaces in front and end of the string
207 *
208 * Check that a value conforms to the lexical space of QName
209 *
210 * Returns 0 if this validates, a positive error code number otherwise
211 * and -1 in case of internal or API error.
212 */
213int
214xmlValidateQName(const xmlChar *value, int space) {
215 const xmlChar *cur = value;
216 int c,l;
217
218 /*
219 * First quick algorithm for ASCII range
220 */
221 if (space)
222 while (IS_BLANK(*cur)) cur++;
223 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
224 (*cur == '_'))
225 cur++;
226 else
227 goto try_complex;
228 while (((*cur >= 'a') && (*cur <= 'z')) ||
229 ((*cur >= 'A') && (*cur <= 'Z')) ||
230 ((*cur >= '0') && (*cur <= '9')) ||
231 (*cur == '_') || (*cur == '-') || (*cur == '.'))
232 cur++;
233 if (*cur == ':') {
234 cur++;
235 if (((*cur >= 'a') && (*cur <= 'z')) ||
236 ((*cur >= 'A') && (*cur <= 'Z')) ||
237 (*cur == '_'))
238 cur++;
239 else
240 goto try_complex;
241 while (((*cur >= 'a') && (*cur <= 'z')) ||
242 ((*cur >= 'A') && (*cur <= 'Z')) ||
243 ((*cur >= '0') && (*cur <= '9')) ||
244 (*cur == '_') || (*cur == '-') || (*cur == '.'))
245 cur++;
246 }
247 if (space)
248 while (IS_BLANK(*cur)) cur++;
249 if (*cur == 0)
250 return(0);
251
252try_complex:
253 /*
254 * Second check for chars outside the ASCII range
255 */
256 cur = value;
257 c = CUR_SCHAR(cur, l);
258 if (space) {
259 while (IS_BLANK(c)) {
260 cur += l;
261 c = CUR_SCHAR(cur, l);
262 }
263 }
264 if ((!xmlIsLetter(c)) && (c != '_'))
265 return(1);
266 cur += l;
267 c = CUR_SCHAR(cur, l);
268 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') ||
269 (c == '-') || (c == '_') || xmlIsCombining(c) ||
270 xmlIsExtender(c)) {
271 cur += l;
272 c = CUR_SCHAR(cur, l);
273 }
274 if (c == ':') {
275 cur += l;
276 c = CUR_SCHAR(cur, l);
277 if ((!xmlIsLetter(c)) && (c != '_'))
278 return(1);
279 cur += l;
280 c = CUR_SCHAR(cur, l);
281 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') ||
282 (c == '-') || (c == '_') || xmlIsCombining(c) ||
283 xmlIsExtender(c)) {
284 cur += l;
285 c = CUR_SCHAR(cur, l);
286 }
287 }
288 if (space) {
289 while (IS_BLANK(c)) {
290 cur += l;
291 c = CUR_SCHAR(cur, l);
292 }
293 }
294 if (c != 0)
295 return(1);
296 return(0);
297}
298
299/**
300 * xmlValidateName:
301 * @value: the value to check
302 * @space: allow spaces in front and end of the string
303 *
304 * Check that a value conforms to the lexical space of Name
305 *
306 * Returns 0 if this validates, a positive error code number otherwise
307 * and -1 in case of internal or API error.
308 */
309int
310xmlValidateName(const xmlChar *value, int space) {
311 const xmlChar *cur = value;
312 int c,l;
313
314 /*
315 * First quick algorithm for ASCII range
316 */
317 if (space)
318 while (IS_BLANK(*cur)) cur++;
319 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
320 (*cur == '_') || (*cur == ':'))
321 cur++;
322 else
323 goto try_complex;
324 while (((*cur >= 'a') && (*cur <= 'z')) ||
325 ((*cur >= 'A') && (*cur <= 'Z')) ||
326 ((*cur >= '0') && (*cur <= '9')) ||
327 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
328 cur++;
329 if (space)
330 while (IS_BLANK(*cur)) cur++;
331 if (*cur == 0)
332 return(0);
333
334try_complex:
335 /*
336 * Second check for chars outside the ASCII range
337 */
338 cur = value;
339 c = CUR_SCHAR(cur, l);
340 if (space) {
341 while (IS_BLANK(c)) {
342 cur += l;
343 c = CUR_SCHAR(cur, l);
344 }
345 }
346 if ((!xmlIsLetter(c)) && (c != '_') && (c != ':'))
347 return(1);
348 cur += l;
349 c = CUR_SCHAR(cur, l);
350 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') || (c == ':') ||
351 (c == '-') || (c == '_') || xmlIsCombining(c) || xmlIsExtender(c)) {
352 cur += l;
353 c = CUR_SCHAR(cur, l);
354 }
355 if (space) {
356 while (IS_BLANK(c)) {
357 cur += l;
358 c = CUR_SCHAR(cur, l);
359 }
360 }
361 if (c != 0)
362 return(1);
363 return(0);
364}
365
Daniel Veillardd4310742003-02-18 21:12:46 +0000366/**
367 * xmlValidateNMToken:
368 * @value: the value to check
369 * @space: allow spaces in front and end of the string
370 *
371 * Check that a value conforms to the lexical space of NMToken
372 *
373 * Returns 0 if this validates, a positive error code number otherwise
374 * and -1 in case of internal or API error.
375 */
376int
377xmlValidateNMToken(const xmlChar *value, int space) {
378 const xmlChar *cur = value;
379 int c,l;
380
381 /*
382 * First quick algorithm for ASCII range
383 */
384 if (space)
385 while (IS_BLANK(*cur)) cur++;
386 if (((*cur >= 'a') && (*cur <= 'z')) ||
387 ((*cur >= 'A') && (*cur <= 'Z')) ||
388 ((*cur >= '0') && (*cur <= '9')) ||
389 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
390 cur++;
391 else
392 goto try_complex;
393 while (((*cur >= 'a') && (*cur <= 'z')) ||
394 ((*cur >= 'A') && (*cur <= 'Z')) ||
395 ((*cur >= '0') && (*cur <= '9')) ||
396 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
397 cur++;
398 if (space)
399 while (IS_BLANK(*cur)) cur++;
400 if (*cur == 0)
401 return(0);
402
403try_complex:
404 /*
405 * Second check for chars outside the ASCII range
406 */
407 cur = value;
408 c = CUR_SCHAR(cur, l);
409 if (space) {
410 while (IS_BLANK(c)) {
411 cur += l;
412 c = CUR_SCHAR(cur, l);
413 }
414 }
415 if (!(xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') || (c == ':') ||
416 (c == '-') || (c == '_') || xmlIsCombining(c) || xmlIsExtender(c)))
417 return(1);
418 cur += l;
419 c = CUR_SCHAR(cur, l);
420 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') || (c == ':') ||
421 (c == '-') || (c == '_') || xmlIsCombining(c) || xmlIsExtender(c)) {
422 cur += l;
423 c = CUR_SCHAR(cur, l);
424 }
425 if (space) {
426 while (IS_BLANK(c)) {
427 cur += l;
428 c = CUR_SCHAR(cur, l);
429 }
430 }
431 if (c != 0)
432 return(1);
433 return(0);
434}
435
Daniel Veillardd2298792003-02-14 16:54:11 +0000436/************************************************************************
437 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000438 * Allocation and deallocation of basic structures *
439 * *
440 ************************************************************************/
441
442/**
443 * xmlSetBufferAllocationScheme:
444 * @scheme: allocation method to use
445 *
446 * Set the buffer allocation method. Types are
447 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
448 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
449 * improves performance
450 */
451void
452xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
453 xmlBufferAllocScheme = scheme;
454}
455
456/**
457 * xmlGetBufferAllocationScheme:
458 *
459 * Types are
460 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
461 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
462 * improves performance
463 *
464 * Returns the current allocation scheme
465 */
466xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000467xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000468 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000469}
470
471/**
472 * xmlNewNs:
473 * @node: the element carrying the namespace
474 * @href: the URI associated
475 * @prefix: the prefix for the namespace
476 *
477 * Creation of a new Namespace. This function will refuse to create
478 * a namespace with a similar prefix than an existing one present on this
479 * node.
480 * We use href==NULL in the case of an element creation where the namespace
481 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000482 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000483 */
484xmlNsPtr
485xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
486 xmlNsPtr cur;
487
488 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
489 return(NULL);
490
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000491 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
492 return(NULL);
493
Owen Taylor3473f882001-02-23 17:55:21 +0000494 /*
495 * Allocate a new Namespace and fill the fields.
496 */
497 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
498 if (cur == NULL) {
499 xmlGenericError(xmlGenericErrorContext,
500 "xmlNewNs : malloc failed\n");
501 return(NULL);
502 }
503 memset(cur, 0, sizeof(xmlNs));
504 cur->type = XML_LOCAL_NAMESPACE;
505
506 if (href != NULL)
507 cur->href = xmlStrdup(href);
508 if (prefix != NULL)
509 cur->prefix = xmlStrdup(prefix);
510
511 /*
512 * Add it at the end to preserve parsing order ...
513 * and checks for existing use of the prefix
514 */
515 if (node != NULL) {
516 if (node->nsDef == NULL) {
517 node->nsDef = cur;
518 } else {
519 xmlNsPtr prev = node->nsDef;
520
521 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
522 (xmlStrEqual(prev->prefix, cur->prefix))) {
523 xmlFreeNs(cur);
524 return(NULL);
525 }
526 while (prev->next != NULL) {
527 prev = prev->next;
528 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
529 (xmlStrEqual(prev->prefix, cur->prefix))) {
530 xmlFreeNs(cur);
531 return(NULL);
532 }
533 }
534 prev->next = cur;
535 }
536 }
537 return(cur);
538}
539
540/**
541 * xmlSetNs:
542 * @node: a node in the document
543 * @ns: a namespace pointer
544 *
545 * Associate a namespace to a node, a posteriori.
546 */
547void
548xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
549 if (node == NULL) {
550#ifdef DEBUG_TREE
551 xmlGenericError(xmlGenericErrorContext,
552 "xmlSetNs: node == NULL\n");
553#endif
554 return;
555 }
556 node->ns = ns;
557}
558
559/**
560 * xmlFreeNs:
561 * @cur: the namespace pointer
562 *
563 * Free up the structures associated to a namespace
564 */
565void
566xmlFreeNs(xmlNsPtr cur) {
567 if (cur == NULL) {
568#ifdef DEBUG_TREE
569 xmlGenericError(xmlGenericErrorContext,
570 "xmlFreeNs : ns == NULL\n");
571#endif
572 return;
573 }
574 if (cur->href != NULL) xmlFree((char *) cur->href);
575 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000576 xmlFree(cur);
577}
578
579/**
580 * xmlFreeNsList:
581 * @cur: the first namespace pointer
582 *
583 * Free up all the structures associated to the chained namespaces.
584 */
585void
586xmlFreeNsList(xmlNsPtr cur) {
587 xmlNsPtr next;
588 if (cur == NULL) {
589#ifdef DEBUG_TREE
590 xmlGenericError(xmlGenericErrorContext,
591 "xmlFreeNsList : ns == NULL\n");
592#endif
593 return;
594 }
595 while (cur != NULL) {
596 next = cur->next;
597 xmlFreeNs(cur);
598 cur = next;
599 }
600}
601
602/**
603 * xmlNewDtd:
604 * @doc: the document pointer
605 * @name: the DTD name
606 * @ExternalID: the external ID
607 * @SystemID: the system ID
608 *
609 * Creation of a new DTD for the external subset. To create an
610 * internal subset, use xmlCreateIntSubset().
611 *
612 * Returns a pointer to the new DTD structure
613 */
614xmlDtdPtr
615xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
616 const xmlChar *ExternalID, const xmlChar *SystemID) {
617 xmlDtdPtr cur;
618
619 if ((doc != NULL) && (doc->extSubset != NULL)) {
620#ifdef DEBUG_TREE
621 xmlGenericError(xmlGenericErrorContext,
622 "xmlNewDtd(%s): document %s already have a DTD %s\n",
623 /* !!! */ (char *) name, doc->name,
624 /* !!! */ (char *)doc->extSubset->name);
625#endif
626 return(NULL);
627 }
628
629 /*
630 * Allocate a new DTD and fill the fields.
631 */
632 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
633 if (cur == NULL) {
634 xmlGenericError(xmlGenericErrorContext,
635 "xmlNewDtd : malloc failed\n");
636 return(NULL);
637 }
638 memset(cur, 0 , sizeof(xmlDtd));
639 cur->type = XML_DTD_NODE;
640
641 if (name != NULL)
642 cur->name = xmlStrdup(name);
643 if (ExternalID != NULL)
644 cur->ExternalID = xmlStrdup(ExternalID);
645 if (SystemID != NULL)
646 cur->SystemID = xmlStrdup(SystemID);
647 if (doc != NULL)
648 doc->extSubset = cur;
649 cur->doc = doc;
650
Daniel Veillard5335dc52003-01-01 20:59:38 +0000651 if (xmlRegisterNodeDefaultValue)
652 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000653 return(cur);
654}
655
656/**
657 * xmlGetIntSubset:
658 * @doc: the document pointer
659 *
660 * Get the internal subset of a document
661 * Returns a pointer to the DTD structure or NULL if not found
662 */
663
664xmlDtdPtr
665xmlGetIntSubset(xmlDocPtr doc) {
666 xmlNodePtr cur;
667
668 if (doc == NULL)
669 return(NULL);
670 cur = doc->children;
671 while (cur != NULL) {
672 if (cur->type == XML_DTD_NODE)
673 return((xmlDtdPtr) cur);
674 cur = cur->next;
675 }
676 return((xmlDtdPtr) doc->intSubset);
677}
678
679/**
680 * xmlCreateIntSubset:
681 * @doc: the document pointer
682 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000683 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000684 * @SystemID: the system ID
685 *
686 * Create the internal subset of a document
687 * Returns a pointer to the new DTD structure
688 */
689xmlDtdPtr
690xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
691 const xmlChar *ExternalID, const xmlChar *SystemID) {
692 xmlDtdPtr cur;
693
694 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
695#ifdef DEBUG_TREE
696 xmlGenericError(xmlGenericErrorContext,
697
698 "xmlCreateIntSubset(): document %s already have an internal subset\n",
699 doc->name);
700#endif
701 return(NULL);
702 }
703
704 /*
705 * Allocate a new DTD and fill the fields.
706 */
707 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
708 if (cur == NULL) {
709 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000710 "xmlCreateIntSubset : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000711 return(NULL);
712 }
713 memset(cur, 0, sizeof(xmlDtd));
714 cur->type = XML_DTD_NODE;
715
716 if (name != NULL)
717 cur->name = xmlStrdup(name);
718 if (ExternalID != NULL)
719 cur->ExternalID = xmlStrdup(ExternalID);
720 if (SystemID != NULL)
721 cur->SystemID = xmlStrdup(SystemID);
722 if (doc != NULL) {
723 doc->intSubset = cur;
724 cur->parent = doc;
725 cur->doc = doc;
726 if (doc->children == NULL) {
727 doc->children = (xmlNodePtr) cur;
728 doc->last = (xmlNodePtr) cur;
729 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000730 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000731 xmlNodePtr prev;
732
Owen Taylor3473f882001-02-23 17:55:21 +0000733 prev = doc->children;
734 prev->prev = (xmlNodePtr) cur;
735 cur->next = prev;
736 doc->children = (xmlNodePtr) cur;
737 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000738 xmlNodePtr next;
739
740 next = doc->children;
741 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
742 next = next->next;
743 if (next == NULL) {
744 cur->prev = doc->last;
745 cur->prev->next = (xmlNodePtr) cur;
746 cur->next = NULL;
747 doc->last = (xmlNodePtr) cur;
748 } else {
749 cur->next = next;
750 cur->prev = next->prev;
751 if (cur->prev == NULL)
752 doc->children = (xmlNodePtr) cur;
753 else
754 cur->prev->next = (xmlNodePtr) cur;
755 next->prev = (xmlNodePtr) cur;
756 }
Owen Taylor3473f882001-02-23 17:55:21 +0000757 }
758 }
759 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000760
761 if (xmlRegisterNodeDefaultValue)
762 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000763 return(cur);
764}
765
766/**
767 * xmlFreeDtd:
768 * @cur: the DTD structure to free up
769 *
770 * Free a DTD structure.
771 */
772void
773xmlFreeDtd(xmlDtdPtr cur) {
774 if (cur == NULL) {
775#ifdef DEBUG_TREE
776 xmlGenericError(xmlGenericErrorContext,
777 "xmlFreeDtd : DTD == NULL\n");
778#endif
779 return;
780 }
Daniel Veillard5335dc52003-01-01 20:59:38 +0000781
782 if (xmlDeregisterNodeDefaultValue)
783 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
784
Owen Taylor3473f882001-02-23 17:55:21 +0000785 if (cur->children != NULL) {
786 xmlNodePtr next, c = cur->children;
787
788 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000789 * Cleanup all the DTD comments they are not in the DTD
Owen Taylor3473f882001-02-23 17:55:21 +0000790 * indexes.
791 */
792 while (c != NULL) {
793 next = c->next;
794 if (c->type == XML_COMMENT_NODE) {
795 xmlUnlinkNode(c);
796 xmlFreeNode(c);
797 }
798 c = next;
799 }
800 }
801 if (cur->name != NULL) xmlFree((char *) cur->name);
802 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
803 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
804 /* TODO !!! */
805 if (cur->notations != NULL)
806 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
807
808 if (cur->elements != NULL)
809 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
810 if (cur->attributes != NULL)
811 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
812 if (cur->entities != NULL)
813 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
814 if (cur->pentities != NULL)
815 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
816
Owen Taylor3473f882001-02-23 17:55:21 +0000817 xmlFree(cur);
818}
819
820/**
821 * xmlNewDoc:
822 * @version: xmlChar string giving the version of XML "1.0"
823 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000824 * Creates a new XML document
825 *
Owen Taylor3473f882001-02-23 17:55:21 +0000826 * Returns a new document
827 */
828xmlDocPtr
829xmlNewDoc(const xmlChar *version) {
830 xmlDocPtr cur;
831
832 if (version == NULL)
833 version = (const xmlChar *) "1.0";
834
835 /*
836 * Allocate a new document and fill the fields.
837 */
838 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
839 if (cur == NULL) {
840 xmlGenericError(xmlGenericErrorContext,
841 "xmlNewDoc : malloc failed\n");
842 return(NULL);
843 }
844 memset(cur, 0, sizeof(xmlDoc));
845 cur->type = XML_DOCUMENT_NODE;
846
847 cur->version = xmlStrdup(version);
848 cur->standalone = -1;
849 cur->compression = -1; /* not initialized */
850 cur->doc = cur;
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000851 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +0000852
853 if (xmlRegisterNodeDefaultValue)
854 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000855 return(cur);
856}
857
858/**
859 * xmlFreeDoc:
860 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +0000861 *
862 * Free up all the structures used by a document, tree included.
863 */
864void
865xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +0000866 xmlDtdPtr extSubset, intSubset;
867
Owen Taylor3473f882001-02-23 17:55:21 +0000868 if (cur == NULL) {
869#ifdef DEBUG_TREE
870 xmlGenericError(xmlGenericErrorContext,
871 "xmlFreeDoc : document == NULL\n");
872#endif
873 return;
874 }
Daniel Veillard5335dc52003-01-01 20:59:38 +0000875
876 if (xmlDeregisterNodeDefaultValue)
877 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
878
Daniel Veillard76d66f42001-05-16 21:05:17 +0000879 /*
880 * Do this before freeing the children list to avoid ID lookups
881 */
882 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
883 cur->ids = NULL;
884 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
885 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000886 extSubset = cur->extSubset;
887 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +0000888 if (intSubset == extSubset)
889 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000890 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000891 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000892 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000893 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000894 }
Daniel Veillarda9142e72001-06-19 11:07:54 +0000895 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000896 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000897 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000898 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000899 }
900
901 if (cur->children != NULL) xmlFreeNodeList(cur->children);
902
Owen Taylor3473f882001-02-23 17:55:21 +0000903 if (cur->version != NULL) xmlFree((char *) cur->version);
904 if (cur->name != NULL) xmlFree((char *) cur->name);
905 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Owen Taylor3473f882001-02-23 17:55:21 +0000906 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +0000907 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Owen Taylor3473f882001-02-23 17:55:21 +0000908 xmlFree(cur);
909}
910
911/**
912 * xmlStringLenGetNodeList:
913 * @doc: the document
914 * @value: the value of the text
915 * @len: the length of the string value
916 *
917 * Parse the value string and build the node list associated. Should
918 * produce a flat tree with only TEXTs and ENTITY_REFs.
919 * Returns a pointer to the first child
920 */
921xmlNodePtr
922xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
923 xmlNodePtr ret = NULL, last = NULL;
924 xmlNodePtr node;
925 xmlChar *val;
926 const xmlChar *cur = value;
927 const xmlChar *q;
928 xmlEntityPtr ent;
929
930 if (value == NULL) return(NULL);
931
932 q = cur;
933 while ((*cur != 0) && (cur - value < len)) {
934 if (*cur == '&') {
935 /*
936 * Save the current text.
937 */
938 if (cur != q) {
939 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
940 xmlNodeAddContentLen(last, q, cur - q);
941 } else {
942 node = xmlNewDocTextLen(doc, q, cur - q);
943 if (node == NULL) return(ret);
944 if (last == NULL)
945 last = ret = node;
946 else {
947 last->next = node;
948 node->prev = last;
949 last = node;
950 }
951 }
952 }
953 /*
954 * Read the entity string
955 */
956 cur++;
957 q = cur;
958 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
959 if ((*cur == 0) || (cur - value >= len)) {
960#ifdef DEBUG_TREE
961 xmlGenericError(xmlGenericErrorContext,
962 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
963#endif
964 return(ret);
965 }
966 if (cur != q) {
967 /*
968 * Predefined entities don't generate nodes
969 */
970 val = xmlStrndup(q, cur - q);
971 ent = xmlGetDocEntity(doc, val);
972 if ((ent != NULL) &&
973 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
974 if (last == NULL) {
975 node = xmlNewDocText(doc, ent->content);
976 last = ret = node;
977 } else
978 xmlNodeAddContent(last, ent->content);
979
980 } else {
981 /*
982 * Create a new REFERENCE_REF node
983 */
984 node = xmlNewReference(doc, val);
985 if (node == NULL) {
986 if (val != NULL) xmlFree(val);
987 return(ret);
988 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +0000989 else if ((ent != NULL) && (ent->children == NULL)) {
990 xmlNodePtr tmp;
991
992 ent->children =
993 xmlStringGetNodeList(doc, (const xmlChar*)node->content);
994 tmp = ent->children;
995 while (tmp) {
996 tmp->parent = (xmlNodePtr)ent;
997 tmp = tmp->next;
998 }
999 }
Owen Taylor3473f882001-02-23 17:55:21 +00001000 if (last == NULL)
1001 last = ret = node;
1002 else {
1003 last->next = node;
1004 node->prev = last;
1005 last = node;
1006 }
1007 }
1008 xmlFree(val);
1009 }
1010 cur++;
1011 q = cur;
1012 } else
1013 cur++;
1014 }
1015 if (cur != q) {
1016 /*
1017 * Handle the last piece of text.
1018 */
1019 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1020 xmlNodeAddContentLen(last, q, cur - q);
1021 } else {
1022 node = xmlNewDocTextLen(doc, q, cur - q);
1023 if (node == NULL) return(ret);
1024 if (last == NULL)
1025 last = ret = node;
1026 else {
1027 last->next = node;
1028 node->prev = last;
1029 last = node;
1030 }
1031 }
1032 }
1033 return(ret);
1034}
1035
1036/**
1037 * xmlStringGetNodeList:
1038 * @doc: the document
1039 * @value: the value of the attribute
1040 *
1041 * Parse the value string and build the node list associated. Should
1042 * produce a flat tree with only TEXTs and ENTITY_REFs.
1043 * Returns a pointer to the first child
1044 */
1045xmlNodePtr
1046xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1047 xmlNodePtr ret = NULL, last = NULL;
1048 xmlNodePtr node;
1049 xmlChar *val;
1050 const xmlChar *cur = value;
1051 const xmlChar *q;
1052 xmlEntityPtr ent;
1053
1054 if (value == NULL) return(NULL);
1055
1056 q = cur;
1057 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001058 if (cur[0] == '&') {
1059 int charval = 0;
1060 xmlChar tmp;
1061
Owen Taylor3473f882001-02-23 17:55:21 +00001062 /*
1063 * Save the current text.
1064 */
1065 if (cur != q) {
1066 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1067 xmlNodeAddContentLen(last, q, cur - q);
1068 } else {
1069 node = xmlNewDocTextLen(doc, q, cur - q);
1070 if (node == NULL) return(ret);
1071 if (last == NULL)
1072 last = ret = node;
1073 else {
1074 last->next = node;
1075 node->prev = last;
1076 last = node;
1077 }
1078 }
1079 }
Owen Taylor3473f882001-02-23 17:55:21 +00001080 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001081 if ((cur[1] == '#') && (cur[2] == 'x')) {
1082 cur += 3;
1083 tmp = *cur;
1084 while (tmp != ';') { /* Non input consuming loop */
1085 if ((tmp >= '0') && (tmp <= '9'))
1086 charval = charval * 16 + (tmp - '0');
1087 else if ((tmp >= 'a') && (tmp <= 'f'))
1088 charval = charval * 16 + (tmp - 'a') + 10;
1089 else if ((tmp >= 'A') && (tmp <= 'F'))
1090 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001091 else {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001092 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001093 "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001094 charval = 0;
1095 break;
1096 }
1097 cur++;
1098 tmp = *cur;
1099 }
1100 if (tmp == ';')
1101 cur++;
1102 q = cur;
1103 } else if (cur[1] == '#') {
1104 cur += 2;
1105 tmp = *cur;
1106 while (tmp != ';') { /* Non input consuming loops */
1107 if ((tmp >= '0') && (tmp <= '9'))
1108 charval = charval * 10 + (tmp - '0');
1109 else {
1110 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001111 "xmlStringGetNodeList: invalid decimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001112 charval = 0;
1113 break;
1114 }
1115 cur++;
1116 tmp = *cur;
1117 }
1118 if (tmp == ';')
1119 cur++;
1120 q = cur;
1121 } else {
1122 /*
1123 * Read the entity string
1124 */
1125 cur++;
1126 q = cur;
1127 while ((*cur != 0) && (*cur != ';')) cur++;
1128 if (*cur == 0) {
1129#ifdef DEBUG_TREE
1130 xmlGenericError(xmlGenericErrorContext,
1131 "xmlStringGetNodeList: unterminated entity %30s\n", q);
1132#endif
1133 return(ret);
1134 }
1135 if (cur != q) {
1136 /*
1137 * Predefined entities don't generate nodes
1138 */
1139 val = xmlStrndup(q, cur - q);
1140 ent = xmlGetDocEntity(doc, val);
1141 if ((ent != NULL) &&
1142 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1143 if (last == NULL) {
1144 node = xmlNewDocText(doc, ent->content);
1145 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001146 } else if (last->type != XML_TEXT_NODE) {
1147 node = xmlNewDocText(doc, ent->content);
1148 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001149 } else
1150 xmlNodeAddContent(last, ent->content);
1151
1152 } else {
1153 /*
1154 * Create a new REFERENCE_REF node
1155 */
1156 node = xmlNewReference(doc, val);
1157 if (node == NULL) {
1158 if (val != NULL) xmlFree(val);
1159 return(ret);
1160 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001161 else if ((ent != NULL) && (ent->children == NULL)) {
1162 xmlNodePtr temp;
1163
1164 ent->children = xmlStringGetNodeList(doc,
1165 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001166 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001167 temp = ent->children;
1168 while (temp) {
1169 temp->parent = (xmlNodePtr)ent;
1170 temp = temp->next;
1171 }
1172 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001173 if (last == NULL) {
1174 last = ret = node;
1175 } else {
1176 last = xmlAddNextSibling(last, node);
1177 }
1178 }
1179 xmlFree(val);
1180 }
1181 cur++;
1182 q = cur;
1183 }
1184 if (charval != 0) {
1185 xmlChar buf[10];
1186 int len;
1187
1188 len = xmlCopyCharMultiByte(buf, charval);
1189 buf[len] = 0;
1190 node = xmlNewDocText(doc, buf);
1191 if (node != NULL) {
1192 if (last == NULL) {
1193 last = ret = node;
1194 } else {
1195 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001196 }
1197 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001198
1199 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001200 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001201 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001202 cur++;
1203 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001204 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001205 /*
1206 * Handle the last piece of text.
1207 */
1208 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1209 xmlNodeAddContentLen(last, q, cur - q);
1210 } else {
1211 node = xmlNewDocTextLen(doc, q, cur - q);
1212 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001213 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001214 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001215 } else {
1216 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001217 }
1218 }
1219 }
1220 return(ret);
1221}
1222
1223/**
1224 * xmlNodeListGetString:
1225 * @doc: the document
1226 * @list: a Node list
1227 * @inLine: should we replace entity contents or show their external form
1228 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001229 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001230 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001231 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001232 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001233 */
1234xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001235xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1236{
Owen Taylor3473f882001-02-23 17:55:21 +00001237 xmlNodePtr node = list;
1238 xmlChar *ret = NULL;
1239 xmlEntityPtr ent;
1240
Daniel Veillard7646b182002-04-20 06:41:40 +00001241 if (list == NULL)
1242 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001243
1244 while (node != NULL) {
1245 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001246 (node->type == XML_CDATA_SECTION_NODE)) {
1247 if (inLine) {
1248 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001249 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001250 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001251
Daniel Veillard7646b182002-04-20 06:41:40 +00001252 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1253 if (buffer != NULL) {
1254 ret = xmlStrcat(ret, buffer);
1255 xmlFree(buffer);
1256 }
1257 }
1258 } else if (node->type == XML_ENTITY_REF_NODE) {
1259 if (inLine) {
1260 ent = xmlGetDocEntity(doc, node->name);
1261 if (ent != NULL) {
1262 xmlChar *buffer;
1263
1264 /* an entity content can be any "well balanced chunk",
1265 * i.e. the result of the content [43] production:
1266 * http://www.w3.org/TR/REC-xml#NT-content.
1267 * So it can contain text, CDATA section or nested
1268 * entity reference nodes (among others).
1269 * -> we recursive call xmlNodeListGetString()
1270 * which handles these types */
1271 buffer = xmlNodeListGetString(doc, ent->children, 1);
1272 if (buffer != NULL) {
1273 ret = xmlStrcat(ret, buffer);
1274 xmlFree(buffer);
1275 }
1276 } else {
1277 ret = xmlStrcat(ret, node->content);
1278 }
1279 } else {
1280 xmlChar buf[2];
1281
1282 buf[0] = '&';
1283 buf[1] = 0;
1284 ret = xmlStrncat(ret, buf, 1);
1285 ret = xmlStrcat(ret, node->name);
1286 buf[0] = ';';
1287 buf[1] = 0;
1288 ret = xmlStrncat(ret, buf, 1);
1289 }
1290 }
1291#if 0
1292 else {
1293 xmlGenericError(xmlGenericErrorContext,
1294 "xmlGetNodeListString : invalid node type %d\n",
1295 node->type);
1296 }
1297#endif
1298 node = node->next;
1299 }
1300 return (ret);
1301}
Owen Taylor3473f882001-02-23 17:55:21 +00001302/**
1303 * xmlNodeListGetRawString:
1304 * @doc: the document
1305 * @list: a Node list
1306 * @inLine: should we replace entity contents or show their external form
1307 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001308 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001309 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1310 * this function doesn't do any character encoding handling.
1311 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001312 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001313 */
1314xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001315xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1316{
Owen Taylor3473f882001-02-23 17:55:21 +00001317 xmlNodePtr node = list;
1318 xmlChar *ret = NULL;
1319 xmlEntityPtr ent;
1320
Daniel Veillard7646b182002-04-20 06:41:40 +00001321 if (list == NULL)
1322 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001323
1324 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001325 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001326 (node->type == XML_CDATA_SECTION_NODE)) {
1327 if (inLine) {
1328 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001329 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001330 xmlChar *buffer;
1331
1332 buffer = xmlEncodeSpecialChars(doc, node->content);
1333 if (buffer != NULL) {
1334 ret = xmlStrcat(ret, buffer);
1335 xmlFree(buffer);
1336 }
1337 }
1338 } else if (node->type == XML_ENTITY_REF_NODE) {
1339 if (inLine) {
1340 ent = xmlGetDocEntity(doc, node->name);
1341 if (ent != NULL) {
1342 xmlChar *buffer;
1343
1344 /* an entity content can be any "well balanced chunk",
1345 * i.e. the result of the content [43] production:
1346 * http://www.w3.org/TR/REC-xml#NT-content.
1347 * So it can contain text, CDATA section or nested
1348 * entity reference nodes (among others).
1349 * -> we recursive call xmlNodeListGetRawString()
1350 * which handles these types */
1351 buffer =
1352 xmlNodeListGetRawString(doc, ent->children, 1);
1353 if (buffer != NULL) {
1354 ret = xmlStrcat(ret, buffer);
1355 xmlFree(buffer);
1356 }
1357 } else {
1358 ret = xmlStrcat(ret, node->content);
1359 }
1360 } else {
1361 xmlChar buf[2];
1362
1363 buf[0] = '&';
1364 buf[1] = 0;
1365 ret = xmlStrncat(ret, buf, 1);
1366 ret = xmlStrcat(ret, node->name);
1367 buf[0] = ';';
1368 buf[1] = 0;
1369 ret = xmlStrncat(ret, buf, 1);
1370 }
1371 }
Owen Taylor3473f882001-02-23 17:55:21 +00001372#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001373 else {
1374 xmlGenericError(xmlGenericErrorContext,
1375 "xmlGetNodeListString : invalid node type %d\n",
1376 node->type);
1377 }
Owen Taylor3473f882001-02-23 17:55:21 +00001378#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001379 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001380 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001381 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001382}
1383
1384/**
1385 * xmlNewProp:
1386 * @node: the holding node
1387 * @name: the name of the attribute
1388 * @value: the value of the attribute
1389 *
1390 * Create a new property carried by a node.
1391 * Returns a pointer to the attribute
1392 */
1393xmlAttrPtr
1394xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1395 xmlAttrPtr cur;
1396 xmlDocPtr doc = NULL;
1397
1398 if (name == NULL) {
1399#ifdef DEBUG_TREE
1400 xmlGenericError(xmlGenericErrorContext,
1401 "xmlNewProp : name == NULL\n");
1402#endif
1403 return(NULL);
1404 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00001405 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
1406 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001407
1408 /*
1409 * Allocate a new property and fill the fields.
1410 */
1411 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1412 if (cur == NULL) {
1413 xmlGenericError(xmlGenericErrorContext,
1414 "xmlNewProp : malloc failed\n");
1415 return(NULL);
1416 }
1417 memset(cur, 0, sizeof(xmlAttr));
1418 cur->type = XML_ATTRIBUTE_NODE;
1419
1420 cur->parent = node;
1421 if (node != NULL) {
1422 doc = node->doc;
1423 cur->doc = doc;
1424 }
1425 cur->name = xmlStrdup(name);
1426 if (value != NULL) {
1427 xmlChar *buffer;
1428 xmlNodePtr tmp;
1429
1430 buffer = xmlEncodeEntitiesReentrant(doc, value);
1431 cur->children = xmlStringGetNodeList(doc, buffer);
1432 cur->last = NULL;
1433 tmp = cur->children;
1434 while (tmp != NULL) {
1435 tmp->parent = (xmlNodePtr) cur;
1436 tmp->doc = doc;
1437 if (tmp->next == NULL)
1438 cur->last = tmp;
1439 tmp = tmp->next;
1440 }
1441 xmlFree(buffer);
1442 }
1443
1444 /*
1445 * Add it at the end to preserve parsing order ...
1446 */
1447 if (node != NULL) {
1448 if (node->properties == NULL) {
1449 node->properties = cur;
1450 } else {
1451 xmlAttrPtr prev = node->properties;
1452
1453 while (prev->next != NULL) prev = prev->next;
1454 prev->next = cur;
1455 cur->prev = prev;
1456 }
1457 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001458
1459 if (xmlRegisterNodeDefaultValue)
1460 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001461 return(cur);
1462}
1463
1464/**
1465 * xmlNewNsProp:
1466 * @node: the holding node
1467 * @ns: the namespace
1468 * @name: the name of the attribute
1469 * @value: the value of the attribute
1470 *
1471 * Create a new property tagged with a namespace and carried by a node.
1472 * Returns a pointer to the attribute
1473 */
1474xmlAttrPtr
1475xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1476 const xmlChar *value) {
1477 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001478 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001479
1480 if (name == NULL) {
1481#ifdef DEBUG_TREE
1482 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001483 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001484#endif
1485 return(NULL);
1486 }
1487
1488 /*
1489 * Allocate a new property and fill the fields.
1490 */
1491 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1492 if (cur == NULL) {
1493 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001494 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001495 return(NULL);
1496 }
1497 memset(cur, 0, sizeof(xmlAttr));
1498 cur->type = XML_ATTRIBUTE_NODE;
1499
1500 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001501 if (node != NULL) {
1502 doc = node->doc;
1503 cur->doc = doc;
1504 }
Owen Taylor3473f882001-02-23 17:55:21 +00001505 cur->ns = ns;
1506 cur->name = xmlStrdup(name);
1507 if (value != NULL) {
1508 xmlChar *buffer;
1509 xmlNodePtr tmp;
1510
Daniel Veillarda682b212001-06-07 19:59:42 +00001511 buffer = xmlEncodeEntitiesReentrant(doc, value);
1512 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001513 cur->last = NULL;
1514 tmp = cur->children;
1515 while (tmp != NULL) {
1516 tmp->parent = (xmlNodePtr) cur;
1517 if (tmp->next == NULL)
1518 cur->last = tmp;
1519 tmp = tmp->next;
1520 }
1521 xmlFree(buffer);
1522 }
1523
1524 /*
1525 * Add it at the end to preserve parsing order ...
1526 */
1527 if (node != NULL) {
1528 if (node->properties == NULL) {
1529 node->properties = cur;
1530 } else {
1531 xmlAttrPtr prev = node->properties;
1532
1533 while (prev->next != NULL) prev = prev->next;
1534 prev->next = cur;
1535 cur->prev = prev;
1536 }
1537 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001538
1539 if (xmlRegisterNodeDefaultValue)
1540 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001541 return(cur);
1542}
1543
1544/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001545 * xmlNewNsPropEatName:
1546 * @node: the holding node
1547 * @ns: the namespace
1548 * @name: the name of the attribute
1549 * @value: the value of the attribute
1550 *
1551 * Create a new property tagged with a namespace and carried by a node.
1552 * Returns a pointer to the attribute
1553 */
1554xmlAttrPtr
1555xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1556 const xmlChar *value) {
1557 xmlAttrPtr cur;
1558 xmlDocPtr doc = NULL;
1559
1560 if (name == NULL) {
1561#ifdef DEBUG_TREE
1562 xmlGenericError(xmlGenericErrorContext,
1563 "xmlNewNsPropEatName : name == NULL\n");
1564#endif
1565 return(NULL);
1566 }
1567
1568 /*
1569 * Allocate a new property and fill the fields.
1570 */
1571 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1572 if (cur == NULL) {
1573 xmlGenericError(xmlGenericErrorContext,
1574 "xmlNewNsPropEatName : malloc failed\n");
1575 return(NULL);
1576 }
1577 memset(cur, 0, sizeof(xmlAttr));
1578 cur->type = XML_ATTRIBUTE_NODE;
1579
1580 cur->parent = node;
1581 if (node != NULL) {
1582 doc = node->doc;
1583 cur->doc = doc;
1584 }
1585 cur->ns = ns;
1586 cur->name = name;
1587 if (value != NULL) {
1588 xmlChar *buffer;
1589 xmlNodePtr tmp;
1590
1591 buffer = xmlEncodeEntitiesReentrant(doc, value);
1592 cur->children = xmlStringGetNodeList(doc, buffer);
1593 cur->last = NULL;
1594 tmp = cur->children;
1595 while (tmp != NULL) {
1596 tmp->parent = (xmlNodePtr) cur;
1597 if (tmp->next == NULL)
1598 cur->last = tmp;
1599 tmp = tmp->next;
1600 }
1601 xmlFree(buffer);
1602 }
1603
1604 /*
1605 * Add it at the end to preserve parsing order ...
1606 */
1607 if (node != NULL) {
1608 if (node->properties == NULL) {
1609 node->properties = cur;
1610 } else {
1611 xmlAttrPtr prev = node->properties;
1612
1613 while (prev->next != NULL) prev = prev->next;
1614 prev->next = cur;
1615 cur->prev = prev;
1616 }
1617 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001618
1619 if (xmlRegisterNodeDefaultValue)
1620 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001621 return(cur);
1622}
1623
1624/**
Owen Taylor3473f882001-02-23 17:55:21 +00001625 * xmlNewDocProp:
1626 * @doc: the document
1627 * @name: the name of the attribute
1628 * @value: the value of the attribute
1629 *
1630 * Create a new property carried by a document.
1631 * Returns a pointer to the attribute
1632 */
1633xmlAttrPtr
1634xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1635 xmlAttrPtr cur;
1636
1637 if (name == NULL) {
1638#ifdef DEBUG_TREE
1639 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001640 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001641#endif
1642 return(NULL);
1643 }
1644
1645 /*
1646 * Allocate a new property and fill the fields.
1647 */
1648 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1649 if (cur == NULL) {
1650 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001651 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001652 return(NULL);
1653 }
1654 memset(cur, 0, sizeof(xmlAttr));
1655 cur->type = XML_ATTRIBUTE_NODE;
1656
1657 cur->name = xmlStrdup(name);
1658 cur->doc = doc;
1659 if (value != NULL) {
1660 xmlNodePtr tmp;
1661
1662 cur->children = xmlStringGetNodeList(doc, value);
1663 cur->last = NULL;
1664
1665 tmp = cur->children;
1666 while (tmp != NULL) {
1667 tmp->parent = (xmlNodePtr) cur;
1668 if (tmp->next == NULL)
1669 cur->last = tmp;
1670 tmp = tmp->next;
1671 }
1672 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001673
1674 if (xmlRegisterNodeDefaultValue)
1675 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001676 return(cur);
1677}
1678
1679/**
1680 * xmlFreePropList:
1681 * @cur: the first property in the list
1682 *
1683 * Free a property and all its siblings, all the children are freed too.
1684 */
1685void
1686xmlFreePropList(xmlAttrPtr cur) {
1687 xmlAttrPtr next;
1688 if (cur == NULL) {
1689#ifdef DEBUG_TREE
1690 xmlGenericError(xmlGenericErrorContext,
1691 "xmlFreePropList : property == NULL\n");
1692#endif
1693 return;
1694 }
1695 while (cur != NULL) {
1696 next = cur->next;
1697 xmlFreeProp(cur);
1698 cur = next;
1699 }
1700}
1701
1702/**
1703 * xmlFreeProp:
1704 * @cur: an attribute
1705 *
1706 * Free one attribute, all the content is freed too
1707 */
1708void
1709xmlFreeProp(xmlAttrPtr cur) {
1710 if (cur == NULL) {
1711#ifdef DEBUG_TREE
1712 xmlGenericError(xmlGenericErrorContext,
1713 "xmlFreeProp : property == NULL\n");
1714#endif
1715 return;
1716 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001717
1718 if (xmlDeregisterNodeDefaultValue)
1719 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1720
Owen Taylor3473f882001-02-23 17:55:21 +00001721 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001722 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1723 ((cur->parent->doc->intSubset != NULL) ||
1724 (cur->parent->doc->extSubset != NULL))) {
1725 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1726 xmlRemoveID(cur->parent->doc, cur);
1727 }
Owen Taylor3473f882001-02-23 17:55:21 +00001728 if (cur->name != NULL) xmlFree((char *) cur->name);
1729 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001730 xmlFree(cur);
1731}
1732
1733/**
1734 * xmlRemoveProp:
1735 * @cur: an attribute
1736 *
1737 * Unlink and free one attribute, all the content is freed too
1738 * Note this doesn't work for namespace definition attributes
1739 *
1740 * Returns 0 if success and -1 in case of error.
1741 */
1742int
1743xmlRemoveProp(xmlAttrPtr cur) {
1744 xmlAttrPtr tmp;
1745 if (cur == NULL) {
1746#ifdef DEBUG_TREE
1747 xmlGenericError(xmlGenericErrorContext,
1748 "xmlRemoveProp : cur == NULL\n");
1749#endif
1750 return(-1);
1751 }
1752 if (cur->parent == NULL) {
1753#ifdef DEBUG_TREE
1754 xmlGenericError(xmlGenericErrorContext,
1755 "xmlRemoveProp : cur->parent == NULL\n");
1756#endif
1757 return(-1);
1758 }
1759 tmp = cur->parent->properties;
1760 if (tmp == cur) {
1761 cur->parent->properties = cur->next;
1762 xmlFreeProp(cur);
1763 return(0);
1764 }
1765 while (tmp != NULL) {
1766 if (tmp->next == cur) {
1767 tmp->next = cur->next;
1768 if (tmp->next != NULL)
1769 tmp->next->prev = tmp;
1770 xmlFreeProp(cur);
1771 return(0);
1772 }
1773 tmp = tmp->next;
1774 }
1775#ifdef DEBUG_TREE
1776 xmlGenericError(xmlGenericErrorContext,
1777 "xmlRemoveProp : attribute not owned by its node\n");
1778#endif
1779 return(-1);
1780}
1781
1782/**
1783 * xmlNewPI:
1784 * @name: the processing instruction name
1785 * @content: the PI content
1786 *
1787 * Creation of a processing instruction element.
1788 * Returns a pointer to the new node object.
1789 */
1790xmlNodePtr
1791xmlNewPI(const xmlChar *name, const xmlChar *content) {
1792 xmlNodePtr cur;
1793
1794 if (name == NULL) {
1795#ifdef DEBUG_TREE
1796 xmlGenericError(xmlGenericErrorContext,
1797 "xmlNewPI : name == NULL\n");
1798#endif
1799 return(NULL);
1800 }
1801
1802 /*
1803 * Allocate a new node and fill the fields.
1804 */
1805 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1806 if (cur == NULL) {
1807 xmlGenericError(xmlGenericErrorContext,
1808 "xmlNewPI : malloc failed\n");
1809 return(NULL);
1810 }
1811 memset(cur, 0, sizeof(xmlNode));
1812 cur->type = XML_PI_NODE;
1813
1814 cur->name = xmlStrdup(name);
1815 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001816 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001817 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001818
1819 if (xmlRegisterNodeDefaultValue)
1820 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001821 return(cur);
1822}
1823
1824/**
1825 * xmlNewNode:
1826 * @ns: namespace if any
1827 * @name: the node name
1828 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001829 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001830 *
1831 * Returns a pointer to the new node object.
1832 */
1833xmlNodePtr
1834xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1835 xmlNodePtr cur;
1836
1837 if (name == NULL) {
1838#ifdef DEBUG_TREE
1839 xmlGenericError(xmlGenericErrorContext,
1840 "xmlNewNode : name == NULL\n");
1841#endif
1842 return(NULL);
1843 }
1844
1845 /*
1846 * Allocate a new node and fill the fields.
1847 */
1848 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1849 if (cur == NULL) {
1850 xmlGenericError(xmlGenericErrorContext,
1851 "xmlNewNode : malloc failed\n");
1852 return(NULL);
1853 }
1854 memset(cur, 0, sizeof(xmlNode));
1855 cur->type = XML_ELEMENT_NODE;
1856
1857 cur->name = xmlStrdup(name);
1858 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001859
1860 if (xmlRegisterNodeDefaultValue)
1861 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001862 return(cur);
1863}
1864
1865/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001866 * xmlNewNodeEatName:
1867 * @ns: namespace if any
1868 * @name: the node name
1869 *
1870 * Creation of a new node element. @ns is optional (NULL).
1871 *
1872 * Returns a pointer to the new node object.
1873 */
1874xmlNodePtr
1875xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
1876 xmlNodePtr cur;
1877
1878 if (name == NULL) {
1879#ifdef DEBUG_TREE
1880 xmlGenericError(xmlGenericErrorContext,
1881 "xmlNewNode : name == NULL\n");
1882#endif
1883 return(NULL);
1884 }
1885
1886 /*
1887 * Allocate a new node and fill the fields.
1888 */
1889 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1890 if (cur == NULL) {
1891 xmlGenericError(xmlGenericErrorContext,
1892 "xmlNewNode : malloc failed\n");
1893 return(NULL);
1894 }
1895 memset(cur, 0, sizeof(xmlNode));
1896 cur->type = XML_ELEMENT_NODE;
1897
1898 cur->name = name;
1899 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001900
1901 if (xmlRegisterNodeDefaultValue)
1902 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001903 return(cur);
1904}
1905
1906/**
Owen Taylor3473f882001-02-23 17:55:21 +00001907 * xmlNewDocNode:
1908 * @doc: the document
1909 * @ns: namespace if any
1910 * @name: the node name
1911 * @content: the XML text content if any
1912 *
1913 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001914 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001915 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1916 * references, but XML special chars need to be escaped first by using
1917 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1918 * need entities support.
1919 *
1920 * Returns a pointer to the new node object.
1921 */
1922xmlNodePtr
1923xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1924 const xmlChar *name, const xmlChar *content) {
1925 xmlNodePtr cur;
1926
1927 cur = xmlNewNode(ns, name);
1928 if (cur != NULL) {
1929 cur->doc = doc;
1930 if (content != NULL) {
1931 cur->children = xmlStringGetNodeList(doc, content);
1932 UPDATE_LAST_CHILD_AND_PARENT(cur)
1933 }
1934 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001935
Owen Taylor3473f882001-02-23 17:55:21 +00001936 return(cur);
1937}
1938
Daniel Veillard46de64e2002-05-29 08:21:33 +00001939/**
1940 * xmlNewDocNodeEatName:
1941 * @doc: the document
1942 * @ns: namespace if any
1943 * @name: the node name
1944 * @content: the XML text content if any
1945 *
1946 * Creation of a new node element within a document. @ns and @content
1947 * are optional (NULL).
1948 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1949 * references, but XML special chars need to be escaped first by using
1950 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1951 * need entities support.
1952 *
1953 * Returns a pointer to the new node object.
1954 */
1955xmlNodePtr
1956xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
1957 xmlChar *name, const xmlChar *content) {
1958 xmlNodePtr cur;
1959
1960 cur = xmlNewNodeEatName(ns, name);
1961 if (cur != NULL) {
1962 cur->doc = doc;
1963 if (content != NULL) {
1964 cur->children = xmlStringGetNodeList(doc, content);
1965 UPDATE_LAST_CHILD_AND_PARENT(cur)
1966 }
1967 }
1968 return(cur);
1969}
1970
Owen Taylor3473f882001-02-23 17:55:21 +00001971
1972/**
1973 * xmlNewDocRawNode:
1974 * @doc: the document
1975 * @ns: namespace if any
1976 * @name: the node name
1977 * @content: the text content if any
1978 *
1979 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001980 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001981 *
1982 * Returns a pointer to the new node object.
1983 */
1984xmlNodePtr
1985xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1986 const xmlChar *name, const xmlChar *content) {
1987 xmlNodePtr cur;
1988
1989 cur = xmlNewNode(ns, name);
1990 if (cur != NULL) {
1991 cur->doc = doc;
1992 if (content != NULL) {
1993 cur->children = xmlNewDocText(doc, content);
1994 UPDATE_LAST_CHILD_AND_PARENT(cur)
1995 }
1996 }
1997 return(cur);
1998}
1999
2000/**
2001 * xmlNewDocFragment:
2002 * @doc: the document owning the fragment
2003 *
2004 * Creation of a new Fragment node.
2005 * Returns a pointer to the new node object.
2006 */
2007xmlNodePtr
2008xmlNewDocFragment(xmlDocPtr doc) {
2009 xmlNodePtr cur;
2010
2011 /*
2012 * Allocate a new DocumentFragment node and fill the fields.
2013 */
2014 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2015 if (cur == NULL) {
2016 xmlGenericError(xmlGenericErrorContext,
2017 "xmlNewDocFragment : malloc failed\n");
2018 return(NULL);
2019 }
2020 memset(cur, 0, sizeof(xmlNode));
2021 cur->type = XML_DOCUMENT_FRAG_NODE;
2022
2023 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002024
2025 if (xmlRegisterNodeDefaultValue)
2026 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002027 return(cur);
2028}
2029
2030/**
2031 * xmlNewText:
2032 * @content: the text content
2033 *
2034 * Creation of a new text node.
2035 * Returns a pointer to the new node object.
2036 */
2037xmlNodePtr
2038xmlNewText(const xmlChar *content) {
2039 xmlNodePtr cur;
2040
2041 /*
2042 * Allocate a new node and fill the fields.
2043 */
2044 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2045 if (cur == NULL) {
2046 xmlGenericError(xmlGenericErrorContext,
2047 "xmlNewText : malloc failed\n");
2048 return(NULL);
2049 }
2050 memset(cur, 0, sizeof(xmlNode));
2051 cur->type = XML_TEXT_NODE;
2052
2053 cur->name = xmlStringText;
2054 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002055 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002056 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002057
2058 if (xmlRegisterNodeDefaultValue)
2059 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002060 return(cur);
2061}
2062
2063/**
2064 * xmlNewTextChild:
2065 * @parent: the parent node
2066 * @ns: a namespace if any
2067 * @name: the name of the child
2068 * @content: the text content of the child if any.
2069 *
2070 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002071 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002072 * a child TEXT node will be created containing the string content.
2073 *
2074 * Returns a pointer to the new node object.
2075 */
2076xmlNodePtr
2077xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2078 const xmlChar *name, const xmlChar *content) {
2079 xmlNodePtr cur, prev;
2080
2081 if (parent == NULL) {
2082#ifdef DEBUG_TREE
2083 xmlGenericError(xmlGenericErrorContext,
2084 "xmlNewTextChild : parent == NULL\n");
2085#endif
2086 return(NULL);
2087 }
2088
2089 if (name == NULL) {
2090#ifdef DEBUG_TREE
2091 xmlGenericError(xmlGenericErrorContext,
2092 "xmlNewTextChild : name == NULL\n");
2093#endif
2094 return(NULL);
2095 }
2096
2097 /*
2098 * Allocate a new node
2099 */
2100 if (ns == NULL)
2101 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2102 else
2103 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2104 if (cur == NULL) return(NULL);
2105
2106 /*
2107 * add the new element at the end of the children list.
2108 */
2109 cur->type = XML_ELEMENT_NODE;
2110 cur->parent = parent;
2111 cur->doc = parent->doc;
2112 if (parent->children == NULL) {
2113 parent->children = cur;
2114 parent->last = cur;
2115 } else {
2116 prev = parent->last;
2117 prev->next = cur;
2118 cur->prev = prev;
2119 parent->last = cur;
2120 }
2121
2122 return(cur);
2123}
2124
2125/**
2126 * xmlNewCharRef:
2127 * @doc: the document
2128 * @name: the char ref string, starting with # or "&# ... ;"
2129 *
2130 * Creation of a new character reference node.
2131 * Returns a pointer to the new node object.
2132 */
2133xmlNodePtr
2134xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2135 xmlNodePtr cur;
2136
2137 /*
2138 * Allocate a new node and fill the fields.
2139 */
2140 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2141 if (cur == NULL) {
2142 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002143 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002144 return(NULL);
2145 }
2146 memset(cur, 0, sizeof(xmlNode));
2147 cur->type = XML_ENTITY_REF_NODE;
2148
2149 cur->doc = doc;
2150 if (name[0] == '&') {
2151 int len;
2152 name++;
2153 len = xmlStrlen(name);
2154 if (name[len - 1] == ';')
2155 cur->name = xmlStrndup(name, len - 1);
2156 else
2157 cur->name = xmlStrndup(name, len);
2158 } else
2159 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002160
2161 if (xmlRegisterNodeDefaultValue)
2162 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002163 return(cur);
2164}
2165
2166/**
2167 * xmlNewReference:
2168 * @doc: the document
2169 * @name: the reference name, or the reference string with & and ;
2170 *
2171 * Creation of a new reference node.
2172 * Returns a pointer to the new node object.
2173 */
2174xmlNodePtr
2175xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2176 xmlNodePtr cur;
2177 xmlEntityPtr ent;
2178
2179 /*
2180 * Allocate a new node and fill the fields.
2181 */
2182 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2183 if (cur == NULL) {
2184 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002185 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002186 return(NULL);
2187 }
2188 memset(cur, 0, sizeof(xmlNode));
2189 cur->type = XML_ENTITY_REF_NODE;
2190
2191 cur->doc = doc;
2192 if (name[0] == '&') {
2193 int len;
2194 name++;
2195 len = xmlStrlen(name);
2196 if (name[len - 1] == ';')
2197 cur->name = xmlStrndup(name, len - 1);
2198 else
2199 cur->name = xmlStrndup(name, len);
2200 } else
2201 cur->name = xmlStrdup(name);
2202
2203 ent = xmlGetDocEntity(doc, cur->name);
2204 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002205 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002206 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002207 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002208 * updated. Not sure if this is 100% correct.
2209 * -George
2210 */
2211 cur->children = (xmlNodePtr) ent;
2212 cur->last = (xmlNodePtr) ent;
2213 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002214
2215 if (xmlRegisterNodeDefaultValue)
2216 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002217 return(cur);
2218}
2219
2220/**
2221 * xmlNewDocText:
2222 * @doc: the document
2223 * @content: the text content
2224 *
2225 * Creation of a new text node within a document.
2226 * Returns a pointer to the new node object.
2227 */
2228xmlNodePtr
2229xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2230 xmlNodePtr cur;
2231
2232 cur = xmlNewText(content);
2233 if (cur != NULL) cur->doc = doc;
2234 return(cur);
2235}
2236
2237/**
2238 * xmlNewTextLen:
2239 * @content: the text content
2240 * @len: the text len.
2241 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002242 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002243 * Returns a pointer to the new node object.
2244 */
2245xmlNodePtr
2246xmlNewTextLen(const xmlChar *content, int len) {
2247 xmlNodePtr cur;
2248
2249 /*
2250 * Allocate a new node and fill the fields.
2251 */
2252 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2253 if (cur == NULL) {
2254 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002255 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002256 return(NULL);
2257 }
2258 memset(cur, 0, sizeof(xmlNode));
2259 cur->type = XML_TEXT_NODE;
2260
2261 cur->name = xmlStringText;
2262 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002263 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002264 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002265
2266 if (xmlRegisterNodeDefaultValue)
2267 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002268 return(cur);
2269}
2270
2271/**
2272 * xmlNewDocTextLen:
2273 * @doc: the document
2274 * @content: the text content
2275 * @len: the text len.
2276 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002277 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002278 * text node pertain to a given document.
2279 * Returns a pointer to the new node object.
2280 */
2281xmlNodePtr
2282xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2283 xmlNodePtr cur;
2284
2285 cur = xmlNewTextLen(content, len);
2286 if (cur != NULL) cur->doc = doc;
2287 return(cur);
2288}
2289
2290/**
2291 * xmlNewComment:
2292 * @content: the comment content
2293 *
2294 * Creation of a new node containing a comment.
2295 * Returns a pointer to the new node object.
2296 */
2297xmlNodePtr
2298xmlNewComment(const xmlChar *content) {
2299 xmlNodePtr cur;
2300
2301 /*
2302 * Allocate a new node and fill the fields.
2303 */
2304 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2305 if (cur == NULL) {
2306 xmlGenericError(xmlGenericErrorContext,
2307 "xmlNewComment : malloc failed\n");
2308 return(NULL);
2309 }
2310 memset(cur, 0, sizeof(xmlNode));
2311 cur->type = XML_COMMENT_NODE;
2312
2313 cur->name = xmlStringComment;
2314 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002315 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002316 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002317
2318 if (xmlRegisterNodeDefaultValue)
2319 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002320 return(cur);
2321}
2322
2323/**
2324 * xmlNewCDataBlock:
2325 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002326 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002327 * @len: the length of the block
2328 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002329 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002330 * Returns a pointer to the new node object.
2331 */
2332xmlNodePtr
2333xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2334 xmlNodePtr cur;
2335
2336 /*
2337 * Allocate a new node and fill the fields.
2338 */
2339 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2340 if (cur == NULL) {
2341 xmlGenericError(xmlGenericErrorContext,
2342 "xmlNewCDataBlock : malloc failed\n");
2343 return(NULL);
2344 }
2345 memset(cur, 0, sizeof(xmlNode));
2346 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002347 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002348
2349 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002350 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002351 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002352
2353 if (xmlRegisterNodeDefaultValue)
2354 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002355 return(cur);
2356}
2357
2358/**
2359 * xmlNewDocComment:
2360 * @doc: the document
2361 * @content: the comment content
2362 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002363 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002364 * Returns a pointer to the new node object.
2365 */
2366xmlNodePtr
2367xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2368 xmlNodePtr cur;
2369
2370 cur = xmlNewComment(content);
2371 if (cur != NULL) cur->doc = doc;
2372 return(cur);
2373}
2374
2375/**
2376 * xmlSetTreeDoc:
2377 * @tree: the top element
2378 * @doc: the document
2379 *
2380 * update all nodes under the tree to point to the right document
2381 */
2382void
2383xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002384 xmlAttrPtr prop;
2385
Owen Taylor3473f882001-02-23 17:55:21 +00002386 if (tree == NULL)
2387 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002388 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002389 if(tree->type == XML_ELEMENT_NODE) {
2390 prop = tree->properties;
2391 while (prop != NULL) {
2392 prop->doc = doc;
2393 xmlSetListDoc(prop->children, doc);
2394 prop = prop->next;
2395 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002396 }
Owen Taylor3473f882001-02-23 17:55:21 +00002397 if (tree->children != NULL)
2398 xmlSetListDoc(tree->children, doc);
2399 tree->doc = doc;
2400 }
2401}
2402
2403/**
2404 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002405 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002406 * @doc: the document
2407 *
2408 * update all nodes in the list to point to the right document
2409 */
2410void
2411xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2412 xmlNodePtr cur;
2413
2414 if (list == NULL)
2415 return;
2416 cur = list;
2417 while (cur != NULL) {
2418 if (cur->doc != doc)
2419 xmlSetTreeDoc(cur, doc);
2420 cur = cur->next;
2421 }
2422}
2423
2424
2425/**
2426 * xmlNewChild:
2427 * @parent: the parent node
2428 * @ns: a namespace if any
2429 * @name: the name of the child
2430 * @content: the XML content of the child if any.
2431 *
2432 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002433 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002434 * a child list containing the TEXTs and ENTITY_REFs node will be created.
2435 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2436 * references, but XML special chars need to be escaped first by using
2437 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
2438 * support is not needed.
2439 *
2440 * Returns a pointer to the new node object.
2441 */
2442xmlNodePtr
2443xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2444 const xmlChar *name, const xmlChar *content) {
2445 xmlNodePtr cur, prev;
2446
2447 if (parent == NULL) {
2448#ifdef DEBUG_TREE
2449 xmlGenericError(xmlGenericErrorContext,
2450 "xmlNewChild : parent == NULL\n");
2451#endif
2452 return(NULL);
2453 }
2454
2455 if (name == NULL) {
2456#ifdef DEBUG_TREE
2457 xmlGenericError(xmlGenericErrorContext,
2458 "xmlNewChild : name == NULL\n");
2459#endif
2460 return(NULL);
2461 }
2462
2463 /*
2464 * Allocate a new node
2465 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002466 if (parent->type == XML_ELEMENT_NODE) {
2467 if (ns == NULL)
2468 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2469 else
2470 cur = xmlNewDocNode(parent->doc, ns, name, content);
2471 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2472 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2473 if (ns == NULL)
2474 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2475 else
2476 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002477 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2478 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002479 } else {
2480 return(NULL);
2481 }
Owen Taylor3473f882001-02-23 17:55:21 +00002482 if (cur == NULL) return(NULL);
2483
2484 /*
2485 * add the new element at the end of the children list.
2486 */
2487 cur->type = XML_ELEMENT_NODE;
2488 cur->parent = parent;
2489 cur->doc = parent->doc;
2490 if (parent->children == NULL) {
2491 parent->children = cur;
2492 parent->last = cur;
2493 } else {
2494 prev = parent->last;
2495 prev->next = cur;
2496 cur->prev = prev;
2497 parent->last = cur;
2498 }
2499
2500 return(cur);
2501}
2502
2503/**
2504 * xmlAddNextSibling:
2505 * @cur: the child node
2506 * @elem: the new node
2507 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002508 * Add a new node @elem as the next sibling of @cur
2509 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002510 * first unlinked from its existing context.
2511 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002512 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2513 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002514 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002515 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002516 */
2517xmlNodePtr
2518xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2519 if (cur == NULL) {
2520#ifdef DEBUG_TREE
2521 xmlGenericError(xmlGenericErrorContext,
2522 "xmlAddNextSibling : cur == NULL\n");
2523#endif
2524 return(NULL);
2525 }
2526 if (elem == NULL) {
2527#ifdef DEBUG_TREE
2528 xmlGenericError(xmlGenericErrorContext,
2529 "xmlAddNextSibling : elem == NULL\n");
2530#endif
2531 return(NULL);
2532 }
2533
2534 xmlUnlinkNode(elem);
2535
2536 if (elem->type == XML_TEXT_NODE) {
2537 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002538 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002539 xmlFreeNode(elem);
2540 return(cur);
2541 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002542 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2543 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002544 xmlChar *tmp;
2545
2546 tmp = xmlStrdup(elem->content);
2547 tmp = xmlStrcat(tmp, cur->next->content);
2548 xmlNodeSetContent(cur->next, tmp);
2549 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002550 xmlFreeNode(elem);
2551 return(cur->next);
2552 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002553 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2554 /* check if an attribute with the same name exists */
2555 xmlAttrPtr attr;
2556
2557 if (elem->ns == NULL)
2558 attr = xmlHasProp(cur->parent, elem->name);
2559 else
2560 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2561 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2562 /* different instance, destroy it (attributes must be unique) */
2563 xmlFreeProp(attr);
2564 }
Owen Taylor3473f882001-02-23 17:55:21 +00002565 }
2566
2567 if (elem->doc != cur->doc) {
2568 xmlSetTreeDoc(elem, cur->doc);
2569 }
2570 elem->parent = cur->parent;
2571 elem->prev = cur;
2572 elem->next = cur->next;
2573 cur->next = elem;
2574 if (elem->next != NULL)
2575 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002576 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002577 elem->parent->last = elem;
2578 return(elem);
2579}
2580
2581/**
2582 * xmlAddPrevSibling:
2583 * @cur: the child node
2584 * @elem: the new node
2585 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002586 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002587 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002588 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002589 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002590 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2591 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002592 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002593 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002594 */
2595xmlNodePtr
2596xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2597 if (cur == NULL) {
2598#ifdef DEBUG_TREE
2599 xmlGenericError(xmlGenericErrorContext,
2600 "xmlAddPrevSibling : cur == NULL\n");
2601#endif
2602 return(NULL);
2603 }
2604 if (elem == NULL) {
2605#ifdef DEBUG_TREE
2606 xmlGenericError(xmlGenericErrorContext,
2607 "xmlAddPrevSibling : elem == NULL\n");
2608#endif
2609 return(NULL);
2610 }
2611
2612 xmlUnlinkNode(elem);
2613
2614 if (elem->type == XML_TEXT_NODE) {
2615 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002616 xmlChar *tmp;
2617
2618 tmp = xmlStrdup(elem->content);
2619 tmp = xmlStrcat(tmp, cur->content);
2620 xmlNodeSetContent(cur, tmp);
2621 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002622 xmlFreeNode(elem);
2623 return(cur);
2624 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002625 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2626 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002627 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002628 xmlFreeNode(elem);
2629 return(cur->prev);
2630 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002631 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2632 /* check if an attribute with the same name exists */
2633 xmlAttrPtr attr;
2634
2635 if (elem->ns == NULL)
2636 attr = xmlHasProp(cur->parent, elem->name);
2637 else
2638 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2639 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2640 /* different instance, destroy it (attributes must be unique) */
2641 xmlFreeProp(attr);
2642 }
Owen Taylor3473f882001-02-23 17:55:21 +00002643 }
2644
2645 if (elem->doc != cur->doc) {
2646 xmlSetTreeDoc(elem, cur->doc);
2647 }
2648 elem->parent = cur->parent;
2649 elem->next = cur;
2650 elem->prev = cur->prev;
2651 cur->prev = elem;
2652 if (elem->prev != NULL)
2653 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002654 if (elem->parent != NULL) {
2655 if (elem->type == XML_ATTRIBUTE_NODE) {
2656 if (elem->parent->properties == (xmlAttrPtr) cur) {
2657 elem->parent->properties = (xmlAttrPtr) elem;
2658 }
2659 } else {
2660 if (elem->parent->children == cur) {
2661 elem->parent->children = elem;
2662 }
2663 }
2664 }
Owen Taylor3473f882001-02-23 17:55:21 +00002665 return(elem);
2666}
2667
2668/**
2669 * xmlAddSibling:
2670 * @cur: the child node
2671 * @elem: the new node
2672 *
2673 * Add a new element @elem to the list of siblings of @cur
2674 * merging adjacent TEXT nodes (@elem may be freed)
2675 * If the new element was already inserted in a document it is
2676 * first unlinked from its existing context.
2677 *
2678 * Returns the new element or NULL in case of error.
2679 */
2680xmlNodePtr
2681xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2682 xmlNodePtr parent;
2683
2684 if (cur == NULL) {
2685#ifdef DEBUG_TREE
2686 xmlGenericError(xmlGenericErrorContext,
2687 "xmlAddSibling : cur == NULL\n");
2688#endif
2689 return(NULL);
2690 }
2691
2692 if (elem == NULL) {
2693#ifdef DEBUG_TREE
2694 xmlGenericError(xmlGenericErrorContext,
2695 "xmlAddSibling : elem == NULL\n");
2696#endif
2697 return(NULL);
2698 }
2699
2700 /*
2701 * Constant time is we can rely on the ->parent->last to find
2702 * the last sibling.
2703 */
2704 if ((cur->parent != NULL) &&
2705 (cur->parent->children != NULL) &&
2706 (cur->parent->last != NULL) &&
2707 (cur->parent->last->next == NULL)) {
2708 cur = cur->parent->last;
2709 } else {
2710 while (cur->next != NULL) cur = cur->next;
2711 }
2712
2713 xmlUnlinkNode(elem);
2714
2715 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002716 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002717 xmlFreeNode(elem);
2718 return(cur);
2719 }
2720
2721 if (elem->doc != cur->doc) {
2722 xmlSetTreeDoc(elem, cur->doc);
2723 }
2724 parent = cur->parent;
2725 elem->prev = cur;
2726 elem->next = NULL;
2727 elem->parent = parent;
2728 cur->next = elem;
2729 if (parent != NULL)
2730 parent->last = elem;
2731
2732 return(elem);
2733}
2734
2735/**
2736 * xmlAddChildList:
2737 * @parent: the parent node
2738 * @cur: the first node in the list
2739 *
2740 * Add a list of node at the end of the child list of the parent
2741 * merging adjacent TEXT nodes (@cur may be freed)
2742 *
2743 * Returns the last child or NULL in case of error.
2744 */
2745xmlNodePtr
2746xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2747 xmlNodePtr prev;
2748
2749 if (parent == NULL) {
2750#ifdef DEBUG_TREE
2751 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002752 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002753#endif
2754 return(NULL);
2755 }
2756
2757 if (cur == NULL) {
2758#ifdef DEBUG_TREE
2759 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002760 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002761#endif
2762 return(NULL);
2763 }
2764
2765 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2766 (cur->doc != parent->doc)) {
2767#ifdef DEBUG_TREE
2768 xmlGenericError(xmlGenericErrorContext,
2769 "Elements moved to a different document\n");
2770#endif
2771 }
2772
2773 /*
2774 * add the first element at the end of the children list.
2775 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00002776
Owen Taylor3473f882001-02-23 17:55:21 +00002777 if (parent->children == NULL) {
2778 parent->children = cur;
2779 } else {
2780 /*
2781 * If cur and parent->last both are TEXT nodes, then merge them.
2782 */
2783 if ((cur->type == XML_TEXT_NODE) &&
2784 (parent->last->type == XML_TEXT_NODE) &&
2785 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00002786 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002787 /*
2788 * if it's the only child, nothing more to be done.
2789 */
2790 if (cur->next == NULL) {
2791 xmlFreeNode(cur);
2792 return(parent->last);
2793 }
2794 prev = cur;
2795 cur = cur->next;
2796 xmlFreeNode(prev);
2797 }
2798 prev = parent->last;
2799 prev->next = cur;
2800 cur->prev = prev;
2801 }
2802 while (cur->next != NULL) {
2803 cur->parent = parent;
2804 if (cur->doc != parent->doc) {
2805 xmlSetTreeDoc(cur, parent->doc);
2806 }
2807 cur = cur->next;
2808 }
2809 cur->parent = parent;
2810 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2811 parent->last = cur;
2812
2813 return(cur);
2814}
2815
2816/**
2817 * xmlAddChild:
2818 * @parent: the parent node
2819 * @cur: the child node
2820 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002821 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00002822 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002823 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2824 * If there is an attribute with equal name, it is first destroyed.
2825 *
Owen Taylor3473f882001-02-23 17:55:21 +00002826 * Returns the child or NULL in case of error.
2827 */
2828xmlNodePtr
2829xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2830 xmlNodePtr prev;
2831
2832 if (parent == NULL) {
2833#ifdef DEBUG_TREE
2834 xmlGenericError(xmlGenericErrorContext,
2835 "xmlAddChild : parent == NULL\n");
2836#endif
2837 return(NULL);
2838 }
2839
2840 if (cur == NULL) {
2841#ifdef DEBUG_TREE
2842 xmlGenericError(xmlGenericErrorContext,
2843 "xmlAddChild : child == NULL\n");
2844#endif
2845 return(NULL);
2846 }
2847
Owen Taylor3473f882001-02-23 17:55:21 +00002848 /*
2849 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002850 * cur is then freed.
2851 */
2852 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002853 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002854 (parent->content != NULL) &&
2855 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002856 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002857 xmlFreeNode(cur);
2858 return(parent);
2859 }
2860 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002861 (parent->last->name == cur->name) &&
2862 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002863 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002864 xmlFreeNode(cur);
2865 return(parent->last);
2866 }
2867 }
2868
2869 /*
2870 * add the new element at the end of the children list.
2871 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00002872 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00002873 cur->parent = parent;
2874 if (cur->doc != parent->doc) {
2875 xmlSetTreeDoc(cur, parent->doc);
2876 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002877 /* this check prevents a loop on tree-traversions if a developer
2878 * tries to add a node to its parent multiple times
2879 */
2880 if (prev == parent)
2881 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002882
2883 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002884 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002885 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002886 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002887 (parent->content != NULL) &&
2888 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002889 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002890 xmlFreeNode(cur);
2891 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002892 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002893 if (cur->type == XML_ATTRIBUTE_NODE) {
2894 if (parent->properties == NULL) {
2895 parent->properties = (xmlAttrPtr) cur;
2896 } else {
2897 /* check if an attribute with the same name exists */
2898 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00002899
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002900 if (cur->ns == NULL)
2901 lastattr = xmlHasProp(parent, cur->name);
2902 else
2903 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
2904 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
2905 /* different instance, destroy it (attributes must be unique) */
2906 xmlFreeProp(lastattr);
2907 }
2908 /* find the end */
2909 lastattr = parent->properties;
2910 while (lastattr->next != NULL) {
2911 lastattr = lastattr->next;
2912 }
2913 lastattr->next = (xmlAttrPtr) cur;
2914 ((xmlAttrPtr) cur)->prev = lastattr;
2915 }
2916 } else {
2917 if (parent->children == NULL) {
2918 parent->children = cur;
2919 parent->last = cur;
2920 } else {
2921 prev = parent->last;
2922 prev->next = cur;
2923 cur->prev = prev;
2924 parent->last = cur;
2925 }
2926 }
Owen Taylor3473f882001-02-23 17:55:21 +00002927 return(cur);
2928}
2929
2930/**
2931 * xmlGetLastChild:
2932 * @parent: the parent node
2933 *
2934 * Search the last child of a node.
2935 * Returns the last child or NULL if none.
2936 */
2937xmlNodePtr
2938xmlGetLastChild(xmlNodePtr parent) {
2939 if (parent == NULL) {
2940#ifdef DEBUG_TREE
2941 xmlGenericError(xmlGenericErrorContext,
2942 "xmlGetLastChild : parent == NULL\n");
2943#endif
2944 return(NULL);
2945 }
2946 return(parent->last);
2947}
2948
2949/**
2950 * xmlFreeNodeList:
2951 * @cur: the first node in the list
2952 *
2953 * Free a node and all its siblings, this is a recursive behaviour, all
2954 * the children are freed too.
2955 */
2956void
2957xmlFreeNodeList(xmlNodePtr cur) {
2958 xmlNodePtr next;
2959 if (cur == NULL) {
2960#ifdef DEBUG_TREE
2961 xmlGenericError(xmlGenericErrorContext,
2962 "xmlFreeNodeList : node == NULL\n");
2963#endif
2964 return;
2965 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00002966 if (cur->type == XML_NAMESPACE_DECL) {
2967 xmlFreeNsList((xmlNsPtr) cur);
2968 return;
2969 }
Owen Taylor3473f882001-02-23 17:55:21 +00002970 while (cur != NULL) {
2971 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002972 /* unroll to speed up freeing the document */
2973 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00002974
2975 if (xmlDeregisterNodeDefaultValue)
2976 xmlDeregisterNodeDefaultValue(cur);
2977
Daniel Veillard02141ea2001-04-30 11:46:40 +00002978 if ((cur->children != NULL) &&
2979 (cur->type != XML_ENTITY_REF_NODE))
2980 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00002981 if (((cur->type == XML_ELEMENT_NODE) ||
2982 (cur->type == XML_XINCLUDE_START) ||
2983 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002984 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00002985 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002986 if ((cur->type != XML_ELEMENT_NODE) &&
2987 (cur->type != XML_XINCLUDE_START) &&
2988 (cur->type != XML_XINCLUDE_END) &&
2989 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002990 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002991 }
2992 if (((cur->type == XML_ELEMENT_NODE) ||
2993 (cur->type == XML_XINCLUDE_START) ||
2994 (cur->type == XML_XINCLUDE_END)) &&
2995 (cur->nsDef != NULL))
2996 xmlFreeNsList(cur->nsDef);
2997
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002998 /*
2999 * When a node is a text node or a comment, it uses a global static
3000 * variable for the name of the node.
3001 *
3002 * The xmlStrEqual comparisons need to be done when (happened with
3003 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003004 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00003005 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003006 * the string addresses compare are not sufficient.
3007 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003008 if ((cur->name != NULL) &&
3009 (cur->name != xmlStringText) &&
3010 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003011 (cur->name != xmlStringComment)) {
3012 if (cur->type == XML_TEXT_NODE) {
3013 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
3014 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
3015 xmlFree((char *) cur->name);
3016 } else if (cur->type == XML_COMMENT_NODE) {
3017 if (!xmlStrEqual(cur->name, xmlStringComment))
3018 xmlFree((char *) cur->name);
3019 } else
3020 xmlFree((char *) cur->name);
3021 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00003022 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003023 xmlFree(cur);
3024 }
Owen Taylor3473f882001-02-23 17:55:21 +00003025 cur = next;
3026 }
3027}
3028
3029/**
3030 * xmlFreeNode:
3031 * @cur: the node
3032 *
3033 * Free a node, this is a recursive behaviour, all the children are freed too.
3034 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3035 */
3036void
3037xmlFreeNode(xmlNodePtr cur) {
3038 if (cur == NULL) {
3039#ifdef DEBUG_TREE
3040 xmlGenericError(xmlGenericErrorContext,
3041 "xmlFreeNode : node == NULL\n");
3042#endif
3043 return;
3044 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003045
Daniel Veillard02141ea2001-04-30 11:46:40 +00003046 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003047 if (cur->type == XML_DTD_NODE) {
3048 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003049 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003050 }
3051 if (cur->type == XML_NAMESPACE_DECL) {
3052 xmlFreeNs((xmlNsPtr) cur);
3053 return;
3054 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003055 if (cur->type == XML_ATTRIBUTE_NODE) {
3056 xmlFreeProp((xmlAttrPtr) cur);
3057 return;
3058 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003059
3060 if (xmlDeregisterNodeDefaultValue)
3061 xmlDeregisterNodeDefaultValue(cur);
3062
Owen Taylor3473f882001-02-23 17:55:21 +00003063 if ((cur->children != NULL) &&
3064 (cur->type != XML_ENTITY_REF_NODE))
3065 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003066 if (((cur->type == XML_ELEMENT_NODE) ||
3067 (cur->type == XML_XINCLUDE_START) ||
3068 (cur->type == XML_XINCLUDE_END)) &&
3069 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003070 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003071 if ((cur->type != XML_ELEMENT_NODE) &&
3072 (cur->content != NULL) &&
3073 (cur->type != XML_ENTITY_REF_NODE) &&
3074 (cur->type != XML_XINCLUDE_END) &&
3075 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003076 xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003077 }
3078
Daniel Veillardacd370f2001-06-09 17:17:51 +00003079 /*
3080 * When a node is a text node or a comment, it uses a global static
3081 * variable for the name of the node.
3082 *
3083 * The xmlStrEqual comparisons need to be done when (happened with
3084 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003085 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00003086 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00003087 * are not sufficient.
3088 */
Owen Taylor3473f882001-02-23 17:55:21 +00003089 if ((cur->name != NULL) &&
3090 (cur->name != xmlStringText) &&
3091 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00003092 (cur->name != xmlStringComment)) {
3093 if (cur->type == XML_TEXT_NODE) {
3094 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
3095 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
3096 xmlFree((char *) cur->name);
3097 } else if (cur->type == XML_COMMENT_NODE) {
3098 if (!xmlStrEqual(cur->name, xmlStringComment))
3099 xmlFree((char *) cur->name);
3100 } else
3101 xmlFree((char *) cur->name);
3102 }
3103
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003104 if (((cur->type == XML_ELEMENT_NODE) ||
3105 (cur->type == XML_XINCLUDE_START) ||
3106 (cur->type == XML_XINCLUDE_END)) &&
3107 (cur->nsDef != NULL))
3108 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003109 xmlFree(cur);
3110}
3111
3112/**
3113 * xmlUnlinkNode:
3114 * @cur: the node
3115 *
3116 * Unlink a node from it's current context, the node is not freed
3117 */
3118void
3119xmlUnlinkNode(xmlNodePtr cur) {
3120 if (cur == NULL) {
3121#ifdef DEBUG_TREE
3122 xmlGenericError(xmlGenericErrorContext,
3123 "xmlUnlinkNode : node == NULL\n");
3124#endif
3125 return;
3126 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003127 if (cur->type == XML_DTD_NODE) {
3128 xmlDocPtr doc;
3129 doc = cur->doc;
3130 if (doc->intSubset == (xmlDtdPtr) cur)
3131 doc->intSubset = NULL;
3132 if (doc->extSubset == (xmlDtdPtr) cur)
3133 doc->extSubset = NULL;
3134 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003135 if (cur->parent != NULL) {
3136 xmlNodePtr parent;
3137 parent = cur->parent;
3138 if (cur->type == XML_ATTRIBUTE_NODE) {
3139 if (parent->properties == (xmlAttrPtr) cur)
3140 parent->properties = ((xmlAttrPtr) cur)->next;
3141 } else {
3142 if (parent->children == cur)
3143 parent->children = cur->next;
3144 if (parent->last == cur)
3145 parent->last = cur->prev;
3146 }
3147 cur->parent = NULL;
3148 }
Owen Taylor3473f882001-02-23 17:55:21 +00003149 if (cur->next != NULL)
3150 cur->next->prev = cur->prev;
3151 if (cur->prev != NULL)
3152 cur->prev->next = cur->next;
3153 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003154}
3155
3156/**
3157 * xmlReplaceNode:
3158 * @old: the old node
3159 * @cur: the node
3160 *
3161 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003162 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003163 * first unlinked from its existing context.
3164 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003165 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003166 */
3167xmlNodePtr
3168xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3169 if (old == NULL) {
3170#ifdef DEBUG_TREE
3171 xmlGenericError(xmlGenericErrorContext,
3172 "xmlReplaceNode : old == NULL\n");
3173#endif
3174 return(NULL);
3175 }
3176 if (cur == NULL) {
3177 xmlUnlinkNode(old);
3178 return(old);
3179 }
3180 if (cur == old) {
3181 return(old);
3182 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003183 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3184#ifdef DEBUG_TREE
3185 xmlGenericError(xmlGenericErrorContext,
3186 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3187#endif
3188 return(old);
3189 }
3190 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3191#ifdef DEBUG_TREE
3192 xmlGenericError(xmlGenericErrorContext,
3193 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3194#endif
3195 return(old);
3196 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003197 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3198#ifdef DEBUG_TREE
3199 xmlGenericError(xmlGenericErrorContext,
3200 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3201#endif
3202 return(old);
3203 }
3204 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3205#ifdef DEBUG_TREE
3206 xmlGenericError(xmlGenericErrorContext,
3207 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3208#endif
3209 return(old);
3210 }
Owen Taylor3473f882001-02-23 17:55:21 +00003211 xmlUnlinkNode(cur);
3212 cur->doc = old->doc;
3213 cur->parent = old->parent;
3214 cur->next = old->next;
3215 if (cur->next != NULL)
3216 cur->next->prev = cur;
3217 cur->prev = old->prev;
3218 if (cur->prev != NULL)
3219 cur->prev->next = cur;
3220 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003221 if (cur->type == XML_ATTRIBUTE_NODE) {
3222 if (cur->parent->properties == (xmlAttrPtr)old)
3223 cur->parent->properties = ((xmlAttrPtr) cur);
3224 } else {
3225 if (cur->parent->children == old)
3226 cur->parent->children = cur;
3227 if (cur->parent->last == old)
3228 cur->parent->last = cur;
3229 }
Owen Taylor3473f882001-02-23 17:55:21 +00003230 }
3231 old->next = old->prev = NULL;
3232 old->parent = NULL;
3233 return(old);
3234}
3235
3236/************************************************************************
3237 * *
3238 * Copy operations *
3239 * *
3240 ************************************************************************/
3241
3242/**
3243 * xmlCopyNamespace:
3244 * @cur: the namespace
3245 *
3246 * Do a copy of the namespace.
3247 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003248 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003249 */
3250xmlNsPtr
3251xmlCopyNamespace(xmlNsPtr cur) {
3252 xmlNsPtr ret;
3253
3254 if (cur == NULL) return(NULL);
3255 switch (cur->type) {
3256 case XML_LOCAL_NAMESPACE:
3257 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3258 break;
3259 default:
3260#ifdef DEBUG_TREE
3261 xmlGenericError(xmlGenericErrorContext,
3262 "xmlCopyNamespace: invalid type %d\n", cur->type);
3263#endif
3264 return(NULL);
3265 }
3266 return(ret);
3267}
3268
3269/**
3270 * xmlCopyNamespaceList:
3271 * @cur: the first namespace
3272 *
3273 * Do a copy of an namespace list.
3274 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003275 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003276 */
3277xmlNsPtr
3278xmlCopyNamespaceList(xmlNsPtr cur) {
3279 xmlNsPtr ret = NULL;
3280 xmlNsPtr p = NULL,q;
3281
3282 while (cur != NULL) {
3283 q = xmlCopyNamespace(cur);
3284 if (p == NULL) {
3285 ret = p = q;
3286 } else {
3287 p->next = q;
3288 p = q;
3289 }
3290 cur = cur->next;
3291 }
3292 return(ret);
3293}
3294
3295static xmlNodePtr
3296xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3297/**
3298 * xmlCopyProp:
3299 * @target: the element where the attribute will be grafted
3300 * @cur: the attribute
3301 *
3302 * Do a copy of the attribute.
3303 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003304 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003305 */
3306xmlAttrPtr
3307xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3308 xmlAttrPtr ret;
3309
3310 if (cur == NULL) return(NULL);
3311 if (target != NULL)
3312 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3313 else if (cur->parent != NULL)
3314 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3315 else if (cur->children != NULL)
3316 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3317 else
3318 ret = xmlNewDocProp(NULL, cur->name, NULL);
3319 if (ret == NULL) return(NULL);
3320 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003321
Owen Taylor3473f882001-02-23 17:55:21 +00003322 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003323 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003324/*
3325 * if (target->doc)
3326 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3327 * else if (cur->doc) / * target may not yet have a doc : KPI * /
3328 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
3329 * else
3330 * ns = NULL;
3331 * ret->ns = ns;
3332 */
3333 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3334 if (ns == NULL) {
3335 /*
3336 * Humm, we are copying an element whose namespace is defined
3337 * out of the new tree scope. Search it in the original tree
3338 * and add it at the top of the new tree
3339 */
3340 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3341 if (ns != NULL) {
3342 xmlNodePtr root = target;
3343 xmlNodePtr pred = NULL;
3344
3345 while (root->parent != NULL) {
3346 pred = root;
3347 root = root->parent;
3348 }
3349 if (root == (xmlNodePtr) target->doc) {
3350 /* correct possibly cycling above the document elt */
3351 root = pred;
3352 }
3353 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3354 }
3355 } else {
3356 /*
3357 * we have to find something appropriate here since
3358 * we cant be sure, that the namespce we found is identified
3359 * by the prefix
3360 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003361 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003362 /* this is the nice case */
3363 ret->ns = ns;
3364 } else {
3365 /*
3366 * we are in trouble: we need a new reconcilied namespace.
3367 * This is expensive
3368 */
3369 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3370 }
3371 }
3372
Owen Taylor3473f882001-02-23 17:55:21 +00003373 } else
3374 ret->ns = NULL;
3375
3376 if (cur->children != NULL) {
3377 xmlNodePtr tmp;
3378
3379 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3380 ret->last = NULL;
3381 tmp = ret->children;
3382 while (tmp != NULL) {
3383 /* tmp->parent = (xmlNodePtr)ret; */
3384 if (tmp->next == NULL)
3385 ret->last = tmp;
3386 tmp = tmp->next;
3387 }
3388 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003389 /*
3390 * Try to handle IDs
3391 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003392 if ((target!= NULL) && (cur!= NULL) &&
3393 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003394 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3395 if (xmlIsID(cur->doc, cur->parent, cur)) {
3396 xmlChar *id;
3397
3398 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3399 if (id != NULL) {
3400 xmlAddID(NULL, target->doc, id, ret);
3401 xmlFree(id);
3402 }
3403 }
3404 }
Owen Taylor3473f882001-02-23 17:55:21 +00003405 return(ret);
3406}
3407
3408/**
3409 * xmlCopyPropList:
3410 * @target: the element where the attributes will be grafted
3411 * @cur: the first attribute
3412 *
3413 * Do a copy of an attribute list.
3414 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003415 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003416 */
3417xmlAttrPtr
3418xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3419 xmlAttrPtr ret = NULL;
3420 xmlAttrPtr p = NULL,q;
3421
3422 while (cur != NULL) {
3423 q = xmlCopyProp(target, cur);
3424 if (p == NULL) {
3425 ret = p = q;
3426 } else {
3427 p->next = q;
3428 q->prev = p;
3429 p = q;
3430 }
3431 cur = cur->next;
3432 }
3433 return(ret);
3434}
3435
3436/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003437 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003438 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003439 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003440 * tricky reason: namespaces. Doing a direct copy of a node
3441 * say RPM:Copyright without changing the namespace pointer to
3442 * something else can produce stale links. One way to do it is
3443 * to keep a reference counter but this doesn't work as soon
3444 * as one move the element or the subtree out of the scope of
3445 * the existing namespace. The actual solution seems to add
3446 * a copy of the namespace at the top of the copied tree if
3447 * not available in the subtree.
3448 * Hence two functions, the public front-end call the inner ones
3449 */
3450
3451static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003452xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003453 int recursive) {
3454 xmlNodePtr ret;
3455
3456 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003457 switch (node->type) {
3458 case XML_TEXT_NODE:
3459 case XML_CDATA_SECTION_NODE:
3460 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003461 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003462 case XML_ENTITY_REF_NODE:
3463 case XML_ENTITY_NODE:
3464 case XML_PI_NODE:
3465 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003466 case XML_XINCLUDE_START:
3467 case XML_XINCLUDE_END:
3468 break;
3469 case XML_ATTRIBUTE_NODE:
3470 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3471 case XML_NAMESPACE_DECL:
3472 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3473
Daniel Veillard39196eb2001-06-19 18:09:42 +00003474 case XML_DOCUMENT_NODE:
3475 case XML_HTML_DOCUMENT_NODE:
3476#ifdef LIBXML_DOCB_ENABLED
3477 case XML_DOCB_DOCUMENT_NODE:
3478#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003479 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00003480 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003481 case XML_NOTATION_NODE:
3482 case XML_DTD_NODE:
3483 case XML_ELEMENT_DECL:
3484 case XML_ATTRIBUTE_DECL:
3485 case XML_ENTITY_DECL:
3486 return(NULL);
3487 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003488
Owen Taylor3473f882001-02-23 17:55:21 +00003489 /*
3490 * Allocate a new node and fill the fields.
3491 */
3492 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3493 if (ret == NULL) {
3494 xmlGenericError(xmlGenericErrorContext,
3495 "xmlStaticCopyNode : malloc failed\n");
3496 return(NULL);
3497 }
3498 memset(ret, 0, sizeof(xmlNode));
3499 ret->type = node->type;
3500
3501 ret->doc = doc;
3502 ret->parent = parent;
3503 if (node->name == xmlStringText)
3504 ret->name = xmlStringText;
3505 else if (node->name == xmlStringTextNoenc)
3506 ret->name = xmlStringTextNoenc;
3507 else if (node->name == xmlStringComment)
3508 ret->name = xmlStringComment;
3509 else if (node->name != NULL)
3510 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003511 if ((node->type != XML_ELEMENT_NODE) &&
3512 (node->content != NULL) &&
3513 (node->type != XML_ENTITY_REF_NODE) &&
3514 (node->type != XML_XINCLUDE_END) &&
3515 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003516 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003517 }else{
3518 if (node->type == XML_ELEMENT_NODE)
3519 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00003520 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003521 if (parent != NULL) {
3522 xmlNodePtr tmp;
3523
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003524 /*
3525 * this is a tricky part for the node register thing:
3526 * in case ret does get coalesced in xmlAddChild
3527 * the deregister-node callback is called; so we register ret now already
3528 */
3529 if (xmlRegisterNodeDefaultValue)
3530 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3531
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003532 tmp = xmlAddChild(parent, ret);
3533 /* node could have coalesced */
3534 if (tmp != ret)
3535 return(tmp);
3536 }
Owen Taylor3473f882001-02-23 17:55:21 +00003537
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003538 if (!recursive)
3539 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003540 if (node->nsDef != NULL)
3541 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3542
3543 if (node->ns != NULL) {
3544 xmlNsPtr ns;
3545
3546 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3547 if (ns == NULL) {
3548 /*
3549 * Humm, we are copying an element whose namespace is defined
3550 * out of the new tree scope. Search it in the original tree
3551 * and add it at the top of the new tree
3552 */
3553 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3554 if (ns != NULL) {
3555 xmlNodePtr root = ret;
3556
3557 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003558 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003559 }
3560 } else {
3561 /*
3562 * reference the existing namespace definition in our own tree.
3563 */
3564 ret->ns = ns;
3565 }
3566 }
3567 if (node->properties != NULL)
3568 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003569 if (node->type == XML_ENTITY_REF_NODE) {
3570 if ((doc == NULL) || (node->doc != doc)) {
3571 /*
3572 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003573 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003574 * we cannot keep the reference. Try to find it in the
3575 * target document.
3576 */
3577 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3578 } else {
3579 ret->children = node->children;
3580 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003581 ret->last = ret->children;
3582 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003583 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003584 UPDATE_LAST_CHILD_AND_PARENT(ret)
3585 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003586
3587out:
3588 /* if parent != NULL we already registered the node above */
3589 if (parent == NULL && xmlRegisterNodeDefaultValue)
3590 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003591 return(ret);
3592}
3593
3594static xmlNodePtr
3595xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3596 xmlNodePtr ret = NULL;
3597 xmlNodePtr p = NULL,q;
3598
3599 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003600 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003601 if (doc == NULL) {
3602 node = node->next;
3603 continue;
3604 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003605 if (doc->intSubset == NULL) {
3606 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3607 q->doc = doc;
3608 q->parent = parent;
3609 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003610 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003611 } else {
3612 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003613 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003614 }
3615 } else
3616 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003617 if (ret == NULL) {
3618 q->prev = NULL;
3619 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003620 } else if (p != q) {
3621 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003622 p->next = q;
3623 q->prev = p;
3624 p = q;
3625 }
3626 node = node->next;
3627 }
3628 return(ret);
3629}
3630
3631/**
3632 * xmlCopyNode:
3633 * @node: the node
3634 * @recursive: if 1 do a recursive copy.
3635 *
3636 * Do a copy of the node.
3637 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003638 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003639 */
3640xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003641xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003642 xmlNodePtr ret;
3643
3644 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3645 return(ret);
3646}
3647
3648/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003649 * xmlDocCopyNode:
3650 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003651 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003652 * @recursive: if 1 do a recursive copy.
3653 *
3654 * Do a copy of the node to a given document.
3655 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003656 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003657 */
3658xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003659xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003660 xmlNodePtr ret;
3661
3662 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3663 return(ret);
3664}
3665
3666/**
Owen Taylor3473f882001-02-23 17:55:21 +00003667 * xmlCopyNodeList:
3668 * @node: the first node in the list.
3669 *
3670 * Do a recursive copy of the node list.
3671 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003672 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003673 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003674xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003675 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3676 return(ret);
3677}
3678
3679/**
Owen Taylor3473f882001-02-23 17:55:21 +00003680 * xmlCopyDtd:
3681 * @dtd: the dtd
3682 *
3683 * Do a copy of the dtd.
3684 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003685 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003686 */
3687xmlDtdPtr
3688xmlCopyDtd(xmlDtdPtr dtd) {
3689 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003690 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003691
3692 if (dtd == NULL) return(NULL);
3693 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3694 if (ret == NULL) return(NULL);
3695 if (dtd->entities != NULL)
3696 ret->entities = (void *) xmlCopyEntitiesTable(
3697 (xmlEntitiesTablePtr) dtd->entities);
3698 if (dtd->notations != NULL)
3699 ret->notations = (void *) xmlCopyNotationTable(
3700 (xmlNotationTablePtr) dtd->notations);
3701 if (dtd->elements != NULL)
3702 ret->elements = (void *) xmlCopyElementTable(
3703 (xmlElementTablePtr) dtd->elements);
3704 if (dtd->attributes != NULL)
3705 ret->attributes = (void *) xmlCopyAttributeTable(
3706 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003707 if (dtd->pentities != NULL)
3708 ret->pentities = (void *) xmlCopyEntitiesTable(
3709 (xmlEntitiesTablePtr) dtd->pentities);
3710
3711 cur = dtd->children;
3712 while (cur != NULL) {
3713 q = NULL;
3714
3715 if (cur->type == XML_ENTITY_DECL) {
3716 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3717 switch (tmp->etype) {
3718 case XML_INTERNAL_GENERAL_ENTITY:
3719 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3720 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3721 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3722 break;
3723 case XML_INTERNAL_PARAMETER_ENTITY:
3724 case XML_EXTERNAL_PARAMETER_ENTITY:
3725 q = (xmlNodePtr)
3726 xmlGetParameterEntityFromDtd(ret, tmp->name);
3727 break;
3728 case XML_INTERNAL_PREDEFINED_ENTITY:
3729 break;
3730 }
3731 } else if (cur->type == XML_ELEMENT_DECL) {
3732 xmlElementPtr tmp = (xmlElementPtr) cur;
3733 q = (xmlNodePtr)
3734 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3735 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3736 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3737 q = (xmlNodePtr)
3738 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3739 } else if (cur->type == XML_COMMENT_NODE) {
3740 q = xmlCopyNode(cur, 0);
3741 }
3742
3743 if (q == NULL) {
3744 cur = cur->next;
3745 continue;
3746 }
3747
3748 if (p == NULL)
3749 ret->children = q;
3750 else
3751 p->next = q;
3752
3753 q->prev = p;
3754 q->parent = (xmlNodePtr) ret;
3755 q->next = NULL;
3756 ret->last = q;
3757 p = q;
3758 cur = cur->next;
3759 }
3760
Owen Taylor3473f882001-02-23 17:55:21 +00003761 return(ret);
3762}
3763
3764/**
3765 * xmlCopyDoc:
3766 * @doc: the document
3767 * @recursive: if 1 do a recursive copy.
3768 *
3769 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003770 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003771 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003772 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003773 */
3774xmlDocPtr
3775xmlCopyDoc(xmlDocPtr doc, int recursive) {
3776 xmlDocPtr ret;
3777
3778 if (doc == NULL) return(NULL);
3779 ret = xmlNewDoc(doc->version);
3780 if (ret == NULL) return(NULL);
3781 if (doc->name != NULL)
3782 ret->name = xmlMemStrdup(doc->name);
3783 if (doc->encoding != NULL)
3784 ret->encoding = xmlStrdup(doc->encoding);
3785 ret->charset = doc->charset;
3786 ret->compression = doc->compression;
3787 ret->standalone = doc->standalone;
3788 if (!recursive) return(ret);
3789
Daniel Veillardb33c2012001-04-25 12:59:04 +00003790 ret->last = NULL;
3791 ret->children = NULL;
3792 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003793 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003794 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003795 ret->intSubset->parent = ret;
3796 }
Owen Taylor3473f882001-02-23 17:55:21 +00003797 if (doc->oldNs != NULL)
3798 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3799 if (doc->children != NULL) {
3800 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003801
3802 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3803 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003804 ret->last = NULL;
3805 tmp = ret->children;
3806 while (tmp != NULL) {
3807 if (tmp->next == NULL)
3808 ret->last = tmp;
3809 tmp = tmp->next;
3810 }
3811 }
3812 return(ret);
3813}
3814
3815/************************************************************************
3816 * *
3817 * Content access functions *
3818 * *
3819 ************************************************************************/
3820
3821/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003822 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003823 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00003824 *
3825 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003826 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003827 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003828 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003829 */
3830long
3831xmlGetLineNo(xmlNodePtr node)
3832{
3833 long result = -1;
3834
3835 if (!node)
3836 return result;
3837 if (node->type == XML_ELEMENT_NODE)
3838 result = (long) node->content;
3839 else if ((node->prev != NULL) &&
3840 ((node->prev->type == XML_ELEMENT_NODE) ||
3841 (node->prev->type == XML_TEXT_NODE)))
3842 result = xmlGetLineNo(node->prev);
3843 else if ((node->parent != NULL) &&
3844 ((node->parent->type == XML_ELEMENT_NODE) ||
3845 (node->parent->type == XML_TEXT_NODE)))
3846 result = xmlGetLineNo(node->parent);
3847
3848 return result;
3849}
3850
3851/**
3852 * xmlGetNodePath:
3853 * @node: a node
3854 *
3855 * Build a structure based Path for the given node
3856 *
3857 * Returns the new path or NULL in case of error. The caller must free
3858 * the returned string
3859 */
3860xmlChar *
3861xmlGetNodePath(xmlNodePtr node)
3862{
3863 xmlNodePtr cur, tmp, next;
3864 xmlChar *buffer = NULL, *temp;
3865 size_t buf_len;
3866 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00003867 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00003868 const char *name;
3869 char nametemp[100];
3870 int occur = 0;
3871
3872 if (node == NULL)
3873 return (NULL);
3874
3875 buf_len = 500;
3876 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3877 if (buffer == NULL)
3878 return (NULL);
3879 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3880 if (buf == NULL) {
3881 xmlFree(buffer);
3882 return (NULL);
3883 }
3884
3885 buffer[0] = 0;
3886 cur = node;
3887 do {
3888 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003889 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003890 occur = 0;
3891 if ((cur->type == XML_DOCUMENT_NODE) ||
3892 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3893 if (buffer[0] == '/')
3894 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003895 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003896 next = NULL;
3897 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003898 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003899 name = (const char *) cur->name;
3900 if (cur->ns) {
3901 snprintf(nametemp, sizeof(nametemp) - 1,
3902 "%s:%s", cur->ns->prefix, cur->name);
3903 nametemp[sizeof(nametemp) - 1] = 0;
3904 name = nametemp;
3905 }
3906 next = cur->parent;
3907
3908 /*
3909 * Thumbler index computation
3910 */
3911 tmp = cur->prev;
3912 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00003913 if ((tmp->type == XML_ELEMENT_NODE) &&
3914 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00003915 occur++;
3916 tmp = tmp->prev;
3917 }
3918 if (occur == 0) {
3919 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00003920 while (tmp != NULL && occur == 0) {
3921 if ((tmp->type == XML_ELEMENT_NODE) &&
3922 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00003923 occur++;
3924 tmp = tmp->next;
3925 }
3926 if (occur != 0)
3927 occur = 1;
3928 } else
3929 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00003930 } else if (cur->type == XML_COMMENT_NODE) {
3931 sep = "/";
3932 name = "comment()";
3933 next = cur->parent;
3934
3935 /*
3936 * Thumbler index computation
3937 */
3938 tmp = cur->prev;
3939 while (tmp != NULL) {
3940 if (tmp->type == XML_COMMENT_NODE)
3941 occur++;
3942 tmp = tmp->prev;
3943 }
3944 if (occur == 0) {
3945 tmp = cur->next;
3946 while (tmp != NULL && occur == 0) {
3947 if (tmp->type == XML_COMMENT_NODE)
3948 occur++;
3949 tmp = tmp->next;
3950 }
3951 if (occur != 0)
3952 occur = 1;
3953 } else
3954 occur++;
3955 } else if ((cur->type == XML_TEXT_NODE) ||
3956 (cur->type == XML_CDATA_SECTION_NODE)) {
3957 sep = "/";
3958 name = "text()";
3959 next = cur->parent;
3960
3961 /*
3962 * Thumbler index computation
3963 */
3964 tmp = cur->prev;
3965 while (tmp != NULL) {
3966 if ((cur->type == XML_TEXT_NODE) ||
3967 (cur->type == XML_CDATA_SECTION_NODE))
3968 occur++;
3969 tmp = tmp->prev;
3970 }
3971 if (occur == 0) {
3972 tmp = cur->next;
3973 while (tmp != NULL && occur == 0) {
3974 if ((cur->type == XML_TEXT_NODE) ||
3975 (cur->type == XML_CDATA_SECTION_NODE))
3976 occur++;
3977 tmp = tmp->next;
3978 }
3979 if (occur != 0)
3980 occur = 1;
3981 } else
3982 occur++;
3983 } else if (cur->type == XML_PI_NODE) {
3984 sep = "/";
3985 snprintf(nametemp, sizeof(nametemp) - 1,
3986 "processing-instruction('%s')", cur->name);
3987 nametemp[sizeof(nametemp) - 1] = 0;
3988 name = nametemp;
3989
3990 next = cur->parent;
3991
3992 /*
3993 * Thumbler index computation
3994 */
3995 tmp = cur->prev;
3996 while (tmp != NULL) {
3997 if ((tmp->type == XML_PI_NODE) &&
3998 (xmlStrEqual(cur->name, tmp->name)))
3999 occur++;
4000 tmp = tmp->prev;
4001 }
4002 if (occur == 0) {
4003 tmp = cur->next;
4004 while (tmp != NULL && occur == 0) {
4005 if ((tmp->type == XML_PI_NODE) &&
4006 (xmlStrEqual(cur->name, tmp->name)))
4007 occur++;
4008 tmp = tmp->next;
4009 }
4010 if (occur != 0)
4011 occur = 1;
4012 } else
4013 occur++;
4014
Daniel Veillard8faa7832001-11-26 15:58:08 +00004015 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004016 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004017 name = (const char *) (((xmlAttrPtr) cur)->name);
4018 next = ((xmlAttrPtr) cur)->parent;
4019 } else {
4020 next = cur->parent;
4021 }
4022
4023 /*
4024 * Make sure there is enough room
4025 */
4026 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4027 buf_len =
4028 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4029 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4030 if (temp == NULL) {
4031 xmlFree(buf);
4032 xmlFree(buffer);
4033 return (NULL);
4034 }
4035 buffer = temp;
4036 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4037 if (temp == NULL) {
4038 xmlFree(buf);
4039 xmlFree(buffer);
4040 return (NULL);
4041 }
4042 buf = temp;
4043 }
4044 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004045 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004046 sep, name, (char *) buffer);
4047 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004048 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004049 sep, name, occur, (char *) buffer);
4050 snprintf((char *) buffer, buf_len, "%s", buf);
4051 cur = next;
4052 } while (cur != NULL);
4053 xmlFree(buf);
4054 return (buffer);
4055}
4056
4057/**
Owen Taylor3473f882001-02-23 17:55:21 +00004058 * xmlDocGetRootElement:
4059 * @doc: the document
4060 *
4061 * Get the root element of the document (doc->children is a list
4062 * containing possibly comments, PIs, etc ...).
4063 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004064 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004065 */
4066xmlNodePtr
4067xmlDocGetRootElement(xmlDocPtr doc) {
4068 xmlNodePtr ret;
4069
4070 if (doc == NULL) return(NULL);
4071 ret = doc->children;
4072 while (ret != NULL) {
4073 if (ret->type == XML_ELEMENT_NODE)
4074 return(ret);
4075 ret = ret->next;
4076 }
4077 return(ret);
4078}
4079
4080/**
4081 * xmlDocSetRootElement:
4082 * @doc: the document
4083 * @root: the new document root element
4084 *
4085 * Set the root element of the document (doc->children is a list
4086 * containing possibly comments, PIs, etc ...).
4087 *
4088 * Returns the old root element if any was found
4089 */
4090xmlNodePtr
4091xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4092 xmlNodePtr old = NULL;
4093
4094 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004095 if (root == NULL)
4096 return(NULL);
4097 xmlUnlinkNode(root);
4098 root->doc = doc;
4099 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004100 old = doc->children;
4101 while (old != NULL) {
4102 if (old->type == XML_ELEMENT_NODE)
4103 break;
4104 old = old->next;
4105 }
4106 if (old == NULL) {
4107 if (doc->children == NULL) {
4108 doc->children = root;
4109 doc->last = root;
4110 } else {
4111 xmlAddSibling(doc->children, root);
4112 }
4113 } else {
4114 xmlReplaceNode(old, root);
4115 }
4116 return(old);
4117}
4118
4119/**
4120 * xmlNodeSetLang:
4121 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004122 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004123 *
4124 * Set the language of a node, i.e. the values of the xml:lang
4125 * attribute.
4126 */
4127void
4128xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004129 xmlNsPtr ns;
4130
Owen Taylor3473f882001-02-23 17:55:21 +00004131 if (cur == NULL) return;
4132 switch(cur->type) {
4133 case XML_TEXT_NODE:
4134 case XML_CDATA_SECTION_NODE:
4135 case XML_COMMENT_NODE:
4136 case XML_DOCUMENT_NODE:
4137 case XML_DOCUMENT_TYPE_NODE:
4138 case XML_DOCUMENT_FRAG_NODE:
4139 case XML_NOTATION_NODE:
4140 case XML_HTML_DOCUMENT_NODE:
4141 case XML_DTD_NODE:
4142 case XML_ELEMENT_DECL:
4143 case XML_ATTRIBUTE_DECL:
4144 case XML_ENTITY_DECL:
4145 case XML_PI_NODE:
4146 case XML_ENTITY_REF_NODE:
4147 case XML_ENTITY_NODE:
4148 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004149#ifdef LIBXML_DOCB_ENABLED
4150 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004151#endif
4152 case XML_XINCLUDE_START:
4153 case XML_XINCLUDE_END:
4154 return;
4155 case XML_ELEMENT_NODE:
4156 case XML_ATTRIBUTE_NODE:
4157 break;
4158 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004159 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4160 if (ns == NULL)
4161 return;
4162 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004163}
4164
4165/**
4166 * xmlNodeGetLang:
4167 * @cur: the node being checked
4168 *
4169 * Searches the language of a node, i.e. the values of the xml:lang
4170 * attribute or the one carried by the nearest ancestor.
4171 *
4172 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004173 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004174 */
4175xmlChar *
4176xmlNodeGetLang(xmlNodePtr cur) {
4177 xmlChar *lang;
4178
4179 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004180 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004181 if (lang != NULL)
4182 return(lang);
4183 cur = cur->parent;
4184 }
4185 return(NULL);
4186}
4187
4188
4189/**
4190 * xmlNodeSetSpacePreserve:
4191 * @cur: the node being changed
4192 * @val: the xml:space value ("0": default, 1: "preserve")
4193 *
4194 * Set (or reset) the space preserving behaviour of a node, i.e. the
4195 * value of the xml:space attribute.
4196 */
4197void
4198xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004199 xmlNsPtr ns;
4200
Owen Taylor3473f882001-02-23 17:55:21 +00004201 if (cur == NULL) return;
4202 switch(cur->type) {
4203 case XML_TEXT_NODE:
4204 case XML_CDATA_SECTION_NODE:
4205 case XML_COMMENT_NODE:
4206 case XML_DOCUMENT_NODE:
4207 case XML_DOCUMENT_TYPE_NODE:
4208 case XML_DOCUMENT_FRAG_NODE:
4209 case XML_NOTATION_NODE:
4210 case XML_HTML_DOCUMENT_NODE:
4211 case XML_DTD_NODE:
4212 case XML_ELEMENT_DECL:
4213 case XML_ATTRIBUTE_DECL:
4214 case XML_ENTITY_DECL:
4215 case XML_PI_NODE:
4216 case XML_ENTITY_REF_NODE:
4217 case XML_ENTITY_NODE:
4218 case XML_NAMESPACE_DECL:
4219 case XML_XINCLUDE_START:
4220 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004221#ifdef LIBXML_DOCB_ENABLED
4222 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004223#endif
4224 return;
4225 case XML_ELEMENT_NODE:
4226 case XML_ATTRIBUTE_NODE:
4227 break;
4228 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004229 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4230 if (ns == NULL)
4231 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004232 switch (val) {
4233 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004234 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004235 break;
4236 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004237 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004238 break;
4239 }
4240}
4241
4242/**
4243 * xmlNodeGetSpacePreserve:
4244 * @cur: the node being checked
4245 *
4246 * Searches the space preserving behaviour of a node, i.e. the values
4247 * of the xml:space attribute or the one carried by the nearest
4248 * ancestor.
4249 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004250 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004251 */
4252int
4253xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4254 xmlChar *space;
4255
4256 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004257 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004258 if (space != NULL) {
4259 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4260 xmlFree(space);
4261 return(1);
4262 }
4263 if (xmlStrEqual(space, BAD_CAST "default")) {
4264 xmlFree(space);
4265 return(0);
4266 }
4267 xmlFree(space);
4268 }
4269 cur = cur->parent;
4270 }
4271 return(-1);
4272}
4273
4274/**
4275 * xmlNodeSetName:
4276 * @cur: the node being changed
4277 * @name: the new tag name
4278 *
4279 * Set (or reset) the name of a node.
4280 */
4281void
4282xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
4283 if (cur == NULL) return;
4284 if (name == NULL) return;
4285 switch(cur->type) {
4286 case XML_TEXT_NODE:
4287 case XML_CDATA_SECTION_NODE:
4288 case XML_COMMENT_NODE:
4289 case XML_DOCUMENT_TYPE_NODE:
4290 case XML_DOCUMENT_FRAG_NODE:
4291 case XML_NOTATION_NODE:
4292 case XML_HTML_DOCUMENT_NODE:
4293 case XML_NAMESPACE_DECL:
4294 case XML_XINCLUDE_START:
4295 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004296#ifdef LIBXML_DOCB_ENABLED
4297 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004298#endif
4299 return;
4300 case XML_ELEMENT_NODE:
4301 case XML_ATTRIBUTE_NODE:
4302 case XML_PI_NODE:
4303 case XML_ENTITY_REF_NODE:
4304 case XML_ENTITY_NODE:
4305 case XML_DTD_NODE:
4306 case XML_DOCUMENT_NODE:
4307 case XML_ELEMENT_DECL:
4308 case XML_ATTRIBUTE_DECL:
4309 case XML_ENTITY_DECL:
4310 break;
4311 }
4312 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4313 cur->name = xmlStrdup(name);
4314}
4315
4316/**
4317 * xmlNodeSetBase:
4318 * @cur: the node being changed
4319 * @uri: the new base URI
4320 *
4321 * Set (or reset) the base URI of a node, i.e. the value of the
4322 * xml:base attribute.
4323 */
4324void
4325xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004326 xmlNsPtr ns;
4327
Owen Taylor3473f882001-02-23 17:55:21 +00004328 if (cur == NULL) return;
4329 switch(cur->type) {
4330 case XML_TEXT_NODE:
4331 case XML_CDATA_SECTION_NODE:
4332 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004333 case XML_DOCUMENT_TYPE_NODE:
4334 case XML_DOCUMENT_FRAG_NODE:
4335 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004336 case XML_DTD_NODE:
4337 case XML_ELEMENT_DECL:
4338 case XML_ATTRIBUTE_DECL:
4339 case XML_ENTITY_DECL:
4340 case XML_PI_NODE:
4341 case XML_ENTITY_REF_NODE:
4342 case XML_ENTITY_NODE:
4343 case XML_NAMESPACE_DECL:
4344 case XML_XINCLUDE_START:
4345 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004346 return;
4347 case XML_ELEMENT_NODE:
4348 case XML_ATTRIBUTE_NODE:
4349 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004350 case XML_DOCUMENT_NODE:
4351#ifdef LIBXML_DOCB_ENABLED
4352 case XML_DOCB_DOCUMENT_NODE:
4353#endif
4354 case XML_HTML_DOCUMENT_NODE: {
4355 xmlDocPtr doc = (xmlDocPtr) cur;
4356
4357 if (doc->URL != NULL)
4358 xmlFree((xmlChar *) doc->URL);
4359 if (uri == NULL)
4360 doc->URL = NULL;
4361 else
4362 doc->URL = xmlStrdup(uri);
4363 return;
4364 }
Owen Taylor3473f882001-02-23 17:55:21 +00004365 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004366
4367 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4368 if (ns == NULL)
4369 return;
4370 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004371}
4372
4373/**
Owen Taylor3473f882001-02-23 17:55:21 +00004374 * xmlNodeGetBase:
4375 * @doc: the document the node pertains to
4376 * @cur: the node being checked
4377 *
4378 * Searches for the BASE URL. The code should work on both XML
4379 * and HTML document even if base mechanisms are completely different.
4380 * It returns the base as defined in RFC 2396 sections
4381 * 5.1.1. Base URI within Document Content
4382 * and
4383 * 5.1.2. Base URI from the Encapsulating Entity
4384 * However it does not return the document base (5.1.3), use
4385 * xmlDocumentGetBase() for this
4386 *
4387 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004388 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004389 */
4390xmlChar *
4391xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004392 xmlChar *oldbase = NULL;
4393 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004394
4395 if ((cur == NULL) && (doc == NULL))
4396 return(NULL);
4397 if (doc == NULL) doc = cur->doc;
4398 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4399 cur = doc->children;
4400 while ((cur != NULL) && (cur->name != NULL)) {
4401 if (cur->type != XML_ELEMENT_NODE) {
4402 cur = cur->next;
4403 continue;
4404 }
4405 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4406 cur = cur->children;
4407 continue;
4408 }
4409 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4410 cur = cur->children;
4411 continue;
4412 }
4413 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4414 return(xmlGetProp(cur, BAD_CAST "href"));
4415 }
4416 cur = cur->next;
4417 }
4418 return(NULL);
4419 }
4420 while (cur != NULL) {
4421 if (cur->type == XML_ENTITY_DECL) {
4422 xmlEntityPtr ent = (xmlEntityPtr) cur;
4423 return(xmlStrdup(ent->URI));
4424 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004425 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004426 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004427 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004428 if (oldbase != NULL) {
4429 newbase = xmlBuildURI(oldbase, base);
4430 if (newbase != NULL) {
4431 xmlFree(oldbase);
4432 xmlFree(base);
4433 oldbase = newbase;
4434 } else {
4435 xmlFree(oldbase);
4436 xmlFree(base);
4437 return(NULL);
4438 }
4439 } else {
4440 oldbase = base;
4441 }
4442 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4443 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4444 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4445 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004446 }
4447 }
Owen Taylor3473f882001-02-23 17:55:21 +00004448 cur = cur->parent;
4449 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004450 if ((doc != NULL) && (doc->URL != NULL)) {
4451 if (oldbase == NULL)
4452 return(xmlStrdup(doc->URL));
4453 newbase = xmlBuildURI(oldbase, doc->URL);
4454 xmlFree(oldbase);
4455 return(newbase);
4456 }
4457 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004458}
4459
4460/**
4461 * xmlNodeGetContent:
4462 * @cur: the node being read
4463 *
4464 * Read the value of a node, this can be either the text carried
4465 * directly by this node if it's a TEXT node or the aggregate string
4466 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004467 * Entity references are substituted.
4468 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004469 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004470 */
4471xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004472xmlNodeGetContent(xmlNodePtr cur)
4473{
4474 if (cur == NULL)
4475 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004476 switch (cur->type) {
4477 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004478 case XML_ELEMENT_NODE:{
4479 xmlNodePtr tmp = cur;
4480 xmlBufferPtr buffer;
4481 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004482
Daniel Veillard814a76d2003-01-23 18:24:20 +00004483 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004484 if (buffer == NULL)
4485 return (NULL);
4486 while (tmp != NULL) {
4487 switch (tmp->type) {
4488 case XML_CDATA_SECTION_NODE:
4489 case XML_TEXT_NODE:
4490 if (tmp->content != NULL)
4491 xmlBufferCat(buffer, tmp->content);
4492 break;
4493 case XML_ENTITY_REF_NODE:{
4494 /* recursive substitution of entity references */
4495 xmlChar *cont = xmlNodeGetContent(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00004496
Daniel Veillard7646b182002-04-20 06:41:40 +00004497 if (cont) {
4498 xmlBufferCat(buffer,
4499 (const xmlChar *) cont);
4500 xmlFree(cont);
4501 }
4502 break;
4503 }
4504 default:
4505 break;
4506 }
4507 /*
4508 * Skip to next node
4509 */
4510 if (tmp->children != NULL) {
4511 if (tmp->children->type != XML_ENTITY_DECL) {
4512 tmp = tmp->children;
4513 continue;
4514 }
4515 }
4516 if (tmp == cur)
4517 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00004518
Daniel Veillard7646b182002-04-20 06:41:40 +00004519 if (tmp->next != NULL) {
4520 tmp = tmp->next;
4521 continue;
4522 }
4523
4524 do {
4525 tmp = tmp->parent;
4526 if (tmp == NULL)
4527 break;
4528 if (tmp == cur) {
4529 tmp = NULL;
4530 break;
4531 }
4532 if (tmp->next != NULL) {
4533 tmp = tmp->next;
4534 break;
4535 }
4536 } while (tmp != NULL);
4537 }
4538 ret = buffer->content;
4539 buffer->content = NULL;
4540 xmlBufferFree(buffer);
4541 return (ret);
4542 }
4543 case XML_ATTRIBUTE_NODE:{
4544 xmlAttrPtr attr = (xmlAttrPtr) cur;
4545
4546 if (attr->parent != NULL)
4547 return (xmlNodeListGetString
4548 (attr->parent->doc, attr->children, 1));
4549 else
4550 return (xmlNodeListGetString(NULL, attr->children, 1));
4551 break;
4552 }
Owen Taylor3473f882001-02-23 17:55:21 +00004553 case XML_COMMENT_NODE:
4554 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004555 if (cur->content != NULL)
4556 return (xmlStrdup(cur->content));
4557 return (NULL);
4558 case XML_ENTITY_REF_NODE:{
4559 xmlEntityPtr ent;
4560 xmlNodePtr tmp;
4561 xmlBufferPtr buffer;
4562 xmlChar *ret;
4563
4564 /* lookup entity declaration */
4565 ent = xmlGetDocEntity(cur->doc, cur->name);
4566 if (ent == NULL)
4567 return (NULL);
4568
4569 buffer = xmlBufferCreate();
4570 if (buffer == NULL)
4571 return (NULL);
4572
4573 /* an entity content can be any "well balanced chunk",
4574 * i.e. the result of the content [43] production:
4575 * http://www.w3.org/TR/REC-xml#NT-content
4576 * -> we iterate through child nodes and recursive call
4577 * xmlNodeGetContent() which handles all possible node types */
4578 tmp = ent->children;
4579 while (tmp) {
4580 xmlChar *cont = xmlNodeGetContent(tmp);
4581
4582 if (cont) {
4583 xmlBufferCat(buffer, (const xmlChar *) cont);
4584 xmlFree(cont);
4585 }
4586 tmp = tmp->next;
4587 }
4588
4589 ret = buffer->content;
4590 buffer->content = NULL;
4591 xmlBufferFree(buffer);
4592 return (ret);
4593 }
Owen Taylor3473f882001-02-23 17:55:21 +00004594 case XML_ENTITY_NODE:
4595 case XML_DOCUMENT_NODE:
4596 case XML_HTML_DOCUMENT_NODE:
4597 case XML_DOCUMENT_TYPE_NODE:
4598 case XML_NOTATION_NODE:
4599 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004600 case XML_XINCLUDE_START:
4601 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004602#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004603 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004604#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00004605 return (NULL);
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004606 case XML_NAMESPACE_DECL: {
4607 xmlChar *tmp;
4608
4609 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4610 return (tmp);
4611 }
Owen Taylor3473f882001-02-23 17:55:21 +00004612 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004613 /* TODO !!! */
4614 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004615 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004616 /* TODO !!! */
4617 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004618 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004619 /* TODO !!! */
4620 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004621 case XML_CDATA_SECTION_NODE:
4622 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004623 if (cur->content != NULL)
4624 return (xmlStrdup(cur->content));
4625 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004626 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004627 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004628}
Owen Taylor3473f882001-02-23 17:55:21 +00004629/**
4630 * xmlNodeSetContent:
4631 * @cur: the node being modified
4632 * @content: the new value of the content
4633 *
4634 * Replace the content of a node.
4635 */
4636void
4637xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4638 if (cur == NULL) {
4639#ifdef DEBUG_TREE
4640 xmlGenericError(xmlGenericErrorContext,
4641 "xmlNodeSetContent : node == NULL\n");
4642#endif
4643 return;
4644 }
4645 switch (cur->type) {
4646 case XML_DOCUMENT_FRAG_NODE:
4647 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004648 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004649 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4650 cur->children = xmlStringGetNodeList(cur->doc, content);
4651 UPDATE_LAST_CHILD_AND_PARENT(cur)
4652 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004653 case XML_TEXT_NODE:
4654 case XML_CDATA_SECTION_NODE:
4655 case XML_ENTITY_REF_NODE:
4656 case XML_ENTITY_NODE:
4657 case XML_PI_NODE:
4658 case XML_COMMENT_NODE:
4659 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004660 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004661 }
4662 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4663 cur->last = cur->children = NULL;
4664 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004665 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00004666 } else
4667 cur->content = NULL;
4668 break;
4669 case XML_DOCUMENT_NODE:
4670 case XML_HTML_DOCUMENT_NODE:
4671 case XML_DOCUMENT_TYPE_NODE:
4672 case XML_XINCLUDE_START:
4673 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004674#ifdef LIBXML_DOCB_ENABLED
4675 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004676#endif
4677 break;
4678 case XML_NOTATION_NODE:
4679 break;
4680 case XML_DTD_NODE:
4681 break;
4682 case XML_NAMESPACE_DECL:
4683 break;
4684 case XML_ELEMENT_DECL:
4685 /* TODO !!! */
4686 break;
4687 case XML_ATTRIBUTE_DECL:
4688 /* TODO !!! */
4689 break;
4690 case XML_ENTITY_DECL:
4691 /* TODO !!! */
4692 break;
4693 }
4694}
4695
4696/**
4697 * xmlNodeSetContentLen:
4698 * @cur: the node being modified
4699 * @content: the new value of the content
4700 * @len: the size of @content
4701 *
4702 * Replace the content of a node.
4703 */
4704void
4705xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4706 if (cur == NULL) {
4707#ifdef DEBUG_TREE
4708 xmlGenericError(xmlGenericErrorContext,
4709 "xmlNodeSetContentLen : node == NULL\n");
4710#endif
4711 return;
4712 }
4713 switch (cur->type) {
4714 case XML_DOCUMENT_FRAG_NODE:
4715 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004716 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004717 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4718 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
4719 UPDATE_LAST_CHILD_AND_PARENT(cur)
4720 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004721 case XML_TEXT_NODE:
4722 case XML_CDATA_SECTION_NODE:
4723 case XML_ENTITY_REF_NODE:
4724 case XML_ENTITY_NODE:
4725 case XML_PI_NODE:
4726 case XML_COMMENT_NODE:
4727 case XML_NOTATION_NODE:
4728 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004729 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004730 }
4731 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4732 cur->children = cur->last = NULL;
4733 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004734 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004735 } else
4736 cur->content = NULL;
4737 break;
4738 case XML_DOCUMENT_NODE:
4739 case XML_DTD_NODE:
4740 case XML_HTML_DOCUMENT_NODE:
4741 case XML_DOCUMENT_TYPE_NODE:
4742 case XML_NAMESPACE_DECL:
4743 case XML_XINCLUDE_START:
4744 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004745#ifdef LIBXML_DOCB_ENABLED
4746 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004747#endif
4748 break;
4749 case XML_ELEMENT_DECL:
4750 /* TODO !!! */
4751 break;
4752 case XML_ATTRIBUTE_DECL:
4753 /* TODO !!! */
4754 break;
4755 case XML_ENTITY_DECL:
4756 /* TODO !!! */
4757 break;
4758 }
4759}
4760
4761/**
4762 * xmlNodeAddContentLen:
4763 * @cur: the node being modified
4764 * @content: extra content
4765 * @len: the size of @content
4766 *
4767 * Append the extra substring to the node content.
4768 */
4769void
4770xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4771 if (cur == NULL) {
4772#ifdef DEBUG_TREE
4773 xmlGenericError(xmlGenericErrorContext,
4774 "xmlNodeAddContentLen : node == NULL\n");
4775#endif
4776 return;
4777 }
4778 if (len <= 0) return;
4779 switch (cur->type) {
4780 case XML_DOCUMENT_FRAG_NODE:
4781 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004782 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004783
Daniel Veillard7db37732001-07-12 01:20:08 +00004784 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004785 newNode = xmlNewTextLen(content, len);
4786 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004787 tmp = xmlAddChild(cur, newNode);
4788 if (tmp != newNode)
4789 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004790 if ((last != NULL) && (last->next == newNode)) {
4791 xmlTextMerge(last, newNode);
4792 }
4793 }
4794 break;
4795 }
4796 case XML_ATTRIBUTE_NODE:
4797 break;
4798 case XML_TEXT_NODE:
4799 case XML_CDATA_SECTION_NODE:
4800 case XML_ENTITY_REF_NODE:
4801 case XML_ENTITY_NODE:
4802 case XML_PI_NODE:
4803 case XML_COMMENT_NODE:
4804 case XML_NOTATION_NODE:
4805 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004806 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004807 }
4808 case XML_DOCUMENT_NODE:
4809 case XML_DTD_NODE:
4810 case XML_HTML_DOCUMENT_NODE:
4811 case XML_DOCUMENT_TYPE_NODE:
4812 case XML_NAMESPACE_DECL:
4813 case XML_XINCLUDE_START:
4814 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004815#ifdef LIBXML_DOCB_ENABLED
4816 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004817#endif
4818 break;
4819 case XML_ELEMENT_DECL:
4820 case XML_ATTRIBUTE_DECL:
4821 case XML_ENTITY_DECL:
4822 break;
4823 }
4824}
4825
4826/**
4827 * xmlNodeAddContent:
4828 * @cur: the node being modified
4829 * @content: extra content
4830 *
4831 * Append the extra substring to the node content.
4832 */
4833void
4834xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
4835 int len;
4836
4837 if (cur == NULL) {
4838#ifdef DEBUG_TREE
4839 xmlGenericError(xmlGenericErrorContext,
4840 "xmlNodeAddContent : node == NULL\n");
4841#endif
4842 return;
4843 }
4844 if (content == NULL) return;
4845 len = xmlStrlen(content);
4846 xmlNodeAddContentLen(cur, content, len);
4847}
4848
4849/**
4850 * xmlTextMerge:
4851 * @first: the first text node
4852 * @second: the second text node being merged
4853 *
4854 * Merge two text nodes into one
4855 * Returns the first text node augmented
4856 */
4857xmlNodePtr
4858xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
4859 if (first == NULL) return(second);
4860 if (second == NULL) return(first);
4861 if (first->type != XML_TEXT_NODE) return(first);
4862 if (second->type != XML_TEXT_NODE) return(first);
4863 if (second->name != first->name)
4864 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00004865 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004866 xmlUnlinkNode(second);
4867 xmlFreeNode(second);
4868 return(first);
4869}
4870
4871/**
4872 * xmlGetNsList:
4873 * @doc: the document
4874 * @node: the current node
4875 *
4876 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00004877 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00004878 * that need to be freed by the caller or NULL if no
4879 * namespace if defined
4880 */
4881xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00004882xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
4883{
Owen Taylor3473f882001-02-23 17:55:21 +00004884 xmlNsPtr cur;
4885 xmlNsPtr *ret = NULL;
4886 int nbns = 0;
4887 int maxns = 10;
4888 int i;
4889
4890 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00004891 if (node->type == XML_ELEMENT_NODE) {
4892 cur = node->nsDef;
4893 while (cur != NULL) {
4894 if (ret == NULL) {
4895 ret =
4896 (xmlNsPtr *) xmlMalloc((maxns + 1) *
4897 sizeof(xmlNsPtr));
4898 if (ret == NULL) {
4899 xmlGenericError(xmlGenericErrorContext,
4900 "xmlGetNsList : out of memory!\n");
4901 return (NULL);
4902 }
4903 ret[nbns] = NULL;
4904 }
4905 for (i = 0; i < nbns; i++) {
4906 if ((cur->prefix == ret[i]->prefix) ||
4907 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
4908 break;
4909 }
4910 if (i >= nbns) {
4911 if (nbns >= maxns) {
4912 maxns *= 2;
4913 ret = (xmlNsPtr *) xmlRealloc(ret,
4914 (maxns +
4915 1) *
4916 sizeof(xmlNsPtr));
4917 if (ret == NULL) {
4918 xmlGenericError(xmlGenericErrorContext,
4919 "xmlGetNsList : realloc failed!\n");
4920 return (NULL);
4921 }
4922 }
4923 ret[nbns++] = cur;
4924 ret[nbns] = NULL;
4925 }
Owen Taylor3473f882001-02-23 17:55:21 +00004926
Daniel Veillard77044732001-06-29 21:31:07 +00004927 cur = cur->next;
4928 }
4929 }
4930 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004931 }
Daniel Veillard77044732001-06-29 21:31:07 +00004932 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004933}
4934
4935/**
4936 * xmlSearchNs:
4937 * @doc: the document
4938 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004939 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004940 *
4941 * Search a Ns registered under a given name space for a document.
4942 * recurse on the parents until it finds the defined namespace
4943 * or return NULL otherwise.
4944 * @nameSpace can be NULL, this is a search for the default namespace.
4945 * We don't allow to cross entities boundaries. If you don't declare
4946 * the namespace within those you will be in troubles !!! A warning
4947 * is generated to cover this case.
4948 *
4949 * Returns the namespace pointer or NULL.
4950 */
4951xmlNsPtr
4952xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4953 xmlNsPtr cur;
4954
4955 if (node == NULL) return(NULL);
4956 if ((nameSpace != NULL) &&
4957 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00004958 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4959 /*
4960 * The XML-1.0 namespace is normally held on the root
4961 * element. In this case exceptionally create it on the
4962 * node element.
4963 */
4964 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4965 if (cur == NULL) {
4966 xmlGenericError(xmlGenericErrorContext,
4967 "xmlSearchNs : malloc failed\n");
4968 return(NULL);
4969 }
4970 memset(cur, 0, sizeof(xmlNs));
4971 cur->type = XML_LOCAL_NAMESPACE;
4972 cur->href = xmlStrdup(XML_XML_NAMESPACE);
4973 cur->prefix = xmlStrdup((const xmlChar *)"xml");
4974 cur->next = node->nsDef;
4975 node->nsDef = cur;
4976 return(cur);
4977 }
Owen Taylor3473f882001-02-23 17:55:21 +00004978 if (doc->oldNs == NULL) {
4979 /*
4980 * Allocate a new Namespace and fill the fields.
4981 */
4982 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4983 if (doc->oldNs == NULL) {
4984 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004985 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004986 return(NULL);
4987 }
4988 memset(doc->oldNs, 0, sizeof(xmlNs));
4989 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4990
4991 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4992 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4993 }
4994 return(doc->oldNs);
4995 }
4996 while (node != NULL) {
4997 if ((node->type == XML_ENTITY_REF_NODE) ||
4998 (node->type == XML_ENTITY_NODE) ||
4999 (node->type == XML_ENTITY_DECL))
5000 return(NULL);
5001 if (node->type == XML_ELEMENT_NODE) {
5002 cur = node->nsDef;
5003 while (cur != NULL) {
5004 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5005 (cur->href != NULL))
5006 return(cur);
5007 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5008 (cur->href != NULL) &&
5009 (xmlStrEqual(cur->prefix, nameSpace)))
5010 return(cur);
5011 cur = cur->next;
5012 }
5013 }
5014 node = node->parent;
5015 }
5016 return(NULL);
5017}
5018
5019/**
5020 * xmlSearchNsByHref:
5021 * @doc: the document
5022 * @node: the current node
5023 * @href: the namespace value
5024 *
5025 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5026 * the defined namespace or return NULL otherwise.
5027 * Returns the namespace pointer or NULL.
5028 */
5029xmlNsPtr
5030xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
5031 xmlNsPtr cur;
5032 xmlNodePtr orig = node;
5033
5034 if ((node == NULL) || (href == NULL)) return(NULL);
5035 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00005036 /*
5037 * Only the document can hold the XML spec namespace.
5038 */
Daniel Veillardc1a0da32002-08-14 08:32:18 +00005039 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5040 /*
5041 * The XML-1.0 namespace is normally held on the root
5042 * element. In this case exceptionally create it on the
5043 * node element.
5044 */
5045 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5046 if (cur == NULL) {
5047 xmlGenericError(xmlGenericErrorContext,
5048 "xmlSearchNs : malloc failed\n");
5049 return(NULL);
5050 }
5051 memset(cur, 0, sizeof(xmlNs));
5052 cur->type = XML_LOCAL_NAMESPACE;
5053 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5054 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5055 cur->next = node->nsDef;
5056 node->nsDef = cur;
5057 return(cur);
5058 }
Owen Taylor3473f882001-02-23 17:55:21 +00005059 if (doc->oldNs == NULL) {
5060 /*
5061 * Allocate a new Namespace and fill the fields.
5062 */
5063 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5064 if (doc->oldNs == NULL) {
5065 xmlGenericError(xmlGenericErrorContext,
5066 "xmlSearchNsByHref : malloc failed\n");
5067 return(NULL);
5068 }
5069 memset(doc->oldNs, 0, sizeof(xmlNs));
5070 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5071
5072 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5073 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5074 }
5075 return(doc->oldNs);
5076 }
5077 while (node != NULL) {
5078 cur = node->nsDef;
5079 while (cur != NULL) {
5080 if ((cur->href != NULL) && (href != NULL) &&
5081 (xmlStrEqual(cur->href, href))) {
5082 /*
5083 * Check that the prefix is not shadowed between orig and node
5084 */
5085 xmlNodePtr check = orig;
5086 xmlNsPtr tst;
5087
5088 while (check != node) {
5089 tst = check->nsDef;
5090 while (tst != NULL) {
5091 if ((tst->prefix == NULL) && (cur->prefix == NULL))
5092 goto shadowed;
5093 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
5094 (xmlStrEqual(tst->prefix, cur->prefix)))
5095 goto shadowed;
5096 tst = tst->next;
5097 }
5098 check = check->parent;
5099 }
5100 return(cur);
5101 }
5102shadowed:
5103 cur = cur->next;
5104 }
5105 node = node->parent;
5106 }
5107 return(NULL);
5108}
5109
5110/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005111 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005112 * @doc: the document
5113 * @tree: a node expected to hold the new namespace
5114 * @ns: the original namespace
5115 *
5116 * This function tries to locate a namespace definition in a tree
5117 * ancestors, or create a new namespace definition node similar to
5118 * @ns trying to reuse the same prefix. However if the given prefix is
5119 * null (default namespace) or reused within the subtree defined by
5120 * @tree or on one of its ancestors then a new prefix is generated.
5121 * Returns the (new) namespace definition or NULL in case of error
5122 */
5123xmlNsPtr
5124xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5125 xmlNsPtr def;
5126 xmlChar prefix[50];
5127 int counter = 1;
5128
5129 if (tree == NULL) {
5130#ifdef DEBUG_TREE
5131 xmlGenericError(xmlGenericErrorContext,
5132 "xmlNewReconciliedNs : tree == NULL\n");
5133#endif
5134 return(NULL);
5135 }
5136 if (ns == NULL) {
5137#ifdef DEBUG_TREE
5138 xmlGenericError(xmlGenericErrorContext,
5139 "xmlNewReconciliedNs : ns == NULL\n");
5140#endif
5141 return(NULL);
5142 }
5143 /*
5144 * Search an existing namespace definition inherited.
5145 */
5146 def = xmlSearchNsByHref(doc, tree, ns->href);
5147 if (def != NULL)
5148 return(def);
5149
5150 /*
5151 * Find a close prefix which is not already in use.
5152 * Let's strip namespace prefixes longer than 20 chars !
5153 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005154 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005155 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005156 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005157 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005158
Owen Taylor3473f882001-02-23 17:55:21 +00005159 def = xmlSearchNs(doc, tree, prefix);
5160 while (def != NULL) {
5161 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005162 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005163 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005164 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005165 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005166 def = xmlSearchNs(doc, tree, prefix);
5167 }
5168
5169 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005170 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005171 */
5172 def = xmlNewNs(tree, ns->href, prefix);
5173 return(def);
5174}
5175
5176/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005177 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005178 * @doc: the document
5179 * @tree: a node defining the subtree to reconciliate
5180 *
5181 * This function checks that all the namespaces declared within the given
5182 * tree are properly declared. This is needed for example after Copy or Cut
5183 * and then paste operations. The subtree may still hold pointers to
5184 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005185 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005186 * the new environment. If not possible the new namespaces are redeclared
5187 * on @tree at the top of the given subtree.
5188 * Returns the number of namespace declarations created or -1 in case of error.
5189 */
5190int
5191xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5192 xmlNsPtr *oldNs = NULL;
5193 xmlNsPtr *newNs = NULL;
5194 int sizeCache = 0;
5195 int nbCache = 0;
5196
5197 xmlNsPtr n;
5198 xmlNodePtr node = tree;
5199 xmlAttrPtr attr;
5200 int ret = 0, i;
5201
5202 while (node != NULL) {
5203 /*
5204 * Reconciliate the node namespace
5205 */
5206 if (node->ns != NULL) {
5207 /*
5208 * initialize the cache if needed
5209 */
5210 if (sizeCache == 0) {
5211 sizeCache = 10;
5212 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5213 sizeof(xmlNsPtr));
5214 if (oldNs == NULL) {
5215 xmlGenericError(xmlGenericErrorContext,
5216 "xmlReconciliateNs : memory pbm\n");
5217 return(-1);
5218 }
5219 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5220 sizeof(xmlNsPtr));
5221 if (newNs == NULL) {
5222 xmlGenericError(xmlGenericErrorContext,
5223 "xmlReconciliateNs : memory pbm\n");
5224 xmlFree(oldNs);
5225 return(-1);
5226 }
5227 }
5228 for (i = 0;i < nbCache;i++) {
5229 if (oldNs[i] == node->ns) {
5230 node->ns = newNs[i];
5231 break;
5232 }
5233 }
5234 if (i == nbCache) {
5235 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005236 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005237 */
5238 n = xmlNewReconciliedNs(doc, tree, node->ns);
5239 if (n != NULL) { /* :-( what if else ??? */
5240 /*
5241 * check if we need to grow the cache buffers.
5242 */
5243 if (sizeCache <= nbCache) {
5244 sizeCache *= 2;
5245 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5246 sizeof(xmlNsPtr));
5247 if (oldNs == NULL) {
5248 xmlGenericError(xmlGenericErrorContext,
5249 "xmlReconciliateNs : memory pbm\n");
5250 xmlFree(newNs);
5251 return(-1);
5252 }
5253 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5254 sizeof(xmlNsPtr));
5255 if (newNs == NULL) {
5256 xmlGenericError(xmlGenericErrorContext,
5257 "xmlReconciliateNs : memory pbm\n");
5258 xmlFree(oldNs);
5259 return(-1);
5260 }
5261 }
5262 newNs[nbCache] = n;
5263 oldNs[nbCache++] = node->ns;
5264 node->ns = n;
5265 }
5266 }
5267 }
5268 /*
5269 * now check for namespace hold by attributes on the node.
5270 */
5271 attr = node->properties;
5272 while (attr != NULL) {
5273 if (attr->ns != NULL) {
5274 /*
5275 * initialize the cache if needed
5276 */
5277 if (sizeCache == 0) {
5278 sizeCache = 10;
5279 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5280 sizeof(xmlNsPtr));
5281 if (oldNs == NULL) {
5282 xmlGenericError(xmlGenericErrorContext,
5283 "xmlReconciliateNs : memory pbm\n");
5284 return(-1);
5285 }
5286 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5287 sizeof(xmlNsPtr));
5288 if (newNs == NULL) {
5289 xmlGenericError(xmlGenericErrorContext,
5290 "xmlReconciliateNs : memory pbm\n");
5291 xmlFree(oldNs);
5292 return(-1);
5293 }
5294 }
5295 for (i = 0;i < nbCache;i++) {
5296 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005297 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005298 break;
5299 }
5300 }
5301 if (i == nbCache) {
5302 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005303 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005304 */
5305 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5306 if (n != NULL) { /* :-( what if else ??? */
5307 /*
5308 * check if we need to grow the cache buffers.
5309 */
5310 if (sizeCache <= nbCache) {
5311 sizeCache *= 2;
5312 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5313 sizeof(xmlNsPtr));
5314 if (oldNs == NULL) {
5315 xmlGenericError(xmlGenericErrorContext,
5316 "xmlReconciliateNs : memory pbm\n");
5317 xmlFree(newNs);
5318 return(-1);
5319 }
5320 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5321 sizeof(xmlNsPtr));
5322 if (newNs == NULL) {
5323 xmlGenericError(xmlGenericErrorContext,
5324 "xmlReconciliateNs : memory pbm\n");
5325 xmlFree(oldNs);
5326 return(-1);
5327 }
5328 }
5329 newNs[nbCache] = n;
5330 oldNs[nbCache++] = attr->ns;
5331 attr->ns = n;
5332 }
5333 }
5334 }
5335 attr = attr->next;
5336 }
5337
5338 /*
5339 * Browse the full subtree, deep first
5340 */
5341 if (node->children != NULL) {
5342 /* deep first */
5343 node = node->children;
5344 } else if ((node != tree) && (node->next != NULL)) {
5345 /* then siblings */
5346 node = node->next;
5347 } else if (node != tree) {
5348 /* go up to parents->next if needed */
5349 while (node != tree) {
5350 if (node->parent != NULL)
5351 node = node->parent;
5352 if ((node != tree) && (node->next != NULL)) {
5353 node = node->next;
5354 break;
5355 }
5356 if (node->parent == NULL) {
5357 node = NULL;
5358 break;
5359 }
5360 }
5361 /* exit condition */
5362 if (node == tree)
5363 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005364 } else
5365 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005366 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005367 if (oldNs != NULL)
5368 xmlFree(oldNs);
5369 if (newNs != NULL)
5370 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005371 return(ret);
5372}
5373
5374/**
5375 * xmlHasProp:
5376 * @node: the node
5377 * @name: the attribute name
5378 *
5379 * Search an attribute associated to a node
5380 * This function also looks in DTD attribute declaration for #FIXED or
5381 * default declaration values unless DTD use has been turned off.
5382 *
5383 * Returns the attribute or the attribute declaration or NULL if
5384 * neither was found.
5385 */
5386xmlAttrPtr
5387xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5388 xmlAttrPtr prop;
5389 xmlDocPtr doc;
5390
5391 if ((node == NULL) || (name == NULL)) return(NULL);
5392 /*
5393 * Check on the properties attached to the node
5394 */
5395 prop = node->properties;
5396 while (prop != NULL) {
5397 if (xmlStrEqual(prop->name, name)) {
5398 return(prop);
5399 }
5400 prop = prop->next;
5401 }
5402 if (!xmlCheckDTD) return(NULL);
5403
5404 /*
5405 * Check if there is a default declaration in the internal
5406 * or external subsets
5407 */
5408 doc = node->doc;
5409 if (doc != NULL) {
5410 xmlAttributePtr attrDecl;
5411 if (doc->intSubset != NULL) {
5412 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5413 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5414 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5415 if (attrDecl != NULL)
5416 return((xmlAttrPtr) attrDecl);
5417 }
5418 }
5419 return(NULL);
5420}
5421
5422/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005423 * xmlHasNsProp:
5424 * @node: the node
5425 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005426 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005427 *
5428 * Search for an attribute associated to a node
5429 * This attribute has to be anchored in the namespace specified.
5430 * This does the entity substitution.
5431 * This function looks in DTD attribute declaration for #FIXED or
5432 * default declaration values unless DTD use has been turned off.
5433 *
5434 * Returns the attribute or the attribute declaration or NULL
5435 * if neither was found.
5436 */
5437xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005438xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005439 xmlAttrPtr prop;
5440 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005441
5442 if (node == NULL)
5443 return(NULL);
5444
5445 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005446 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005447 return(xmlHasProp(node, name));
5448 while (prop != NULL) {
5449 /*
5450 * One need to have
5451 * - same attribute names
5452 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005453 */
5454 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005455 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5456 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005457 }
5458 prop = prop->next;
5459 }
5460 if (!xmlCheckDTD) return(NULL);
5461
5462 /*
5463 * Check if there is a default declaration in the internal
5464 * or external subsets
5465 */
5466 doc = node->doc;
5467 if (doc != NULL) {
5468 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005469 xmlAttributePtr attrDecl = NULL;
5470 xmlNsPtr *nsList, *cur;
5471 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005472
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005473 nsList = xmlGetNsList(node->doc, node);
5474 if (nsList == NULL)
5475 return(NULL);
5476 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5477 ename = xmlStrdup(node->ns->prefix);
5478 ename = xmlStrcat(ename, BAD_CAST ":");
5479 ename = xmlStrcat(ename, node->name);
5480 } else {
5481 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005482 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005483 if (ename == NULL) {
5484 xmlFree(nsList);
5485 return(NULL);
5486 }
5487
5488 cur = nsList;
5489 while (*cur != NULL) {
5490 if (xmlStrEqual((*cur)->href, nameSpace)) {
5491 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5492 name, (*cur)->prefix);
5493 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5494 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5495 name, (*cur)->prefix);
5496 }
5497 cur++;
5498 }
5499 xmlFree(nsList);
5500 xmlFree(ename);
5501 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005502 }
5503 }
5504 return(NULL);
5505}
5506
5507/**
Owen Taylor3473f882001-02-23 17:55:21 +00005508 * xmlGetProp:
5509 * @node: the node
5510 * @name: the attribute name
5511 *
5512 * Search and get the value of an attribute associated to a node
5513 * This does the entity substitution.
5514 * This function looks in DTD attribute declaration for #FIXED or
5515 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00005516 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00005517 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
5518 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00005519 *
5520 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005521 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005522 */
5523xmlChar *
5524xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5525 xmlAttrPtr prop;
5526 xmlDocPtr doc;
5527
5528 if ((node == NULL) || (name == NULL)) return(NULL);
5529 /*
5530 * Check on the properties attached to the node
5531 */
5532 prop = node->properties;
5533 while (prop != NULL) {
5534 if (xmlStrEqual(prop->name, name)) {
5535 xmlChar *ret;
5536
5537 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5538 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5539 return(ret);
5540 }
5541 prop = prop->next;
5542 }
5543 if (!xmlCheckDTD) return(NULL);
5544
5545 /*
5546 * Check if there is a default declaration in the internal
5547 * or external subsets
5548 */
5549 doc = node->doc;
5550 if (doc != NULL) {
5551 xmlAttributePtr attrDecl;
5552 if (doc->intSubset != NULL) {
5553 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5554 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5555 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5556 if (attrDecl != NULL)
5557 return(xmlStrdup(attrDecl->defaultValue));
5558 }
5559 }
5560 return(NULL);
5561}
5562
5563/**
Daniel Veillard71531f32003-02-05 13:19:53 +00005564 * xmlGetNoNsProp:
5565 * @node: the node
5566 * @name: the attribute name
5567 *
5568 * Search and get the value of an attribute associated to a node
5569 * This does the entity substitution.
5570 * This function looks in DTD attribute declaration for #FIXED or
5571 * default declaration values unless DTD use has been turned off.
5572 * This function is similar to xmlGetProp except it will accept only
5573 * an attribute in no namespace.
5574 *
5575 * Returns the attribute value or NULL if not found.
5576 * It's up to the caller to free the memory with xmlFree().
5577 */
5578xmlChar *
5579xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
5580 xmlAttrPtr prop;
5581 xmlDocPtr doc;
5582
5583 if ((node == NULL) || (name == NULL)) return(NULL);
5584 /*
5585 * Check on the properties attached to the node
5586 */
5587 prop = node->properties;
5588 while (prop != NULL) {
5589 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
5590 xmlChar *ret;
5591
5592 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5593 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5594 return(ret);
5595 }
5596 prop = prop->next;
5597 }
5598 if (!xmlCheckDTD) return(NULL);
5599
5600 /*
5601 * Check if there is a default declaration in the internal
5602 * or external subsets
5603 */
5604 doc = node->doc;
5605 if (doc != NULL) {
5606 xmlAttributePtr attrDecl;
5607 if (doc->intSubset != NULL) {
5608 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5609 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5610 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5611 if (attrDecl != NULL)
5612 return(xmlStrdup(attrDecl->defaultValue));
5613 }
5614 }
5615 return(NULL);
5616}
5617
5618/**
Owen Taylor3473f882001-02-23 17:55:21 +00005619 * xmlGetNsProp:
5620 * @node: the node
5621 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005622 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005623 *
5624 * Search and get the value of an attribute associated to a node
5625 * This attribute has to be anchored in the namespace specified.
5626 * This does the entity substitution.
5627 * This function looks in DTD attribute declaration for #FIXED or
5628 * default declaration values unless DTD use has been turned off.
5629 *
5630 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005631 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005632 */
5633xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00005634xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00005635 xmlAttrPtr prop;
5636 xmlDocPtr doc;
5637 xmlNsPtr ns;
5638
5639 if (node == NULL)
5640 return(NULL);
5641
5642 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005643 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00005644 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00005645 while (prop != NULL) {
5646 /*
5647 * One need to have
5648 * - same attribute names
5649 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005650 */
5651 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00005652 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00005653 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005654 xmlChar *ret;
5655
5656 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5657 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5658 return(ret);
5659 }
5660 prop = prop->next;
5661 }
5662 if (!xmlCheckDTD) return(NULL);
5663
5664 /*
5665 * Check if there is a default declaration in the internal
5666 * or external subsets
5667 */
5668 doc = node->doc;
5669 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005670 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00005671 xmlAttributePtr attrDecl;
5672
Owen Taylor3473f882001-02-23 17:55:21 +00005673 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5674 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5675 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5676
5677 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
5678 /*
5679 * The DTD declaration only allows a prefix search
5680 */
5681 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00005682 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00005683 return(xmlStrdup(attrDecl->defaultValue));
5684 }
5685 }
5686 }
5687 return(NULL);
5688}
5689
5690/**
5691 * xmlSetProp:
5692 * @node: the node
5693 * @name: the attribute name
5694 * @value: the attribute value
5695 *
5696 * Set (or reset) an attribute carried by a node.
5697 * Returns the attribute pointer.
5698 */
5699xmlAttrPtr
5700xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005701 xmlAttrPtr prop;
5702 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00005703
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00005704 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00005705 return(NULL);
5706 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005707 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00005708 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005709 if ((xmlStrEqual(prop->name, name)) &&
5710 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005711 xmlNodePtr oldprop = prop->children;
5712
Owen Taylor3473f882001-02-23 17:55:21 +00005713 prop->children = NULL;
5714 prop->last = NULL;
5715 if (value != NULL) {
5716 xmlChar *buffer;
5717 xmlNodePtr tmp;
5718
5719 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5720 prop->children = xmlStringGetNodeList(node->doc, buffer);
5721 prop->last = NULL;
5722 prop->doc = doc;
5723 tmp = prop->children;
5724 while (tmp != NULL) {
5725 tmp->parent = (xmlNodePtr) prop;
5726 tmp->doc = doc;
5727 if (tmp->next == NULL)
5728 prop->last = tmp;
5729 tmp = tmp->next;
5730 }
5731 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00005732 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005733 if (oldprop != NULL)
5734 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00005735 return(prop);
5736 }
5737 prop = prop->next;
5738 }
5739 prop = xmlNewProp(node, name, value);
5740 return(prop);
5741}
5742
5743/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005744 * xmlUnsetProp:
5745 * @node: the node
5746 * @name: the attribute name
5747 *
5748 * Remove an attribute carried by a node.
5749 * Returns 0 if successful, -1 if not found
5750 */
5751int
5752xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Daniel Veillard814a76d2003-01-23 18:24:20 +00005753 xmlAttrPtr prop, prev = NULL;;
Daniel Veillard75bea542001-05-11 17:41:21 +00005754
5755 if ((node == NULL) || (name == NULL))
5756 return(-1);
Daniel Veillard814a76d2003-01-23 18:24:20 +00005757 prop = node->properties;
Daniel Veillard75bea542001-05-11 17:41:21 +00005758 while (prop != NULL) {
5759 if ((xmlStrEqual(prop->name, name)) &&
5760 (prop->ns == NULL)) {
5761 if (prev == NULL)
5762 node->properties = prop->next;
5763 else
5764 prev->next = prop->next;
5765 xmlFreeProp(prop);
5766 return(0);
5767 }
5768 prev = prop;
5769 prop = prop->next;
5770 }
5771 return(-1);
5772}
5773
5774/**
Owen Taylor3473f882001-02-23 17:55:21 +00005775 * xmlSetNsProp:
5776 * @node: the node
5777 * @ns: the namespace definition
5778 * @name: the attribute name
5779 * @value: the attribute value
5780 *
5781 * Set (or reset) an attribute carried by a node.
5782 * The ns structure must be in scope, this is not checked.
5783 *
5784 * Returns the attribute pointer.
5785 */
5786xmlAttrPtr
5787xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
5788 const xmlChar *value) {
5789 xmlAttrPtr prop;
5790
5791 if ((node == NULL) || (name == NULL))
5792 return(NULL);
5793
5794 if (ns == NULL)
5795 return(xmlSetProp(node, name, value));
5796 if (ns->href == NULL)
5797 return(NULL);
5798 prop = node->properties;
5799
5800 while (prop != NULL) {
5801 /*
5802 * One need to have
5803 * - same attribute names
5804 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005805 */
5806 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00005807 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005808 if (prop->children != NULL)
5809 xmlFreeNodeList(prop->children);
5810 prop->children = NULL;
5811 prop->last = NULL;
5812 prop->ns = ns;
5813 if (value != NULL) {
5814 xmlChar *buffer;
5815 xmlNodePtr tmp;
5816
5817 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5818 prop->children = xmlStringGetNodeList(node->doc, buffer);
5819 prop->last = NULL;
5820 tmp = prop->children;
5821 while (tmp != NULL) {
5822 tmp->parent = (xmlNodePtr) prop;
5823 if (tmp->next == NULL)
5824 prop->last = tmp;
5825 tmp = tmp->next;
5826 }
5827 xmlFree(buffer);
5828 }
5829 return(prop);
5830 }
5831 prop = prop->next;
5832 }
5833 prop = xmlNewNsProp(node, ns, name, value);
5834 return(prop);
5835}
5836
5837/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005838 * xmlUnsetNsProp:
5839 * @node: the node
5840 * @ns: the namespace definition
5841 * @name: the attribute name
5842 *
5843 * Remove an attribute carried by a node.
5844 * Returns 0 if successful, -1 if not found
5845 */
5846int
5847xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
5848 xmlAttrPtr prop = node->properties, prev = NULL;;
5849
5850 if ((node == NULL) || (name == NULL))
5851 return(-1);
5852 if (ns == NULL)
5853 return(xmlUnsetProp(node, name));
5854 if (ns->href == NULL)
5855 return(-1);
5856 while (prop != NULL) {
5857 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00005858 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005859 if (prev == NULL)
5860 node->properties = prop->next;
5861 else
5862 prev->next = prop->next;
5863 xmlFreeProp(prop);
5864 return(0);
5865 }
5866 prev = prop;
5867 prop = prop->next;
5868 }
5869 return(-1);
5870}
5871
5872/**
Owen Taylor3473f882001-02-23 17:55:21 +00005873 * xmlNodeIsText:
5874 * @node: the node
5875 *
5876 * Is this node a Text node ?
5877 * Returns 1 yes, 0 no
5878 */
5879int
5880xmlNodeIsText(xmlNodePtr node) {
5881 if (node == NULL) return(0);
5882
5883 if (node->type == XML_TEXT_NODE) return(1);
5884 return(0);
5885}
5886
5887/**
5888 * xmlIsBlankNode:
5889 * @node: the node
5890 *
5891 * Checks whether this node is an empty or whitespace only
5892 * (and possibly ignorable) text-node.
5893 *
5894 * Returns 1 yes, 0 no
5895 */
5896int
5897xmlIsBlankNode(xmlNodePtr node) {
5898 const xmlChar *cur;
5899 if (node == NULL) return(0);
5900
Daniel Veillard7db37732001-07-12 01:20:08 +00005901 if ((node->type != XML_TEXT_NODE) &&
5902 (node->type != XML_CDATA_SECTION_NODE))
5903 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005904 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00005905 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00005906 while (*cur != 0) {
5907 if (!IS_BLANK(*cur)) return(0);
5908 cur++;
5909 }
5910
5911 return(1);
5912}
5913
5914/**
5915 * xmlTextConcat:
5916 * @node: the node
5917 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00005918 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00005919 *
5920 * Concat the given string at the end of the existing node content
5921 */
5922
5923void
5924xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
5925 if (node == NULL) return;
5926
5927 if ((node->type != XML_TEXT_NODE) &&
5928 (node->type != XML_CDATA_SECTION_NODE)) {
5929#ifdef DEBUG_TREE
5930 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005931 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005932#endif
5933 return;
5934 }
Owen Taylor3473f882001-02-23 17:55:21 +00005935 node->content = xmlStrncat(node->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005936}
5937
5938/************************************************************************
5939 * *
5940 * Output : to a FILE or in memory *
5941 * *
5942 ************************************************************************/
5943
Owen Taylor3473f882001-02-23 17:55:21 +00005944/**
5945 * xmlBufferCreate:
5946 *
5947 * routine to create an XML buffer.
5948 * returns the new structure.
5949 */
5950xmlBufferPtr
5951xmlBufferCreate(void) {
5952 xmlBufferPtr ret;
5953
5954 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5955 if (ret == NULL) {
5956 xmlGenericError(xmlGenericErrorContext,
5957 "xmlBufferCreate : out of memory!\n");
5958 return(NULL);
5959 }
5960 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00005961 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00005962 ret->alloc = xmlBufferAllocScheme;
5963 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5964 if (ret->content == NULL) {
5965 xmlGenericError(xmlGenericErrorContext,
5966 "xmlBufferCreate : out of memory!\n");
5967 xmlFree(ret);
5968 return(NULL);
5969 }
5970 ret->content[0] = 0;
5971 return(ret);
5972}
5973
5974/**
5975 * xmlBufferCreateSize:
5976 * @size: initial size of buffer
5977 *
5978 * routine to create an XML buffer.
5979 * returns the new structure.
5980 */
5981xmlBufferPtr
5982xmlBufferCreateSize(size_t size) {
5983 xmlBufferPtr ret;
5984
5985 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5986 if (ret == NULL) {
5987 xmlGenericError(xmlGenericErrorContext,
5988 "xmlBufferCreate : out of memory!\n");
5989 return(NULL);
5990 }
5991 ret->use = 0;
5992 ret->alloc = xmlBufferAllocScheme;
5993 ret->size = (size ? size+2 : 0); /* +1 for ending null */
5994 if (ret->size){
5995 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5996 if (ret->content == NULL) {
5997 xmlGenericError(xmlGenericErrorContext,
5998 "xmlBufferCreate : out of memory!\n");
5999 xmlFree(ret);
6000 return(NULL);
6001 }
6002 ret->content[0] = 0;
6003 } else
6004 ret->content = NULL;
6005 return(ret);
6006}
6007
6008/**
6009 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006010 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006011 * @scheme: allocation scheme to use
6012 *
6013 * Sets the allocation scheme for this buffer
6014 */
6015void
6016xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6017 xmlBufferAllocationScheme scheme) {
6018 if (buf == NULL) {
6019#ifdef DEBUG_BUFFER
6020 xmlGenericError(xmlGenericErrorContext,
6021 "xmlBufferSetAllocationScheme: buf == NULL\n");
6022#endif
6023 return;
6024 }
6025
6026 buf->alloc = scheme;
6027}
6028
6029/**
6030 * xmlBufferFree:
6031 * @buf: the buffer to free
6032 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006033 * Frees an XML buffer. It frees both the content and the structure which
6034 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006035 */
6036void
6037xmlBufferFree(xmlBufferPtr buf) {
6038 if (buf == NULL) {
6039#ifdef DEBUG_BUFFER
6040 xmlGenericError(xmlGenericErrorContext,
6041 "xmlBufferFree: buf == NULL\n");
6042#endif
6043 return;
6044 }
Daniel Veillard561b7f82002-03-20 21:55:57 +00006045 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006046 xmlFree(buf->content);
6047 }
Owen Taylor3473f882001-02-23 17:55:21 +00006048 xmlFree(buf);
6049}
6050
6051/**
6052 * xmlBufferEmpty:
6053 * @buf: the buffer
6054 *
6055 * empty a buffer.
6056 */
6057void
6058xmlBufferEmpty(xmlBufferPtr buf) {
6059 if (buf->content == NULL) return;
6060 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006061 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00006062}
6063
6064/**
6065 * xmlBufferShrink:
6066 * @buf: the buffer to dump
6067 * @len: the number of xmlChar to remove
6068 *
6069 * Remove the beginning of an XML buffer.
6070 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006071 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006072 */
6073int
6074xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
6075 if (len == 0) return(0);
6076 if (len > buf->use) return(-1);
6077
6078 buf->use -= len;
6079 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6080
6081 buf->content[buf->use] = 0;
6082 return(len);
6083}
6084
6085/**
6086 * xmlBufferGrow:
6087 * @buf: the buffer
6088 * @len: the minimum free size to allocate
6089 *
6090 * Grow the available space of an XML buffer.
6091 *
6092 * Returns the new available space or -1 in case of error
6093 */
6094int
6095xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6096 int size;
6097 xmlChar *newbuf;
6098
6099 if (len + buf->use < buf->size) return(0);
6100
6101 size = buf->use + len + 100;
6102
6103 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
6104 if (newbuf == NULL) return(-1);
6105 buf->content = newbuf;
6106 buf->size = size;
6107 return(buf->size - buf->use);
6108}
6109
6110/**
6111 * xmlBufferDump:
6112 * @file: the file output
6113 * @buf: the buffer to dump
6114 *
6115 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006116 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006117 */
6118int
6119xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6120 int ret;
6121
6122 if (buf == NULL) {
6123#ifdef DEBUG_BUFFER
6124 xmlGenericError(xmlGenericErrorContext,
6125 "xmlBufferDump: buf == NULL\n");
6126#endif
6127 return(0);
6128 }
6129 if (buf->content == NULL) {
6130#ifdef DEBUG_BUFFER
6131 xmlGenericError(xmlGenericErrorContext,
6132 "xmlBufferDump: buf->content == NULL\n");
6133#endif
6134 return(0);
6135 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006136 if (file == NULL)
6137 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006138 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6139 return(ret);
6140}
6141
6142/**
6143 * xmlBufferContent:
6144 * @buf: the buffer
6145 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006146 * Function to extract the content of a buffer
6147 *
Owen Taylor3473f882001-02-23 17:55:21 +00006148 * Returns the internal content
6149 */
6150
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006151const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006152xmlBufferContent(const xmlBufferPtr buf)
6153{
6154 if(!buf)
6155 return NULL;
6156
6157 return buf->content;
6158}
6159
6160/**
6161 * xmlBufferLength:
6162 * @buf: the buffer
6163 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006164 * Function to get the length of a buffer
6165 *
Owen Taylor3473f882001-02-23 17:55:21 +00006166 * Returns the length of data in the internal content
6167 */
6168
6169int
6170xmlBufferLength(const xmlBufferPtr buf)
6171{
6172 if(!buf)
6173 return 0;
6174
6175 return buf->use;
6176}
6177
6178/**
6179 * xmlBufferResize:
6180 * @buf: the buffer to resize
6181 * @size: the desired size
6182 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006183 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006184 *
6185 * Returns 0 in case of problems, 1 otherwise
6186 */
6187int
6188xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6189{
6190 unsigned int newSize;
6191 xmlChar* rebuf = NULL;
6192
6193 /*take care of empty case*/
6194 newSize = (buf->size ? buf->size*2 : size);
6195
6196 /* Don't resize if we don't have to */
6197 if (size < buf->size)
6198 return 1;
6199
6200 /* figure out new size */
6201 switch (buf->alloc){
6202 case XML_BUFFER_ALLOC_DOUBLEIT:
6203 while (size > newSize) newSize *= 2;
6204 break;
6205 case XML_BUFFER_ALLOC_EXACT:
6206 newSize = size+10;
6207 break;
6208 default:
6209 newSize = size+10;
6210 break;
6211 }
6212
6213 if (buf->content == NULL)
6214 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
6215 else
6216 rebuf = (xmlChar *) xmlRealloc(buf->content,
6217 newSize * sizeof(xmlChar));
6218 if (rebuf == NULL) {
6219 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006220 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006221 return 0;
6222 }
6223 buf->content = rebuf;
6224 buf->size = newSize;
6225
6226 return 1;
6227}
6228
6229/**
6230 * xmlBufferAdd:
6231 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006232 * @str: the #xmlChar string
6233 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006234 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006235 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006236 * str is recomputed.
6237 */
6238void
6239xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6240 unsigned int needSize;
6241
6242 if (str == NULL) {
6243#ifdef DEBUG_BUFFER
6244 xmlGenericError(xmlGenericErrorContext,
6245 "xmlBufferAdd: str == NULL\n");
6246#endif
6247 return;
6248 }
6249 if (len < -1) {
6250#ifdef DEBUG_BUFFER
6251 xmlGenericError(xmlGenericErrorContext,
6252 "xmlBufferAdd: len < 0\n");
6253#endif
6254 return;
6255 }
6256 if (len == 0) return;
6257
6258 if (len < 0)
6259 len = xmlStrlen(str);
6260
6261 if (len <= 0) return;
6262
6263 needSize = buf->use + len + 2;
6264 if (needSize > buf->size){
6265 if (!xmlBufferResize(buf, needSize)){
6266 xmlGenericError(xmlGenericErrorContext,
6267 "xmlBufferAdd : out of memory!\n");
6268 return;
6269 }
6270 }
6271
6272 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6273 buf->use += len;
6274 buf->content[buf->use] = 0;
6275}
6276
6277/**
6278 * xmlBufferAddHead:
6279 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006280 * @str: the #xmlChar string
6281 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006282 *
6283 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006284 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00006285 */
6286void
6287xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6288 unsigned int needSize;
6289
6290 if (str == NULL) {
6291#ifdef DEBUG_BUFFER
6292 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006293 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006294#endif
6295 return;
6296 }
6297 if (len < -1) {
6298#ifdef DEBUG_BUFFER
6299 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006300 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006301#endif
6302 return;
6303 }
6304 if (len == 0) return;
6305
6306 if (len < 0)
6307 len = xmlStrlen(str);
6308
6309 if (len <= 0) return;
6310
6311 needSize = buf->use + len + 2;
6312 if (needSize > buf->size){
6313 if (!xmlBufferResize(buf, needSize)){
6314 xmlGenericError(xmlGenericErrorContext,
6315 "xmlBufferAddHead : out of memory!\n");
6316 return;
6317 }
6318 }
6319
6320 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6321 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6322 buf->use += len;
6323 buf->content[buf->use] = 0;
6324}
6325
6326/**
6327 * xmlBufferCat:
6328 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006329 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006330 *
6331 * Append a zero terminated string to an XML buffer.
6332 */
6333void
6334xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
6335 if (str != NULL)
6336 xmlBufferAdd(buf, str, -1);
6337}
6338
6339/**
6340 * xmlBufferCCat:
6341 * @buf: the buffer to dump
6342 * @str: the C char string
6343 *
6344 * Append a zero terminated C string to an XML buffer.
6345 */
6346void
6347xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6348 const char *cur;
6349
6350 if (str == NULL) {
6351#ifdef DEBUG_BUFFER
6352 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006353 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006354#endif
6355 return;
6356 }
6357 for (cur = str;*cur != 0;cur++) {
6358 if (buf->use + 10 >= buf->size) {
6359 if (!xmlBufferResize(buf, buf->use+10)){
6360 xmlGenericError(xmlGenericErrorContext,
6361 "xmlBufferCCat : out of memory!\n");
6362 return;
6363 }
6364 }
6365 buf->content[buf->use++] = *cur;
6366 }
6367 buf->content[buf->use] = 0;
6368}
6369
6370/**
6371 * xmlBufferWriteCHAR:
6372 * @buf: the XML buffer
6373 * @string: the string to add
6374 *
6375 * routine which manages and grows an output buffer. This one adds
6376 * xmlChars at the end of the buffer.
6377 */
6378void
Owen Taylor3473f882001-02-23 17:55:21 +00006379xmlBufferWriteCHAR
Owen Taylor3473f882001-02-23 17:55:21 +00006380(xmlBufferPtr buf, const xmlChar *string) {
6381 xmlBufferCat(buf, string);
6382}
6383
6384/**
6385 * xmlBufferWriteChar:
6386 * @buf: the XML buffer output
6387 * @string: the string to add
6388 *
6389 * routine which manage and grows an output buffer. This one add
6390 * C chars at the end of the array.
6391 */
6392void
6393xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
6394 xmlBufferCCat(buf, string);
6395}
6396
6397
6398/**
6399 * xmlBufferWriteQuotedString:
6400 * @buf: the XML buffer output
6401 * @string: the string to add
6402 *
6403 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00006404 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00006405 * quote or double-quotes internally
6406 */
6407void
6408xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
6409 if (xmlStrchr(string, '"')) {
6410 if (xmlStrchr(string, '\'')) {
6411#ifdef DEBUG_BUFFER
6412 xmlGenericError(xmlGenericErrorContext,
6413 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
6414#endif
6415 }
6416 xmlBufferCCat(buf, "'");
6417 xmlBufferCat(buf, string);
6418 xmlBufferCCat(buf, "'");
6419 } else {
6420 xmlBufferCCat(buf, "\"");
6421 xmlBufferCat(buf, string);
6422 xmlBufferCCat(buf, "\"");
6423 }
6424}
6425
6426
6427/************************************************************************
6428 * *
6429 * Dumping XML tree content to a simple buffer *
6430 * *
6431 ************************************************************************/
6432
Owen Taylor3473f882001-02-23 17:55:21 +00006433/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00006434 * xmlAttrSerializeContent:
6435 * @buf: the XML buffer output
6436 * @doc: the document
6437 * @attr: the attribute pointer
6438 *
6439 * Serialize the attribute in the buffer
6440 */
6441static void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006442xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr)
6443{
Daniel Veillarda6d05382002-02-13 13:07:41 +00006444 const xmlChar *cur, *base;
6445 xmlNodePtr children;
6446
6447 children = attr->children;
6448 while (children != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006449 switch (children->type) {
6450 case XML_TEXT_NODE:
6451 base = cur = children->content;
6452 while (*cur != 0) {
6453 if (*cur == '\n') {
6454 if (base != cur)
6455 xmlBufferAdd(buf, base, cur - base);
6456 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
6457 cur++;
6458 base = cur;
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006459 } else if (*cur == '\r') {
6460 if (base != cur)
6461 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006462 xmlBufferAdd(buf, BAD_CAST "&#13;", 5);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006463 cur++;
6464 base = cur;
6465 } else if (*cur == '\t') {
6466 if (base != cur)
6467 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006468 xmlBufferAdd(buf, BAD_CAST "&#9;", 4);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006469 cur++;
6470 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006471#if 0
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006472 } else if (*cur == '\'') {
6473 if (base != cur)
6474 xmlBufferAdd(buf, base, cur - base);
6475 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
6476 cur++;
6477 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006478#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006479 } else if (*cur == '"') {
6480 if (base != cur)
6481 xmlBufferAdd(buf, base, cur - base);
6482 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6483 cur++;
6484 base = cur;
6485 } else if (*cur == '<') {
6486 if (base != cur)
6487 xmlBufferAdd(buf, base, cur - base);
6488 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
6489 cur++;
6490 base = cur;
6491 } else if (*cur == '>') {
6492 if (base != cur)
6493 xmlBufferAdd(buf, base, cur - base);
6494 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
6495 cur++;
6496 base = cur;
6497 } else if (*cur == '&') {
6498 if (base != cur)
6499 xmlBufferAdd(buf, base, cur - base);
6500 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
6501 cur++;
6502 base = cur;
6503 } else if ((*cur >= 0x80) && ((doc == NULL) ||
6504 (doc->encoding ==
6505 NULL))) {
6506 /*
6507 * We assume we have UTF-8 content.
6508 */
6509 char tmp[10];
6510 int val = 0, l = 1;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006511
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006512 if (base != cur)
6513 xmlBufferAdd(buf, base, cur - base);
6514 if (*cur < 0xC0) {
6515 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6d05382002-02-13 13:07:41 +00006516 "xmlAttrSerializeContent : input not UTF-8\n");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006517 if (doc != NULL)
6518 doc->encoding =
6519 xmlStrdup(BAD_CAST "ISO-8859-1");
6520 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6521 tmp[sizeof(tmp) - 1] = 0;
6522 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6523 cur++;
6524 base = cur;
6525 continue;
6526 } else if (*cur < 0xE0) {
6527 val = (cur[0]) & 0x1F;
6528 val <<= 6;
6529 val |= (cur[1]) & 0x3F;
6530 l = 2;
6531 } else if (*cur < 0xF0) {
6532 val = (cur[0]) & 0x0F;
6533 val <<= 6;
6534 val |= (cur[1]) & 0x3F;
6535 val <<= 6;
6536 val |= (cur[2]) & 0x3F;
6537 l = 3;
6538 } else if (*cur < 0xF8) {
6539 val = (cur[0]) & 0x07;
6540 val <<= 6;
6541 val |= (cur[1]) & 0x3F;
6542 val <<= 6;
6543 val |= (cur[2]) & 0x3F;
6544 val <<= 6;
6545 val |= (cur[3]) & 0x3F;
6546 l = 4;
6547 }
6548 if ((l == 1) || (!IS_CHAR(val))) {
6549 xmlGenericError(xmlGenericErrorContext,
6550 "xmlAttrSerializeContent : char out of range\n");
6551 if (doc != NULL)
6552 doc->encoding =
6553 xmlStrdup(BAD_CAST "ISO-8859-1");
6554 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6555 tmp[sizeof(tmp) - 1] = 0;
6556 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6557 cur++;
6558 base = cur;
6559 continue;
6560 }
6561 /*
6562 * We could do multiple things here. Just save
6563 * as a char ref
6564 */
6565 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
6566 tmp[sizeof(tmp) - 1] = 0;
6567 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6568 cur += l;
6569 base = cur;
6570 } else {
6571 cur++;
6572 }
6573 }
6574 if (base != cur)
6575 xmlBufferAdd(buf, base, cur - base);
6576 break;
6577 case XML_ENTITY_REF_NODE:
6578 xmlBufferAdd(buf, BAD_CAST "&", 1);
6579 xmlBufferAdd(buf, children->name,
6580 xmlStrlen(children->name));
6581 xmlBufferAdd(buf, BAD_CAST ";", 1);
6582 break;
6583 default:
6584 /* should not happen unless we have a badly built tree */
6585 break;
6586 }
6587 children = children->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006588 }
6589}
6590
6591/**
6592 * xmlNodeDump:
6593 * @buf: the XML buffer output
6594 * @doc: the document
6595 * @cur: the current node
6596 * @level: the imbrication level for indenting
6597 * @format: is formatting allowed
6598 *
6599 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00006600 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006601 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006602 *
6603 * Returns the number of bytes written to the buffer or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00006604 */
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006605int
Owen Taylor3473f882001-02-23 17:55:21 +00006606xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006607 int format)
6608{
6609 unsigned int use;
6610 int ret;
6611 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006612
6613 if (cur == NULL) {
6614#ifdef DEBUG_TREE
6615 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006616 "xmlNodeDump : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006617#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006618 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006619 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006620 if (buf == NULL) {
6621#ifdef DEBUG_TREE
6622 xmlGenericError(xmlGenericErrorContext,
6623 "xmlNodeDump : buf == NULL\n");
6624#endif
6625 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006626 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006627 outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
6628 if (outbuf == NULL) {
6629 xmlGenericError(xmlGenericErrorContext,
6630 "xmlNodeDump: out of memory!\n");
6631 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006632 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006633 memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
6634 outbuf->buffer = buf;
6635 outbuf->encoder = NULL;
6636 outbuf->writecallback = NULL;
6637 outbuf->closecallback = NULL;
6638 outbuf->context = NULL;
6639 outbuf->written = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006640
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006641 use = buf->use;
6642 xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
6643 xmlFree(outbuf);
6644 ret = buf->use - use;
6645 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006646}
6647
6648/**
6649 * xmlElemDump:
6650 * @f: the FILE * for the output
6651 * @doc: the document
6652 * @cur: the current node
6653 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006654 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006655 */
6656void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006657xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur)
6658{
6659 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006660
6661 if (cur == NULL) {
6662#ifdef DEBUG_TREE
6663 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006664 "xmlElemDump : cur == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006665#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006666 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006667 }
Owen Taylor3473f882001-02-23 17:55:21 +00006668#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006669 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006670 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006671 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006672 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006673#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006674
6675 outbuf = xmlOutputBufferCreateFile(f, NULL);
6676 if (outbuf == NULL)
6677 return;
6678 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006679#ifdef LIBXML_HTML_ENABLED
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006680 htmlNodeDumpOutput(outbuf, doc, cur, NULL);
6681#else
6682 xmlGenericError(xmlGenericErrorContext,
6683 "HTML support not compiled in\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006684#endif /* LIBXML_HTML_ENABLED */
6685 } else
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006686 xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL);
6687 xmlOutputBufferClose(outbuf);
Owen Taylor3473f882001-02-23 17:55:21 +00006688}
6689
6690/************************************************************************
6691 * *
6692 * Dumping XML tree content to an I/O output buffer *
6693 * *
6694 ************************************************************************/
6695
Owen Taylor3473f882001-02-23 17:55:21 +00006696static void
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006697xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6698 int level, int format, const char *encoding);
6699static void
Owen Taylor3473f882001-02-23 17:55:21 +00006700xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6701 int level, int format, const char *encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006702static void
6703xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
6704 xmlNodePtr cur, int level, int format, const char *encoding);
6705
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00006706void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
6707
Owen Taylor3473f882001-02-23 17:55:21 +00006708/**
6709 * xmlNsDumpOutput:
6710 * @buf: the XML buffer output
6711 * @cur: a namespace
6712 *
6713 * Dump a local Namespace definition.
6714 * Should be called in the context of attributes dumps.
6715 */
6716static void
6717xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6718 if (cur == NULL) {
6719#ifdef DEBUG_TREE
6720 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006721 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006722#endif
6723 return;
6724 }
6725 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00006726 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
6727 return;
6728
Owen Taylor3473f882001-02-23 17:55:21 +00006729 /* Within the context of an element attributes */
6730 if (cur->prefix != NULL) {
6731 xmlOutputBufferWriteString(buf, " xmlns:");
6732 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6733 } else
6734 xmlOutputBufferWriteString(buf, " xmlns");
6735 xmlOutputBufferWriteString(buf, "=");
6736 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6737 }
6738}
6739
6740/**
6741 * xmlNsListDumpOutput:
6742 * @buf: the XML buffer output
6743 * @cur: the first namespace
6744 *
6745 * Dump a list of local Namespace definitions.
6746 * Should be called in the context of attributes dumps.
6747 */
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00006748void
Owen Taylor3473f882001-02-23 17:55:21 +00006749xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6750 while (cur != NULL) {
6751 xmlNsDumpOutput(buf, cur);
6752 cur = cur->next;
6753 }
6754}
6755
6756/**
6757 * xmlDtdDumpOutput:
6758 * @buf: the XML buffer output
6759 * @doc: the document
6760 * @encoding: an optional encoding string
6761 *
6762 * Dump the XML document DTD, if any.
6763 */
6764static void
6765xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6766 if (dtd == NULL) {
6767#ifdef DEBUG_TREE
6768 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006769 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006770#endif
6771 return;
6772 }
6773 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6774 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6775 if (dtd->ExternalID != NULL) {
6776 xmlOutputBufferWriteString(buf, " PUBLIC ");
6777 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6778 xmlOutputBufferWriteString(buf, " ");
6779 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6780 } else if (dtd->SystemID != NULL) {
6781 xmlOutputBufferWriteString(buf, " SYSTEM ");
6782 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6783 }
6784 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6785 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6786 xmlOutputBufferWriteString(buf, ">");
6787 return;
6788 }
6789 xmlOutputBufferWriteString(buf, " [\n");
6790 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6791 xmlOutputBufferWriteString(buf, "]>");
6792}
6793
6794/**
6795 * xmlAttrDumpOutput:
6796 * @buf: the XML buffer output
6797 * @doc: the document
6798 * @cur: the attribute pointer
6799 * @encoding: an optional encoding string
6800 *
6801 * Dump an XML attribute
6802 */
6803static void
6804xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006805 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006806 if (cur == NULL) {
6807#ifdef DEBUG_TREE
6808 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006809 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006810#endif
6811 return;
6812 }
6813 xmlOutputBufferWriteString(buf, " ");
6814 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6815 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6816 xmlOutputBufferWriteString(buf, ":");
6817 }
6818 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006819 xmlOutputBufferWriteString(buf, "=\"");
6820 xmlAttrSerializeContent(buf->buffer, doc, cur);
6821 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006822}
6823
6824/**
6825 * xmlAttrListDumpOutput:
6826 * @buf: the XML buffer output
6827 * @doc: the document
6828 * @cur: the first attribute pointer
6829 * @encoding: an optional encoding string
6830 *
6831 * Dump a list of XML attributes
6832 */
6833static void
6834xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6835 xmlAttrPtr cur, const char *encoding) {
6836 if (cur == NULL) {
6837#ifdef DEBUG_TREE
6838 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006839 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006840#endif
6841 return;
6842 }
6843 while (cur != NULL) {
6844 xmlAttrDumpOutput(buf, doc, cur, encoding);
6845 cur = cur->next;
6846 }
6847}
6848
6849
6850
6851/**
6852 * xmlNodeListDumpOutput:
6853 * @buf: the XML buffer output
6854 * @doc: the document
6855 * @cur: the first node
6856 * @level: the imbrication level for indenting
6857 * @format: is formatting allowed
6858 * @encoding: an optional encoding string
6859 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006860 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00006861 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006862 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006863 */
6864static void
6865xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6866 xmlNodePtr cur, int level, int format, const char *encoding) {
6867 int i;
6868
6869 if (cur == NULL) {
6870#ifdef DEBUG_TREE
6871 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006872 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006873#endif
6874 return;
6875 }
6876 while (cur != NULL) {
6877 if ((format) && (xmlIndentTreeOutput) &&
6878 (cur->type == XML_ELEMENT_NODE))
6879 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006880 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006881 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00006882 if (format) {
6883 xmlOutputBufferWriteString(buf, "\n");
6884 }
6885 cur = cur->next;
6886 }
6887}
6888
6889/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006890 * xmlNodeDumpOutputInternal:
Owen Taylor3473f882001-02-23 17:55:21 +00006891 * @buf: the XML buffer output
6892 * @doc: the document
6893 * @cur: the current node
6894 * @level: the imbrication level for indenting
6895 * @format: is formatting allowed
6896 * @encoding: an optional encoding string
6897 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006898 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00006899 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006900 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006901 */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006902static void
6903xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
6904 xmlNodePtr cur, int level, int format, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00006905 int i;
6906 xmlNodePtr tmp;
6907
6908 if (cur == NULL) {
6909#ifdef DEBUG_TREE
6910 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006911 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006912#endif
6913 return;
6914 }
6915 if (cur->type == XML_XINCLUDE_START)
6916 return;
6917 if (cur->type == XML_XINCLUDE_END)
6918 return;
6919 if (cur->type == XML_DTD_NODE) {
6920 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6921 return;
6922 }
6923 if (cur->type == XML_ELEMENT_DECL) {
6924 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6925 return;
6926 }
6927 if (cur->type == XML_ATTRIBUTE_DECL) {
6928 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6929 return;
6930 }
6931 if (cur->type == XML_ENTITY_DECL) {
6932 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6933 return;
6934 }
6935 if (cur->type == XML_TEXT_NODE) {
6936 if (cur->content != NULL) {
6937 if ((cur->name == xmlStringText) ||
6938 (cur->name != xmlStringTextNoenc)) {
6939 xmlChar *buffer;
6940
Owen Taylor3473f882001-02-23 17:55:21 +00006941 if (encoding == NULL)
6942 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6943 else
6944 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006945 if (buffer != NULL) {
6946 xmlOutputBufferWriteString(buf, (const char *)buffer);
6947 xmlFree(buffer);
6948 }
6949 } else {
6950 /*
6951 * Disable escaping, needed for XSLT
6952 */
Owen Taylor3473f882001-02-23 17:55:21 +00006953 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006954 }
6955 }
6956
6957 return;
6958 }
6959 if (cur->type == XML_PI_NODE) {
6960 if (cur->content != NULL) {
6961 xmlOutputBufferWriteString(buf, "<?");
6962 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6963 if (cur->content != NULL) {
6964 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00006965 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006966 }
6967 xmlOutputBufferWriteString(buf, "?>");
6968 } else {
6969 xmlOutputBufferWriteString(buf, "<?");
6970 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6971 xmlOutputBufferWriteString(buf, "?>");
6972 }
6973 return;
6974 }
6975 if (cur->type == XML_COMMENT_NODE) {
6976 if (cur->content != NULL) {
6977 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006978 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006979 xmlOutputBufferWriteString(buf, "-->");
6980 }
6981 return;
6982 }
6983 if (cur->type == XML_ENTITY_REF_NODE) {
6984 xmlOutputBufferWriteString(buf, "&");
6985 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6986 xmlOutputBufferWriteString(buf, ";");
6987 return;
6988 }
6989 if (cur->type == XML_CDATA_SECTION_NODE) {
6990 xmlOutputBufferWriteString(buf, "<![CDATA[");
6991 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006992 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006993 xmlOutputBufferWriteString(buf, "]]>");
6994 return;
6995 }
Daniel Veillard6aa2f602003-02-10 00:01:56 +00006996 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00006997 xmlNsDumpOutput(buf, (xmlNsPtr) cur);
Daniel Veillard6aa2f602003-02-10 00:01:56 +00006998 return;
6999 }
Owen Taylor3473f882001-02-23 17:55:21 +00007000
7001 if (format == 1) {
7002 tmp = cur->children;
7003 while (tmp != NULL) {
7004 if ((tmp->type == XML_TEXT_NODE) ||
7005 (tmp->type == XML_ENTITY_REF_NODE)) {
7006 format = 0;
7007 break;
7008 }
7009 tmp = tmp->next;
7010 }
7011 }
7012 xmlOutputBufferWriteString(buf, "<");
7013 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7014 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7015 xmlOutputBufferWriteString(buf, ":");
7016 }
7017
7018 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7019 if (cur->nsDef)
7020 xmlNsListDumpOutput(buf, cur->nsDef);
7021 if (cur->properties != NULL)
7022 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7023
Daniel Veillard7db37732001-07-12 01:20:08 +00007024 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
7025 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007026 xmlOutputBufferWriteString(buf, "/>");
7027 return;
7028 }
7029 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00007030 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007031 xmlChar *buffer;
7032
Owen Taylor3473f882001-02-23 17:55:21 +00007033 if (encoding == NULL)
7034 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7035 else
7036 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007037 if (buffer != NULL) {
7038 xmlOutputBufferWriteString(buf, (const char *)buffer);
7039 xmlFree(buffer);
7040 }
7041 }
7042 if (cur->children != NULL) {
7043 if (format) xmlOutputBufferWriteString(buf, "\n");
7044 xmlNodeListDumpOutput(buf, doc, cur->children,
7045 (level >= 0?level+1:-1), format, encoding);
7046 if ((xmlIndentTreeOutput) && (format))
7047 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007048 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00007049 }
7050 xmlOutputBufferWriteString(buf, "</");
7051 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7052 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7053 xmlOutputBufferWriteString(buf, ":");
7054 }
7055
7056 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7057 xmlOutputBufferWriteString(buf, ">");
7058}
7059
7060/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007061 * xmlNodeDumpOutput:
7062 * @buf: the XML buffer output
7063 * @doc: the document
7064 * @cur: the current node
7065 * @level: the imbrication level for indenting
7066 * @format: is formatting allowed
7067 * @encoding: an optional encoding string
7068 *
7069 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007070 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007071 * or xmlKeepBlanksDefault(0) was called
7072 */
7073void
7074xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007075 int level, int format, const char *encoding)
7076{
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007077#ifdef LIBXML_HTML_ENABLED
7078 xmlDtdPtr dtd;
7079 int is_xhtml = 0;
7080
7081 dtd = xmlGetIntSubset(doc);
7082 if (dtd != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007083 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7084 if (is_xhtml < 0)
7085 is_xhtml = 0;
7086 if ((is_xhtml) && (cur->parent == (xmlNodePtr) doc) &&
7087 (cur->type == XML_ELEMENT_NODE) &&
7088 (xmlStrEqual(cur->name, BAD_CAST "html"))) {
7089 if (encoding != NULL)
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007090 htmlSetMetaEncoding((htmlDocPtr) doc,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007091 (const xmlChar *) encoding);
7092 else
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007093 htmlSetMetaEncoding((htmlDocPtr) doc, BAD_CAST "UTF-8");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007094 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007095 }
7096
7097 if (is_xhtml)
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007098 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007099 else
7100#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007101 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007102}
7103
7104/**
Owen Taylor3473f882001-02-23 17:55:21 +00007105 * xmlDocContentDumpOutput:
7106 * @buf: the XML buffer output
7107 * @cur: the document
7108 * @encoding: an optional encoding string
7109 * @format: should formatting spaces been added
7110 *
7111 * Dump an XML document.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007112 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007113 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007114 */
7115static void
7116xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
7117 const char *encoding, int format) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007118#ifdef LIBXML_HTML_ENABLED
7119 xmlDtdPtr dtd;
7120 int is_xhtml = 0;
7121#endif
7122
Owen Taylor3473f882001-02-23 17:55:21 +00007123 xmlOutputBufferWriteString(buf, "<?xml version=");
7124 if (cur->version != NULL)
7125 xmlBufferWriteQuotedString(buf->buffer, cur->version);
7126 else
7127 xmlOutputBufferWriteString(buf, "\"1.0\"");
7128 if (encoding == NULL) {
7129 if (cur->encoding != NULL)
7130 encoding = (const char *) cur->encoding;
7131 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
7132 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
7133 }
7134 if (encoding != NULL) {
7135 xmlOutputBufferWriteString(buf, " encoding=");
7136 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
7137 }
7138 switch (cur->standalone) {
7139 case 0:
7140 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
7141 break;
7142 case 1:
7143 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
7144 break;
7145 }
7146 xmlOutputBufferWriteString(buf, "?>\n");
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007147
7148#ifdef LIBXML_HTML_ENABLED
7149 dtd = xmlGetIntSubset(cur);
7150 if (dtd != NULL) {
7151 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7152 if (is_xhtml < 0) is_xhtml = 0;
7153 }
7154 if (is_xhtml) {
7155 if (encoding != NULL)
7156 htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
7157 else
7158 htmlSetMetaEncoding(cur, BAD_CAST "UTF-8");
7159 }
7160#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007161 if (cur->children != NULL) {
7162 xmlNodePtr child = cur->children;
7163
7164 while (child != NULL) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007165#ifdef LIBXML_HTML_ENABLED
7166 if (is_xhtml)
7167 xhtmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
7168 else
7169#endif
7170 xmlNodeDumpOutputInternal(buf, cur, child, 0, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007171 xmlOutputBufferWriteString(buf, "\n");
7172 child = child->next;
7173 }
7174 }
7175}
7176
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007177#ifdef LIBXML_HTML_ENABLED
7178/************************************************************************
7179 * *
7180 * Functions specific to XHTML serialization *
7181 * *
7182 ************************************************************************/
7183
7184#define XHTML_STRICT_PUBLIC_ID BAD_CAST \
7185 "-//W3C//DTD XHTML 1.0 Strict//EN"
7186#define XHTML_STRICT_SYSTEM_ID BAD_CAST \
7187 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
7188#define XHTML_FRAME_PUBLIC_ID BAD_CAST \
7189 "-//W3C//DTD XHTML 1.0 Frameset//EN"
7190#define XHTML_FRAME_SYSTEM_ID BAD_CAST \
7191 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
7192#define XHTML_TRANS_PUBLIC_ID BAD_CAST \
7193 "-//W3C//DTD XHTML 1.0 Transitional//EN"
7194#define XHTML_TRANS_SYSTEM_ID BAD_CAST \
7195 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
7196
7197#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
7198/**
7199 * xmlIsXHTML:
7200 * @systemID: the system identifier
7201 * @publicID: the public identifier
7202 *
7203 * Try to find if the document correspond to an XHTML DTD
7204 *
7205 * Returns 1 if true, 0 if not and -1 in case of error
7206 */
7207int
7208xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) {
7209 if ((systemID == NULL) && (publicID == NULL))
7210 return(-1);
7211 if (publicID != NULL) {
7212 if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1);
7213 if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1);
7214 if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1);
7215 }
7216 if (systemID != NULL) {
7217 if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1);
7218 if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1);
7219 if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1);
7220 }
7221 return(0);
7222}
7223
7224/**
7225 * xhtmlIsEmpty:
7226 * @node: the node
7227 *
7228 * Check if a node is an empty xhtml node
7229 *
7230 * Returns 1 if the node is an empty node, 0 if not and -1 in case of error
7231 */
7232static int
7233xhtmlIsEmpty(xmlNodePtr node) {
7234 if (node == NULL)
7235 return(-1);
7236 if (node->type != XML_ELEMENT_NODE)
7237 return(0);
7238 if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME)))
7239 return(0);
7240 if (node->children != NULL)
7241 return(0);
7242 switch (node->name[0]) {
7243 case 'a':
7244 if (xmlStrEqual(node->name, BAD_CAST "area"))
7245 return(1);
7246 return(0);
7247 case 'b':
7248 if (xmlStrEqual(node->name, BAD_CAST "br"))
7249 return(1);
7250 if (xmlStrEqual(node->name, BAD_CAST "base"))
7251 return(1);
7252 if (xmlStrEqual(node->name, BAD_CAST "basefont"))
7253 return(1);
7254 return(0);
7255 case 'c':
7256 if (xmlStrEqual(node->name, BAD_CAST "col"))
7257 return(1);
7258 return(0);
7259 case 'f':
7260 if (xmlStrEqual(node->name, BAD_CAST "frame"))
7261 return(1);
7262 return(0);
7263 case 'h':
7264 if (xmlStrEqual(node->name, BAD_CAST "hr"))
7265 return(1);
7266 return(0);
7267 case 'i':
7268 if (xmlStrEqual(node->name, BAD_CAST "img"))
7269 return(1);
7270 if (xmlStrEqual(node->name, BAD_CAST "input"))
7271 return(1);
7272 if (xmlStrEqual(node->name, BAD_CAST "isindex"))
7273 return(1);
7274 return(0);
7275 case 'l':
7276 if (xmlStrEqual(node->name, BAD_CAST "link"))
7277 return(1);
7278 return(0);
7279 case 'm':
7280 if (xmlStrEqual(node->name, BAD_CAST "meta"))
7281 return(1);
7282 return(0);
7283 case 'p':
7284 if (xmlStrEqual(node->name, BAD_CAST "param"))
7285 return(1);
7286 return(0);
7287 }
7288 return(0);
7289}
7290
7291/**
7292 * xhtmlAttrListDumpOutput:
7293 * @buf: the XML buffer output
7294 * @doc: the document
7295 * @cur: the first attribute pointer
7296 * @encoding: an optional encoding string
7297 *
7298 * Dump a list of XML attributes
7299 */
7300static void
7301xhtmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7302 xmlAttrPtr cur, const char *encoding) {
7303 xmlAttrPtr xml_lang = NULL;
7304 xmlAttrPtr lang = NULL;
7305 xmlAttrPtr name = NULL;
7306 xmlAttrPtr id = NULL;
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007307 xmlNodePtr parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007308
7309 if (cur == NULL) {
7310#ifdef DEBUG_TREE
7311 xmlGenericError(xmlGenericErrorContext,
7312 "xmlAttrListDumpOutput : property == NULL\n");
7313#endif
7314 return;
7315 }
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007316 parent = cur->parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007317 while (cur != NULL) {
7318 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id")))
7319 id = cur;
7320 else
7321 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name")))
7322 name = cur;
7323 else
7324 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")))
7325 lang = cur;
7326 else
7327 if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) &&
7328 (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml")))
7329 xml_lang = cur;
7330 else if ((cur->ns == NULL) &&
7331 ((cur->children == NULL) ||
7332 (cur->children->content == NULL) ||
7333 (cur->children->content[0] == 0)) &&
7334 (htmlIsBooleanAttr(cur->name))) {
7335 if (cur->children != NULL)
7336 xmlFreeNode(cur->children);
7337 cur->children = xmlNewText(cur->name);
7338 if (cur->children != NULL)
7339 cur->children->parent = (xmlNodePtr) cur;
7340 }
7341 xmlAttrDumpOutput(buf, doc, cur, encoding);
7342 cur = cur->next;
7343 }
7344 /*
7345 * C.8
7346 */
7347 if ((name != NULL) && (id == NULL)) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007348 if ((parent != NULL) && (parent->name != NULL) &&
7349 ((xmlStrEqual(parent->name, BAD_CAST "a")) ||
7350 (xmlStrEqual(parent->name, BAD_CAST "p")) ||
7351 (xmlStrEqual(parent->name, BAD_CAST "div")) ||
7352 (xmlStrEqual(parent->name, BAD_CAST "img")) ||
7353 (xmlStrEqual(parent->name, BAD_CAST "map")) ||
7354 (xmlStrEqual(parent->name, BAD_CAST "applet")) ||
7355 (xmlStrEqual(parent->name, BAD_CAST "form")) ||
7356 (xmlStrEqual(parent->name, BAD_CAST "frame")) ||
7357 (xmlStrEqual(parent->name, BAD_CAST "iframe")))) {
7358 xmlOutputBufferWriteString(buf, " id=\"");
7359 xmlAttrSerializeContent(buf->buffer, doc, name);
7360 xmlOutputBufferWriteString(buf, "\"");
7361 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007362 }
7363 /*
7364 * C.7.
7365 */
7366 if ((lang != NULL) && (xml_lang == NULL)) {
7367 xmlOutputBufferWriteString(buf, " xml:lang=\"");
7368 xmlAttrSerializeContent(buf->buffer, doc, lang);
7369 xmlOutputBufferWriteString(buf, "\"");
7370 } else
7371 if ((xml_lang != NULL) && (lang == NULL)) {
7372 xmlOutputBufferWriteString(buf, " lang=\"");
7373 xmlAttrSerializeContent(buf->buffer, doc, xml_lang);
7374 xmlOutputBufferWriteString(buf, "\"");
7375 }
7376}
7377
7378/**
7379 * xhtmlNodeListDumpOutput:
7380 * @buf: the XML buffer output
7381 * @doc: the XHTML document
7382 * @cur: the first node
7383 * @level: the imbrication level for indenting
7384 * @format: is formatting allowed
7385 * @encoding: an optional encoding string
7386 *
7387 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007388 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007389 * or xmlKeepBlanksDefault(0) was called
7390 */
7391static void
7392xhtmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7393 xmlNodePtr cur, int level, int format, const char *encoding) {
7394 int i;
7395
7396 if (cur == NULL) {
7397#ifdef DEBUG_TREE
7398 xmlGenericError(xmlGenericErrorContext,
7399 "xhtmlNodeListDumpOutput : node == NULL\n");
7400#endif
7401 return;
7402 }
7403 while (cur != NULL) {
7404 if ((format) && (xmlIndentTreeOutput) &&
7405 (cur->type == XML_ELEMENT_NODE))
7406 for (i = 0;i < level;i++)
7407 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7408 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
7409 if (format) {
7410 xmlOutputBufferWriteString(buf, "\n");
7411 }
7412 cur = cur->next;
7413 }
7414}
7415
7416/**
7417 * xhtmlNodeDumpOutput:
7418 * @buf: the XML buffer output
7419 * @doc: the XHTML document
7420 * @cur: the current node
7421 * @level: the imbrication level for indenting
7422 * @format: is formatting allowed
7423 * @encoding: an optional encoding string
7424 *
7425 * Dump an XHTML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007426 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007427 * or xmlKeepBlanksDefault(0) was called
7428 */
7429static void
7430xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7431 int level, int format, const char *encoding) {
7432 int i;
7433 xmlNodePtr tmp;
7434
7435 if (cur == NULL) {
7436#ifdef DEBUG_TREE
7437 xmlGenericError(xmlGenericErrorContext,
7438 "xmlNodeDumpOutput : node == NULL\n");
7439#endif
7440 return;
7441 }
7442 if (cur->type == XML_XINCLUDE_START)
7443 return;
7444 if (cur->type == XML_XINCLUDE_END)
7445 return;
7446 if (cur->type == XML_DTD_NODE) {
7447 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7448 return;
7449 }
7450 if (cur->type == XML_ELEMENT_DECL) {
7451 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7452 return;
7453 }
7454 if (cur->type == XML_ATTRIBUTE_DECL) {
7455 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7456 return;
7457 }
7458 if (cur->type == XML_ENTITY_DECL) {
7459 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7460 return;
7461 }
7462 if (cur->type == XML_TEXT_NODE) {
7463 if (cur->content != NULL) {
7464 if ((cur->name == xmlStringText) ||
7465 (cur->name != xmlStringTextNoenc)) {
7466 xmlChar *buffer;
7467
7468 if (encoding == NULL)
7469 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7470 else
7471 buffer = xmlEncodeSpecialChars(doc, cur->content);
7472 if (buffer != NULL) {
7473 xmlOutputBufferWriteString(buf, (const char *)buffer);
7474 xmlFree(buffer);
7475 }
7476 } else {
7477 /*
7478 * Disable escaping, needed for XSLT
7479 */
7480 xmlOutputBufferWriteString(buf, (const char *) cur->content);
7481 }
7482 }
7483
7484 return;
7485 }
7486 if (cur->type == XML_PI_NODE) {
7487 if (cur->content != NULL) {
7488 xmlOutputBufferWriteString(buf, "<?");
7489 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7490 if (cur->content != NULL) {
7491 xmlOutputBufferWriteString(buf, " ");
7492 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7493 }
7494 xmlOutputBufferWriteString(buf, "?>");
7495 } else {
7496 xmlOutputBufferWriteString(buf, "<?");
7497 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7498 xmlOutputBufferWriteString(buf, "?>");
7499 }
7500 return;
7501 }
7502 if (cur->type == XML_COMMENT_NODE) {
7503 if (cur->content != NULL) {
7504 xmlOutputBufferWriteString(buf, "<!--");
7505 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7506 xmlOutputBufferWriteString(buf, "-->");
7507 }
7508 return;
7509 }
7510 if (cur->type == XML_ENTITY_REF_NODE) {
7511 xmlOutputBufferWriteString(buf, "&");
7512 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7513 xmlOutputBufferWriteString(buf, ";");
7514 return;
7515 }
7516 if (cur->type == XML_CDATA_SECTION_NODE) {
7517 xmlOutputBufferWriteString(buf, "<![CDATA[");
7518 if (cur->content != NULL)
7519 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7520 xmlOutputBufferWriteString(buf, "]]>");
7521 return;
7522 }
7523
7524 if (format == 1) {
7525 tmp = cur->children;
7526 while (tmp != NULL) {
7527 if ((tmp->type == XML_TEXT_NODE) ||
7528 (tmp->type == XML_ENTITY_REF_NODE)) {
7529 format = 0;
7530 break;
7531 }
7532 tmp = tmp->next;
7533 }
7534 }
7535 xmlOutputBufferWriteString(buf, "<");
7536 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7537 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7538 xmlOutputBufferWriteString(buf, ":");
7539 }
7540
7541 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7542 if (cur->nsDef)
7543 xmlNsListDumpOutput(buf, cur->nsDef);
7544 if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
7545 (cur->ns == NULL) && (cur->nsDef == NULL))) {
7546 /*
7547 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
7548 */
7549 xmlOutputBufferWriteString(buf,
7550 " xmlns=\"http://www.w3.org/1999/xhtml\"");
7551 }
7552 if (cur->properties != NULL)
7553 xhtmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7554
7555 if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) {
7556 if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
7557 (xhtmlIsEmpty(cur) == 1)) {
7558 /*
7559 * C.2. Empty Elements
7560 */
7561 xmlOutputBufferWriteString(buf, " />");
7562 } else {
7563 /*
7564 * C.3. Element Minimization and Empty Element Content
7565 */
7566 xmlOutputBufferWriteString(buf, "></");
7567 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7568 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7569 xmlOutputBufferWriteString(buf, ":");
7570 }
7571 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7572 xmlOutputBufferWriteString(buf, ">");
7573 }
7574 return;
7575 }
7576 xmlOutputBufferWriteString(buf, ">");
7577 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
7578 xmlChar *buffer;
7579
7580 if (encoding == NULL)
7581 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7582 else
7583 buffer = xmlEncodeSpecialChars(doc, cur->content);
7584 if (buffer != NULL) {
7585 xmlOutputBufferWriteString(buf, (const char *)buffer);
7586 xmlFree(buffer);
7587 }
7588 }
7589
7590 /*
7591 * 4.8. Script and Style elements
7592 */
7593 if ((cur->type == XML_ELEMENT_NODE) &&
7594 ((xmlStrEqual(cur->name, BAD_CAST "script")) ||
7595 (xmlStrEqual(cur->name, BAD_CAST "style"))) &&
7596 ((cur->ns == NULL) ||
7597 (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) {
7598 xmlNodePtr child = cur->children;
7599
7600 while (child != NULL) {
7601 if ((child->type == XML_TEXT_NODE) ||
7602 (child->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard64b35282002-12-04 15:10:40 +00007603 /*
7604 * Apparently CDATA escaping for style just break on IE,
7605 * mozilla and galeon, so ...
7606 */
7607 if (xmlStrEqual(cur->name, BAD_CAST "style") &&
7608 (xmlStrchr(child->content, '<') == NULL) &&
7609 (xmlStrchr(child->content, '>') == NULL) &&
7610 (xmlStrchr(child->content, '&') == NULL)) {
7611 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7612 } else {
7613 xmlOutputBufferWriteString(buf, "<![CDATA[");
7614 if (child->content != NULL)
7615 xmlOutputBufferWriteString(buf,
7616 (const char *)child->content);
7617 xmlOutputBufferWriteString(buf, "]]>");
7618 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007619 } else {
7620 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7621 }
7622 child = child->next;
7623 }
7624 } else if (cur->children != NULL) {
7625 if (format) xmlOutputBufferWriteString(buf, "\n");
7626 xhtmlNodeListDumpOutput(buf, doc, cur->children,
7627 (level >= 0?level+1:-1), format, encoding);
7628 if ((xmlIndentTreeOutput) && (format))
7629 for (i = 0;i < level;i++)
7630 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7631 }
7632 xmlOutputBufferWriteString(buf, "</");
7633 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7634 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7635 xmlOutputBufferWriteString(buf, ":");
7636 }
7637
7638 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7639 xmlOutputBufferWriteString(buf, ">");
7640}
7641#endif
7642
Owen Taylor3473f882001-02-23 17:55:21 +00007643/************************************************************************
7644 * *
7645 * Saving functions front-ends *
7646 * *
7647 ************************************************************************/
7648
7649/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00007650 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00007651 * @out_doc: Document to generate XML text from
7652 * @doc_txt_ptr: Memory pointer for allocated XML text
7653 * @doc_txt_len: Length of the generated XML text
7654 * @txt_encoding: Character encoding to use when generating XML text
7655 * @format: should formatting spaces been added
7656 *
7657 * Dump the current DOM tree into memory using the character encoding specified
7658 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007659 * allocated memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00007660 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007661 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007662 */
7663
7664void
7665xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007666 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007667 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007668 int dummy = 0;
7669
7670 xmlCharEncoding doc_charset;
7671 xmlOutputBufferPtr out_buff = NULL;
7672 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
7673
7674 if (doc_txt_len == NULL) {
7675 doc_txt_len = &dummy; /* Continue, caller just won't get length */
7676 }
7677
7678 if (doc_txt_ptr == NULL) {
7679 *doc_txt_len = 0;
7680 xmlGenericError(xmlGenericErrorContext,
7681 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
7682 return;
7683 }
7684
7685 *doc_txt_ptr = NULL;
7686 *doc_txt_len = 0;
7687
7688 if (out_doc == NULL) {
7689 /* No document, no output */
7690 xmlGenericError(xmlGenericErrorContext,
7691 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
7692 return;
7693 }
7694
7695 /*
7696 * Validate the encoding value, if provided.
7697 * This logic is copied from xmlSaveFileEnc.
7698 */
7699
7700 if (txt_encoding == NULL)
7701 txt_encoding = (const char *) out_doc->encoding;
7702 if (txt_encoding != NULL) {
7703 doc_charset = xmlParseCharEncoding(txt_encoding);
7704
7705 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
7706 xmlGenericError(xmlGenericErrorContext,
7707 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
7708 return;
7709
7710 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
7711 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
7712 if ( conv_hdlr == NULL ) {
7713 xmlGenericError(xmlGenericErrorContext,
7714 "%s: %s %s '%s'\n",
7715 "xmlDocDumpFormatMemoryEnc",
7716 "Failed to identify encoding handler for",
7717 "character set",
7718 txt_encoding);
7719 return;
7720 }
7721 }
7722 }
7723
7724 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
7725 xmlGenericError(xmlGenericErrorContext,
7726 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
7727 return;
7728 }
7729
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007730 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007731 xmlOutputBufferFlush(out_buff);
7732 if (out_buff->conv != NULL) {
7733 *doc_txt_len = out_buff->conv->use;
7734 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
7735 } else {
7736 *doc_txt_len = out_buff->buffer->use;
7737 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
7738 }
7739 (void)xmlOutputBufferClose(out_buff);
7740
7741 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
7742 *doc_txt_len = 0;
7743 xmlGenericError(xmlGenericErrorContext,
7744 "xmlDocDumpFormatMemoryEnc: %s\n",
7745 "Failed to allocate memory for document text representation.");
7746 }
7747
7748 return;
7749}
7750
7751/**
7752 * xmlDocDumpMemory:
7753 * @cur: the document
7754 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007755 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007756 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007757 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007758 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007759 */
7760void
7761xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
7762 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
7763}
7764
7765/**
7766 * xmlDocDumpFormatMemory:
7767 * @cur: the document
7768 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007769 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007770 * @format: should formatting spaces been added
7771 *
7772 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007773 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007774 * It's up to the caller to free the memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00007775 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007776 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007777 */
7778void
7779xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
7780 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
7781}
7782
7783/**
7784 * xmlDocDumpMemoryEnc:
7785 * @out_doc: Document to generate XML text from
7786 * @doc_txt_ptr: Memory pointer for allocated XML text
7787 * @doc_txt_len: Length of the generated XML text
7788 * @txt_encoding: Character encoding to use when generating XML text
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().
Owen Taylor3473f882001-02-23 17:55:21 +00007793 */
7794
7795void
7796xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
7797 int * doc_txt_len, const char * txt_encoding) {
7798 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007799 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007800}
7801
7802/**
7803 * xmlGetDocCompressMode:
7804 * @doc: the document
7805 *
7806 * get the compression ratio for a document, ZLIB based
7807 * Returns 0 (uncompressed) to 9 (max compression)
7808 */
7809int
7810xmlGetDocCompressMode (xmlDocPtr doc) {
7811 if (doc == NULL) return(-1);
7812 return(doc->compression);
7813}
7814
7815/**
7816 * xmlSetDocCompressMode:
7817 * @doc: the document
7818 * @mode: the compression ratio
7819 *
7820 * set the compression ratio for a document, ZLIB based
7821 * Correct values: 0 (uncompressed) to 9 (max compression)
7822 */
7823void
7824xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7825 if (doc == NULL) return;
7826 if (mode < 0) doc->compression = 0;
7827 else if (mode > 9) doc->compression = 9;
7828 else doc->compression = mode;
7829}
7830
7831/**
7832 * xmlGetCompressMode:
7833 *
7834 * get the default compression mode used, ZLIB based.
7835 * Returns 0 (uncompressed) to 9 (max compression)
7836 */
7837int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007838xmlGetCompressMode(void)
7839{
7840 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00007841}
7842
7843/**
7844 * xmlSetCompressMode:
7845 * @mode: the compression ratio
7846 *
7847 * set the default compression mode used, ZLIB based
7848 * Correct values: 0 (uncompressed) to 9 (max compression)
7849 */
7850void
7851xmlSetCompressMode(int mode) {
7852 if (mode < 0) xmlCompressMode = 0;
7853 else if (mode > 9) xmlCompressMode = 9;
7854 else xmlCompressMode = mode;
7855}
7856
7857/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007858 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00007859 * @f: the FILE*
7860 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00007861 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007862 *
7863 * Dump an XML document to an open FILE.
7864 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007865 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007866 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7867 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007868 */
7869int
Daniel Veillard9e412302002-06-10 15:59:44 +00007870xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007871 xmlOutputBufferPtr buf;
7872 const char * encoding;
7873 xmlCharEncodingHandlerPtr handler = NULL;
7874 int ret;
7875
7876 if (cur == NULL) {
7877#ifdef DEBUG_TREE
7878 xmlGenericError(xmlGenericErrorContext,
7879 "xmlDocDump : document == NULL\n");
7880#endif
7881 return(-1);
7882 }
7883 encoding = (const char *) cur->encoding;
7884
7885 if (encoding != NULL) {
7886 xmlCharEncoding enc;
7887
7888 enc = xmlParseCharEncoding(encoding);
7889
7890 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7891 xmlGenericError(xmlGenericErrorContext,
7892 "xmlDocDump: document not in UTF8\n");
7893 return(-1);
7894 }
7895 if (enc != XML_CHAR_ENCODING_UTF8) {
7896 handler = xmlFindCharEncodingHandler(encoding);
7897 if (handler == NULL) {
7898 xmlFree((char *) cur->encoding);
7899 cur->encoding = NULL;
7900 }
7901 }
7902 }
7903 buf = xmlOutputBufferCreateFile(f, handler);
7904 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00007905 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007906
7907 ret = xmlOutputBufferClose(buf);
7908 return(ret);
7909}
7910
7911/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007912 * xmlDocDump:
7913 * @f: the FILE*
7914 * @cur: the document
7915 *
7916 * Dump an XML document to an open FILE.
7917 *
7918 * returns: the number of bytes written or -1 in case of failure.
7919 */
7920int
7921xmlDocDump(FILE *f, xmlDocPtr cur) {
7922 return(xmlDocFormatDump (f, cur, 0));
7923}
7924
7925/**
Owen Taylor3473f882001-02-23 17:55:21 +00007926 * xmlSaveFileTo:
7927 * @buf: an output I/O buffer
7928 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007929 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00007930 *
7931 * Dump an XML document to an I/O buffer.
7932 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007933 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007934 */
7935int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007936xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007937 int ret;
7938
7939 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007940 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007941 ret = xmlOutputBufferClose(buf);
7942 return(ret);
7943}
7944
7945/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00007946 * xmlSaveFormatFileTo:
7947 * @buf: an output I/O buffer
7948 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007949 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00007950 * @format: should formatting spaces been added
7951 *
7952 * Dump an XML document to an I/O buffer.
7953 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007954 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007955 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7956 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardeefd4492001-04-28 16:55:50 +00007957 */
7958int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007959xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00007960 int ret;
7961
7962 if (buf == NULL) return(0);
7963 xmlDocContentDumpOutput(buf, cur, encoding, format);
7964 ret = xmlOutputBufferClose(buf);
7965 return(ret);
7966}
7967
7968/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00007969 * xmlSaveFormatFileEnc:
Daniel Veillardf012a642001-07-23 19:10:52 +00007970 * @filename: the filename or URL to output
7971 * @cur: the document being saved
7972 * @encoding: the name of the encoding to use or NULL.
7973 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00007974 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00007975 * Dump an XML document to a file or an URL.
7976 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007977 * Returns the number of bytes written or -1 in case of error.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007978 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7979 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007980 */
7981int
Daniel Veillardf012a642001-07-23 19:10:52 +00007982xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
7983 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00007984 xmlOutputBufferPtr buf;
7985 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00007986 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00007987 int ret;
7988
Daniel Veillard4dbe77a2003-01-14 00:17:42 +00007989 if (cur == NULL)
7990 return(-1);
7991
Daniel Veillardfb25a512002-01-13 20:32:08 +00007992 if (encoding == NULL)
7993 encoding = (const char *) cur->encoding;
7994
Owen Taylor3473f882001-02-23 17:55:21 +00007995 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00007996
7997 enc = xmlParseCharEncoding(encoding);
7998 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7999 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00008000 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00008001 return(-1);
8002 }
8003 if (enc != XML_CHAR_ENCODING_UTF8) {
8004 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00008005 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00008006 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00008007 }
8008 }
8009
Daniel Veillardf012a642001-07-23 19:10:52 +00008010#ifdef HAVE_ZLIB_H
8011 if (cur->compression < 0) cur->compression = xmlCompressMode;
8012#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008013 /*
8014 * save the content to a temp buffer.
8015 */
Daniel Veillardf012a642001-07-23 19:10:52 +00008016 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00008017 if (buf == NULL) return(-1);
8018
Daniel Veillardf012a642001-07-23 19:10:52 +00008019 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008020
8021 ret = xmlOutputBufferClose(buf);
8022 return(ret);
8023}
8024
Daniel Veillardf012a642001-07-23 19:10:52 +00008025
8026/**
8027 * xmlSaveFileEnc:
8028 * @filename: the filename (or URL)
8029 * @cur: the document
8030 * @encoding: the name of an encoding (or NULL)
8031 *
8032 * Dump an XML document, converting it to the given encoding
8033 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008034 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00008035 */
8036int
8037xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
8038 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
8039}
8040
Owen Taylor3473f882001-02-23 17:55:21 +00008041/**
Daniel Veillard67fee942001-04-26 18:59:03 +00008042 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00008043 * @filename: the filename (or URL)
8044 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00008045 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00008046 *
8047 * Dump an XML document to a file. Will use compression if
8048 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00008049 * used. If @format is set then the document will be indented on output.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008050 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8051 * or xmlKeepBlanksDefault(0) was called
Daniel Veillard67fee942001-04-26 18:59:03 +00008052 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008053 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008054 */
8055int
Daniel Veillard67fee942001-04-26 18:59:03 +00008056xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008057 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00008058}
8059
Daniel Veillard67fee942001-04-26 18:59:03 +00008060/**
8061 * xmlSaveFile:
8062 * @filename: the filename (or URL)
8063 * @cur: the document
8064 *
8065 * Dump an XML document to a file. Will use compression if
8066 * compiled in and enabled. If @filename is "-" the stdout file is
8067 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00008068 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00008069 */
8070int
8071xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008072 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00008073}
8074