blob: dbe94fbc6a7b80e50b1e4877e030faa81643a06e [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 }
1405
1406 /*
1407 * Allocate a new property and fill the fields.
1408 */
1409 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1410 if (cur == NULL) {
1411 xmlGenericError(xmlGenericErrorContext,
1412 "xmlNewProp : malloc failed\n");
1413 return(NULL);
1414 }
1415 memset(cur, 0, sizeof(xmlAttr));
1416 cur->type = XML_ATTRIBUTE_NODE;
1417
1418 cur->parent = node;
1419 if (node != NULL) {
1420 doc = node->doc;
1421 cur->doc = doc;
1422 }
1423 cur->name = xmlStrdup(name);
1424 if (value != NULL) {
1425 xmlChar *buffer;
1426 xmlNodePtr tmp;
1427
1428 buffer = xmlEncodeEntitiesReentrant(doc, value);
1429 cur->children = xmlStringGetNodeList(doc, buffer);
1430 cur->last = NULL;
1431 tmp = cur->children;
1432 while (tmp != NULL) {
1433 tmp->parent = (xmlNodePtr) cur;
1434 tmp->doc = doc;
1435 if (tmp->next == NULL)
1436 cur->last = tmp;
1437 tmp = tmp->next;
1438 }
1439 xmlFree(buffer);
1440 }
1441
1442 /*
1443 * Add it at the end to preserve parsing order ...
1444 */
1445 if (node != NULL) {
1446 if (node->properties == NULL) {
1447 node->properties = cur;
1448 } else {
1449 xmlAttrPtr prev = node->properties;
1450
1451 while (prev->next != NULL) prev = prev->next;
1452 prev->next = cur;
1453 cur->prev = prev;
1454 }
1455 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001456
1457 if (xmlRegisterNodeDefaultValue)
1458 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001459 return(cur);
1460}
1461
1462/**
1463 * xmlNewNsProp:
1464 * @node: the holding node
1465 * @ns: the namespace
1466 * @name: the name of the attribute
1467 * @value: the value of the attribute
1468 *
1469 * Create a new property tagged with a namespace and carried by a node.
1470 * Returns a pointer to the attribute
1471 */
1472xmlAttrPtr
1473xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1474 const xmlChar *value) {
1475 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001476 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001477
1478 if (name == NULL) {
1479#ifdef DEBUG_TREE
1480 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001481 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001482#endif
1483 return(NULL);
1484 }
1485
1486 /*
1487 * Allocate a new property and fill the fields.
1488 */
1489 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1490 if (cur == NULL) {
1491 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001492 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001493 return(NULL);
1494 }
1495 memset(cur, 0, sizeof(xmlAttr));
1496 cur->type = XML_ATTRIBUTE_NODE;
1497
1498 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001499 if (node != NULL) {
1500 doc = node->doc;
1501 cur->doc = doc;
1502 }
Owen Taylor3473f882001-02-23 17:55:21 +00001503 cur->ns = ns;
1504 cur->name = xmlStrdup(name);
1505 if (value != NULL) {
1506 xmlChar *buffer;
1507 xmlNodePtr tmp;
1508
Daniel Veillarda682b212001-06-07 19:59:42 +00001509 buffer = xmlEncodeEntitiesReentrant(doc, value);
1510 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001511 cur->last = NULL;
1512 tmp = cur->children;
1513 while (tmp != NULL) {
1514 tmp->parent = (xmlNodePtr) cur;
1515 if (tmp->next == NULL)
1516 cur->last = tmp;
1517 tmp = tmp->next;
1518 }
1519 xmlFree(buffer);
1520 }
1521
1522 /*
1523 * Add it at the end to preserve parsing order ...
1524 */
1525 if (node != NULL) {
1526 if (node->properties == NULL) {
1527 node->properties = cur;
1528 } else {
1529 xmlAttrPtr prev = node->properties;
1530
1531 while (prev->next != NULL) prev = prev->next;
1532 prev->next = cur;
1533 cur->prev = prev;
1534 }
1535 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001536
1537 if (xmlRegisterNodeDefaultValue)
1538 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001539 return(cur);
1540}
1541
1542/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001543 * xmlNewNsPropEatName:
1544 * @node: the holding node
1545 * @ns: the namespace
1546 * @name: the name of the attribute
1547 * @value: the value of the attribute
1548 *
1549 * Create a new property tagged with a namespace and carried by a node.
1550 * Returns a pointer to the attribute
1551 */
1552xmlAttrPtr
1553xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1554 const xmlChar *value) {
1555 xmlAttrPtr cur;
1556 xmlDocPtr doc = NULL;
1557
1558 if (name == NULL) {
1559#ifdef DEBUG_TREE
1560 xmlGenericError(xmlGenericErrorContext,
1561 "xmlNewNsPropEatName : name == NULL\n");
1562#endif
1563 return(NULL);
1564 }
1565
1566 /*
1567 * Allocate a new property and fill the fields.
1568 */
1569 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1570 if (cur == NULL) {
1571 xmlGenericError(xmlGenericErrorContext,
1572 "xmlNewNsPropEatName : malloc failed\n");
1573 return(NULL);
1574 }
1575 memset(cur, 0, sizeof(xmlAttr));
1576 cur->type = XML_ATTRIBUTE_NODE;
1577
1578 cur->parent = node;
1579 if (node != NULL) {
1580 doc = node->doc;
1581 cur->doc = doc;
1582 }
1583 cur->ns = ns;
1584 cur->name = name;
1585 if (value != NULL) {
1586 xmlChar *buffer;
1587 xmlNodePtr tmp;
1588
1589 buffer = xmlEncodeEntitiesReentrant(doc, value);
1590 cur->children = xmlStringGetNodeList(doc, buffer);
1591 cur->last = NULL;
1592 tmp = cur->children;
1593 while (tmp != NULL) {
1594 tmp->parent = (xmlNodePtr) cur;
1595 if (tmp->next == NULL)
1596 cur->last = tmp;
1597 tmp = tmp->next;
1598 }
1599 xmlFree(buffer);
1600 }
1601
1602 /*
1603 * Add it at the end to preserve parsing order ...
1604 */
1605 if (node != NULL) {
1606 if (node->properties == NULL) {
1607 node->properties = cur;
1608 } else {
1609 xmlAttrPtr prev = node->properties;
1610
1611 while (prev->next != NULL) prev = prev->next;
1612 prev->next = cur;
1613 cur->prev = prev;
1614 }
1615 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001616
1617 if (xmlRegisterNodeDefaultValue)
1618 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001619 return(cur);
1620}
1621
1622/**
Owen Taylor3473f882001-02-23 17:55:21 +00001623 * xmlNewDocProp:
1624 * @doc: the document
1625 * @name: the name of the attribute
1626 * @value: the value of the attribute
1627 *
1628 * Create a new property carried by a document.
1629 * Returns a pointer to the attribute
1630 */
1631xmlAttrPtr
1632xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1633 xmlAttrPtr cur;
1634
1635 if (name == NULL) {
1636#ifdef DEBUG_TREE
1637 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001638 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001639#endif
1640 return(NULL);
1641 }
1642
1643 /*
1644 * Allocate a new property and fill the fields.
1645 */
1646 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1647 if (cur == NULL) {
1648 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001649 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001650 return(NULL);
1651 }
1652 memset(cur, 0, sizeof(xmlAttr));
1653 cur->type = XML_ATTRIBUTE_NODE;
1654
1655 cur->name = xmlStrdup(name);
1656 cur->doc = doc;
1657 if (value != NULL) {
1658 xmlNodePtr tmp;
1659
1660 cur->children = xmlStringGetNodeList(doc, value);
1661 cur->last = NULL;
1662
1663 tmp = cur->children;
1664 while (tmp != NULL) {
1665 tmp->parent = (xmlNodePtr) cur;
1666 if (tmp->next == NULL)
1667 cur->last = tmp;
1668 tmp = tmp->next;
1669 }
1670 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001671
1672 if (xmlRegisterNodeDefaultValue)
1673 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001674 return(cur);
1675}
1676
1677/**
1678 * xmlFreePropList:
1679 * @cur: the first property in the list
1680 *
1681 * Free a property and all its siblings, all the children are freed too.
1682 */
1683void
1684xmlFreePropList(xmlAttrPtr cur) {
1685 xmlAttrPtr next;
1686 if (cur == NULL) {
1687#ifdef DEBUG_TREE
1688 xmlGenericError(xmlGenericErrorContext,
1689 "xmlFreePropList : property == NULL\n");
1690#endif
1691 return;
1692 }
1693 while (cur != NULL) {
1694 next = cur->next;
1695 xmlFreeProp(cur);
1696 cur = next;
1697 }
1698}
1699
1700/**
1701 * xmlFreeProp:
1702 * @cur: an attribute
1703 *
1704 * Free one attribute, all the content is freed too
1705 */
1706void
1707xmlFreeProp(xmlAttrPtr cur) {
1708 if (cur == NULL) {
1709#ifdef DEBUG_TREE
1710 xmlGenericError(xmlGenericErrorContext,
1711 "xmlFreeProp : property == NULL\n");
1712#endif
1713 return;
1714 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001715
1716 if (xmlDeregisterNodeDefaultValue)
1717 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1718
Owen Taylor3473f882001-02-23 17:55:21 +00001719 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001720 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1721 ((cur->parent->doc->intSubset != NULL) ||
1722 (cur->parent->doc->extSubset != NULL))) {
1723 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1724 xmlRemoveID(cur->parent->doc, cur);
1725 }
Owen Taylor3473f882001-02-23 17:55:21 +00001726 if (cur->name != NULL) xmlFree((char *) cur->name);
1727 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001728 xmlFree(cur);
1729}
1730
1731/**
1732 * xmlRemoveProp:
1733 * @cur: an attribute
1734 *
1735 * Unlink and free one attribute, all the content is freed too
1736 * Note this doesn't work for namespace definition attributes
1737 *
1738 * Returns 0 if success and -1 in case of error.
1739 */
1740int
1741xmlRemoveProp(xmlAttrPtr cur) {
1742 xmlAttrPtr tmp;
1743 if (cur == NULL) {
1744#ifdef DEBUG_TREE
1745 xmlGenericError(xmlGenericErrorContext,
1746 "xmlRemoveProp : cur == NULL\n");
1747#endif
1748 return(-1);
1749 }
1750 if (cur->parent == NULL) {
1751#ifdef DEBUG_TREE
1752 xmlGenericError(xmlGenericErrorContext,
1753 "xmlRemoveProp : cur->parent == NULL\n");
1754#endif
1755 return(-1);
1756 }
1757 tmp = cur->parent->properties;
1758 if (tmp == cur) {
1759 cur->parent->properties = cur->next;
1760 xmlFreeProp(cur);
1761 return(0);
1762 }
1763 while (tmp != NULL) {
1764 if (tmp->next == cur) {
1765 tmp->next = cur->next;
1766 if (tmp->next != NULL)
1767 tmp->next->prev = tmp;
1768 xmlFreeProp(cur);
1769 return(0);
1770 }
1771 tmp = tmp->next;
1772 }
1773#ifdef DEBUG_TREE
1774 xmlGenericError(xmlGenericErrorContext,
1775 "xmlRemoveProp : attribute not owned by its node\n");
1776#endif
1777 return(-1);
1778}
1779
1780/**
1781 * xmlNewPI:
1782 * @name: the processing instruction name
1783 * @content: the PI content
1784 *
1785 * Creation of a processing instruction element.
1786 * Returns a pointer to the new node object.
1787 */
1788xmlNodePtr
1789xmlNewPI(const xmlChar *name, const xmlChar *content) {
1790 xmlNodePtr cur;
1791
1792 if (name == NULL) {
1793#ifdef DEBUG_TREE
1794 xmlGenericError(xmlGenericErrorContext,
1795 "xmlNewPI : name == NULL\n");
1796#endif
1797 return(NULL);
1798 }
1799
1800 /*
1801 * Allocate a new node and fill the fields.
1802 */
1803 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1804 if (cur == NULL) {
1805 xmlGenericError(xmlGenericErrorContext,
1806 "xmlNewPI : malloc failed\n");
1807 return(NULL);
1808 }
1809 memset(cur, 0, sizeof(xmlNode));
1810 cur->type = XML_PI_NODE;
1811
1812 cur->name = xmlStrdup(name);
1813 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001814 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001815 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001816
1817 if (xmlRegisterNodeDefaultValue)
1818 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001819 return(cur);
1820}
1821
1822/**
1823 * xmlNewNode:
1824 * @ns: namespace if any
1825 * @name: the node name
1826 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001827 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001828 *
1829 * Returns a pointer to the new node object.
1830 */
1831xmlNodePtr
1832xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1833 xmlNodePtr cur;
1834
1835 if (name == NULL) {
1836#ifdef DEBUG_TREE
1837 xmlGenericError(xmlGenericErrorContext,
1838 "xmlNewNode : name == NULL\n");
1839#endif
1840 return(NULL);
1841 }
1842
1843 /*
1844 * Allocate a new node and fill the fields.
1845 */
1846 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1847 if (cur == NULL) {
1848 xmlGenericError(xmlGenericErrorContext,
1849 "xmlNewNode : malloc failed\n");
1850 return(NULL);
1851 }
1852 memset(cur, 0, sizeof(xmlNode));
1853 cur->type = XML_ELEMENT_NODE;
1854
1855 cur->name = xmlStrdup(name);
1856 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001857
1858 if (xmlRegisterNodeDefaultValue)
1859 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001860 return(cur);
1861}
1862
1863/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001864 * xmlNewNodeEatName:
1865 * @ns: namespace if any
1866 * @name: the node name
1867 *
1868 * Creation of a new node element. @ns is optional (NULL).
1869 *
1870 * Returns a pointer to the new node object.
1871 */
1872xmlNodePtr
1873xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
1874 xmlNodePtr cur;
1875
1876 if (name == NULL) {
1877#ifdef DEBUG_TREE
1878 xmlGenericError(xmlGenericErrorContext,
1879 "xmlNewNode : name == NULL\n");
1880#endif
1881 return(NULL);
1882 }
1883
1884 /*
1885 * Allocate a new node and fill the fields.
1886 */
1887 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1888 if (cur == NULL) {
1889 xmlGenericError(xmlGenericErrorContext,
1890 "xmlNewNode : malloc failed\n");
1891 return(NULL);
1892 }
1893 memset(cur, 0, sizeof(xmlNode));
1894 cur->type = XML_ELEMENT_NODE;
1895
1896 cur->name = name;
1897 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001898
1899 if (xmlRegisterNodeDefaultValue)
1900 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001901 return(cur);
1902}
1903
1904/**
Owen Taylor3473f882001-02-23 17:55:21 +00001905 * xmlNewDocNode:
1906 * @doc: the document
1907 * @ns: namespace if any
1908 * @name: the node name
1909 * @content: the XML text content if any
1910 *
1911 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001912 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001913 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1914 * references, but XML special chars need to be escaped first by using
1915 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1916 * need entities support.
1917 *
1918 * Returns a pointer to the new node object.
1919 */
1920xmlNodePtr
1921xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1922 const xmlChar *name, const xmlChar *content) {
1923 xmlNodePtr cur;
1924
1925 cur = xmlNewNode(ns, name);
1926 if (cur != NULL) {
1927 cur->doc = doc;
1928 if (content != NULL) {
1929 cur->children = xmlStringGetNodeList(doc, content);
1930 UPDATE_LAST_CHILD_AND_PARENT(cur)
1931 }
1932 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001933
Owen Taylor3473f882001-02-23 17:55:21 +00001934 return(cur);
1935}
1936
Daniel Veillard46de64e2002-05-29 08:21:33 +00001937/**
1938 * xmlNewDocNodeEatName:
1939 * @doc: the document
1940 * @ns: namespace if any
1941 * @name: the node name
1942 * @content: the XML text content if any
1943 *
1944 * Creation of a new node element within a document. @ns and @content
1945 * are optional (NULL).
1946 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1947 * references, but XML special chars need to be escaped first by using
1948 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1949 * need entities support.
1950 *
1951 * Returns a pointer to the new node object.
1952 */
1953xmlNodePtr
1954xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
1955 xmlChar *name, const xmlChar *content) {
1956 xmlNodePtr cur;
1957
1958 cur = xmlNewNodeEatName(ns, name);
1959 if (cur != NULL) {
1960 cur->doc = doc;
1961 if (content != NULL) {
1962 cur->children = xmlStringGetNodeList(doc, content);
1963 UPDATE_LAST_CHILD_AND_PARENT(cur)
1964 }
1965 }
1966 return(cur);
1967}
1968
Owen Taylor3473f882001-02-23 17:55:21 +00001969
1970/**
1971 * xmlNewDocRawNode:
1972 * @doc: the document
1973 * @ns: namespace if any
1974 * @name: the node name
1975 * @content: the text content if any
1976 *
1977 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001978 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001979 *
1980 * Returns a pointer to the new node object.
1981 */
1982xmlNodePtr
1983xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1984 const xmlChar *name, const xmlChar *content) {
1985 xmlNodePtr cur;
1986
1987 cur = xmlNewNode(ns, name);
1988 if (cur != NULL) {
1989 cur->doc = doc;
1990 if (content != NULL) {
1991 cur->children = xmlNewDocText(doc, content);
1992 UPDATE_LAST_CHILD_AND_PARENT(cur)
1993 }
1994 }
1995 return(cur);
1996}
1997
1998/**
1999 * xmlNewDocFragment:
2000 * @doc: the document owning the fragment
2001 *
2002 * Creation of a new Fragment node.
2003 * Returns a pointer to the new node object.
2004 */
2005xmlNodePtr
2006xmlNewDocFragment(xmlDocPtr doc) {
2007 xmlNodePtr cur;
2008
2009 /*
2010 * Allocate a new DocumentFragment node and fill the fields.
2011 */
2012 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2013 if (cur == NULL) {
2014 xmlGenericError(xmlGenericErrorContext,
2015 "xmlNewDocFragment : malloc failed\n");
2016 return(NULL);
2017 }
2018 memset(cur, 0, sizeof(xmlNode));
2019 cur->type = XML_DOCUMENT_FRAG_NODE;
2020
2021 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002022
2023 if (xmlRegisterNodeDefaultValue)
2024 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002025 return(cur);
2026}
2027
2028/**
2029 * xmlNewText:
2030 * @content: the text content
2031 *
2032 * Creation of a new text node.
2033 * Returns a pointer to the new node object.
2034 */
2035xmlNodePtr
2036xmlNewText(const xmlChar *content) {
2037 xmlNodePtr cur;
2038
2039 /*
2040 * Allocate a new node and fill the fields.
2041 */
2042 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2043 if (cur == NULL) {
2044 xmlGenericError(xmlGenericErrorContext,
2045 "xmlNewText : malloc failed\n");
2046 return(NULL);
2047 }
2048 memset(cur, 0, sizeof(xmlNode));
2049 cur->type = XML_TEXT_NODE;
2050
2051 cur->name = xmlStringText;
2052 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002053 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002054 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002055
2056 if (xmlRegisterNodeDefaultValue)
2057 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002058 return(cur);
2059}
2060
2061/**
2062 * xmlNewTextChild:
2063 * @parent: the parent node
2064 * @ns: a namespace if any
2065 * @name: the name of the child
2066 * @content: the text content of the child if any.
2067 *
2068 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002069 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002070 * a child TEXT node will be created containing the string content.
2071 *
2072 * Returns a pointer to the new node object.
2073 */
2074xmlNodePtr
2075xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2076 const xmlChar *name, const xmlChar *content) {
2077 xmlNodePtr cur, prev;
2078
2079 if (parent == NULL) {
2080#ifdef DEBUG_TREE
2081 xmlGenericError(xmlGenericErrorContext,
2082 "xmlNewTextChild : parent == NULL\n");
2083#endif
2084 return(NULL);
2085 }
2086
2087 if (name == NULL) {
2088#ifdef DEBUG_TREE
2089 xmlGenericError(xmlGenericErrorContext,
2090 "xmlNewTextChild : name == NULL\n");
2091#endif
2092 return(NULL);
2093 }
2094
2095 /*
2096 * Allocate a new node
2097 */
2098 if (ns == NULL)
2099 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2100 else
2101 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2102 if (cur == NULL) return(NULL);
2103
2104 /*
2105 * add the new element at the end of the children list.
2106 */
2107 cur->type = XML_ELEMENT_NODE;
2108 cur->parent = parent;
2109 cur->doc = parent->doc;
2110 if (parent->children == NULL) {
2111 parent->children = cur;
2112 parent->last = cur;
2113 } else {
2114 prev = parent->last;
2115 prev->next = cur;
2116 cur->prev = prev;
2117 parent->last = cur;
2118 }
2119
2120 return(cur);
2121}
2122
2123/**
2124 * xmlNewCharRef:
2125 * @doc: the document
2126 * @name: the char ref string, starting with # or "&# ... ;"
2127 *
2128 * Creation of a new character reference node.
2129 * Returns a pointer to the new node object.
2130 */
2131xmlNodePtr
2132xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2133 xmlNodePtr cur;
2134
2135 /*
2136 * Allocate a new node and fill the fields.
2137 */
2138 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2139 if (cur == NULL) {
2140 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002141 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002142 return(NULL);
2143 }
2144 memset(cur, 0, sizeof(xmlNode));
2145 cur->type = XML_ENTITY_REF_NODE;
2146
2147 cur->doc = doc;
2148 if (name[0] == '&') {
2149 int len;
2150 name++;
2151 len = xmlStrlen(name);
2152 if (name[len - 1] == ';')
2153 cur->name = xmlStrndup(name, len - 1);
2154 else
2155 cur->name = xmlStrndup(name, len);
2156 } else
2157 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002158
2159 if (xmlRegisterNodeDefaultValue)
2160 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002161 return(cur);
2162}
2163
2164/**
2165 * xmlNewReference:
2166 * @doc: the document
2167 * @name: the reference name, or the reference string with & and ;
2168 *
2169 * Creation of a new reference node.
2170 * Returns a pointer to the new node object.
2171 */
2172xmlNodePtr
2173xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2174 xmlNodePtr cur;
2175 xmlEntityPtr ent;
2176
2177 /*
2178 * Allocate a new node and fill the fields.
2179 */
2180 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2181 if (cur == NULL) {
2182 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002183 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002184 return(NULL);
2185 }
2186 memset(cur, 0, sizeof(xmlNode));
2187 cur->type = XML_ENTITY_REF_NODE;
2188
2189 cur->doc = doc;
2190 if (name[0] == '&') {
2191 int len;
2192 name++;
2193 len = xmlStrlen(name);
2194 if (name[len - 1] == ';')
2195 cur->name = xmlStrndup(name, len - 1);
2196 else
2197 cur->name = xmlStrndup(name, len);
2198 } else
2199 cur->name = xmlStrdup(name);
2200
2201 ent = xmlGetDocEntity(doc, cur->name);
2202 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002203 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002204 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002205 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002206 * updated. Not sure if this is 100% correct.
2207 * -George
2208 */
2209 cur->children = (xmlNodePtr) ent;
2210 cur->last = (xmlNodePtr) ent;
2211 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002212
2213 if (xmlRegisterNodeDefaultValue)
2214 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002215 return(cur);
2216}
2217
2218/**
2219 * xmlNewDocText:
2220 * @doc: the document
2221 * @content: the text content
2222 *
2223 * Creation of a new text node within a document.
2224 * Returns a pointer to the new node object.
2225 */
2226xmlNodePtr
2227xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2228 xmlNodePtr cur;
2229
2230 cur = xmlNewText(content);
2231 if (cur != NULL) cur->doc = doc;
2232 return(cur);
2233}
2234
2235/**
2236 * xmlNewTextLen:
2237 * @content: the text content
2238 * @len: the text len.
2239 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002240 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002241 * Returns a pointer to the new node object.
2242 */
2243xmlNodePtr
2244xmlNewTextLen(const xmlChar *content, int len) {
2245 xmlNodePtr cur;
2246
2247 /*
2248 * Allocate a new node and fill the fields.
2249 */
2250 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2251 if (cur == NULL) {
2252 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002253 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002254 return(NULL);
2255 }
2256 memset(cur, 0, sizeof(xmlNode));
2257 cur->type = XML_TEXT_NODE;
2258
2259 cur->name = xmlStringText;
2260 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002261 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002262 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002263
2264 if (xmlRegisterNodeDefaultValue)
2265 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002266 return(cur);
2267}
2268
2269/**
2270 * xmlNewDocTextLen:
2271 * @doc: the document
2272 * @content: the text content
2273 * @len: the text len.
2274 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002275 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002276 * text node pertain to a given document.
2277 * Returns a pointer to the new node object.
2278 */
2279xmlNodePtr
2280xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2281 xmlNodePtr cur;
2282
2283 cur = xmlNewTextLen(content, len);
2284 if (cur != NULL) cur->doc = doc;
2285 return(cur);
2286}
2287
2288/**
2289 * xmlNewComment:
2290 * @content: the comment content
2291 *
2292 * Creation of a new node containing a comment.
2293 * Returns a pointer to the new node object.
2294 */
2295xmlNodePtr
2296xmlNewComment(const xmlChar *content) {
2297 xmlNodePtr cur;
2298
2299 /*
2300 * Allocate a new node and fill the fields.
2301 */
2302 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2303 if (cur == NULL) {
2304 xmlGenericError(xmlGenericErrorContext,
2305 "xmlNewComment : malloc failed\n");
2306 return(NULL);
2307 }
2308 memset(cur, 0, sizeof(xmlNode));
2309 cur->type = XML_COMMENT_NODE;
2310
2311 cur->name = xmlStringComment;
2312 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002313 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002314 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002315
2316 if (xmlRegisterNodeDefaultValue)
2317 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002318 return(cur);
2319}
2320
2321/**
2322 * xmlNewCDataBlock:
2323 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002324 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002325 * @len: the length of the block
2326 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002327 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002328 * Returns a pointer to the new node object.
2329 */
2330xmlNodePtr
2331xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2332 xmlNodePtr cur;
2333
2334 /*
2335 * Allocate a new node and fill the fields.
2336 */
2337 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2338 if (cur == NULL) {
2339 xmlGenericError(xmlGenericErrorContext,
2340 "xmlNewCDataBlock : malloc failed\n");
2341 return(NULL);
2342 }
2343 memset(cur, 0, sizeof(xmlNode));
2344 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002345 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002346
2347 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002348 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002349 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002350
2351 if (xmlRegisterNodeDefaultValue)
2352 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002353 return(cur);
2354}
2355
2356/**
2357 * xmlNewDocComment:
2358 * @doc: the document
2359 * @content: the comment content
2360 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002361 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002362 * Returns a pointer to the new node object.
2363 */
2364xmlNodePtr
2365xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2366 xmlNodePtr cur;
2367
2368 cur = xmlNewComment(content);
2369 if (cur != NULL) cur->doc = doc;
2370 return(cur);
2371}
2372
2373/**
2374 * xmlSetTreeDoc:
2375 * @tree: the top element
2376 * @doc: the document
2377 *
2378 * update all nodes under the tree to point to the right document
2379 */
2380void
2381xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002382 xmlAttrPtr prop;
2383
Owen Taylor3473f882001-02-23 17:55:21 +00002384 if (tree == NULL)
2385 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002386 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002387 if(tree->type == XML_ELEMENT_NODE) {
2388 prop = tree->properties;
2389 while (prop != NULL) {
2390 prop->doc = doc;
2391 xmlSetListDoc(prop->children, doc);
2392 prop = prop->next;
2393 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002394 }
Owen Taylor3473f882001-02-23 17:55:21 +00002395 if (tree->children != NULL)
2396 xmlSetListDoc(tree->children, doc);
2397 tree->doc = doc;
2398 }
2399}
2400
2401/**
2402 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002403 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002404 * @doc: the document
2405 *
2406 * update all nodes in the list to point to the right document
2407 */
2408void
2409xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2410 xmlNodePtr cur;
2411
2412 if (list == NULL)
2413 return;
2414 cur = list;
2415 while (cur != NULL) {
2416 if (cur->doc != doc)
2417 xmlSetTreeDoc(cur, doc);
2418 cur = cur->next;
2419 }
2420}
2421
2422
2423/**
2424 * xmlNewChild:
2425 * @parent: the parent node
2426 * @ns: a namespace if any
2427 * @name: the name of the child
2428 * @content: the XML content of the child if any.
2429 *
2430 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002431 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002432 * a child list containing the TEXTs and ENTITY_REFs node will be created.
2433 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2434 * references, but XML special chars need to be escaped first by using
2435 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
2436 * support is not needed.
2437 *
2438 * Returns a pointer to the new node object.
2439 */
2440xmlNodePtr
2441xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2442 const xmlChar *name, const xmlChar *content) {
2443 xmlNodePtr cur, prev;
2444
2445 if (parent == NULL) {
2446#ifdef DEBUG_TREE
2447 xmlGenericError(xmlGenericErrorContext,
2448 "xmlNewChild : parent == NULL\n");
2449#endif
2450 return(NULL);
2451 }
2452
2453 if (name == NULL) {
2454#ifdef DEBUG_TREE
2455 xmlGenericError(xmlGenericErrorContext,
2456 "xmlNewChild : name == NULL\n");
2457#endif
2458 return(NULL);
2459 }
2460
2461 /*
2462 * Allocate a new node
2463 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002464 if (parent->type == XML_ELEMENT_NODE) {
2465 if (ns == NULL)
2466 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2467 else
2468 cur = xmlNewDocNode(parent->doc, ns, name, content);
2469 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2470 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2471 if (ns == NULL)
2472 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2473 else
2474 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002475 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2476 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002477 } else {
2478 return(NULL);
2479 }
Owen Taylor3473f882001-02-23 17:55:21 +00002480 if (cur == NULL) return(NULL);
2481
2482 /*
2483 * add the new element at the end of the children list.
2484 */
2485 cur->type = XML_ELEMENT_NODE;
2486 cur->parent = parent;
2487 cur->doc = parent->doc;
2488 if (parent->children == NULL) {
2489 parent->children = cur;
2490 parent->last = cur;
2491 } else {
2492 prev = parent->last;
2493 prev->next = cur;
2494 cur->prev = prev;
2495 parent->last = cur;
2496 }
2497
2498 return(cur);
2499}
2500
2501/**
2502 * xmlAddNextSibling:
2503 * @cur: the child node
2504 * @elem: the new node
2505 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002506 * Add a new node @elem as the next sibling of @cur
2507 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002508 * first unlinked from its existing context.
2509 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002510 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2511 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002512 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002513 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002514 */
2515xmlNodePtr
2516xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2517 if (cur == NULL) {
2518#ifdef DEBUG_TREE
2519 xmlGenericError(xmlGenericErrorContext,
2520 "xmlAddNextSibling : cur == NULL\n");
2521#endif
2522 return(NULL);
2523 }
2524 if (elem == NULL) {
2525#ifdef DEBUG_TREE
2526 xmlGenericError(xmlGenericErrorContext,
2527 "xmlAddNextSibling : elem == NULL\n");
2528#endif
2529 return(NULL);
2530 }
2531
2532 xmlUnlinkNode(elem);
2533
2534 if (elem->type == XML_TEXT_NODE) {
2535 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002536 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002537 xmlFreeNode(elem);
2538 return(cur);
2539 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002540 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2541 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002542 xmlChar *tmp;
2543
2544 tmp = xmlStrdup(elem->content);
2545 tmp = xmlStrcat(tmp, cur->next->content);
2546 xmlNodeSetContent(cur->next, tmp);
2547 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002548 xmlFreeNode(elem);
2549 return(cur->next);
2550 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002551 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2552 /* check if an attribute with the same name exists */
2553 xmlAttrPtr attr;
2554
2555 if (elem->ns == NULL)
2556 attr = xmlHasProp(cur->parent, elem->name);
2557 else
2558 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2559 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2560 /* different instance, destroy it (attributes must be unique) */
2561 xmlFreeProp(attr);
2562 }
Owen Taylor3473f882001-02-23 17:55:21 +00002563 }
2564
2565 if (elem->doc != cur->doc) {
2566 xmlSetTreeDoc(elem, cur->doc);
2567 }
2568 elem->parent = cur->parent;
2569 elem->prev = cur;
2570 elem->next = cur->next;
2571 cur->next = elem;
2572 if (elem->next != NULL)
2573 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002574 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002575 elem->parent->last = elem;
2576 return(elem);
2577}
2578
2579/**
2580 * xmlAddPrevSibling:
2581 * @cur: the child node
2582 * @elem: the new node
2583 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002584 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002585 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002586 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002587 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002588 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2589 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002590 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002591 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002592 */
2593xmlNodePtr
2594xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2595 if (cur == NULL) {
2596#ifdef DEBUG_TREE
2597 xmlGenericError(xmlGenericErrorContext,
2598 "xmlAddPrevSibling : cur == NULL\n");
2599#endif
2600 return(NULL);
2601 }
2602 if (elem == NULL) {
2603#ifdef DEBUG_TREE
2604 xmlGenericError(xmlGenericErrorContext,
2605 "xmlAddPrevSibling : elem == NULL\n");
2606#endif
2607 return(NULL);
2608 }
2609
2610 xmlUnlinkNode(elem);
2611
2612 if (elem->type == XML_TEXT_NODE) {
2613 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002614 xmlChar *tmp;
2615
2616 tmp = xmlStrdup(elem->content);
2617 tmp = xmlStrcat(tmp, cur->content);
2618 xmlNodeSetContent(cur, tmp);
2619 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002620 xmlFreeNode(elem);
2621 return(cur);
2622 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002623 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2624 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002625 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002626 xmlFreeNode(elem);
2627 return(cur->prev);
2628 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002629 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2630 /* check if an attribute with the same name exists */
2631 xmlAttrPtr attr;
2632
2633 if (elem->ns == NULL)
2634 attr = xmlHasProp(cur->parent, elem->name);
2635 else
2636 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2637 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2638 /* different instance, destroy it (attributes must be unique) */
2639 xmlFreeProp(attr);
2640 }
Owen Taylor3473f882001-02-23 17:55:21 +00002641 }
2642
2643 if (elem->doc != cur->doc) {
2644 xmlSetTreeDoc(elem, cur->doc);
2645 }
2646 elem->parent = cur->parent;
2647 elem->next = cur;
2648 elem->prev = cur->prev;
2649 cur->prev = elem;
2650 if (elem->prev != NULL)
2651 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002652 if (elem->parent != NULL) {
2653 if (elem->type == XML_ATTRIBUTE_NODE) {
2654 if (elem->parent->properties == (xmlAttrPtr) cur) {
2655 elem->parent->properties = (xmlAttrPtr) elem;
2656 }
2657 } else {
2658 if (elem->parent->children == cur) {
2659 elem->parent->children = elem;
2660 }
2661 }
2662 }
Owen Taylor3473f882001-02-23 17:55:21 +00002663 return(elem);
2664}
2665
2666/**
2667 * xmlAddSibling:
2668 * @cur: the child node
2669 * @elem: the new node
2670 *
2671 * Add a new element @elem to the list of siblings of @cur
2672 * merging adjacent TEXT nodes (@elem may be freed)
2673 * If the new element was already inserted in a document it is
2674 * first unlinked from its existing context.
2675 *
2676 * Returns the new element or NULL in case of error.
2677 */
2678xmlNodePtr
2679xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2680 xmlNodePtr parent;
2681
2682 if (cur == NULL) {
2683#ifdef DEBUG_TREE
2684 xmlGenericError(xmlGenericErrorContext,
2685 "xmlAddSibling : cur == NULL\n");
2686#endif
2687 return(NULL);
2688 }
2689
2690 if (elem == NULL) {
2691#ifdef DEBUG_TREE
2692 xmlGenericError(xmlGenericErrorContext,
2693 "xmlAddSibling : elem == NULL\n");
2694#endif
2695 return(NULL);
2696 }
2697
2698 /*
2699 * Constant time is we can rely on the ->parent->last to find
2700 * the last sibling.
2701 */
2702 if ((cur->parent != NULL) &&
2703 (cur->parent->children != NULL) &&
2704 (cur->parent->last != NULL) &&
2705 (cur->parent->last->next == NULL)) {
2706 cur = cur->parent->last;
2707 } else {
2708 while (cur->next != NULL) cur = cur->next;
2709 }
2710
2711 xmlUnlinkNode(elem);
2712
2713 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002714 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002715 xmlFreeNode(elem);
2716 return(cur);
2717 }
2718
2719 if (elem->doc != cur->doc) {
2720 xmlSetTreeDoc(elem, cur->doc);
2721 }
2722 parent = cur->parent;
2723 elem->prev = cur;
2724 elem->next = NULL;
2725 elem->parent = parent;
2726 cur->next = elem;
2727 if (parent != NULL)
2728 parent->last = elem;
2729
2730 return(elem);
2731}
2732
2733/**
2734 * xmlAddChildList:
2735 * @parent: the parent node
2736 * @cur: the first node in the list
2737 *
2738 * Add a list of node at the end of the child list of the parent
2739 * merging adjacent TEXT nodes (@cur may be freed)
2740 *
2741 * Returns the last child or NULL in case of error.
2742 */
2743xmlNodePtr
2744xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2745 xmlNodePtr prev;
2746
2747 if (parent == NULL) {
2748#ifdef DEBUG_TREE
2749 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002750 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002751#endif
2752 return(NULL);
2753 }
2754
2755 if (cur == NULL) {
2756#ifdef DEBUG_TREE
2757 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002758 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002759#endif
2760 return(NULL);
2761 }
2762
2763 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2764 (cur->doc != parent->doc)) {
2765#ifdef DEBUG_TREE
2766 xmlGenericError(xmlGenericErrorContext,
2767 "Elements moved to a different document\n");
2768#endif
2769 }
2770
2771 /*
2772 * add the first element at the end of the children list.
2773 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00002774
Owen Taylor3473f882001-02-23 17:55:21 +00002775 if (parent->children == NULL) {
2776 parent->children = cur;
2777 } else {
2778 /*
2779 * If cur and parent->last both are TEXT nodes, then merge them.
2780 */
2781 if ((cur->type == XML_TEXT_NODE) &&
2782 (parent->last->type == XML_TEXT_NODE) &&
2783 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00002784 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002785 /*
2786 * if it's the only child, nothing more to be done.
2787 */
2788 if (cur->next == NULL) {
2789 xmlFreeNode(cur);
2790 return(parent->last);
2791 }
2792 prev = cur;
2793 cur = cur->next;
2794 xmlFreeNode(prev);
2795 }
2796 prev = parent->last;
2797 prev->next = cur;
2798 cur->prev = prev;
2799 }
2800 while (cur->next != NULL) {
2801 cur->parent = parent;
2802 if (cur->doc != parent->doc) {
2803 xmlSetTreeDoc(cur, parent->doc);
2804 }
2805 cur = cur->next;
2806 }
2807 cur->parent = parent;
2808 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2809 parent->last = cur;
2810
2811 return(cur);
2812}
2813
2814/**
2815 * xmlAddChild:
2816 * @parent: the parent node
2817 * @cur: the child node
2818 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002819 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00002820 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002821 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2822 * If there is an attribute with equal name, it is first destroyed.
2823 *
Owen Taylor3473f882001-02-23 17:55:21 +00002824 * Returns the child or NULL in case of error.
2825 */
2826xmlNodePtr
2827xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2828 xmlNodePtr prev;
2829
2830 if (parent == NULL) {
2831#ifdef DEBUG_TREE
2832 xmlGenericError(xmlGenericErrorContext,
2833 "xmlAddChild : parent == NULL\n");
2834#endif
2835 return(NULL);
2836 }
2837
2838 if (cur == NULL) {
2839#ifdef DEBUG_TREE
2840 xmlGenericError(xmlGenericErrorContext,
2841 "xmlAddChild : child == NULL\n");
2842#endif
2843 return(NULL);
2844 }
2845
Owen Taylor3473f882001-02-23 17:55:21 +00002846 /*
2847 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002848 * cur is then freed.
2849 */
2850 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002851 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002852 (parent->content != NULL) &&
2853 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002854 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002855 xmlFreeNode(cur);
2856 return(parent);
2857 }
2858 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002859 (parent->last->name == cur->name) &&
2860 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002861 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002862 xmlFreeNode(cur);
2863 return(parent->last);
2864 }
2865 }
2866
2867 /*
2868 * add the new element at the end of the children list.
2869 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00002870 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00002871 cur->parent = parent;
2872 if (cur->doc != parent->doc) {
2873 xmlSetTreeDoc(cur, parent->doc);
2874 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002875 /* this check prevents a loop on tree-traversions if a developer
2876 * tries to add a node to its parent multiple times
2877 */
2878 if (prev == parent)
2879 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002880
2881 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002882 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002883 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002884 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002885 (parent->content != NULL) &&
2886 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002887 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002888 xmlFreeNode(cur);
2889 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002890 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002891 if (cur->type == XML_ATTRIBUTE_NODE) {
2892 if (parent->properties == NULL) {
2893 parent->properties = (xmlAttrPtr) cur;
2894 } else {
2895 /* check if an attribute with the same name exists */
2896 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00002897
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002898 if (cur->ns == NULL)
2899 lastattr = xmlHasProp(parent, cur->name);
2900 else
2901 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
2902 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
2903 /* different instance, destroy it (attributes must be unique) */
2904 xmlFreeProp(lastattr);
2905 }
2906 /* find the end */
2907 lastattr = parent->properties;
2908 while (lastattr->next != NULL) {
2909 lastattr = lastattr->next;
2910 }
2911 lastattr->next = (xmlAttrPtr) cur;
2912 ((xmlAttrPtr) cur)->prev = lastattr;
2913 }
2914 } else {
2915 if (parent->children == NULL) {
2916 parent->children = cur;
2917 parent->last = cur;
2918 } else {
2919 prev = parent->last;
2920 prev->next = cur;
2921 cur->prev = prev;
2922 parent->last = cur;
2923 }
2924 }
Owen Taylor3473f882001-02-23 17:55:21 +00002925 return(cur);
2926}
2927
2928/**
2929 * xmlGetLastChild:
2930 * @parent: the parent node
2931 *
2932 * Search the last child of a node.
2933 * Returns the last child or NULL if none.
2934 */
2935xmlNodePtr
2936xmlGetLastChild(xmlNodePtr parent) {
2937 if (parent == NULL) {
2938#ifdef DEBUG_TREE
2939 xmlGenericError(xmlGenericErrorContext,
2940 "xmlGetLastChild : parent == NULL\n");
2941#endif
2942 return(NULL);
2943 }
2944 return(parent->last);
2945}
2946
2947/**
2948 * xmlFreeNodeList:
2949 * @cur: the first node in the list
2950 *
2951 * Free a node and all its siblings, this is a recursive behaviour, all
2952 * the children are freed too.
2953 */
2954void
2955xmlFreeNodeList(xmlNodePtr cur) {
2956 xmlNodePtr next;
2957 if (cur == NULL) {
2958#ifdef DEBUG_TREE
2959 xmlGenericError(xmlGenericErrorContext,
2960 "xmlFreeNodeList : node == NULL\n");
2961#endif
2962 return;
2963 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00002964 if (cur->type == XML_NAMESPACE_DECL) {
2965 xmlFreeNsList((xmlNsPtr) cur);
2966 return;
2967 }
Owen Taylor3473f882001-02-23 17:55:21 +00002968 while (cur != NULL) {
2969 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002970 /* unroll to speed up freeing the document */
2971 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00002972
2973 if (xmlDeregisterNodeDefaultValue)
2974 xmlDeregisterNodeDefaultValue(cur);
2975
Daniel Veillard02141ea2001-04-30 11:46:40 +00002976 if ((cur->children != NULL) &&
2977 (cur->type != XML_ENTITY_REF_NODE))
2978 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00002979 if (((cur->type == XML_ELEMENT_NODE) ||
2980 (cur->type == XML_XINCLUDE_START) ||
2981 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002982 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00002983 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002984 if ((cur->type != XML_ELEMENT_NODE) &&
2985 (cur->type != XML_XINCLUDE_START) &&
2986 (cur->type != XML_XINCLUDE_END) &&
2987 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002988 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002989 }
2990 if (((cur->type == XML_ELEMENT_NODE) ||
2991 (cur->type == XML_XINCLUDE_START) ||
2992 (cur->type == XML_XINCLUDE_END)) &&
2993 (cur->nsDef != NULL))
2994 xmlFreeNsList(cur->nsDef);
2995
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002996 /*
2997 * When a node is a text node or a comment, it uses a global static
2998 * variable for the name of the node.
2999 *
3000 * The xmlStrEqual comparisons need to be done when (happened with
3001 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003002 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00003003 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003004 * the string addresses compare are not sufficient.
3005 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003006 if ((cur->name != NULL) &&
3007 (cur->name != xmlStringText) &&
3008 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003009 (cur->name != xmlStringComment)) {
3010 if (cur->type == XML_TEXT_NODE) {
3011 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
3012 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
3013 xmlFree((char *) cur->name);
3014 } else if (cur->type == XML_COMMENT_NODE) {
3015 if (!xmlStrEqual(cur->name, xmlStringComment))
3016 xmlFree((char *) cur->name);
3017 } else
3018 xmlFree((char *) cur->name);
3019 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00003020 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003021 xmlFree(cur);
3022 }
Owen Taylor3473f882001-02-23 17:55:21 +00003023 cur = next;
3024 }
3025}
3026
3027/**
3028 * xmlFreeNode:
3029 * @cur: the node
3030 *
3031 * Free a node, this is a recursive behaviour, all the children are freed too.
3032 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3033 */
3034void
3035xmlFreeNode(xmlNodePtr cur) {
3036 if (cur == NULL) {
3037#ifdef DEBUG_TREE
3038 xmlGenericError(xmlGenericErrorContext,
3039 "xmlFreeNode : node == NULL\n");
3040#endif
3041 return;
3042 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003043
Daniel Veillard02141ea2001-04-30 11:46:40 +00003044 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003045 if (cur->type == XML_DTD_NODE) {
3046 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003047 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003048 }
3049 if (cur->type == XML_NAMESPACE_DECL) {
3050 xmlFreeNs((xmlNsPtr) cur);
3051 return;
3052 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003053 if (cur->type == XML_ATTRIBUTE_NODE) {
3054 xmlFreeProp((xmlAttrPtr) cur);
3055 return;
3056 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003057
3058 if (xmlDeregisterNodeDefaultValue)
3059 xmlDeregisterNodeDefaultValue(cur);
3060
Owen Taylor3473f882001-02-23 17:55:21 +00003061 if ((cur->children != NULL) &&
3062 (cur->type != XML_ENTITY_REF_NODE))
3063 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003064 if (((cur->type == XML_ELEMENT_NODE) ||
3065 (cur->type == XML_XINCLUDE_START) ||
3066 (cur->type == XML_XINCLUDE_END)) &&
3067 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003068 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003069 if ((cur->type != XML_ELEMENT_NODE) &&
3070 (cur->content != NULL) &&
3071 (cur->type != XML_ENTITY_REF_NODE) &&
3072 (cur->type != XML_XINCLUDE_END) &&
3073 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003074 xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003075 }
3076
Daniel Veillardacd370f2001-06-09 17:17:51 +00003077 /*
3078 * When a node is a text node or a comment, it uses a global static
3079 * variable for the name of the node.
3080 *
3081 * The xmlStrEqual comparisons need to be done when (happened with
3082 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003083 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00003084 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00003085 * are not sufficient.
3086 */
Owen Taylor3473f882001-02-23 17:55:21 +00003087 if ((cur->name != NULL) &&
3088 (cur->name != xmlStringText) &&
3089 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00003090 (cur->name != xmlStringComment)) {
3091 if (cur->type == XML_TEXT_NODE) {
3092 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
3093 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
3094 xmlFree((char *) cur->name);
3095 } else if (cur->type == XML_COMMENT_NODE) {
3096 if (!xmlStrEqual(cur->name, xmlStringComment))
3097 xmlFree((char *) cur->name);
3098 } else
3099 xmlFree((char *) cur->name);
3100 }
3101
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003102 if (((cur->type == XML_ELEMENT_NODE) ||
3103 (cur->type == XML_XINCLUDE_START) ||
3104 (cur->type == XML_XINCLUDE_END)) &&
3105 (cur->nsDef != NULL))
3106 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003107 xmlFree(cur);
3108}
3109
3110/**
3111 * xmlUnlinkNode:
3112 * @cur: the node
3113 *
3114 * Unlink a node from it's current context, the node is not freed
3115 */
3116void
3117xmlUnlinkNode(xmlNodePtr cur) {
3118 if (cur == NULL) {
3119#ifdef DEBUG_TREE
3120 xmlGenericError(xmlGenericErrorContext,
3121 "xmlUnlinkNode : node == NULL\n");
3122#endif
3123 return;
3124 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003125 if (cur->type == XML_DTD_NODE) {
3126 xmlDocPtr doc;
3127 doc = cur->doc;
3128 if (doc->intSubset == (xmlDtdPtr) cur)
3129 doc->intSubset = NULL;
3130 if (doc->extSubset == (xmlDtdPtr) cur)
3131 doc->extSubset = NULL;
3132 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003133 if (cur->parent != NULL) {
3134 xmlNodePtr parent;
3135 parent = cur->parent;
3136 if (cur->type == XML_ATTRIBUTE_NODE) {
3137 if (parent->properties == (xmlAttrPtr) cur)
3138 parent->properties = ((xmlAttrPtr) cur)->next;
3139 } else {
3140 if (parent->children == cur)
3141 parent->children = cur->next;
3142 if (parent->last == cur)
3143 parent->last = cur->prev;
3144 }
3145 cur->parent = NULL;
3146 }
Owen Taylor3473f882001-02-23 17:55:21 +00003147 if (cur->next != NULL)
3148 cur->next->prev = cur->prev;
3149 if (cur->prev != NULL)
3150 cur->prev->next = cur->next;
3151 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003152}
3153
3154/**
3155 * xmlReplaceNode:
3156 * @old: the old node
3157 * @cur: the node
3158 *
3159 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003160 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003161 * first unlinked from its existing context.
3162 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003163 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003164 */
3165xmlNodePtr
3166xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3167 if (old == NULL) {
3168#ifdef DEBUG_TREE
3169 xmlGenericError(xmlGenericErrorContext,
3170 "xmlReplaceNode : old == NULL\n");
3171#endif
3172 return(NULL);
3173 }
3174 if (cur == NULL) {
3175 xmlUnlinkNode(old);
3176 return(old);
3177 }
3178 if (cur == old) {
3179 return(old);
3180 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003181 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3182#ifdef DEBUG_TREE
3183 xmlGenericError(xmlGenericErrorContext,
3184 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3185#endif
3186 return(old);
3187 }
3188 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3189#ifdef DEBUG_TREE
3190 xmlGenericError(xmlGenericErrorContext,
3191 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3192#endif
3193 return(old);
3194 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003195 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3196#ifdef DEBUG_TREE
3197 xmlGenericError(xmlGenericErrorContext,
3198 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3199#endif
3200 return(old);
3201 }
3202 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3203#ifdef DEBUG_TREE
3204 xmlGenericError(xmlGenericErrorContext,
3205 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3206#endif
3207 return(old);
3208 }
Owen Taylor3473f882001-02-23 17:55:21 +00003209 xmlUnlinkNode(cur);
3210 cur->doc = old->doc;
3211 cur->parent = old->parent;
3212 cur->next = old->next;
3213 if (cur->next != NULL)
3214 cur->next->prev = cur;
3215 cur->prev = old->prev;
3216 if (cur->prev != NULL)
3217 cur->prev->next = cur;
3218 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003219 if (cur->type == XML_ATTRIBUTE_NODE) {
3220 if (cur->parent->properties == (xmlAttrPtr)old)
3221 cur->parent->properties = ((xmlAttrPtr) cur);
3222 } else {
3223 if (cur->parent->children == old)
3224 cur->parent->children = cur;
3225 if (cur->parent->last == old)
3226 cur->parent->last = cur;
3227 }
Owen Taylor3473f882001-02-23 17:55:21 +00003228 }
3229 old->next = old->prev = NULL;
3230 old->parent = NULL;
3231 return(old);
3232}
3233
3234/************************************************************************
3235 * *
3236 * Copy operations *
3237 * *
3238 ************************************************************************/
3239
3240/**
3241 * xmlCopyNamespace:
3242 * @cur: the namespace
3243 *
3244 * Do a copy of the namespace.
3245 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003246 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003247 */
3248xmlNsPtr
3249xmlCopyNamespace(xmlNsPtr cur) {
3250 xmlNsPtr ret;
3251
3252 if (cur == NULL) return(NULL);
3253 switch (cur->type) {
3254 case XML_LOCAL_NAMESPACE:
3255 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3256 break;
3257 default:
3258#ifdef DEBUG_TREE
3259 xmlGenericError(xmlGenericErrorContext,
3260 "xmlCopyNamespace: invalid type %d\n", cur->type);
3261#endif
3262 return(NULL);
3263 }
3264 return(ret);
3265}
3266
3267/**
3268 * xmlCopyNamespaceList:
3269 * @cur: the first namespace
3270 *
3271 * Do a copy of an namespace list.
3272 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003273 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003274 */
3275xmlNsPtr
3276xmlCopyNamespaceList(xmlNsPtr cur) {
3277 xmlNsPtr ret = NULL;
3278 xmlNsPtr p = NULL,q;
3279
3280 while (cur != NULL) {
3281 q = xmlCopyNamespace(cur);
3282 if (p == NULL) {
3283 ret = p = q;
3284 } else {
3285 p->next = q;
3286 p = q;
3287 }
3288 cur = cur->next;
3289 }
3290 return(ret);
3291}
3292
3293static xmlNodePtr
3294xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3295/**
3296 * xmlCopyProp:
3297 * @target: the element where the attribute will be grafted
3298 * @cur: the attribute
3299 *
3300 * Do a copy of the attribute.
3301 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003302 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003303 */
3304xmlAttrPtr
3305xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3306 xmlAttrPtr ret;
3307
3308 if (cur == NULL) return(NULL);
3309 if (target != NULL)
3310 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3311 else if (cur->parent != NULL)
3312 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3313 else if (cur->children != NULL)
3314 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3315 else
3316 ret = xmlNewDocProp(NULL, cur->name, NULL);
3317 if (ret == NULL) return(NULL);
3318 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003319
Owen Taylor3473f882001-02-23 17:55:21 +00003320 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003321 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003322/*
3323 * if (target->doc)
3324 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3325 * else if (cur->doc) / * target may not yet have a doc : KPI * /
3326 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
3327 * else
3328 * ns = NULL;
3329 * ret->ns = ns;
3330 */
3331 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3332 if (ns == NULL) {
3333 /*
3334 * Humm, we are copying an element whose namespace is defined
3335 * out of the new tree scope. Search it in the original tree
3336 * and add it at the top of the new tree
3337 */
3338 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3339 if (ns != NULL) {
3340 xmlNodePtr root = target;
3341 xmlNodePtr pred = NULL;
3342
3343 while (root->parent != NULL) {
3344 pred = root;
3345 root = root->parent;
3346 }
3347 if (root == (xmlNodePtr) target->doc) {
3348 /* correct possibly cycling above the document elt */
3349 root = pred;
3350 }
3351 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3352 }
3353 } else {
3354 /*
3355 * we have to find something appropriate here since
3356 * we cant be sure, that the namespce we found is identified
3357 * by the prefix
3358 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003359 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003360 /* this is the nice case */
3361 ret->ns = ns;
3362 } else {
3363 /*
3364 * we are in trouble: we need a new reconcilied namespace.
3365 * This is expensive
3366 */
3367 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3368 }
3369 }
3370
Owen Taylor3473f882001-02-23 17:55:21 +00003371 } else
3372 ret->ns = NULL;
3373
3374 if (cur->children != NULL) {
3375 xmlNodePtr tmp;
3376
3377 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3378 ret->last = NULL;
3379 tmp = ret->children;
3380 while (tmp != NULL) {
3381 /* tmp->parent = (xmlNodePtr)ret; */
3382 if (tmp->next == NULL)
3383 ret->last = tmp;
3384 tmp = tmp->next;
3385 }
3386 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003387 /*
3388 * Try to handle IDs
3389 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003390 if ((target!= NULL) && (cur!= NULL) &&
3391 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003392 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3393 if (xmlIsID(cur->doc, cur->parent, cur)) {
3394 xmlChar *id;
3395
3396 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3397 if (id != NULL) {
3398 xmlAddID(NULL, target->doc, id, ret);
3399 xmlFree(id);
3400 }
3401 }
3402 }
Owen Taylor3473f882001-02-23 17:55:21 +00003403 return(ret);
3404}
3405
3406/**
3407 * xmlCopyPropList:
3408 * @target: the element where the attributes will be grafted
3409 * @cur: the first attribute
3410 *
3411 * Do a copy of an attribute list.
3412 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003413 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003414 */
3415xmlAttrPtr
3416xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3417 xmlAttrPtr ret = NULL;
3418 xmlAttrPtr p = NULL,q;
3419
3420 while (cur != NULL) {
3421 q = xmlCopyProp(target, cur);
3422 if (p == NULL) {
3423 ret = p = q;
3424 } else {
3425 p->next = q;
3426 q->prev = p;
3427 p = q;
3428 }
3429 cur = cur->next;
3430 }
3431 return(ret);
3432}
3433
3434/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003435 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003436 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003437 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003438 * tricky reason: namespaces. Doing a direct copy of a node
3439 * say RPM:Copyright without changing the namespace pointer to
3440 * something else can produce stale links. One way to do it is
3441 * to keep a reference counter but this doesn't work as soon
3442 * as one move the element or the subtree out of the scope of
3443 * the existing namespace. The actual solution seems to add
3444 * a copy of the namespace at the top of the copied tree if
3445 * not available in the subtree.
3446 * Hence two functions, the public front-end call the inner ones
3447 */
3448
3449static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003450xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003451 int recursive) {
3452 xmlNodePtr ret;
3453
3454 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003455 switch (node->type) {
3456 case XML_TEXT_NODE:
3457 case XML_CDATA_SECTION_NODE:
3458 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003459 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003460 case XML_ENTITY_REF_NODE:
3461 case XML_ENTITY_NODE:
3462 case XML_PI_NODE:
3463 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003464 case XML_XINCLUDE_START:
3465 case XML_XINCLUDE_END:
3466 break;
3467 case XML_ATTRIBUTE_NODE:
3468 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3469 case XML_NAMESPACE_DECL:
3470 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3471
Daniel Veillard39196eb2001-06-19 18:09:42 +00003472 case XML_DOCUMENT_NODE:
3473 case XML_HTML_DOCUMENT_NODE:
3474#ifdef LIBXML_DOCB_ENABLED
3475 case XML_DOCB_DOCUMENT_NODE:
3476#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003477 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00003478 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003479 case XML_NOTATION_NODE:
3480 case XML_DTD_NODE:
3481 case XML_ELEMENT_DECL:
3482 case XML_ATTRIBUTE_DECL:
3483 case XML_ENTITY_DECL:
3484 return(NULL);
3485 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003486
Owen Taylor3473f882001-02-23 17:55:21 +00003487 /*
3488 * Allocate a new node and fill the fields.
3489 */
3490 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3491 if (ret == NULL) {
3492 xmlGenericError(xmlGenericErrorContext,
3493 "xmlStaticCopyNode : malloc failed\n");
3494 return(NULL);
3495 }
3496 memset(ret, 0, sizeof(xmlNode));
3497 ret->type = node->type;
3498
3499 ret->doc = doc;
3500 ret->parent = parent;
3501 if (node->name == xmlStringText)
3502 ret->name = xmlStringText;
3503 else if (node->name == xmlStringTextNoenc)
3504 ret->name = xmlStringTextNoenc;
3505 else if (node->name == xmlStringComment)
3506 ret->name = xmlStringComment;
3507 else if (node->name != NULL)
3508 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003509 if ((node->type != XML_ELEMENT_NODE) &&
3510 (node->content != NULL) &&
3511 (node->type != XML_ENTITY_REF_NODE) &&
3512 (node->type != XML_XINCLUDE_END) &&
3513 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003514 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003515 }else{
3516 if (node->type == XML_ELEMENT_NODE)
3517 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00003518 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003519 if (parent != NULL) {
3520 xmlNodePtr tmp;
3521
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003522 /*
3523 * this is a tricky part for the node register thing:
3524 * in case ret does get coalesced in xmlAddChild
3525 * the deregister-node callback is called; so we register ret now already
3526 */
3527 if (xmlRegisterNodeDefaultValue)
3528 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3529
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003530 tmp = xmlAddChild(parent, ret);
3531 /* node could have coalesced */
3532 if (tmp != ret)
3533 return(tmp);
3534 }
Owen Taylor3473f882001-02-23 17:55:21 +00003535
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003536 if (!recursive)
3537 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003538 if (node->nsDef != NULL)
3539 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3540
3541 if (node->ns != NULL) {
3542 xmlNsPtr ns;
3543
3544 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3545 if (ns == NULL) {
3546 /*
3547 * Humm, we are copying an element whose namespace is defined
3548 * out of the new tree scope. Search it in the original tree
3549 * and add it at the top of the new tree
3550 */
3551 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3552 if (ns != NULL) {
3553 xmlNodePtr root = ret;
3554
3555 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003556 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003557 }
3558 } else {
3559 /*
3560 * reference the existing namespace definition in our own tree.
3561 */
3562 ret->ns = ns;
3563 }
3564 }
3565 if (node->properties != NULL)
3566 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003567 if (node->type == XML_ENTITY_REF_NODE) {
3568 if ((doc == NULL) || (node->doc != doc)) {
3569 /*
3570 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003571 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003572 * we cannot keep the reference. Try to find it in the
3573 * target document.
3574 */
3575 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3576 } else {
3577 ret->children = node->children;
3578 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003579 ret->last = ret->children;
3580 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003581 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003582 UPDATE_LAST_CHILD_AND_PARENT(ret)
3583 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003584
3585out:
3586 /* if parent != NULL we already registered the node above */
3587 if (parent == NULL && xmlRegisterNodeDefaultValue)
3588 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003589 return(ret);
3590}
3591
3592static xmlNodePtr
3593xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3594 xmlNodePtr ret = NULL;
3595 xmlNodePtr p = NULL,q;
3596
3597 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003598 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003599 if (doc == NULL) {
3600 node = node->next;
3601 continue;
3602 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003603 if (doc->intSubset == NULL) {
3604 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3605 q->doc = doc;
3606 q->parent = parent;
3607 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003608 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003609 } else {
3610 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003611 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003612 }
3613 } else
3614 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003615 if (ret == NULL) {
3616 q->prev = NULL;
3617 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003618 } else if (p != q) {
3619 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003620 p->next = q;
3621 q->prev = p;
3622 p = q;
3623 }
3624 node = node->next;
3625 }
3626 return(ret);
3627}
3628
3629/**
3630 * xmlCopyNode:
3631 * @node: the node
3632 * @recursive: if 1 do a recursive copy.
3633 *
3634 * Do a copy of the node.
3635 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003636 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003637 */
3638xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003639xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003640 xmlNodePtr ret;
3641
3642 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3643 return(ret);
3644}
3645
3646/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003647 * xmlDocCopyNode:
3648 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003649 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003650 * @recursive: if 1 do a recursive copy.
3651 *
3652 * Do a copy of the node to a given document.
3653 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003654 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003655 */
3656xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003657xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003658 xmlNodePtr ret;
3659
3660 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3661 return(ret);
3662}
3663
3664/**
Owen Taylor3473f882001-02-23 17:55:21 +00003665 * xmlCopyNodeList:
3666 * @node: the first node in the list.
3667 *
3668 * Do a recursive copy of the node list.
3669 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003670 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003671 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003672xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003673 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3674 return(ret);
3675}
3676
3677/**
Owen Taylor3473f882001-02-23 17:55:21 +00003678 * xmlCopyDtd:
3679 * @dtd: the dtd
3680 *
3681 * Do a copy of the dtd.
3682 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003683 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003684 */
3685xmlDtdPtr
3686xmlCopyDtd(xmlDtdPtr dtd) {
3687 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003688 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003689
3690 if (dtd == NULL) return(NULL);
3691 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3692 if (ret == NULL) return(NULL);
3693 if (dtd->entities != NULL)
3694 ret->entities = (void *) xmlCopyEntitiesTable(
3695 (xmlEntitiesTablePtr) dtd->entities);
3696 if (dtd->notations != NULL)
3697 ret->notations = (void *) xmlCopyNotationTable(
3698 (xmlNotationTablePtr) dtd->notations);
3699 if (dtd->elements != NULL)
3700 ret->elements = (void *) xmlCopyElementTable(
3701 (xmlElementTablePtr) dtd->elements);
3702 if (dtd->attributes != NULL)
3703 ret->attributes = (void *) xmlCopyAttributeTable(
3704 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003705 if (dtd->pentities != NULL)
3706 ret->pentities = (void *) xmlCopyEntitiesTable(
3707 (xmlEntitiesTablePtr) dtd->pentities);
3708
3709 cur = dtd->children;
3710 while (cur != NULL) {
3711 q = NULL;
3712
3713 if (cur->type == XML_ENTITY_DECL) {
3714 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3715 switch (tmp->etype) {
3716 case XML_INTERNAL_GENERAL_ENTITY:
3717 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3718 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3719 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3720 break;
3721 case XML_INTERNAL_PARAMETER_ENTITY:
3722 case XML_EXTERNAL_PARAMETER_ENTITY:
3723 q = (xmlNodePtr)
3724 xmlGetParameterEntityFromDtd(ret, tmp->name);
3725 break;
3726 case XML_INTERNAL_PREDEFINED_ENTITY:
3727 break;
3728 }
3729 } else if (cur->type == XML_ELEMENT_DECL) {
3730 xmlElementPtr tmp = (xmlElementPtr) cur;
3731 q = (xmlNodePtr)
3732 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3733 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3734 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3735 q = (xmlNodePtr)
3736 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3737 } else if (cur->type == XML_COMMENT_NODE) {
3738 q = xmlCopyNode(cur, 0);
3739 }
3740
3741 if (q == NULL) {
3742 cur = cur->next;
3743 continue;
3744 }
3745
3746 if (p == NULL)
3747 ret->children = q;
3748 else
3749 p->next = q;
3750
3751 q->prev = p;
3752 q->parent = (xmlNodePtr) ret;
3753 q->next = NULL;
3754 ret->last = q;
3755 p = q;
3756 cur = cur->next;
3757 }
3758
Owen Taylor3473f882001-02-23 17:55:21 +00003759 return(ret);
3760}
3761
3762/**
3763 * xmlCopyDoc:
3764 * @doc: the document
3765 * @recursive: if 1 do a recursive copy.
3766 *
3767 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003768 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003769 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003770 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003771 */
3772xmlDocPtr
3773xmlCopyDoc(xmlDocPtr doc, int recursive) {
3774 xmlDocPtr ret;
3775
3776 if (doc == NULL) return(NULL);
3777 ret = xmlNewDoc(doc->version);
3778 if (ret == NULL) return(NULL);
3779 if (doc->name != NULL)
3780 ret->name = xmlMemStrdup(doc->name);
3781 if (doc->encoding != NULL)
3782 ret->encoding = xmlStrdup(doc->encoding);
3783 ret->charset = doc->charset;
3784 ret->compression = doc->compression;
3785 ret->standalone = doc->standalone;
3786 if (!recursive) return(ret);
3787
Daniel Veillardb33c2012001-04-25 12:59:04 +00003788 ret->last = NULL;
3789 ret->children = NULL;
3790 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003791 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003792 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003793 ret->intSubset->parent = ret;
3794 }
Owen Taylor3473f882001-02-23 17:55:21 +00003795 if (doc->oldNs != NULL)
3796 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3797 if (doc->children != NULL) {
3798 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003799
3800 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3801 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003802 ret->last = NULL;
3803 tmp = ret->children;
3804 while (tmp != NULL) {
3805 if (tmp->next == NULL)
3806 ret->last = tmp;
3807 tmp = tmp->next;
3808 }
3809 }
3810 return(ret);
3811}
3812
3813/************************************************************************
3814 * *
3815 * Content access functions *
3816 * *
3817 ************************************************************************/
3818
3819/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003820 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003821 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00003822 *
3823 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003824 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003825 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003826 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003827 */
3828long
3829xmlGetLineNo(xmlNodePtr node)
3830{
3831 long result = -1;
3832
3833 if (!node)
3834 return result;
3835 if (node->type == XML_ELEMENT_NODE)
3836 result = (long) node->content;
3837 else if ((node->prev != NULL) &&
3838 ((node->prev->type == XML_ELEMENT_NODE) ||
3839 (node->prev->type == XML_TEXT_NODE)))
3840 result = xmlGetLineNo(node->prev);
3841 else if ((node->parent != NULL) &&
3842 ((node->parent->type == XML_ELEMENT_NODE) ||
3843 (node->parent->type == XML_TEXT_NODE)))
3844 result = xmlGetLineNo(node->parent);
3845
3846 return result;
3847}
3848
3849/**
3850 * xmlGetNodePath:
3851 * @node: a node
3852 *
3853 * Build a structure based Path for the given node
3854 *
3855 * Returns the new path or NULL in case of error. The caller must free
3856 * the returned string
3857 */
3858xmlChar *
3859xmlGetNodePath(xmlNodePtr node)
3860{
3861 xmlNodePtr cur, tmp, next;
3862 xmlChar *buffer = NULL, *temp;
3863 size_t buf_len;
3864 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00003865 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00003866 const char *name;
3867 char nametemp[100];
3868 int occur = 0;
3869
3870 if (node == NULL)
3871 return (NULL);
3872
3873 buf_len = 500;
3874 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3875 if (buffer == NULL)
3876 return (NULL);
3877 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3878 if (buf == NULL) {
3879 xmlFree(buffer);
3880 return (NULL);
3881 }
3882
3883 buffer[0] = 0;
3884 cur = node;
3885 do {
3886 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003887 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003888 occur = 0;
3889 if ((cur->type == XML_DOCUMENT_NODE) ||
3890 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3891 if (buffer[0] == '/')
3892 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003893 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003894 next = NULL;
3895 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003896 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003897 name = (const char *) cur->name;
3898 if (cur->ns) {
3899 snprintf(nametemp, sizeof(nametemp) - 1,
3900 "%s:%s", cur->ns->prefix, cur->name);
3901 nametemp[sizeof(nametemp) - 1] = 0;
3902 name = nametemp;
3903 }
3904 next = cur->parent;
3905
3906 /*
3907 * Thumbler index computation
3908 */
3909 tmp = cur->prev;
3910 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00003911 if ((tmp->type == XML_ELEMENT_NODE) &&
3912 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00003913 occur++;
3914 tmp = tmp->prev;
3915 }
3916 if (occur == 0) {
3917 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00003918 while (tmp != NULL && occur == 0) {
3919 if ((tmp->type == XML_ELEMENT_NODE) &&
3920 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00003921 occur++;
3922 tmp = tmp->next;
3923 }
3924 if (occur != 0)
3925 occur = 1;
3926 } else
3927 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00003928 } else if (cur->type == XML_COMMENT_NODE) {
3929 sep = "/";
3930 name = "comment()";
3931 next = cur->parent;
3932
3933 /*
3934 * Thumbler index computation
3935 */
3936 tmp = cur->prev;
3937 while (tmp != NULL) {
3938 if (tmp->type == XML_COMMENT_NODE)
3939 occur++;
3940 tmp = tmp->prev;
3941 }
3942 if (occur == 0) {
3943 tmp = cur->next;
3944 while (tmp != NULL && occur == 0) {
3945 if (tmp->type == XML_COMMENT_NODE)
3946 occur++;
3947 tmp = tmp->next;
3948 }
3949 if (occur != 0)
3950 occur = 1;
3951 } else
3952 occur++;
3953 } else if ((cur->type == XML_TEXT_NODE) ||
3954 (cur->type == XML_CDATA_SECTION_NODE)) {
3955 sep = "/";
3956 name = "text()";
3957 next = cur->parent;
3958
3959 /*
3960 * Thumbler index computation
3961 */
3962 tmp = cur->prev;
3963 while (tmp != NULL) {
3964 if ((cur->type == XML_TEXT_NODE) ||
3965 (cur->type == XML_CDATA_SECTION_NODE))
3966 occur++;
3967 tmp = tmp->prev;
3968 }
3969 if (occur == 0) {
3970 tmp = cur->next;
3971 while (tmp != NULL && occur == 0) {
3972 if ((cur->type == XML_TEXT_NODE) ||
3973 (cur->type == XML_CDATA_SECTION_NODE))
3974 occur++;
3975 tmp = tmp->next;
3976 }
3977 if (occur != 0)
3978 occur = 1;
3979 } else
3980 occur++;
3981 } else if (cur->type == XML_PI_NODE) {
3982 sep = "/";
3983 snprintf(nametemp, sizeof(nametemp) - 1,
3984 "processing-instruction('%s')", cur->name);
3985 nametemp[sizeof(nametemp) - 1] = 0;
3986 name = nametemp;
3987
3988 next = cur->parent;
3989
3990 /*
3991 * Thumbler index computation
3992 */
3993 tmp = cur->prev;
3994 while (tmp != NULL) {
3995 if ((tmp->type == XML_PI_NODE) &&
3996 (xmlStrEqual(cur->name, tmp->name)))
3997 occur++;
3998 tmp = tmp->prev;
3999 }
4000 if (occur == 0) {
4001 tmp = cur->next;
4002 while (tmp != NULL && occur == 0) {
4003 if ((tmp->type == XML_PI_NODE) &&
4004 (xmlStrEqual(cur->name, tmp->name)))
4005 occur++;
4006 tmp = tmp->next;
4007 }
4008 if (occur != 0)
4009 occur = 1;
4010 } else
4011 occur++;
4012
Daniel Veillard8faa7832001-11-26 15:58:08 +00004013 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004014 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004015 name = (const char *) (((xmlAttrPtr) cur)->name);
4016 next = ((xmlAttrPtr) cur)->parent;
4017 } else {
4018 next = cur->parent;
4019 }
4020
4021 /*
4022 * Make sure there is enough room
4023 */
4024 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4025 buf_len =
4026 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4027 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4028 if (temp == NULL) {
4029 xmlFree(buf);
4030 xmlFree(buffer);
4031 return (NULL);
4032 }
4033 buffer = temp;
4034 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4035 if (temp == NULL) {
4036 xmlFree(buf);
4037 xmlFree(buffer);
4038 return (NULL);
4039 }
4040 buf = temp;
4041 }
4042 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004043 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004044 sep, name, (char *) buffer);
4045 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004046 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004047 sep, name, occur, (char *) buffer);
4048 snprintf((char *) buffer, buf_len, "%s", buf);
4049 cur = next;
4050 } while (cur != NULL);
4051 xmlFree(buf);
4052 return (buffer);
4053}
4054
4055/**
Owen Taylor3473f882001-02-23 17:55:21 +00004056 * xmlDocGetRootElement:
4057 * @doc: the document
4058 *
4059 * Get the root element of the document (doc->children is a list
4060 * containing possibly comments, PIs, etc ...).
4061 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004062 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004063 */
4064xmlNodePtr
4065xmlDocGetRootElement(xmlDocPtr doc) {
4066 xmlNodePtr ret;
4067
4068 if (doc == NULL) return(NULL);
4069 ret = doc->children;
4070 while (ret != NULL) {
4071 if (ret->type == XML_ELEMENT_NODE)
4072 return(ret);
4073 ret = ret->next;
4074 }
4075 return(ret);
4076}
4077
4078/**
4079 * xmlDocSetRootElement:
4080 * @doc: the document
4081 * @root: the new document root element
4082 *
4083 * Set the root element of the document (doc->children is a list
4084 * containing possibly comments, PIs, etc ...).
4085 *
4086 * Returns the old root element if any was found
4087 */
4088xmlNodePtr
4089xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4090 xmlNodePtr old = NULL;
4091
4092 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004093 if (root == NULL)
4094 return(NULL);
4095 xmlUnlinkNode(root);
4096 root->doc = doc;
4097 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004098 old = doc->children;
4099 while (old != NULL) {
4100 if (old->type == XML_ELEMENT_NODE)
4101 break;
4102 old = old->next;
4103 }
4104 if (old == NULL) {
4105 if (doc->children == NULL) {
4106 doc->children = root;
4107 doc->last = root;
4108 } else {
4109 xmlAddSibling(doc->children, root);
4110 }
4111 } else {
4112 xmlReplaceNode(old, root);
4113 }
4114 return(old);
4115}
4116
4117/**
4118 * xmlNodeSetLang:
4119 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004120 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004121 *
4122 * Set the language of a node, i.e. the values of the xml:lang
4123 * attribute.
4124 */
4125void
4126xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004127 xmlNsPtr ns;
4128
Owen Taylor3473f882001-02-23 17:55:21 +00004129 if (cur == NULL) return;
4130 switch(cur->type) {
4131 case XML_TEXT_NODE:
4132 case XML_CDATA_SECTION_NODE:
4133 case XML_COMMENT_NODE:
4134 case XML_DOCUMENT_NODE:
4135 case XML_DOCUMENT_TYPE_NODE:
4136 case XML_DOCUMENT_FRAG_NODE:
4137 case XML_NOTATION_NODE:
4138 case XML_HTML_DOCUMENT_NODE:
4139 case XML_DTD_NODE:
4140 case XML_ELEMENT_DECL:
4141 case XML_ATTRIBUTE_DECL:
4142 case XML_ENTITY_DECL:
4143 case XML_PI_NODE:
4144 case XML_ENTITY_REF_NODE:
4145 case XML_ENTITY_NODE:
4146 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004147#ifdef LIBXML_DOCB_ENABLED
4148 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004149#endif
4150 case XML_XINCLUDE_START:
4151 case XML_XINCLUDE_END:
4152 return;
4153 case XML_ELEMENT_NODE:
4154 case XML_ATTRIBUTE_NODE:
4155 break;
4156 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004157 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4158 if (ns == NULL)
4159 return;
4160 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004161}
4162
4163/**
4164 * xmlNodeGetLang:
4165 * @cur: the node being checked
4166 *
4167 * Searches the language of a node, i.e. the values of the xml:lang
4168 * attribute or the one carried by the nearest ancestor.
4169 *
4170 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004171 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004172 */
4173xmlChar *
4174xmlNodeGetLang(xmlNodePtr cur) {
4175 xmlChar *lang;
4176
4177 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004178 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004179 if (lang != NULL)
4180 return(lang);
4181 cur = cur->parent;
4182 }
4183 return(NULL);
4184}
4185
4186
4187/**
4188 * xmlNodeSetSpacePreserve:
4189 * @cur: the node being changed
4190 * @val: the xml:space value ("0": default, 1: "preserve")
4191 *
4192 * Set (or reset) the space preserving behaviour of a node, i.e. the
4193 * value of the xml:space attribute.
4194 */
4195void
4196xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004197 xmlNsPtr ns;
4198
Owen Taylor3473f882001-02-23 17:55:21 +00004199 if (cur == NULL) return;
4200 switch(cur->type) {
4201 case XML_TEXT_NODE:
4202 case XML_CDATA_SECTION_NODE:
4203 case XML_COMMENT_NODE:
4204 case XML_DOCUMENT_NODE:
4205 case XML_DOCUMENT_TYPE_NODE:
4206 case XML_DOCUMENT_FRAG_NODE:
4207 case XML_NOTATION_NODE:
4208 case XML_HTML_DOCUMENT_NODE:
4209 case XML_DTD_NODE:
4210 case XML_ELEMENT_DECL:
4211 case XML_ATTRIBUTE_DECL:
4212 case XML_ENTITY_DECL:
4213 case XML_PI_NODE:
4214 case XML_ENTITY_REF_NODE:
4215 case XML_ENTITY_NODE:
4216 case XML_NAMESPACE_DECL:
4217 case XML_XINCLUDE_START:
4218 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004219#ifdef LIBXML_DOCB_ENABLED
4220 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004221#endif
4222 return;
4223 case XML_ELEMENT_NODE:
4224 case XML_ATTRIBUTE_NODE:
4225 break;
4226 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004227 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4228 if (ns == NULL)
4229 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004230 switch (val) {
4231 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004232 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004233 break;
4234 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004235 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004236 break;
4237 }
4238}
4239
4240/**
4241 * xmlNodeGetSpacePreserve:
4242 * @cur: the node being checked
4243 *
4244 * Searches the space preserving behaviour of a node, i.e. the values
4245 * of the xml:space attribute or the one carried by the nearest
4246 * ancestor.
4247 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004248 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004249 */
4250int
4251xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4252 xmlChar *space;
4253
4254 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004255 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004256 if (space != NULL) {
4257 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4258 xmlFree(space);
4259 return(1);
4260 }
4261 if (xmlStrEqual(space, BAD_CAST "default")) {
4262 xmlFree(space);
4263 return(0);
4264 }
4265 xmlFree(space);
4266 }
4267 cur = cur->parent;
4268 }
4269 return(-1);
4270}
4271
4272/**
4273 * xmlNodeSetName:
4274 * @cur: the node being changed
4275 * @name: the new tag name
4276 *
4277 * Set (or reset) the name of a node.
4278 */
4279void
4280xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
4281 if (cur == NULL) return;
4282 if (name == NULL) return;
4283 switch(cur->type) {
4284 case XML_TEXT_NODE:
4285 case XML_CDATA_SECTION_NODE:
4286 case XML_COMMENT_NODE:
4287 case XML_DOCUMENT_TYPE_NODE:
4288 case XML_DOCUMENT_FRAG_NODE:
4289 case XML_NOTATION_NODE:
4290 case XML_HTML_DOCUMENT_NODE:
4291 case XML_NAMESPACE_DECL:
4292 case XML_XINCLUDE_START:
4293 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004294#ifdef LIBXML_DOCB_ENABLED
4295 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004296#endif
4297 return;
4298 case XML_ELEMENT_NODE:
4299 case XML_ATTRIBUTE_NODE:
4300 case XML_PI_NODE:
4301 case XML_ENTITY_REF_NODE:
4302 case XML_ENTITY_NODE:
4303 case XML_DTD_NODE:
4304 case XML_DOCUMENT_NODE:
4305 case XML_ELEMENT_DECL:
4306 case XML_ATTRIBUTE_DECL:
4307 case XML_ENTITY_DECL:
4308 break;
4309 }
4310 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4311 cur->name = xmlStrdup(name);
4312}
4313
4314/**
4315 * xmlNodeSetBase:
4316 * @cur: the node being changed
4317 * @uri: the new base URI
4318 *
4319 * Set (or reset) the base URI of a node, i.e. the value of the
4320 * xml:base attribute.
4321 */
4322void
4323xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004324 xmlNsPtr ns;
4325
Owen Taylor3473f882001-02-23 17:55:21 +00004326 if (cur == NULL) return;
4327 switch(cur->type) {
4328 case XML_TEXT_NODE:
4329 case XML_CDATA_SECTION_NODE:
4330 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004331 case XML_DOCUMENT_TYPE_NODE:
4332 case XML_DOCUMENT_FRAG_NODE:
4333 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004334 case XML_DTD_NODE:
4335 case XML_ELEMENT_DECL:
4336 case XML_ATTRIBUTE_DECL:
4337 case XML_ENTITY_DECL:
4338 case XML_PI_NODE:
4339 case XML_ENTITY_REF_NODE:
4340 case XML_ENTITY_NODE:
4341 case XML_NAMESPACE_DECL:
4342 case XML_XINCLUDE_START:
4343 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004344 return;
4345 case XML_ELEMENT_NODE:
4346 case XML_ATTRIBUTE_NODE:
4347 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004348 case XML_DOCUMENT_NODE:
4349#ifdef LIBXML_DOCB_ENABLED
4350 case XML_DOCB_DOCUMENT_NODE:
4351#endif
4352 case XML_HTML_DOCUMENT_NODE: {
4353 xmlDocPtr doc = (xmlDocPtr) cur;
4354
4355 if (doc->URL != NULL)
4356 xmlFree((xmlChar *) doc->URL);
4357 if (uri == NULL)
4358 doc->URL = NULL;
4359 else
4360 doc->URL = xmlStrdup(uri);
4361 return;
4362 }
Owen Taylor3473f882001-02-23 17:55:21 +00004363 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004364
4365 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4366 if (ns == NULL)
4367 return;
4368 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004369}
4370
4371/**
Owen Taylor3473f882001-02-23 17:55:21 +00004372 * xmlNodeGetBase:
4373 * @doc: the document the node pertains to
4374 * @cur: the node being checked
4375 *
4376 * Searches for the BASE URL. The code should work on both XML
4377 * and HTML document even if base mechanisms are completely different.
4378 * It returns the base as defined in RFC 2396 sections
4379 * 5.1.1. Base URI within Document Content
4380 * and
4381 * 5.1.2. Base URI from the Encapsulating Entity
4382 * However it does not return the document base (5.1.3), use
4383 * xmlDocumentGetBase() for this
4384 *
4385 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004386 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004387 */
4388xmlChar *
4389xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004390 xmlChar *oldbase = NULL;
4391 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004392
4393 if ((cur == NULL) && (doc == NULL))
4394 return(NULL);
4395 if (doc == NULL) doc = cur->doc;
4396 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4397 cur = doc->children;
4398 while ((cur != NULL) && (cur->name != NULL)) {
4399 if (cur->type != XML_ELEMENT_NODE) {
4400 cur = cur->next;
4401 continue;
4402 }
4403 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4404 cur = cur->children;
4405 continue;
4406 }
4407 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4408 cur = cur->children;
4409 continue;
4410 }
4411 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4412 return(xmlGetProp(cur, BAD_CAST "href"));
4413 }
4414 cur = cur->next;
4415 }
4416 return(NULL);
4417 }
4418 while (cur != NULL) {
4419 if (cur->type == XML_ENTITY_DECL) {
4420 xmlEntityPtr ent = (xmlEntityPtr) cur;
4421 return(xmlStrdup(ent->URI));
4422 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004423 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004424 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004425 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004426 if (oldbase != NULL) {
4427 newbase = xmlBuildURI(oldbase, base);
4428 if (newbase != NULL) {
4429 xmlFree(oldbase);
4430 xmlFree(base);
4431 oldbase = newbase;
4432 } else {
4433 xmlFree(oldbase);
4434 xmlFree(base);
4435 return(NULL);
4436 }
4437 } else {
4438 oldbase = base;
4439 }
4440 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4441 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4442 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4443 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004444 }
4445 }
Owen Taylor3473f882001-02-23 17:55:21 +00004446 cur = cur->parent;
4447 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004448 if ((doc != NULL) && (doc->URL != NULL)) {
4449 if (oldbase == NULL)
4450 return(xmlStrdup(doc->URL));
4451 newbase = xmlBuildURI(oldbase, doc->URL);
4452 xmlFree(oldbase);
4453 return(newbase);
4454 }
4455 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004456}
4457
4458/**
4459 * xmlNodeGetContent:
4460 * @cur: the node being read
4461 *
4462 * Read the value of a node, this can be either the text carried
4463 * directly by this node if it's a TEXT node or the aggregate string
4464 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004465 * Entity references are substituted.
4466 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004467 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004468 */
4469xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004470xmlNodeGetContent(xmlNodePtr cur)
4471{
4472 if (cur == NULL)
4473 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004474 switch (cur->type) {
4475 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004476 case XML_ELEMENT_NODE:{
4477 xmlNodePtr tmp = cur;
4478 xmlBufferPtr buffer;
4479 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004480
Daniel Veillard814a76d2003-01-23 18:24:20 +00004481 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004482 if (buffer == NULL)
4483 return (NULL);
4484 while (tmp != NULL) {
4485 switch (tmp->type) {
4486 case XML_CDATA_SECTION_NODE:
4487 case XML_TEXT_NODE:
4488 if (tmp->content != NULL)
4489 xmlBufferCat(buffer, tmp->content);
4490 break;
4491 case XML_ENTITY_REF_NODE:{
4492 /* recursive substitution of entity references */
4493 xmlChar *cont = xmlNodeGetContent(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00004494
Daniel Veillard7646b182002-04-20 06:41:40 +00004495 if (cont) {
4496 xmlBufferCat(buffer,
4497 (const xmlChar *) cont);
4498 xmlFree(cont);
4499 }
4500 break;
4501 }
4502 default:
4503 break;
4504 }
4505 /*
4506 * Skip to next node
4507 */
4508 if (tmp->children != NULL) {
4509 if (tmp->children->type != XML_ENTITY_DECL) {
4510 tmp = tmp->children;
4511 continue;
4512 }
4513 }
4514 if (tmp == cur)
4515 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00004516
Daniel Veillard7646b182002-04-20 06:41:40 +00004517 if (tmp->next != NULL) {
4518 tmp = tmp->next;
4519 continue;
4520 }
4521
4522 do {
4523 tmp = tmp->parent;
4524 if (tmp == NULL)
4525 break;
4526 if (tmp == cur) {
4527 tmp = NULL;
4528 break;
4529 }
4530 if (tmp->next != NULL) {
4531 tmp = tmp->next;
4532 break;
4533 }
4534 } while (tmp != NULL);
4535 }
4536 ret = buffer->content;
4537 buffer->content = NULL;
4538 xmlBufferFree(buffer);
4539 return (ret);
4540 }
4541 case XML_ATTRIBUTE_NODE:{
4542 xmlAttrPtr attr = (xmlAttrPtr) cur;
4543
4544 if (attr->parent != NULL)
4545 return (xmlNodeListGetString
4546 (attr->parent->doc, attr->children, 1));
4547 else
4548 return (xmlNodeListGetString(NULL, attr->children, 1));
4549 break;
4550 }
Owen Taylor3473f882001-02-23 17:55:21 +00004551 case XML_COMMENT_NODE:
4552 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004553 if (cur->content != NULL)
4554 return (xmlStrdup(cur->content));
4555 return (NULL);
4556 case XML_ENTITY_REF_NODE:{
4557 xmlEntityPtr ent;
4558 xmlNodePtr tmp;
4559 xmlBufferPtr buffer;
4560 xmlChar *ret;
4561
4562 /* lookup entity declaration */
4563 ent = xmlGetDocEntity(cur->doc, cur->name);
4564 if (ent == NULL)
4565 return (NULL);
4566
4567 buffer = xmlBufferCreate();
4568 if (buffer == NULL)
4569 return (NULL);
4570
4571 /* an entity content can be any "well balanced chunk",
4572 * i.e. the result of the content [43] production:
4573 * http://www.w3.org/TR/REC-xml#NT-content
4574 * -> we iterate through child nodes and recursive call
4575 * xmlNodeGetContent() which handles all possible node types */
4576 tmp = ent->children;
4577 while (tmp) {
4578 xmlChar *cont = xmlNodeGetContent(tmp);
4579
4580 if (cont) {
4581 xmlBufferCat(buffer, (const xmlChar *) cont);
4582 xmlFree(cont);
4583 }
4584 tmp = tmp->next;
4585 }
4586
4587 ret = buffer->content;
4588 buffer->content = NULL;
4589 xmlBufferFree(buffer);
4590 return (ret);
4591 }
Owen Taylor3473f882001-02-23 17:55:21 +00004592 case XML_ENTITY_NODE:
4593 case XML_DOCUMENT_NODE:
4594 case XML_HTML_DOCUMENT_NODE:
4595 case XML_DOCUMENT_TYPE_NODE:
4596 case XML_NOTATION_NODE:
4597 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004598 case XML_XINCLUDE_START:
4599 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004600#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004601 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004602#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00004603 return (NULL);
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004604 case XML_NAMESPACE_DECL: {
4605 xmlChar *tmp;
4606
4607 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4608 return (tmp);
4609 }
Owen Taylor3473f882001-02-23 17:55:21 +00004610 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004611 /* TODO !!! */
4612 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004613 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004614 /* TODO !!! */
4615 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004616 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004617 /* TODO !!! */
4618 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004619 case XML_CDATA_SECTION_NODE:
4620 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004621 if (cur->content != NULL)
4622 return (xmlStrdup(cur->content));
4623 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004624 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004625 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004626}
Owen Taylor3473f882001-02-23 17:55:21 +00004627/**
4628 * xmlNodeSetContent:
4629 * @cur: the node being modified
4630 * @content: the new value of the content
4631 *
4632 * Replace the content of a node.
4633 */
4634void
4635xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4636 if (cur == NULL) {
4637#ifdef DEBUG_TREE
4638 xmlGenericError(xmlGenericErrorContext,
4639 "xmlNodeSetContent : node == NULL\n");
4640#endif
4641 return;
4642 }
4643 switch (cur->type) {
4644 case XML_DOCUMENT_FRAG_NODE:
4645 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004646 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004647 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4648 cur->children = xmlStringGetNodeList(cur->doc, content);
4649 UPDATE_LAST_CHILD_AND_PARENT(cur)
4650 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004651 case XML_TEXT_NODE:
4652 case XML_CDATA_SECTION_NODE:
4653 case XML_ENTITY_REF_NODE:
4654 case XML_ENTITY_NODE:
4655 case XML_PI_NODE:
4656 case XML_COMMENT_NODE:
4657 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004658 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004659 }
4660 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4661 cur->last = cur->children = NULL;
4662 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004663 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00004664 } else
4665 cur->content = NULL;
4666 break;
4667 case XML_DOCUMENT_NODE:
4668 case XML_HTML_DOCUMENT_NODE:
4669 case XML_DOCUMENT_TYPE_NODE:
4670 case XML_XINCLUDE_START:
4671 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004672#ifdef LIBXML_DOCB_ENABLED
4673 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004674#endif
4675 break;
4676 case XML_NOTATION_NODE:
4677 break;
4678 case XML_DTD_NODE:
4679 break;
4680 case XML_NAMESPACE_DECL:
4681 break;
4682 case XML_ELEMENT_DECL:
4683 /* TODO !!! */
4684 break;
4685 case XML_ATTRIBUTE_DECL:
4686 /* TODO !!! */
4687 break;
4688 case XML_ENTITY_DECL:
4689 /* TODO !!! */
4690 break;
4691 }
4692}
4693
4694/**
4695 * xmlNodeSetContentLen:
4696 * @cur: the node being modified
4697 * @content: the new value of the content
4698 * @len: the size of @content
4699 *
4700 * Replace the content of a node.
4701 */
4702void
4703xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4704 if (cur == NULL) {
4705#ifdef DEBUG_TREE
4706 xmlGenericError(xmlGenericErrorContext,
4707 "xmlNodeSetContentLen : node == NULL\n");
4708#endif
4709 return;
4710 }
4711 switch (cur->type) {
4712 case XML_DOCUMENT_FRAG_NODE:
4713 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004714 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004715 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4716 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
4717 UPDATE_LAST_CHILD_AND_PARENT(cur)
4718 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004719 case XML_TEXT_NODE:
4720 case XML_CDATA_SECTION_NODE:
4721 case XML_ENTITY_REF_NODE:
4722 case XML_ENTITY_NODE:
4723 case XML_PI_NODE:
4724 case XML_COMMENT_NODE:
4725 case XML_NOTATION_NODE:
4726 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004727 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004728 }
4729 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4730 cur->children = cur->last = NULL;
4731 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004732 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004733 } else
4734 cur->content = NULL;
4735 break;
4736 case XML_DOCUMENT_NODE:
4737 case XML_DTD_NODE:
4738 case XML_HTML_DOCUMENT_NODE:
4739 case XML_DOCUMENT_TYPE_NODE:
4740 case XML_NAMESPACE_DECL:
4741 case XML_XINCLUDE_START:
4742 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004743#ifdef LIBXML_DOCB_ENABLED
4744 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004745#endif
4746 break;
4747 case XML_ELEMENT_DECL:
4748 /* TODO !!! */
4749 break;
4750 case XML_ATTRIBUTE_DECL:
4751 /* TODO !!! */
4752 break;
4753 case XML_ENTITY_DECL:
4754 /* TODO !!! */
4755 break;
4756 }
4757}
4758
4759/**
4760 * xmlNodeAddContentLen:
4761 * @cur: the node being modified
4762 * @content: extra content
4763 * @len: the size of @content
4764 *
4765 * Append the extra substring to the node content.
4766 */
4767void
4768xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4769 if (cur == NULL) {
4770#ifdef DEBUG_TREE
4771 xmlGenericError(xmlGenericErrorContext,
4772 "xmlNodeAddContentLen : node == NULL\n");
4773#endif
4774 return;
4775 }
4776 if (len <= 0) return;
4777 switch (cur->type) {
4778 case XML_DOCUMENT_FRAG_NODE:
4779 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004780 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004781
Daniel Veillard7db37732001-07-12 01:20:08 +00004782 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004783 newNode = xmlNewTextLen(content, len);
4784 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004785 tmp = xmlAddChild(cur, newNode);
4786 if (tmp != newNode)
4787 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004788 if ((last != NULL) && (last->next == newNode)) {
4789 xmlTextMerge(last, newNode);
4790 }
4791 }
4792 break;
4793 }
4794 case XML_ATTRIBUTE_NODE:
4795 break;
4796 case XML_TEXT_NODE:
4797 case XML_CDATA_SECTION_NODE:
4798 case XML_ENTITY_REF_NODE:
4799 case XML_ENTITY_NODE:
4800 case XML_PI_NODE:
4801 case XML_COMMENT_NODE:
4802 case XML_NOTATION_NODE:
4803 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004804 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004805 }
4806 case XML_DOCUMENT_NODE:
4807 case XML_DTD_NODE:
4808 case XML_HTML_DOCUMENT_NODE:
4809 case XML_DOCUMENT_TYPE_NODE:
4810 case XML_NAMESPACE_DECL:
4811 case XML_XINCLUDE_START:
4812 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004813#ifdef LIBXML_DOCB_ENABLED
4814 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004815#endif
4816 break;
4817 case XML_ELEMENT_DECL:
4818 case XML_ATTRIBUTE_DECL:
4819 case XML_ENTITY_DECL:
4820 break;
4821 }
4822}
4823
4824/**
4825 * xmlNodeAddContent:
4826 * @cur: the node being modified
4827 * @content: extra content
4828 *
4829 * Append the extra substring to the node content.
4830 */
4831void
4832xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
4833 int len;
4834
4835 if (cur == NULL) {
4836#ifdef DEBUG_TREE
4837 xmlGenericError(xmlGenericErrorContext,
4838 "xmlNodeAddContent : node == NULL\n");
4839#endif
4840 return;
4841 }
4842 if (content == NULL) return;
4843 len = xmlStrlen(content);
4844 xmlNodeAddContentLen(cur, content, len);
4845}
4846
4847/**
4848 * xmlTextMerge:
4849 * @first: the first text node
4850 * @second: the second text node being merged
4851 *
4852 * Merge two text nodes into one
4853 * Returns the first text node augmented
4854 */
4855xmlNodePtr
4856xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
4857 if (first == NULL) return(second);
4858 if (second == NULL) return(first);
4859 if (first->type != XML_TEXT_NODE) return(first);
4860 if (second->type != XML_TEXT_NODE) return(first);
4861 if (second->name != first->name)
4862 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00004863 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004864 xmlUnlinkNode(second);
4865 xmlFreeNode(second);
4866 return(first);
4867}
4868
4869/**
4870 * xmlGetNsList:
4871 * @doc: the document
4872 * @node: the current node
4873 *
4874 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00004875 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00004876 * that need to be freed by the caller or NULL if no
4877 * namespace if defined
4878 */
4879xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00004880xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
4881{
Owen Taylor3473f882001-02-23 17:55:21 +00004882 xmlNsPtr cur;
4883 xmlNsPtr *ret = NULL;
4884 int nbns = 0;
4885 int maxns = 10;
4886 int i;
4887
4888 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00004889 if (node->type == XML_ELEMENT_NODE) {
4890 cur = node->nsDef;
4891 while (cur != NULL) {
4892 if (ret == NULL) {
4893 ret =
4894 (xmlNsPtr *) xmlMalloc((maxns + 1) *
4895 sizeof(xmlNsPtr));
4896 if (ret == NULL) {
4897 xmlGenericError(xmlGenericErrorContext,
4898 "xmlGetNsList : out of memory!\n");
4899 return (NULL);
4900 }
4901 ret[nbns] = NULL;
4902 }
4903 for (i = 0; i < nbns; i++) {
4904 if ((cur->prefix == ret[i]->prefix) ||
4905 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
4906 break;
4907 }
4908 if (i >= nbns) {
4909 if (nbns >= maxns) {
4910 maxns *= 2;
4911 ret = (xmlNsPtr *) xmlRealloc(ret,
4912 (maxns +
4913 1) *
4914 sizeof(xmlNsPtr));
4915 if (ret == NULL) {
4916 xmlGenericError(xmlGenericErrorContext,
4917 "xmlGetNsList : realloc failed!\n");
4918 return (NULL);
4919 }
4920 }
4921 ret[nbns++] = cur;
4922 ret[nbns] = NULL;
4923 }
Owen Taylor3473f882001-02-23 17:55:21 +00004924
Daniel Veillard77044732001-06-29 21:31:07 +00004925 cur = cur->next;
4926 }
4927 }
4928 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004929 }
Daniel Veillard77044732001-06-29 21:31:07 +00004930 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004931}
4932
4933/**
4934 * xmlSearchNs:
4935 * @doc: the document
4936 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004937 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004938 *
4939 * Search a Ns registered under a given name space for a document.
4940 * recurse on the parents until it finds the defined namespace
4941 * or return NULL otherwise.
4942 * @nameSpace can be NULL, this is a search for the default namespace.
4943 * We don't allow to cross entities boundaries. If you don't declare
4944 * the namespace within those you will be in troubles !!! A warning
4945 * is generated to cover this case.
4946 *
4947 * Returns the namespace pointer or NULL.
4948 */
4949xmlNsPtr
4950xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4951 xmlNsPtr cur;
4952
4953 if (node == NULL) return(NULL);
4954 if ((nameSpace != NULL) &&
4955 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00004956 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4957 /*
4958 * The XML-1.0 namespace is normally held on the root
4959 * element. In this case exceptionally create it on the
4960 * node element.
4961 */
4962 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4963 if (cur == NULL) {
4964 xmlGenericError(xmlGenericErrorContext,
4965 "xmlSearchNs : malloc failed\n");
4966 return(NULL);
4967 }
4968 memset(cur, 0, sizeof(xmlNs));
4969 cur->type = XML_LOCAL_NAMESPACE;
4970 cur->href = xmlStrdup(XML_XML_NAMESPACE);
4971 cur->prefix = xmlStrdup((const xmlChar *)"xml");
4972 cur->next = node->nsDef;
4973 node->nsDef = cur;
4974 return(cur);
4975 }
Owen Taylor3473f882001-02-23 17:55:21 +00004976 if (doc->oldNs == NULL) {
4977 /*
4978 * Allocate a new Namespace and fill the fields.
4979 */
4980 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4981 if (doc->oldNs == NULL) {
4982 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004983 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004984 return(NULL);
4985 }
4986 memset(doc->oldNs, 0, sizeof(xmlNs));
4987 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4988
4989 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4990 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4991 }
4992 return(doc->oldNs);
4993 }
4994 while (node != NULL) {
4995 if ((node->type == XML_ENTITY_REF_NODE) ||
4996 (node->type == XML_ENTITY_NODE) ||
4997 (node->type == XML_ENTITY_DECL))
4998 return(NULL);
4999 if (node->type == XML_ELEMENT_NODE) {
5000 cur = node->nsDef;
5001 while (cur != NULL) {
5002 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5003 (cur->href != NULL))
5004 return(cur);
5005 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5006 (cur->href != NULL) &&
5007 (xmlStrEqual(cur->prefix, nameSpace)))
5008 return(cur);
5009 cur = cur->next;
5010 }
5011 }
5012 node = node->parent;
5013 }
5014 return(NULL);
5015}
5016
5017/**
5018 * xmlSearchNsByHref:
5019 * @doc: the document
5020 * @node: the current node
5021 * @href: the namespace value
5022 *
5023 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5024 * the defined namespace or return NULL otherwise.
5025 * Returns the namespace pointer or NULL.
5026 */
5027xmlNsPtr
5028xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
5029 xmlNsPtr cur;
5030 xmlNodePtr orig = node;
5031
5032 if ((node == NULL) || (href == NULL)) return(NULL);
5033 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00005034 /*
5035 * Only the document can hold the XML spec namespace.
5036 */
Daniel Veillardc1a0da32002-08-14 08:32:18 +00005037 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5038 /*
5039 * The XML-1.0 namespace is normally held on the root
5040 * element. In this case exceptionally create it on the
5041 * node element.
5042 */
5043 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5044 if (cur == NULL) {
5045 xmlGenericError(xmlGenericErrorContext,
5046 "xmlSearchNs : malloc failed\n");
5047 return(NULL);
5048 }
5049 memset(cur, 0, sizeof(xmlNs));
5050 cur->type = XML_LOCAL_NAMESPACE;
5051 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5052 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5053 cur->next = node->nsDef;
5054 node->nsDef = cur;
5055 return(cur);
5056 }
Owen Taylor3473f882001-02-23 17:55:21 +00005057 if (doc->oldNs == NULL) {
5058 /*
5059 * Allocate a new Namespace and fill the fields.
5060 */
5061 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5062 if (doc->oldNs == NULL) {
5063 xmlGenericError(xmlGenericErrorContext,
5064 "xmlSearchNsByHref : malloc failed\n");
5065 return(NULL);
5066 }
5067 memset(doc->oldNs, 0, sizeof(xmlNs));
5068 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5069
5070 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5071 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5072 }
5073 return(doc->oldNs);
5074 }
5075 while (node != NULL) {
5076 cur = node->nsDef;
5077 while (cur != NULL) {
5078 if ((cur->href != NULL) && (href != NULL) &&
5079 (xmlStrEqual(cur->href, href))) {
5080 /*
5081 * Check that the prefix is not shadowed between orig and node
5082 */
5083 xmlNodePtr check = orig;
5084 xmlNsPtr tst;
5085
5086 while (check != node) {
5087 tst = check->nsDef;
5088 while (tst != NULL) {
5089 if ((tst->prefix == NULL) && (cur->prefix == NULL))
5090 goto shadowed;
5091 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
5092 (xmlStrEqual(tst->prefix, cur->prefix)))
5093 goto shadowed;
5094 tst = tst->next;
5095 }
5096 check = check->parent;
5097 }
5098 return(cur);
5099 }
5100shadowed:
5101 cur = cur->next;
5102 }
5103 node = node->parent;
5104 }
5105 return(NULL);
5106}
5107
5108/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005109 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005110 * @doc: the document
5111 * @tree: a node expected to hold the new namespace
5112 * @ns: the original namespace
5113 *
5114 * This function tries to locate a namespace definition in a tree
5115 * ancestors, or create a new namespace definition node similar to
5116 * @ns trying to reuse the same prefix. However if the given prefix is
5117 * null (default namespace) or reused within the subtree defined by
5118 * @tree or on one of its ancestors then a new prefix is generated.
5119 * Returns the (new) namespace definition or NULL in case of error
5120 */
5121xmlNsPtr
5122xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5123 xmlNsPtr def;
5124 xmlChar prefix[50];
5125 int counter = 1;
5126
5127 if (tree == NULL) {
5128#ifdef DEBUG_TREE
5129 xmlGenericError(xmlGenericErrorContext,
5130 "xmlNewReconciliedNs : tree == NULL\n");
5131#endif
5132 return(NULL);
5133 }
5134 if (ns == NULL) {
5135#ifdef DEBUG_TREE
5136 xmlGenericError(xmlGenericErrorContext,
5137 "xmlNewReconciliedNs : ns == NULL\n");
5138#endif
5139 return(NULL);
5140 }
5141 /*
5142 * Search an existing namespace definition inherited.
5143 */
5144 def = xmlSearchNsByHref(doc, tree, ns->href);
5145 if (def != NULL)
5146 return(def);
5147
5148 /*
5149 * Find a close prefix which is not already in use.
5150 * Let's strip namespace prefixes longer than 20 chars !
5151 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005152 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005153 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005154 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005155 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005156
Owen Taylor3473f882001-02-23 17:55:21 +00005157 def = xmlSearchNs(doc, tree, prefix);
5158 while (def != NULL) {
5159 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005160 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005161 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005162 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005163 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005164 def = xmlSearchNs(doc, tree, prefix);
5165 }
5166
5167 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005168 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005169 */
5170 def = xmlNewNs(tree, ns->href, prefix);
5171 return(def);
5172}
5173
5174/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005175 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005176 * @doc: the document
5177 * @tree: a node defining the subtree to reconciliate
5178 *
5179 * This function checks that all the namespaces declared within the given
5180 * tree are properly declared. This is needed for example after Copy or Cut
5181 * and then paste operations. The subtree may still hold pointers to
5182 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005183 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005184 * the new environment. If not possible the new namespaces are redeclared
5185 * on @tree at the top of the given subtree.
5186 * Returns the number of namespace declarations created or -1 in case of error.
5187 */
5188int
5189xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5190 xmlNsPtr *oldNs = NULL;
5191 xmlNsPtr *newNs = NULL;
5192 int sizeCache = 0;
5193 int nbCache = 0;
5194
5195 xmlNsPtr n;
5196 xmlNodePtr node = tree;
5197 xmlAttrPtr attr;
5198 int ret = 0, i;
5199
5200 while (node != NULL) {
5201 /*
5202 * Reconciliate the node namespace
5203 */
5204 if (node->ns != NULL) {
5205 /*
5206 * initialize the cache if needed
5207 */
5208 if (sizeCache == 0) {
5209 sizeCache = 10;
5210 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5211 sizeof(xmlNsPtr));
5212 if (oldNs == NULL) {
5213 xmlGenericError(xmlGenericErrorContext,
5214 "xmlReconciliateNs : memory pbm\n");
5215 return(-1);
5216 }
5217 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5218 sizeof(xmlNsPtr));
5219 if (newNs == NULL) {
5220 xmlGenericError(xmlGenericErrorContext,
5221 "xmlReconciliateNs : memory pbm\n");
5222 xmlFree(oldNs);
5223 return(-1);
5224 }
5225 }
5226 for (i = 0;i < nbCache;i++) {
5227 if (oldNs[i] == node->ns) {
5228 node->ns = newNs[i];
5229 break;
5230 }
5231 }
5232 if (i == nbCache) {
5233 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005234 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005235 */
5236 n = xmlNewReconciliedNs(doc, tree, node->ns);
5237 if (n != NULL) { /* :-( what if else ??? */
5238 /*
5239 * check if we need to grow the cache buffers.
5240 */
5241 if (sizeCache <= nbCache) {
5242 sizeCache *= 2;
5243 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5244 sizeof(xmlNsPtr));
5245 if (oldNs == NULL) {
5246 xmlGenericError(xmlGenericErrorContext,
5247 "xmlReconciliateNs : memory pbm\n");
5248 xmlFree(newNs);
5249 return(-1);
5250 }
5251 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5252 sizeof(xmlNsPtr));
5253 if (newNs == NULL) {
5254 xmlGenericError(xmlGenericErrorContext,
5255 "xmlReconciliateNs : memory pbm\n");
5256 xmlFree(oldNs);
5257 return(-1);
5258 }
5259 }
5260 newNs[nbCache] = n;
5261 oldNs[nbCache++] = node->ns;
5262 node->ns = n;
5263 }
5264 }
5265 }
5266 /*
5267 * now check for namespace hold by attributes on the node.
5268 */
5269 attr = node->properties;
5270 while (attr != NULL) {
5271 if (attr->ns != NULL) {
5272 /*
5273 * initialize the cache if needed
5274 */
5275 if (sizeCache == 0) {
5276 sizeCache = 10;
5277 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5278 sizeof(xmlNsPtr));
5279 if (oldNs == NULL) {
5280 xmlGenericError(xmlGenericErrorContext,
5281 "xmlReconciliateNs : memory pbm\n");
5282 return(-1);
5283 }
5284 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5285 sizeof(xmlNsPtr));
5286 if (newNs == NULL) {
5287 xmlGenericError(xmlGenericErrorContext,
5288 "xmlReconciliateNs : memory pbm\n");
5289 xmlFree(oldNs);
5290 return(-1);
5291 }
5292 }
5293 for (i = 0;i < nbCache;i++) {
5294 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005295 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005296 break;
5297 }
5298 }
5299 if (i == nbCache) {
5300 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005301 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005302 */
5303 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5304 if (n != NULL) { /* :-( what if else ??? */
5305 /*
5306 * check if we need to grow the cache buffers.
5307 */
5308 if (sizeCache <= nbCache) {
5309 sizeCache *= 2;
5310 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5311 sizeof(xmlNsPtr));
5312 if (oldNs == NULL) {
5313 xmlGenericError(xmlGenericErrorContext,
5314 "xmlReconciliateNs : memory pbm\n");
5315 xmlFree(newNs);
5316 return(-1);
5317 }
5318 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5319 sizeof(xmlNsPtr));
5320 if (newNs == NULL) {
5321 xmlGenericError(xmlGenericErrorContext,
5322 "xmlReconciliateNs : memory pbm\n");
5323 xmlFree(oldNs);
5324 return(-1);
5325 }
5326 }
5327 newNs[nbCache] = n;
5328 oldNs[nbCache++] = attr->ns;
5329 attr->ns = n;
5330 }
5331 }
5332 }
5333 attr = attr->next;
5334 }
5335
5336 /*
5337 * Browse the full subtree, deep first
5338 */
5339 if (node->children != NULL) {
5340 /* deep first */
5341 node = node->children;
5342 } else if ((node != tree) && (node->next != NULL)) {
5343 /* then siblings */
5344 node = node->next;
5345 } else if (node != tree) {
5346 /* go up to parents->next if needed */
5347 while (node != tree) {
5348 if (node->parent != NULL)
5349 node = node->parent;
5350 if ((node != tree) && (node->next != NULL)) {
5351 node = node->next;
5352 break;
5353 }
5354 if (node->parent == NULL) {
5355 node = NULL;
5356 break;
5357 }
5358 }
5359 /* exit condition */
5360 if (node == tree)
5361 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005362 } else
5363 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005364 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005365 if (oldNs != NULL)
5366 xmlFree(oldNs);
5367 if (newNs != NULL)
5368 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005369 return(ret);
5370}
5371
5372/**
5373 * xmlHasProp:
5374 * @node: the node
5375 * @name: the attribute name
5376 *
5377 * Search an attribute associated to a node
5378 * This function also looks in DTD attribute declaration for #FIXED or
5379 * default declaration values unless DTD use has been turned off.
5380 *
5381 * Returns the attribute or the attribute declaration or NULL if
5382 * neither was found.
5383 */
5384xmlAttrPtr
5385xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5386 xmlAttrPtr prop;
5387 xmlDocPtr doc;
5388
5389 if ((node == NULL) || (name == NULL)) return(NULL);
5390 /*
5391 * Check on the properties attached to the node
5392 */
5393 prop = node->properties;
5394 while (prop != NULL) {
5395 if (xmlStrEqual(prop->name, name)) {
5396 return(prop);
5397 }
5398 prop = prop->next;
5399 }
5400 if (!xmlCheckDTD) return(NULL);
5401
5402 /*
5403 * Check if there is a default declaration in the internal
5404 * or external subsets
5405 */
5406 doc = node->doc;
5407 if (doc != NULL) {
5408 xmlAttributePtr attrDecl;
5409 if (doc->intSubset != NULL) {
5410 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5411 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5412 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5413 if (attrDecl != NULL)
5414 return((xmlAttrPtr) attrDecl);
5415 }
5416 }
5417 return(NULL);
5418}
5419
5420/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005421 * xmlHasNsProp:
5422 * @node: the node
5423 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005424 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005425 *
5426 * Search for an attribute associated to a node
5427 * This attribute has to be anchored in the namespace specified.
5428 * This does the entity substitution.
5429 * This function looks in DTD attribute declaration for #FIXED or
5430 * default declaration values unless DTD use has been turned off.
5431 *
5432 * Returns the attribute or the attribute declaration or NULL
5433 * if neither was found.
5434 */
5435xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005436xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005437 xmlAttrPtr prop;
5438 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005439
5440 if (node == NULL)
5441 return(NULL);
5442
5443 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005444 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005445 return(xmlHasProp(node, name));
5446 while (prop != NULL) {
5447 /*
5448 * One need to have
5449 * - same attribute names
5450 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005451 */
5452 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005453 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5454 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005455 }
5456 prop = prop->next;
5457 }
5458 if (!xmlCheckDTD) return(NULL);
5459
5460 /*
5461 * Check if there is a default declaration in the internal
5462 * or external subsets
5463 */
5464 doc = node->doc;
5465 if (doc != NULL) {
5466 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005467 xmlAttributePtr attrDecl = NULL;
5468 xmlNsPtr *nsList, *cur;
5469 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005470
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005471 nsList = xmlGetNsList(node->doc, node);
5472 if (nsList == NULL)
5473 return(NULL);
5474 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5475 ename = xmlStrdup(node->ns->prefix);
5476 ename = xmlStrcat(ename, BAD_CAST ":");
5477 ename = xmlStrcat(ename, node->name);
5478 } else {
5479 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005480 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005481 if (ename == NULL) {
5482 xmlFree(nsList);
5483 return(NULL);
5484 }
5485
5486 cur = nsList;
5487 while (*cur != NULL) {
5488 if (xmlStrEqual((*cur)->href, nameSpace)) {
5489 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5490 name, (*cur)->prefix);
5491 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5492 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5493 name, (*cur)->prefix);
5494 }
5495 cur++;
5496 }
5497 xmlFree(nsList);
5498 xmlFree(ename);
5499 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005500 }
5501 }
5502 return(NULL);
5503}
5504
5505/**
Owen Taylor3473f882001-02-23 17:55:21 +00005506 * xmlGetProp:
5507 * @node: the node
5508 * @name: the attribute name
5509 *
5510 * Search and get the value of an attribute associated to a node
5511 * This does the entity substitution.
5512 * This function looks in DTD attribute declaration for #FIXED or
5513 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00005514 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00005515 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
5516 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00005517 *
5518 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005519 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005520 */
5521xmlChar *
5522xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5523 xmlAttrPtr prop;
5524 xmlDocPtr doc;
5525
5526 if ((node == NULL) || (name == NULL)) return(NULL);
5527 /*
5528 * Check on the properties attached to the node
5529 */
5530 prop = node->properties;
5531 while (prop != NULL) {
5532 if (xmlStrEqual(prop->name, name)) {
5533 xmlChar *ret;
5534
5535 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5536 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5537 return(ret);
5538 }
5539 prop = prop->next;
5540 }
5541 if (!xmlCheckDTD) return(NULL);
5542
5543 /*
5544 * Check if there is a default declaration in the internal
5545 * or external subsets
5546 */
5547 doc = node->doc;
5548 if (doc != NULL) {
5549 xmlAttributePtr attrDecl;
5550 if (doc->intSubset != NULL) {
5551 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5552 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5553 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5554 if (attrDecl != NULL)
5555 return(xmlStrdup(attrDecl->defaultValue));
5556 }
5557 }
5558 return(NULL);
5559}
5560
5561/**
Daniel Veillard71531f32003-02-05 13:19:53 +00005562 * xmlGetNoNsProp:
5563 * @node: the node
5564 * @name: the attribute name
5565 *
5566 * Search and get the value of an attribute associated to a node
5567 * This does the entity substitution.
5568 * This function looks in DTD attribute declaration for #FIXED or
5569 * default declaration values unless DTD use has been turned off.
5570 * This function is similar to xmlGetProp except it will accept only
5571 * an attribute in no namespace.
5572 *
5573 * Returns the attribute value or NULL if not found.
5574 * It's up to the caller to free the memory with xmlFree().
5575 */
5576xmlChar *
5577xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
5578 xmlAttrPtr prop;
5579 xmlDocPtr doc;
5580
5581 if ((node == NULL) || (name == NULL)) return(NULL);
5582 /*
5583 * Check on the properties attached to the node
5584 */
5585 prop = node->properties;
5586 while (prop != NULL) {
5587 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
5588 xmlChar *ret;
5589
5590 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5591 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5592 return(ret);
5593 }
5594 prop = prop->next;
5595 }
5596 if (!xmlCheckDTD) return(NULL);
5597
5598 /*
5599 * Check if there is a default declaration in the internal
5600 * or external subsets
5601 */
5602 doc = node->doc;
5603 if (doc != NULL) {
5604 xmlAttributePtr attrDecl;
5605 if (doc->intSubset != NULL) {
5606 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5607 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5608 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5609 if (attrDecl != NULL)
5610 return(xmlStrdup(attrDecl->defaultValue));
5611 }
5612 }
5613 return(NULL);
5614}
5615
5616/**
Owen Taylor3473f882001-02-23 17:55:21 +00005617 * xmlGetNsProp:
5618 * @node: the node
5619 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005620 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005621 *
5622 * Search and get the value of an attribute associated to a node
5623 * This attribute has to be anchored in the namespace specified.
5624 * This does the entity substitution.
5625 * This function looks in DTD attribute declaration for #FIXED or
5626 * default declaration values unless DTD use has been turned off.
5627 *
5628 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005629 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005630 */
5631xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00005632xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00005633 xmlAttrPtr prop;
5634 xmlDocPtr doc;
5635 xmlNsPtr ns;
5636
5637 if (node == NULL)
5638 return(NULL);
5639
5640 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005641 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00005642 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00005643 while (prop != NULL) {
5644 /*
5645 * One need to have
5646 * - same attribute names
5647 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005648 */
5649 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00005650 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00005651 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005652 xmlChar *ret;
5653
5654 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5655 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5656 return(ret);
5657 }
5658 prop = prop->next;
5659 }
5660 if (!xmlCheckDTD) return(NULL);
5661
5662 /*
5663 * Check if there is a default declaration in the internal
5664 * or external subsets
5665 */
5666 doc = node->doc;
5667 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005668 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00005669 xmlAttributePtr attrDecl;
5670
Owen Taylor3473f882001-02-23 17:55:21 +00005671 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5672 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5673 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5674
5675 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
5676 /*
5677 * The DTD declaration only allows a prefix search
5678 */
5679 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00005680 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00005681 return(xmlStrdup(attrDecl->defaultValue));
5682 }
5683 }
5684 }
5685 return(NULL);
5686}
5687
5688/**
5689 * xmlSetProp:
5690 * @node: the node
5691 * @name: the attribute name
5692 * @value: the attribute value
5693 *
5694 * Set (or reset) an attribute carried by a node.
5695 * Returns the attribute pointer.
5696 */
5697xmlAttrPtr
5698xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005699 xmlAttrPtr prop;
5700 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00005701
5702 if ((node == NULL) || (name == NULL))
5703 return(NULL);
5704 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005705 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00005706 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005707 if ((xmlStrEqual(prop->name, name)) &&
5708 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005709 xmlNodePtr oldprop = prop->children;
5710
Owen Taylor3473f882001-02-23 17:55:21 +00005711 prop->children = NULL;
5712 prop->last = NULL;
5713 if (value != NULL) {
5714 xmlChar *buffer;
5715 xmlNodePtr tmp;
5716
5717 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5718 prop->children = xmlStringGetNodeList(node->doc, buffer);
5719 prop->last = NULL;
5720 prop->doc = doc;
5721 tmp = prop->children;
5722 while (tmp != NULL) {
5723 tmp->parent = (xmlNodePtr) prop;
5724 tmp->doc = doc;
5725 if (tmp->next == NULL)
5726 prop->last = tmp;
5727 tmp = tmp->next;
5728 }
5729 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00005730 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005731 if (oldprop != NULL)
5732 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00005733 return(prop);
5734 }
5735 prop = prop->next;
5736 }
5737 prop = xmlNewProp(node, name, value);
5738 return(prop);
5739}
5740
5741/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005742 * xmlUnsetProp:
5743 * @node: the node
5744 * @name: the attribute name
5745 *
5746 * Remove an attribute carried by a node.
5747 * Returns 0 if successful, -1 if not found
5748 */
5749int
5750xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Daniel Veillard814a76d2003-01-23 18:24:20 +00005751 xmlAttrPtr prop, prev = NULL;;
Daniel Veillard75bea542001-05-11 17:41:21 +00005752
5753 if ((node == NULL) || (name == NULL))
5754 return(-1);
Daniel Veillard814a76d2003-01-23 18:24:20 +00005755 prop = node->properties;
Daniel Veillard75bea542001-05-11 17:41:21 +00005756 while (prop != NULL) {
5757 if ((xmlStrEqual(prop->name, name)) &&
5758 (prop->ns == NULL)) {
5759 if (prev == NULL)
5760 node->properties = prop->next;
5761 else
5762 prev->next = prop->next;
5763 xmlFreeProp(prop);
5764 return(0);
5765 }
5766 prev = prop;
5767 prop = prop->next;
5768 }
5769 return(-1);
5770}
5771
5772/**
Owen Taylor3473f882001-02-23 17:55:21 +00005773 * xmlSetNsProp:
5774 * @node: the node
5775 * @ns: the namespace definition
5776 * @name: the attribute name
5777 * @value: the attribute value
5778 *
5779 * Set (or reset) an attribute carried by a node.
5780 * The ns structure must be in scope, this is not checked.
5781 *
5782 * Returns the attribute pointer.
5783 */
5784xmlAttrPtr
5785xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
5786 const xmlChar *value) {
5787 xmlAttrPtr prop;
5788
5789 if ((node == NULL) || (name == NULL))
5790 return(NULL);
5791
5792 if (ns == NULL)
5793 return(xmlSetProp(node, name, value));
5794 if (ns->href == NULL)
5795 return(NULL);
5796 prop = node->properties;
5797
5798 while (prop != NULL) {
5799 /*
5800 * One need to have
5801 * - same attribute names
5802 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005803 */
5804 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00005805 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005806 if (prop->children != NULL)
5807 xmlFreeNodeList(prop->children);
5808 prop->children = NULL;
5809 prop->last = NULL;
5810 prop->ns = ns;
5811 if (value != NULL) {
5812 xmlChar *buffer;
5813 xmlNodePtr tmp;
5814
5815 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5816 prop->children = xmlStringGetNodeList(node->doc, buffer);
5817 prop->last = NULL;
5818 tmp = prop->children;
5819 while (tmp != NULL) {
5820 tmp->parent = (xmlNodePtr) prop;
5821 if (tmp->next == NULL)
5822 prop->last = tmp;
5823 tmp = tmp->next;
5824 }
5825 xmlFree(buffer);
5826 }
5827 return(prop);
5828 }
5829 prop = prop->next;
5830 }
5831 prop = xmlNewNsProp(node, ns, name, value);
5832 return(prop);
5833}
5834
5835/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005836 * xmlUnsetNsProp:
5837 * @node: the node
5838 * @ns: the namespace definition
5839 * @name: the attribute name
5840 *
5841 * Remove an attribute carried by a node.
5842 * Returns 0 if successful, -1 if not found
5843 */
5844int
5845xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
5846 xmlAttrPtr prop = node->properties, prev = NULL;;
5847
5848 if ((node == NULL) || (name == NULL))
5849 return(-1);
5850 if (ns == NULL)
5851 return(xmlUnsetProp(node, name));
5852 if (ns->href == NULL)
5853 return(-1);
5854 while (prop != NULL) {
5855 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00005856 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005857 if (prev == NULL)
5858 node->properties = prop->next;
5859 else
5860 prev->next = prop->next;
5861 xmlFreeProp(prop);
5862 return(0);
5863 }
5864 prev = prop;
5865 prop = prop->next;
5866 }
5867 return(-1);
5868}
5869
5870/**
Owen Taylor3473f882001-02-23 17:55:21 +00005871 * xmlNodeIsText:
5872 * @node: the node
5873 *
5874 * Is this node a Text node ?
5875 * Returns 1 yes, 0 no
5876 */
5877int
5878xmlNodeIsText(xmlNodePtr node) {
5879 if (node == NULL) return(0);
5880
5881 if (node->type == XML_TEXT_NODE) return(1);
5882 return(0);
5883}
5884
5885/**
5886 * xmlIsBlankNode:
5887 * @node: the node
5888 *
5889 * Checks whether this node is an empty or whitespace only
5890 * (and possibly ignorable) text-node.
5891 *
5892 * Returns 1 yes, 0 no
5893 */
5894int
5895xmlIsBlankNode(xmlNodePtr node) {
5896 const xmlChar *cur;
5897 if (node == NULL) return(0);
5898
Daniel Veillard7db37732001-07-12 01:20:08 +00005899 if ((node->type != XML_TEXT_NODE) &&
5900 (node->type != XML_CDATA_SECTION_NODE))
5901 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005902 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00005903 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00005904 while (*cur != 0) {
5905 if (!IS_BLANK(*cur)) return(0);
5906 cur++;
5907 }
5908
5909 return(1);
5910}
5911
5912/**
5913 * xmlTextConcat:
5914 * @node: the node
5915 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00005916 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00005917 *
5918 * Concat the given string at the end of the existing node content
5919 */
5920
5921void
5922xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
5923 if (node == NULL) return;
5924
5925 if ((node->type != XML_TEXT_NODE) &&
5926 (node->type != XML_CDATA_SECTION_NODE)) {
5927#ifdef DEBUG_TREE
5928 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005929 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005930#endif
5931 return;
5932 }
Owen Taylor3473f882001-02-23 17:55:21 +00005933 node->content = xmlStrncat(node->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005934}
5935
5936/************************************************************************
5937 * *
5938 * Output : to a FILE or in memory *
5939 * *
5940 ************************************************************************/
5941
Owen Taylor3473f882001-02-23 17:55:21 +00005942/**
5943 * xmlBufferCreate:
5944 *
5945 * routine to create an XML buffer.
5946 * returns the new structure.
5947 */
5948xmlBufferPtr
5949xmlBufferCreate(void) {
5950 xmlBufferPtr ret;
5951
5952 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5953 if (ret == NULL) {
5954 xmlGenericError(xmlGenericErrorContext,
5955 "xmlBufferCreate : out of memory!\n");
5956 return(NULL);
5957 }
5958 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00005959 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00005960 ret->alloc = xmlBufferAllocScheme;
5961 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5962 if (ret->content == NULL) {
5963 xmlGenericError(xmlGenericErrorContext,
5964 "xmlBufferCreate : out of memory!\n");
5965 xmlFree(ret);
5966 return(NULL);
5967 }
5968 ret->content[0] = 0;
5969 return(ret);
5970}
5971
5972/**
5973 * xmlBufferCreateSize:
5974 * @size: initial size of buffer
5975 *
5976 * routine to create an XML buffer.
5977 * returns the new structure.
5978 */
5979xmlBufferPtr
5980xmlBufferCreateSize(size_t size) {
5981 xmlBufferPtr ret;
5982
5983 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5984 if (ret == NULL) {
5985 xmlGenericError(xmlGenericErrorContext,
5986 "xmlBufferCreate : out of memory!\n");
5987 return(NULL);
5988 }
5989 ret->use = 0;
5990 ret->alloc = xmlBufferAllocScheme;
5991 ret->size = (size ? size+2 : 0); /* +1 for ending null */
5992 if (ret->size){
5993 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5994 if (ret->content == NULL) {
5995 xmlGenericError(xmlGenericErrorContext,
5996 "xmlBufferCreate : out of memory!\n");
5997 xmlFree(ret);
5998 return(NULL);
5999 }
6000 ret->content[0] = 0;
6001 } else
6002 ret->content = NULL;
6003 return(ret);
6004}
6005
6006/**
6007 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006008 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006009 * @scheme: allocation scheme to use
6010 *
6011 * Sets the allocation scheme for this buffer
6012 */
6013void
6014xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6015 xmlBufferAllocationScheme scheme) {
6016 if (buf == NULL) {
6017#ifdef DEBUG_BUFFER
6018 xmlGenericError(xmlGenericErrorContext,
6019 "xmlBufferSetAllocationScheme: buf == NULL\n");
6020#endif
6021 return;
6022 }
6023
6024 buf->alloc = scheme;
6025}
6026
6027/**
6028 * xmlBufferFree:
6029 * @buf: the buffer to free
6030 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006031 * Frees an XML buffer. It frees both the content and the structure which
6032 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006033 */
6034void
6035xmlBufferFree(xmlBufferPtr buf) {
6036 if (buf == NULL) {
6037#ifdef DEBUG_BUFFER
6038 xmlGenericError(xmlGenericErrorContext,
6039 "xmlBufferFree: buf == NULL\n");
6040#endif
6041 return;
6042 }
Daniel Veillard561b7f82002-03-20 21:55:57 +00006043 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006044 xmlFree(buf->content);
6045 }
Owen Taylor3473f882001-02-23 17:55:21 +00006046 xmlFree(buf);
6047}
6048
6049/**
6050 * xmlBufferEmpty:
6051 * @buf: the buffer
6052 *
6053 * empty a buffer.
6054 */
6055void
6056xmlBufferEmpty(xmlBufferPtr buf) {
6057 if (buf->content == NULL) return;
6058 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006059 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00006060}
6061
6062/**
6063 * xmlBufferShrink:
6064 * @buf: the buffer to dump
6065 * @len: the number of xmlChar to remove
6066 *
6067 * Remove the beginning of an XML buffer.
6068 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006069 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006070 */
6071int
6072xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
6073 if (len == 0) return(0);
6074 if (len > buf->use) return(-1);
6075
6076 buf->use -= len;
6077 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6078
6079 buf->content[buf->use] = 0;
6080 return(len);
6081}
6082
6083/**
6084 * xmlBufferGrow:
6085 * @buf: the buffer
6086 * @len: the minimum free size to allocate
6087 *
6088 * Grow the available space of an XML buffer.
6089 *
6090 * Returns the new available space or -1 in case of error
6091 */
6092int
6093xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6094 int size;
6095 xmlChar *newbuf;
6096
6097 if (len + buf->use < buf->size) return(0);
6098
6099 size = buf->use + len + 100;
6100
6101 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
6102 if (newbuf == NULL) return(-1);
6103 buf->content = newbuf;
6104 buf->size = size;
6105 return(buf->size - buf->use);
6106}
6107
6108/**
6109 * xmlBufferDump:
6110 * @file: the file output
6111 * @buf: the buffer to dump
6112 *
6113 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006114 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006115 */
6116int
6117xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6118 int ret;
6119
6120 if (buf == NULL) {
6121#ifdef DEBUG_BUFFER
6122 xmlGenericError(xmlGenericErrorContext,
6123 "xmlBufferDump: buf == NULL\n");
6124#endif
6125 return(0);
6126 }
6127 if (buf->content == NULL) {
6128#ifdef DEBUG_BUFFER
6129 xmlGenericError(xmlGenericErrorContext,
6130 "xmlBufferDump: buf->content == NULL\n");
6131#endif
6132 return(0);
6133 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006134 if (file == NULL)
6135 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006136 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6137 return(ret);
6138}
6139
6140/**
6141 * xmlBufferContent:
6142 * @buf: the buffer
6143 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006144 * Function to extract the content of a buffer
6145 *
Owen Taylor3473f882001-02-23 17:55:21 +00006146 * Returns the internal content
6147 */
6148
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006149const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006150xmlBufferContent(const xmlBufferPtr buf)
6151{
6152 if(!buf)
6153 return NULL;
6154
6155 return buf->content;
6156}
6157
6158/**
6159 * xmlBufferLength:
6160 * @buf: the buffer
6161 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006162 * Function to get the length of a buffer
6163 *
Owen Taylor3473f882001-02-23 17:55:21 +00006164 * Returns the length of data in the internal content
6165 */
6166
6167int
6168xmlBufferLength(const xmlBufferPtr buf)
6169{
6170 if(!buf)
6171 return 0;
6172
6173 return buf->use;
6174}
6175
6176/**
6177 * xmlBufferResize:
6178 * @buf: the buffer to resize
6179 * @size: the desired size
6180 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006181 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006182 *
6183 * Returns 0 in case of problems, 1 otherwise
6184 */
6185int
6186xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6187{
6188 unsigned int newSize;
6189 xmlChar* rebuf = NULL;
6190
6191 /*take care of empty case*/
6192 newSize = (buf->size ? buf->size*2 : size);
6193
6194 /* Don't resize if we don't have to */
6195 if (size < buf->size)
6196 return 1;
6197
6198 /* figure out new size */
6199 switch (buf->alloc){
6200 case XML_BUFFER_ALLOC_DOUBLEIT:
6201 while (size > newSize) newSize *= 2;
6202 break;
6203 case XML_BUFFER_ALLOC_EXACT:
6204 newSize = size+10;
6205 break;
6206 default:
6207 newSize = size+10;
6208 break;
6209 }
6210
6211 if (buf->content == NULL)
6212 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
6213 else
6214 rebuf = (xmlChar *) xmlRealloc(buf->content,
6215 newSize * sizeof(xmlChar));
6216 if (rebuf == NULL) {
6217 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006218 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006219 return 0;
6220 }
6221 buf->content = rebuf;
6222 buf->size = newSize;
6223
6224 return 1;
6225}
6226
6227/**
6228 * xmlBufferAdd:
6229 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006230 * @str: the #xmlChar string
6231 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006232 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006233 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006234 * str is recomputed.
6235 */
6236void
6237xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6238 unsigned int needSize;
6239
6240 if (str == NULL) {
6241#ifdef DEBUG_BUFFER
6242 xmlGenericError(xmlGenericErrorContext,
6243 "xmlBufferAdd: str == NULL\n");
6244#endif
6245 return;
6246 }
6247 if (len < -1) {
6248#ifdef DEBUG_BUFFER
6249 xmlGenericError(xmlGenericErrorContext,
6250 "xmlBufferAdd: len < 0\n");
6251#endif
6252 return;
6253 }
6254 if (len == 0) return;
6255
6256 if (len < 0)
6257 len = xmlStrlen(str);
6258
6259 if (len <= 0) return;
6260
6261 needSize = buf->use + len + 2;
6262 if (needSize > buf->size){
6263 if (!xmlBufferResize(buf, needSize)){
6264 xmlGenericError(xmlGenericErrorContext,
6265 "xmlBufferAdd : out of memory!\n");
6266 return;
6267 }
6268 }
6269
6270 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6271 buf->use += len;
6272 buf->content[buf->use] = 0;
6273}
6274
6275/**
6276 * xmlBufferAddHead:
6277 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006278 * @str: the #xmlChar string
6279 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006280 *
6281 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006282 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00006283 */
6284void
6285xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6286 unsigned int needSize;
6287
6288 if (str == NULL) {
6289#ifdef DEBUG_BUFFER
6290 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006291 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006292#endif
6293 return;
6294 }
6295 if (len < -1) {
6296#ifdef DEBUG_BUFFER
6297 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006298 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006299#endif
6300 return;
6301 }
6302 if (len == 0) return;
6303
6304 if (len < 0)
6305 len = xmlStrlen(str);
6306
6307 if (len <= 0) return;
6308
6309 needSize = buf->use + len + 2;
6310 if (needSize > buf->size){
6311 if (!xmlBufferResize(buf, needSize)){
6312 xmlGenericError(xmlGenericErrorContext,
6313 "xmlBufferAddHead : out of memory!\n");
6314 return;
6315 }
6316 }
6317
6318 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6319 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6320 buf->use += len;
6321 buf->content[buf->use] = 0;
6322}
6323
6324/**
6325 * xmlBufferCat:
6326 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006327 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006328 *
6329 * Append a zero terminated string to an XML buffer.
6330 */
6331void
6332xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
6333 if (str != NULL)
6334 xmlBufferAdd(buf, str, -1);
6335}
6336
6337/**
6338 * xmlBufferCCat:
6339 * @buf: the buffer to dump
6340 * @str: the C char string
6341 *
6342 * Append a zero terminated C string to an XML buffer.
6343 */
6344void
6345xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6346 const char *cur;
6347
6348 if (str == NULL) {
6349#ifdef DEBUG_BUFFER
6350 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006351 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006352#endif
6353 return;
6354 }
6355 for (cur = str;*cur != 0;cur++) {
6356 if (buf->use + 10 >= buf->size) {
6357 if (!xmlBufferResize(buf, buf->use+10)){
6358 xmlGenericError(xmlGenericErrorContext,
6359 "xmlBufferCCat : out of memory!\n");
6360 return;
6361 }
6362 }
6363 buf->content[buf->use++] = *cur;
6364 }
6365 buf->content[buf->use] = 0;
6366}
6367
6368/**
6369 * xmlBufferWriteCHAR:
6370 * @buf: the XML buffer
6371 * @string: the string to add
6372 *
6373 * routine which manages and grows an output buffer. This one adds
6374 * xmlChars at the end of the buffer.
6375 */
6376void
Owen Taylor3473f882001-02-23 17:55:21 +00006377xmlBufferWriteCHAR
Owen Taylor3473f882001-02-23 17:55:21 +00006378(xmlBufferPtr buf, const xmlChar *string) {
6379 xmlBufferCat(buf, string);
6380}
6381
6382/**
6383 * xmlBufferWriteChar:
6384 * @buf: the XML buffer output
6385 * @string: the string to add
6386 *
6387 * routine which manage and grows an output buffer. This one add
6388 * C chars at the end of the array.
6389 */
6390void
6391xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
6392 xmlBufferCCat(buf, string);
6393}
6394
6395
6396/**
6397 * xmlBufferWriteQuotedString:
6398 * @buf: the XML buffer output
6399 * @string: the string to add
6400 *
6401 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00006402 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00006403 * quote or double-quotes internally
6404 */
6405void
6406xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
6407 if (xmlStrchr(string, '"')) {
6408 if (xmlStrchr(string, '\'')) {
6409#ifdef DEBUG_BUFFER
6410 xmlGenericError(xmlGenericErrorContext,
6411 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
6412#endif
6413 }
6414 xmlBufferCCat(buf, "'");
6415 xmlBufferCat(buf, string);
6416 xmlBufferCCat(buf, "'");
6417 } else {
6418 xmlBufferCCat(buf, "\"");
6419 xmlBufferCat(buf, string);
6420 xmlBufferCCat(buf, "\"");
6421 }
6422}
6423
6424
6425/************************************************************************
6426 * *
6427 * Dumping XML tree content to a simple buffer *
6428 * *
6429 ************************************************************************/
6430
Owen Taylor3473f882001-02-23 17:55:21 +00006431/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00006432 * xmlAttrSerializeContent:
6433 * @buf: the XML buffer output
6434 * @doc: the document
6435 * @attr: the attribute pointer
6436 *
6437 * Serialize the attribute in the buffer
6438 */
6439static void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006440xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr)
6441{
Daniel Veillarda6d05382002-02-13 13:07:41 +00006442 const xmlChar *cur, *base;
6443 xmlNodePtr children;
6444
6445 children = attr->children;
6446 while (children != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006447 switch (children->type) {
6448 case XML_TEXT_NODE:
6449 base = cur = children->content;
6450 while (*cur != 0) {
6451 if (*cur == '\n') {
6452 if (base != cur)
6453 xmlBufferAdd(buf, base, cur - base);
6454 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
6455 cur++;
6456 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006457#if 0
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006458 } else if (*cur == '\'') {
6459 if (base != cur)
6460 xmlBufferAdd(buf, base, cur - base);
6461 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
6462 cur++;
6463 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006464#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006465 } else if (*cur == '"') {
6466 if (base != cur)
6467 xmlBufferAdd(buf, base, cur - base);
6468 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6469 cur++;
6470 base = cur;
6471 } else if (*cur == '<') {
6472 if (base != cur)
6473 xmlBufferAdd(buf, base, cur - base);
6474 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
6475 cur++;
6476 base = cur;
6477 } else if (*cur == '>') {
6478 if (base != cur)
6479 xmlBufferAdd(buf, base, cur - base);
6480 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
6481 cur++;
6482 base = cur;
6483 } else if (*cur == '&') {
6484 if (base != cur)
6485 xmlBufferAdd(buf, base, cur - base);
6486 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
6487 cur++;
6488 base = cur;
6489 } else if ((*cur >= 0x80) && ((doc == NULL) ||
6490 (doc->encoding ==
6491 NULL))) {
6492 /*
6493 * We assume we have UTF-8 content.
6494 */
6495 char tmp[10];
6496 int val = 0, l = 1;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006497
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006498 if (base != cur)
6499 xmlBufferAdd(buf, base, cur - base);
6500 if (*cur < 0xC0) {
6501 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6d05382002-02-13 13:07:41 +00006502 "xmlAttrSerializeContent : input not UTF-8\n");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006503 if (doc != NULL)
6504 doc->encoding =
6505 xmlStrdup(BAD_CAST "ISO-8859-1");
6506 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6507 tmp[sizeof(tmp) - 1] = 0;
6508 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6509 cur++;
6510 base = cur;
6511 continue;
6512 } else if (*cur < 0xE0) {
6513 val = (cur[0]) & 0x1F;
6514 val <<= 6;
6515 val |= (cur[1]) & 0x3F;
6516 l = 2;
6517 } else if (*cur < 0xF0) {
6518 val = (cur[0]) & 0x0F;
6519 val <<= 6;
6520 val |= (cur[1]) & 0x3F;
6521 val <<= 6;
6522 val |= (cur[2]) & 0x3F;
6523 l = 3;
6524 } else if (*cur < 0xF8) {
6525 val = (cur[0]) & 0x07;
6526 val <<= 6;
6527 val |= (cur[1]) & 0x3F;
6528 val <<= 6;
6529 val |= (cur[2]) & 0x3F;
6530 val <<= 6;
6531 val |= (cur[3]) & 0x3F;
6532 l = 4;
6533 }
6534 if ((l == 1) || (!IS_CHAR(val))) {
6535 xmlGenericError(xmlGenericErrorContext,
6536 "xmlAttrSerializeContent : char out of range\n");
6537 if (doc != NULL)
6538 doc->encoding =
6539 xmlStrdup(BAD_CAST "ISO-8859-1");
6540 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6541 tmp[sizeof(tmp) - 1] = 0;
6542 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6543 cur++;
6544 base = cur;
6545 continue;
6546 }
6547 /*
6548 * We could do multiple things here. Just save
6549 * as a char ref
6550 */
6551 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
6552 tmp[sizeof(tmp) - 1] = 0;
6553 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6554 cur += l;
6555 base = cur;
6556 } else {
6557 cur++;
6558 }
6559 }
6560 if (base != cur)
6561 xmlBufferAdd(buf, base, cur - base);
6562 break;
6563 case XML_ENTITY_REF_NODE:
6564 xmlBufferAdd(buf, BAD_CAST "&", 1);
6565 xmlBufferAdd(buf, children->name,
6566 xmlStrlen(children->name));
6567 xmlBufferAdd(buf, BAD_CAST ";", 1);
6568 break;
6569 default:
6570 /* should not happen unless we have a badly built tree */
6571 break;
6572 }
6573 children = children->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006574 }
6575}
6576
6577/**
6578 * xmlNodeDump:
6579 * @buf: the XML buffer output
6580 * @doc: the document
6581 * @cur: the current node
6582 * @level: the imbrication level for indenting
6583 * @format: is formatting allowed
6584 *
6585 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00006586 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006587 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006588 *
6589 * Returns the number of bytes written to the buffer or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00006590 */
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006591int
Owen Taylor3473f882001-02-23 17:55:21 +00006592xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006593 int format)
6594{
6595 unsigned int use;
6596 int ret;
6597 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006598
6599 if (cur == NULL) {
6600#ifdef DEBUG_TREE
6601 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006602 "xmlNodeDump : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006603#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006604 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006605 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006606 if (buf == NULL) {
6607#ifdef DEBUG_TREE
6608 xmlGenericError(xmlGenericErrorContext,
6609 "xmlNodeDump : buf == NULL\n");
6610#endif
6611 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006612 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006613 outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
6614 if (outbuf == NULL) {
6615 xmlGenericError(xmlGenericErrorContext,
6616 "xmlNodeDump: out of memory!\n");
6617 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006618 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006619 memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
6620 outbuf->buffer = buf;
6621 outbuf->encoder = NULL;
6622 outbuf->writecallback = NULL;
6623 outbuf->closecallback = NULL;
6624 outbuf->context = NULL;
6625 outbuf->written = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006626
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006627 use = buf->use;
6628 xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
6629 xmlFree(outbuf);
6630 ret = buf->use - use;
6631 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006632}
6633
6634/**
6635 * xmlElemDump:
6636 * @f: the FILE * for the output
6637 * @doc: the document
6638 * @cur: the current node
6639 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006640 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006641 */
6642void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006643xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur)
6644{
6645 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006646
6647 if (cur == NULL) {
6648#ifdef DEBUG_TREE
6649 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006650 "xmlElemDump : cur == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006651#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006652 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006653 }
Owen Taylor3473f882001-02-23 17:55:21 +00006654#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006655 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006656 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006657 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006658 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006659#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006660
6661 outbuf = xmlOutputBufferCreateFile(f, NULL);
6662 if (outbuf == NULL)
6663 return;
6664 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006665#ifdef LIBXML_HTML_ENABLED
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006666 htmlNodeDumpOutput(outbuf, doc, cur, NULL);
6667#else
6668 xmlGenericError(xmlGenericErrorContext,
6669 "HTML support not compiled in\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006670#endif /* LIBXML_HTML_ENABLED */
6671 } else
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006672 xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL);
6673 xmlOutputBufferClose(outbuf);
Owen Taylor3473f882001-02-23 17:55:21 +00006674}
6675
6676/************************************************************************
6677 * *
6678 * Dumping XML tree content to an I/O output buffer *
6679 * *
6680 ************************************************************************/
6681
Owen Taylor3473f882001-02-23 17:55:21 +00006682static void
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006683xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6684 int level, int format, const char *encoding);
6685static void
Owen Taylor3473f882001-02-23 17:55:21 +00006686xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6687 int level, int format, const char *encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006688static void
6689xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
6690 xmlNodePtr cur, int level, int format, const char *encoding);
6691
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00006692void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
6693
Owen Taylor3473f882001-02-23 17:55:21 +00006694/**
6695 * xmlNsDumpOutput:
6696 * @buf: the XML buffer output
6697 * @cur: a namespace
6698 *
6699 * Dump a local Namespace definition.
6700 * Should be called in the context of attributes dumps.
6701 */
6702static void
6703xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6704 if (cur == NULL) {
6705#ifdef DEBUG_TREE
6706 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006707 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006708#endif
6709 return;
6710 }
6711 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00006712 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
6713 return;
6714
Owen Taylor3473f882001-02-23 17:55:21 +00006715 /* Within the context of an element attributes */
6716 if (cur->prefix != NULL) {
6717 xmlOutputBufferWriteString(buf, " xmlns:");
6718 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6719 } else
6720 xmlOutputBufferWriteString(buf, " xmlns");
6721 xmlOutputBufferWriteString(buf, "=");
6722 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6723 }
6724}
6725
6726/**
6727 * xmlNsListDumpOutput:
6728 * @buf: the XML buffer output
6729 * @cur: the first namespace
6730 *
6731 * Dump a list of local Namespace definitions.
6732 * Should be called in the context of attributes dumps.
6733 */
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00006734void
Owen Taylor3473f882001-02-23 17:55:21 +00006735xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6736 while (cur != NULL) {
6737 xmlNsDumpOutput(buf, cur);
6738 cur = cur->next;
6739 }
6740}
6741
6742/**
6743 * xmlDtdDumpOutput:
6744 * @buf: the XML buffer output
6745 * @doc: the document
6746 * @encoding: an optional encoding string
6747 *
6748 * Dump the XML document DTD, if any.
6749 */
6750static void
6751xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6752 if (dtd == NULL) {
6753#ifdef DEBUG_TREE
6754 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006755 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006756#endif
6757 return;
6758 }
6759 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6760 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6761 if (dtd->ExternalID != NULL) {
6762 xmlOutputBufferWriteString(buf, " PUBLIC ");
6763 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6764 xmlOutputBufferWriteString(buf, " ");
6765 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6766 } else if (dtd->SystemID != NULL) {
6767 xmlOutputBufferWriteString(buf, " SYSTEM ");
6768 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6769 }
6770 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6771 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6772 xmlOutputBufferWriteString(buf, ">");
6773 return;
6774 }
6775 xmlOutputBufferWriteString(buf, " [\n");
6776 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6777 xmlOutputBufferWriteString(buf, "]>");
6778}
6779
6780/**
6781 * xmlAttrDumpOutput:
6782 * @buf: the XML buffer output
6783 * @doc: the document
6784 * @cur: the attribute pointer
6785 * @encoding: an optional encoding string
6786 *
6787 * Dump an XML attribute
6788 */
6789static void
6790xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006791 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006792 if (cur == NULL) {
6793#ifdef DEBUG_TREE
6794 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006795 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006796#endif
6797 return;
6798 }
6799 xmlOutputBufferWriteString(buf, " ");
6800 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6801 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6802 xmlOutputBufferWriteString(buf, ":");
6803 }
6804 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006805 xmlOutputBufferWriteString(buf, "=\"");
6806 xmlAttrSerializeContent(buf->buffer, doc, cur);
6807 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006808}
6809
6810/**
6811 * xmlAttrListDumpOutput:
6812 * @buf: the XML buffer output
6813 * @doc: the document
6814 * @cur: the first attribute pointer
6815 * @encoding: an optional encoding string
6816 *
6817 * Dump a list of XML attributes
6818 */
6819static void
6820xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6821 xmlAttrPtr cur, const char *encoding) {
6822 if (cur == NULL) {
6823#ifdef DEBUG_TREE
6824 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006825 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006826#endif
6827 return;
6828 }
6829 while (cur != NULL) {
6830 xmlAttrDumpOutput(buf, doc, cur, encoding);
6831 cur = cur->next;
6832 }
6833}
6834
6835
6836
6837/**
6838 * xmlNodeListDumpOutput:
6839 * @buf: the XML buffer output
6840 * @doc: the document
6841 * @cur: the first node
6842 * @level: the imbrication level for indenting
6843 * @format: is formatting allowed
6844 * @encoding: an optional encoding string
6845 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006846 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00006847 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006848 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006849 */
6850static void
6851xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6852 xmlNodePtr cur, int level, int format, const char *encoding) {
6853 int i;
6854
6855 if (cur == NULL) {
6856#ifdef DEBUG_TREE
6857 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006858 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006859#endif
6860 return;
6861 }
6862 while (cur != NULL) {
6863 if ((format) && (xmlIndentTreeOutput) &&
6864 (cur->type == XML_ELEMENT_NODE))
6865 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006866 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006867 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00006868 if (format) {
6869 xmlOutputBufferWriteString(buf, "\n");
6870 }
6871 cur = cur->next;
6872 }
6873}
6874
6875/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006876 * xmlNodeDumpOutputInternal:
Owen Taylor3473f882001-02-23 17:55:21 +00006877 * @buf: the XML buffer output
6878 * @doc: the document
6879 * @cur: the current node
6880 * @level: the imbrication level for indenting
6881 * @format: is formatting allowed
6882 * @encoding: an optional encoding string
6883 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006884 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00006885 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006886 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006887 */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006888static void
6889xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
6890 xmlNodePtr cur, int level, int format, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00006891 int i;
6892 xmlNodePtr tmp;
6893
6894 if (cur == NULL) {
6895#ifdef DEBUG_TREE
6896 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006897 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006898#endif
6899 return;
6900 }
6901 if (cur->type == XML_XINCLUDE_START)
6902 return;
6903 if (cur->type == XML_XINCLUDE_END)
6904 return;
6905 if (cur->type == XML_DTD_NODE) {
6906 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6907 return;
6908 }
6909 if (cur->type == XML_ELEMENT_DECL) {
6910 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6911 return;
6912 }
6913 if (cur->type == XML_ATTRIBUTE_DECL) {
6914 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6915 return;
6916 }
6917 if (cur->type == XML_ENTITY_DECL) {
6918 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6919 return;
6920 }
6921 if (cur->type == XML_TEXT_NODE) {
6922 if (cur->content != NULL) {
6923 if ((cur->name == xmlStringText) ||
6924 (cur->name != xmlStringTextNoenc)) {
6925 xmlChar *buffer;
6926
Owen Taylor3473f882001-02-23 17:55:21 +00006927 if (encoding == NULL)
6928 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6929 else
6930 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006931 if (buffer != NULL) {
6932 xmlOutputBufferWriteString(buf, (const char *)buffer);
6933 xmlFree(buffer);
6934 }
6935 } else {
6936 /*
6937 * Disable escaping, needed for XSLT
6938 */
Owen Taylor3473f882001-02-23 17:55:21 +00006939 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006940 }
6941 }
6942
6943 return;
6944 }
6945 if (cur->type == XML_PI_NODE) {
6946 if (cur->content != NULL) {
6947 xmlOutputBufferWriteString(buf, "<?");
6948 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6949 if (cur->content != NULL) {
6950 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00006951 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006952 }
6953 xmlOutputBufferWriteString(buf, "?>");
6954 } else {
6955 xmlOutputBufferWriteString(buf, "<?");
6956 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6957 xmlOutputBufferWriteString(buf, "?>");
6958 }
6959 return;
6960 }
6961 if (cur->type == XML_COMMENT_NODE) {
6962 if (cur->content != NULL) {
6963 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006964 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006965 xmlOutputBufferWriteString(buf, "-->");
6966 }
6967 return;
6968 }
6969 if (cur->type == XML_ENTITY_REF_NODE) {
6970 xmlOutputBufferWriteString(buf, "&");
6971 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6972 xmlOutputBufferWriteString(buf, ";");
6973 return;
6974 }
6975 if (cur->type == XML_CDATA_SECTION_NODE) {
6976 xmlOutputBufferWriteString(buf, "<![CDATA[");
6977 if (cur->content != NULL)
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 return;
6981 }
Daniel Veillard6aa2f602003-02-10 00:01:56 +00006982 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00006983 xmlNsDumpOutput(buf, (xmlNsPtr) cur);
Daniel Veillard6aa2f602003-02-10 00:01:56 +00006984 return;
6985 }
Owen Taylor3473f882001-02-23 17:55:21 +00006986
6987 if (format == 1) {
6988 tmp = cur->children;
6989 while (tmp != NULL) {
6990 if ((tmp->type == XML_TEXT_NODE) ||
6991 (tmp->type == XML_ENTITY_REF_NODE)) {
6992 format = 0;
6993 break;
6994 }
6995 tmp = tmp->next;
6996 }
6997 }
6998 xmlOutputBufferWriteString(buf, "<");
6999 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7000 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7001 xmlOutputBufferWriteString(buf, ":");
7002 }
7003
7004 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7005 if (cur->nsDef)
7006 xmlNsListDumpOutput(buf, cur->nsDef);
7007 if (cur->properties != NULL)
7008 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7009
Daniel Veillard7db37732001-07-12 01:20:08 +00007010 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
7011 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007012 xmlOutputBufferWriteString(buf, "/>");
7013 return;
7014 }
7015 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00007016 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007017 xmlChar *buffer;
7018
Owen Taylor3473f882001-02-23 17:55:21 +00007019 if (encoding == NULL)
7020 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7021 else
7022 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007023 if (buffer != NULL) {
7024 xmlOutputBufferWriteString(buf, (const char *)buffer);
7025 xmlFree(buffer);
7026 }
7027 }
7028 if (cur->children != NULL) {
7029 if (format) xmlOutputBufferWriteString(buf, "\n");
7030 xmlNodeListDumpOutput(buf, doc, cur->children,
7031 (level >= 0?level+1:-1), format, encoding);
7032 if ((xmlIndentTreeOutput) && (format))
7033 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007034 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00007035 }
7036 xmlOutputBufferWriteString(buf, "</");
7037 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7038 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7039 xmlOutputBufferWriteString(buf, ":");
7040 }
7041
7042 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7043 xmlOutputBufferWriteString(buf, ">");
7044}
7045
7046/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007047 * xmlNodeDumpOutput:
7048 * @buf: the XML buffer output
7049 * @doc: the document
7050 * @cur: the current node
7051 * @level: the imbrication level for indenting
7052 * @format: is formatting allowed
7053 * @encoding: an optional encoding string
7054 *
7055 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007056 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007057 * or xmlKeepBlanksDefault(0) was called
7058 */
7059void
7060xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007061 int level, int format, const char *encoding)
7062{
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007063#ifdef LIBXML_HTML_ENABLED
7064 xmlDtdPtr dtd;
7065 int is_xhtml = 0;
7066
7067 dtd = xmlGetIntSubset(doc);
7068 if (dtd != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007069 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7070 if (is_xhtml < 0)
7071 is_xhtml = 0;
7072 if ((is_xhtml) && (cur->parent == (xmlNodePtr) doc) &&
7073 (cur->type == XML_ELEMENT_NODE) &&
7074 (xmlStrEqual(cur->name, BAD_CAST "html"))) {
7075 if (encoding != NULL)
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007076 htmlSetMetaEncoding((htmlDocPtr) doc,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007077 (const xmlChar *) encoding);
7078 else
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007079 htmlSetMetaEncoding((htmlDocPtr) doc, BAD_CAST "UTF-8");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007080 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007081 }
7082
7083 if (is_xhtml)
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007084 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007085 else
7086#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007087 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007088}
7089
7090/**
Owen Taylor3473f882001-02-23 17:55:21 +00007091 * xmlDocContentDumpOutput:
7092 * @buf: the XML buffer output
7093 * @cur: the document
7094 * @encoding: an optional encoding string
7095 * @format: should formatting spaces been added
7096 *
7097 * Dump an XML document.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007098 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007099 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007100 */
7101static void
7102xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
7103 const char *encoding, int format) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007104#ifdef LIBXML_HTML_ENABLED
7105 xmlDtdPtr dtd;
7106 int is_xhtml = 0;
7107#endif
7108
Owen Taylor3473f882001-02-23 17:55:21 +00007109 xmlOutputBufferWriteString(buf, "<?xml version=");
7110 if (cur->version != NULL)
7111 xmlBufferWriteQuotedString(buf->buffer, cur->version);
7112 else
7113 xmlOutputBufferWriteString(buf, "\"1.0\"");
7114 if (encoding == NULL) {
7115 if (cur->encoding != NULL)
7116 encoding = (const char *) cur->encoding;
7117 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
7118 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
7119 }
7120 if (encoding != NULL) {
7121 xmlOutputBufferWriteString(buf, " encoding=");
7122 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
7123 }
7124 switch (cur->standalone) {
7125 case 0:
7126 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
7127 break;
7128 case 1:
7129 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
7130 break;
7131 }
7132 xmlOutputBufferWriteString(buf, "?>\n");
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007133
7134#ifdef LIBXML_HTML_ENABLED
7135 dtd = xmlGetIntSubset(cur);
7136 if (dtd != NULL) {
7137 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7138 if (is_xhtml < 0) is_xhtml = 0;
7139 }
7140 if (is_xhtml) {
7141 if (encoding != NULL)
7142 htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
7143 else
7144 htmlSetMetaEncoding(cur, BAD_CAST "UTF-8");
7145 }
7146#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007147 if (cur->children != NULL) {
7148 xmlNodePtr child = cur->children;
7149
7150 while (child != NULL) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007151#ifdef LIBXML_HTML_ENABLED
7152 if (is_xhtml)
7153 xhtmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
7154 else
7155#endif
7156 xmlNodeDumpOutputInternal(buf, cur, child, 0, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007157 xmlOutputBufferWriteString(buf, "\n");
7158 child = child->next;
7159 }
7160 }
7161}
7162
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007163#ifdef LIBXML_HTML_ENABLED
7164/************************************************************************
7165 * *
7166 * Functions specific to XHTML serialization *
7167 * *
7168 ************************************************************************/
7169
7170#define XHTML_STRICT_PUBLIC_ID BAD_CAST \
7171 "-//W3C//DTD XHTML 1.0 Strict//EN"
7172#define XHTML_STRICT_SYSTEM_ID BAD_CAST \
7173 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
7174#define XHTML_FRAME_PUBLIC_ID BAD_CAST \
7175 "-//W3C//DTD XHTML 1.0 Frameset//EN"
7176#define XHTML_FRAME_SYSTEM_ID BAD_CAST \
7177 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
7178#define XHTML_TRANS_PUBLIC_ID BAD_CAST \
7179 "-//W3C//DTD XHTML 1.0 Transitional//EN"
7180#define XHTML_TRANS_SYSTEM_ID BAD_CAST \
7181 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
7182
7183#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
7184/**
7185 * xmlIsXHTML:
7186 * @systemID: the system identifier
7187 * @publicID: the public identifier
7188 *
7189 * Try to find if the document correspond to an XHTML DTD
7190 *
7191 * Returns 1 if true, 0 if not and -1 in case of error
7192 */
7193int
7194xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) {
7195 if ((systemID == NULL) && (publicID == NULL))
7196 return(-1);
7197 if (publicID != NULL) {
7198 if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1);
7199 if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1);
7200 if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1);
7201 }
7202 if (systemID != NULL) {
7203 if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1);
7204 if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1);
7205 if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1);
7206 }
7207 return(0);
7208}
7209
7210/**
7211 * xhtmlIsEmpty:
7212 * @node: the node
7213 *
7214 * Check if a node is an empty xhtml node
7215 *
7216 * Returns 1 if the node is an empty node, 0 if not and -1 in case of error
7217 */
7218static int
7219xhtmlIsEmpty(xmlNodePtr node) {
7220 if (node == NULL)
7221 return(-1);
7222 if (node->type != XML_ELEMENT_NODE)
7223 return(0);
7224 if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME)))
7225 return(0);
7226 if (node->children != NULL)
7227 return(0);
7228 switch (node->name[0]) {
7229 case 'a':
7230 if (xmlStrEqual(node->name, BAD_CAST "area"))
7231 return(1);
7232 return(0);
7233 case 'b':
7234 if (xmlStrEqual(node->name, BAD_CAST "br"))
7235 return(1);
7236 if (xmlStrEqual(node->name, BAD_CAST "base"))
7237 return(1);
7238 if (xmlStrEqual(node->name, BAD_CAST "basefont"))
7239 return(1);
7240 return(0);
7241 case 'c':
7242 if (xmlStrEqual(node->name, BAD_CAST "col"))
7243 return(1);
7244 return(0);
7245 case 'f':
7246 if (xmlStrEqual(node->name, BAD_CAST "frame"))
7247 return(1);
7248 return(0);
7249 case 'h':
7250 if (xmlStrEqual(node->name, BAD_CAST "hr"))
7251 return(1);
7252 return(0);
7253 case 'i':
7254 if (xmlStrEqual(node->name, BAD_CAST "img"))
7255 return(1);
7256 if (xmlStrEqual(node->name, BAD_CAST "input"))
7257 return(1);
7258 if (xmlStrEqual(node->name, BAD_CAST "isindex"))
7259 return(1);
7260 return(0);
7261 case 'l':
7262 if (xmlStrEqual(node->name, BAD_CAST "link"))
7263 return(1);
7264 return(0);
7265 case 'm':
7266 if (xmlStrEqual(node->name, BAD_CAST "meta"))
7267 return(1);
7268 return(0);
7269 case 'p':
7270 if (xmlStrEqual(node->name, BAD_CAST "param"))
7271 return(1);
7272 return(0);
7273 }
7274 return(0);
7275}
7276
7277/**
7278 * xhtmlAttrListDumpOutput:
7279 * @buf: the XML buffer output
7280 * @doc: the document
7281 * @cur: the first attribute pointer
7282 * @encoding: an optional encoding string
7283 *
7284 * Dump a list of XML attributes
7285 */
7286static void
7287xhtmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7288 xmlAttrPtr cur, const char *encoding) {
7289 xmlAttrPtr xml_lang = NULL;
7290 xmlAttrPtr lang = NULL;
7291 xmlAttrPtr name = NULL;
7292 xmlAttrPtr id = NULL;
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007293 xmlNodePtr parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007294
7295 if (cur == NULL) {
7296#ifdef DEBUG_TREE
7297 xmlGenericError(xmlGenericErrorContext,
7298 "xmlAttrListDumpOutput : property == NULL\n");
7299#endif
7300 return;
7301 }
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007302 parent = cur->parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007303 while (cur != NULL) {
7304 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id")))
7305 id = cur;
7306 else
7307 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name")))
7308 name = cur;
7309 else
7310 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")))
7311 lang = cur;
7312 else
7313 if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) &&
7314 (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml")))
7315 xml_lang = cur;
7316 else if ((cur->ns == NULL) &&
7317 ((cur->children == NULL) ||
7318 (cur->children->content == NULL) ||
7319 (cur->children->content[0] == 0)) &&
7320 (htmlIsBooleanAttr(cur->name))) {
7321 if (cur->children != NULL)
7322 xmlFreeNode(cur->children);
7323 cur->children = xmlNewText(cur->name);
7324 if (cur->children != NULL)
7325 cur->children->parent = (xmlNodePtr) cur;
7326 }
7327 xmlAttrDumpOutput(buf, doc, cur, encoding);
7328 cur = cur->next;
7329 }
7330 /*
7331 * C.8
7332 */
7333 if ((name != NULL) && (id == NULL)) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007334 if ((parent != NULL) && (parent->name != NULL) &&
7335 ((xmlStrEqual(parent->name, BAD_CAST "a")) ||
7336 (xmlStrEqual(parent->name, BAD_CAST "p")) ||
7337 (xmlStrEqual(parent->name, BAD_CAST "div")) ||
7338 (xmlStrEqual(parent->name, BAD_CAST "img")) ||
7339 (xmlStrEqual(parent->name, BAD_CAST "map")) ||
7340 (xmlStrEqual(parent->name, BAD_CAST "applet")) ||
7341 (xmlStrEqual(parent->name, BAD_CAST "form")) ||
7342 (xmlStrEqual(parent->name, BAD_CAST "frame")) ||
7343 (xmlStrEqual(parent->name, BAD_CAST "iframe")))) {
7344 xmlOutputBufferWriteString(buf, " id=\"");
7345 xmlAttrSerializeContent(buf->buffer, doc, name);
7346 xmlOutputBufferWriteString(buf, "\"");
7347 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007348 }
7349 /*
7350 * C.7.
7351 */
7352 if ((lang != NULL) && (xml_lang == NULL)) {
7353 xmlOutputBufferWriteString(buf, " xml:lang=\"");
7354 xmlAttrSerializeContent(buf->buffer, doc, lang);
7355 xmlOutputBufferWriteString(buf, "\"");
7356 } else
7357 if ((xml_lang != NULL) && (lang == NULL)) {
7358 xmlOutputBufferWriteString(buf, " lang=\"");
7359 xmlAttrSerializeContent(buf->buffer, doc, xml_lang);
7360 xmlOutputBufferWriteString(buf, "\"");
7361 }
7362}
7363
7364/**
7365 * xhtmlNodeListDumpOutput:
7366 * @buf: the XML buffer output
7367 * @doc: the XHTML document
7368 * @cur: the first node
7369 * @level: the imbrication level for indenting
7370 * @format: is formatting allowed
7371 * @encoding: an optional encoding string
7372 *
7373 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007374 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007375 * or xmlKeepBlanksDefault(0) was called
7376 */
7377static void
7378xhtmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7379 xmlNodePtr cur, int level, int format, const char *encoding) {
7380 int i;
7381
7382 if (cur == NULL) {
7383#ifdef DEBUG_TREE
7384 xmlGenericError(xmlGenericErrorContext,
7385 "xhtmlNodeListDumpOutput : node == NULL\n");
7386#endif
7387 return;
7388 }
7389 while (cur != NULL) {
7390 if ((format) && (xmlIndentTreeOutput) &&
7391 (cur->type == XML_ELEMENT_NODE))
7392 for (i = 0;i < level;i++)
7393 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7394 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
7395 if (format) {
7396 xmlOutputBufferWriteString(buf, "\n");
7397 }
7398 cur = cur->next;
7399 }
7400}
7401
7402/**
7403 * xhtmlNodeDumpOutput:
7404 * @buf: the XML buffer output
7405 * @doc: the XHTML document
7406 * @cur: the current node
7407 * @level: the imbrication level for indenting
7408 * @format: is formatting allowed
7409 * @encoding: an optional encoding string
7410 *
7411 * Dump an XHTML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007412 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007413 * or xmlKeepBlanksDefault(0) was called
7414 */
7415static void
7416xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7417 int level, int format, const char *encoding) {
7418 int i;
7419 xmlNodePtr tmp;
7420
7421 if (cur == NULL) {
7422#ifdef DEBUG_TREE
7423 xmlGenericError(xmlGenericErrorContext,
7424 "xmlNodeDumpOutput : node == NULL\n");
7425#endif
7426 return;
7427 }
7428 if (cur->type == XML_XINCLUDE_START)
7429 return;
7430 if (cur->type == XML_XINCLUDE_END)
7431 return;
7432 if (cur->type == XML_DTD_NODE) {
7433 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7434 return;
7435 }
7436 if (cur->type == XML_ELEMENT_DECL) {
7437 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7438 return;
7439 }
7440 if (cur->type == XML_ATTRIBUTE_DECL) {
7441 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7442 return;
7443 }
7444 if (cur->type == XML_ENTITY_DECL) {
7445 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7446 return;
7447 }
7448 if (cur->type == XML_TEXT_NODE) {
7449 if (cur->content != NULL) {
7450 if ((cur->name == xmlStringText) ||
7451 (cur->name != xmlStringTextNoenc)) {
7452 xmlChar *buffer;
7453
7454 if (encoding == NULL)
7455 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7456 else
7457 buffer = xmlEncodeSpecialChars(doc, cur->content);
7458 if (buffer != NULL) {
7459 xmlOutputBufferWriteString(buf, (const char *)buffer);
7460 xmlFree(buffer);
7461 }
7462 } else {
7463 /*
7464 * Disable escaping, needed for XSLT
7465 */
7466 xmlOutputBufferWriteString(buf, (const char *) cur->content);
7467 }
7468 }
7469
7470 return;
7471 }
7472 if (cur->type == XML_PI_NODE) {
7473 if (cur->content != NULL) {
7474 xmlOutputBufferWriteString(buf, "<?");
7475 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7476 if (cur->content != NULL) {
7477 xmlOutputBufferWriteString(buf, " ");
7478 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7479 }
7480 xmlOutputBufferWriteString(buf, "?>");
7481 } else {
7482 xmlOutputBufferWriteString(buf, "<?");
7483 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7484 xmlOutputBufferWriteString(buf, "?>");
7485 }
7486 return;
7487 }
7488 if (cur->type == XML_COMMENT_NODE) {
7489 if (cur->content != NULL) {
7490 xmlOutputBufferWriteString(buf, "<!--");
7491 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7492 xmlOutputBufferWriteString(buf, "-->");
7493 }
7494 return;
7495 }
7496 if (cur->type == XML_ENTITY_REF_NODE) {
7497 xmlOutputBufferWriteString(buf, "&");
7498 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7499 xmlOutputBufferWriteString(buf, ";");
7500 return;
7501 }
7502 if (cur->type == XML_CDATA_SECTION_NODE) {
7503 xmlOutputBufferWriteString(buf, "<![CDATA[");
7504 if (cur->content != NULL)
7505 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7506 xmlOutputBufferWriteString(buf, "]]>");
7507 return;
7508 }
7509
7510 if (format == 1) {
7511 tmp = cur->children;
7512 while (tmp != NULL) {
7513 if ((tmp->type == XML_TEXT_NODE) ||
7514 (tmp->type == XML_ENTITY_REF_NODE)) {
7515 format = 0;
7516 break;
7517 }
7518 tmp = tmp->next;
7519 }
7520 }
7521 xmlOutputBufferWriteString(buf, "<");
7522 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7523 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7524 xmlOutputBufferWriteString(buf, ":");
7525 }
7526
7527 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7528 if (cur->nsDef)
7529 xmlNsListDumpOutput(buf, cur->nsDef);
7530 if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
7531 (cur->ns == NULL) && (cur->nsDef == NULL))) {
7532 /*
7533 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
7534 */
7535 xmlOutputBufferWriteString(buf,
7536 " xmlns=\"http://www.w3.org/1999/xhtml\"");
7537 }
7538 if (cur->properties != NULL)
7539 xhtmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7540
7541 if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) {
7542 if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
7543 (xhtmlIsEmpty(cur) == 1)) {
7544 /*
7545 * C.2. Empty Elements
7546 */
7547 xmlOutputBufferWriteString(buf, " />");
7548 } else {
7549 /*
7550 * C.3. Element Minimization and Empty Element Content
7551 */
7552 xmlOutputBufferWriteString(buf, "></");
7553 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7554 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7555 xmlOutputBufferWriteString(buf, ":");
7556 }
7557 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7558 xmlOutputBufferWriteString(buf, ">");
7559 }
7560 return;
7561 }
7562 xmlOutputBufferWriteString(buf, ">");
7563 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
7564 xmlChar *buffer;
7565
7566 if (encoding == NULL)
7567 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7568 else
7569 buffer = xmlEncodeSpecialChars(doc, cur->content);
7570 if (buffer != NULL) {
7571 xmlOutputBufferWriteString(buf, (const char *)buffer);
7572 xmlFree(buffer);
7573 }
7574 }
7575
7576 /*
7577 * 4.8. Script and Style elements
7578 */
7579 if ((cur->type == XML_ELEMENT_NODE) &&
7580 ((xmlStrEqual(cur->name, BAD_CAST "script")) ||
7581 (xmlStrEqual(cur->name, BAD_CAST "style"))) &&
7582 ((cur->ns == NULL) ||
7583 (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) {
7584 xmlNodePtr child = cur->children;
7585
7586 while (child != NULL) {
7587 if ((child->type == XML_TEXT_NODE) ||
7588 (child->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard64b35282002-12-04 15:10:40 +00007589 /*
7590 * Apparently CDATA escaping for style just break on IE,
7591 * mozilla and galeon, so ...
7592 */
7593 if (xmlStrEqual(cur->name, BAD_CAST "style") &&
7594 (xmlStrchr(child->content, '<') == NULL) &&
7595 (xmlStrchr(child->content, '>') == NULL) &&
7596 (xmlStrchr(child->content, '&') == NULL)) {
7597 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7598 } else {
7599 xmlOutputBufferWriteString(buf, "<![CDATA[");
7600 if (child->content != NULL)
7601 xmlOutputBufferWriteString(buf,
7602 (const char *)child->content);
7603 xmlOutputBufferWriteString(buf, "]]>");
7604 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007605 } else {
7606 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7607 }
7608 child = child->next;
7609 }
7610 } else if (cur->children != NULL) {
7611 if (format) xmlOutputBufferWriteString(buf, "\n");
7612 xhtmlNodeListDumpOutput(buf, doc, cur->children,
7613 (level >= 0?level+1:-1), format, encoding);
7614 if ((xmlIndentTreeOutput) && (format))
7615 for (i = 0;i < level;i++)
7616 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7617 }
7618 xmlOutputBufferWriteString(buf, "</");
7619 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7620 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7621 xmlOutputBufferWriteString(buf, ":");
7622 }
7623
7624 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7625 xmlOutputBufferWriteString(buf, ">");
7626}
7627#endif
7628
Owen Taylor3473f882001-02-23 17:55:21 +00007629/************************************************************************
7630 * *
7631 * Saving functions front-ends *
7632 * *
7633 ************************************************************************/
7634
7635/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00007636 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00007637 * @out_doc: Document to generate XML text from
7638 * @doc_txt_ptr: Memory pointer for allocated XML text
7639 * @doc_txt_len: Length of the generated XML text
7640 * @txt_encoding: Character encoding to use when generating XML text
7641 * @format: should formatting spaces been added
7642 *
7643 * Dump the current DOM tree into memory using the character encoding specified
7644 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007645 * allocated memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00007646 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007647 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007648 */
7649
7650void
7651xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007652 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007653 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007654 int dummy = 0;
7655
7656 xmlCharEncoding doc_charset;
7657 xmlOutputBufferPtr out_buff = NULL;
7658 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
7659
7660 if (doc_txt_len == NULL) {
7661 doc_txt_len = &dummy; /* Continue, caller just won't get length */
7662 }
7663
7664 if (doc_txt_ptr == NULL) {
7665 *doc_txt_len = 0;
7666 xmlGenericError(xmlGenericErrorContext,
7667 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
7668 return;
7669 }
7670
7671 *doc_txt_ptr = NULL;
7672 *doc_txt_len = 0;
7673
7674 if (out_doc == NULL) {
7675 /* No document, no output */
7676 xmlGenericError(xmlGenericErrorContext,
7677 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
7678 return;
7679 }
7680
7681 /*
7682 * Validate the encoding value, if provided.
7683 * This logic is copied from xmlSaveFileEnc.
7684 */
7685
7686 if (txt_encoding == NULL)
7687 txt_encoding = (const char *) out_doc->encoding;
7688 if (txt_encoding != NULL) {
7689 doc_charset = xmlParseCharEncoding(txt_encoding);
7690
7691 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
7692 xmlGenericError(xmlGenericErrorContext,
7693 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
7694 return;
7695
7696 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
7697 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
7698 if ( conv_hdlr == NULL ) {
7699 xmlGenericError(xmlGenericErrorContext,
7700 "%s: %s %s '%s'\n",
7701 "xmlDocDumpFormatMemoryEnc",
7702 "Failed to identify encoding handler for",
7703 "character set",
7704 txt_encoding);
7705 return;
7706 }
7707 }
7708 }
7709
7710 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
7711 xmlGenericError(xmlGenericErrorContext,
7712 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
7713 return;
7714 }
7715
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007716 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007717 xmlOutputBufferFlush(out_buff);
7718 if (out_buff->conv != NULL) {
7719 *doc_txt_len = out_buff->conv->use;
7720 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
7721 } else {
7722 *doc_txt_len = out_buff->buffer->use;
7723 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
7724 }
7725 (void)xmlOutputBufferClose(out_buff);
7726
7727 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
7728 *doc_txt_len = 0;
7729 xmlGenericError(xmlGenericErrorContext,
7730 "xmlDocDumpFormatMemoryEnc: %s\n",
7731 "Failed to allocate memory for document text representation.");
7732 }
7733
7734 return;
7735}
7736
7737/**
7738 * xmlDocDumpMemory:
7739 * @cur: the document
7740 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007741 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007742 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007743 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007744 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007745 */
7746void
7747xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
7748 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
7749}
7750
7751/**
7752 * xmlDocDumpFormatMemory:
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 * @format: should formatting spaces been added
7757 *
7758 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007759 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007760 * It's up to the caller to free the memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00007761 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007762 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007763 */
7764void
7765xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
7766 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
7767}
7768
7769/**
7770 * xmlDocDumpMemoryEnc:
7771 * @out_doc: Document to generate XML text from
7772 * @doc_txt_ptr: Memory pointer for allocated XML text
7773 * @doc_txt_len: Length of the generated XML text
7774 * @txt_encoding: Character encoding to use when generating XML text
7775 *
7776 * Dump the current DOM tree into memory using the character encoding specified
7777 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007778 * allocated memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007779 */
7780
7781void
7782xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
7783 int * doc_txt_len, const char * txt_encoding) {
7784 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007785 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007786}
7787
7788/**
7789 * xmlGetDocCompressMode:
7790 * @doc: the document
7791 *
7792 * get the compression ratio for a document, ZLIB based
7793 * Returns 0 (uncompressed) to 9 (max compression)
7794 */
7795int
7796xmlGetDocCompressMode (xmlDocPtr doc) {
7797 if (doc == NULL) return(-1);
7798 return(doc->compression);
7799}
7800
7801/**
7802 * xmlSetDocCompressMode:
7803 * @doc: the document
7804 * @mode: the compression ratio
7805 *
7806 * set the compression ratio for a document, ZLIB based
7807 * Correct values: 0 (uncompressed) to 9 (max compression)
7808 */
7809void
7810xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7811 if (doc == NULL) return;
7812 if (mode < 0) doc->compression = 0;
7813 else if (mode > 9) doc->compression = 9;
7814 else doc->compression = mode;
7815}
7816
7817/**
7818 * xmlGetCompressMode:
7819 *
7820 * get the default compression mode used, ZLIB based.
7821 * Returns 0 (uncompressed) to 9 (max compression)
7822 */
7823int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007824xmlGetCompressMode(void)
7825{
7826 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00007827}
7828
7829/**
7830 * xmlSetCompressMode:
7831 * @mode: the compression ratio
7832 *
7833 * set the default compression mode used, ZLIB based
7834 * Correct values: 0 (uncompressed) to 9 (max compression)
7835 */
7836void
7837xmlSetCompressMode(int mode) {
7838 if (mode < 0) xmlCompressMode = 0;
7839 else if (mode > 9) xmlCompressMode = 9;
7840 else xmlCompressMode = mode;
7841}
7842
7843/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007844 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00007845 * @f: the FILE*
7846 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00007847 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007848 *
7849 * Dump an XML document to an open FILE.
7850 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007851 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007852 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7853 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007854 */
7855int
Daniel Veillard9e412302002-06-10 15:59:44 +00007856xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007857 xmlOutputBufferPtr buf;
7858 const char * encoding;
7859 xmlCharEncodingHandlerPtr handler = NULL;
7860 int ret;
7861
7862 if (cur == NULL) {
7863#ifdef DEBUG_TREE
7864 xmlGenericError(xmlGenericErrorContext,
7865 "xmlDocDump : document == NULL\n");
7866#endif
7867 return(-1);
7868 }
7869 encoding = (const char *) cur->encoding;
7870
7871 if (encoding != NULL) {
7872 xmlCharEncoding enc;
7873
7874 enc = xmlParseCharEncoding(encoding);
7875
7876 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7877 xmlGenericError(xmlGenericErrorContext,
7878 "xmlDocDump: document not in UTF8\n");
7879 return(-1);
7880 }
7881 if (enc != XML_CHAR_ENCODING_UTF8) {
7882 handler = xmlFindCharEncodingHandler(encoding);
7883 if (handler == NULL) {
7884 xmlFree((char *) cur->encoding);
7885 cur->encoding = NULL;
7886 }
7887 }
7888 }
7889 buf = xmlOutputBufferCreateFile(f, handler);
7890 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00007891 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007892
7893 ret = xmlOutputBufferClose(buf);
7894 return(ret);
7895}
7896
7897/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007898 * xmlDocDump:
7899 * @f: the FILE*
7900 * @cur: the document
7901 *
7902 * Dump an XML document to an open FILE.
7903 *
7904 * returns: the number of bytes written or -1 in case of failure.
7905 */
7906int
7907xmlDocDump(FILE *f, xmlDocPtr cur) {
7908 return(xmlDocFormatDump (f, cur, 0));
7909}
7910
7911/**
Owen Taylor3473f882001-02-23 17:55:21 +00007912 * xmlSaveFileTo:
7913 * @buf: an output I/O buffer
7914 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007915 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00007916 *
7917 * Dump an XML document to an I/O buffer.
7918 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007919 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007920 */
7921int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007922xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007923 int ret;
7924
7925 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007926 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007927 ret = xmlOutputBufferClose(buf);
7928 return(ret);
7929}
7930
7931/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00007932 * xmlSaveFormatFileTo:
7933 * @buf: an output I/O buffer
7934 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007935 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00007936 * @format: should formatting spaces been added
7937 *
7938 * Dump an XML document to an I/O buffer.
7939 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007940 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007941 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7942 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardeefd4492001-04-28 16:55:50 +00007943 */
7944int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007945xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00007946 int ret;
7947
7948 if (buf == NULL) return(0);
7949 xmlDocContentDumpOutput(buf, cur, encoding, format);
7950 ret = xmlOutputBufferClose(buf);
7951 return(ret);
7952}
7953
7954/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00007955 * xmlSaveFormatFileEnc:
Daniel Veillardf012a642001-07-23 19:10:52 +00007956 * @filename: the filename or URL to output
7957 * @cur: the document being saved
7958 * @encoding: the name of the encoding to use or NULL.
7959 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00007960 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00007961 * Dump an XML document to a file or an URL.
7962 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007963 * Returns the number of bytes written or -1 in case of error.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007964 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7965 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007966 */
7967int
Daniel Veillardf012a642001-07-23 19:10:52 +00007968xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
7969 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00007970 xmlOutputBufferPtr buf;
7971 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00007972 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00007973 int ret;
7974
Daniel Veillard4dbe77a2003-01-14 00:17:42 +00007975 if (cur == NULL)
7976 return(-1);
7977
Daniel Veillardfb25a512002-01-13 20:32:08 +00007978 if (encoding == NULL)
7979 encoding = (const char *) cur->encoding;
7980
Owen Taylor3473f882001-02-23 17:55:21 +00007981 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00007982
7983 enc = xmlParseCharEncoding(encoding);
7984 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7985 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007986 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007987 return(-1);
7988 }
7989 if (enc != XML_CHAR_ENCODING_UTF8) {
7990 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00007991 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007992 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007993 }
7994 }
7995
Daniel Veillardf012a642001-07-23 19:10:52 +00007996#ifdef HAVE_ZLIB_H
7997 if (cur->compression < 0) cur->compression = xmlCompressMode;
7998#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007999 /*
8000 * save the content to a temp buffer.
8001 */
Daniel Veillardf012a642001-07-23 19:10:52 +00008002 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00008003 if (buf == NULL) return(-1);
8004
Daniel Veillardf012a642001-07-23 19:10:52 +00008005 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008006
8007 ret = xmlOutputBufferClose(buf);
8008 return(ret);
8009}
8010
Daniel Veillardf012a642001-07-23 19:10:52 +00008011
8012/**
8013 * xmlSaveFileEnc:
8014 * @filename: the filename (or URL)
8015 * @cur: the document
8016 * @encoding: the name of an encoding (or NULL)
8017 *
8018 * Dump an XML document, converting it to the given encoding
8019 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008020 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00008021 */
8022int
8023xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
8024 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
8025}
8026
Owen Taylor3473f882001-02-23 17:55:21 +00008027/**
Daniel Veillard67fee942001-04-26 18:59:03 +00008028 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00008029 * @filename: the filename (or URL)
8030 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00008031 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00008032 *
8033 * Dump an XML document to a file. Will use compression if
8034 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00008035 * used. If @format is set then the document will be indented on output.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008036 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8037 * or xmlKeepBlanksDefault(0) was called
Daniel Veillard67fee942001-04-26 18:59:03 +00008038 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008039 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008040 */
8041int
Daniel Veillard67fee942001-04-26 18:59:03 +00008042xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008043 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00008044}
8045
Daniel Veillard67fee942001-04-26 18:59:03 +00008046/**
8047 * xmlSaveFile:
8048 * @filename: the filename (or URL)
8049 * @cur: the document
8050 *
8051 * Dump an XML document to a file. Will use compression if
8052 * compiled in and enabled. If @filename is "-" the stdout file is
8053 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00008054 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00008055 */
8056int
8057xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008058 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00008059}
8060