blob: 67f4399f81222faff3c96a3382cdbc17dcfe32dc [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002 * tree.c : implementation of access function for an XML tree.
Owen Taylor3473f882001-02-23 17:55:21 +00003 *
Daniel Veillardd5c2f922002-11-21 14:10:52 +00004 * References:
5 * XHTML 1.0 W3C REC: http://www.w3.org/TR/2002/REC-xhtml1-20020801/
6 *
Owen Taylor3473f882001-02-23 17:55:21 +00007 * See Copyright for the status of this software.
8 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00009 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000010 *
Owen Taylor3473f882001-02-23 17:55:21 +000011 */
12
Daniel Veillard34ce8be2002-03-18 19:37:11 +000013#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000014#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000015
Owen Taylor3473f882001-02-23 17:55:21 +000016#include <string.h> /* for memset() only ! */
17
18#ifdef HAVE_CTYPE_H
19#include <ctype.h>
20#endif
21#ifdef HAVE_STDLIB_H
22#include <stdlib.h>
23#endif
24#ifdef HAVE_ZLIB_H
25#include <zlib.h>
26#endif
27
28#include <libxml/xmlmemory.h>
29#include <libxml/tree.h>
30#include <libxml/parser.h>
Daniel Veillardb8c9be92001-07-09 16:01:19 +000031#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000032#include <libxml/entities.h>
33#include <libxml/valid.h>
34#include <libxml/xmlerror.h>
Daniel Veillardbdb9ba72001-04-11 11:28:06 +000035#include <libxml/parserInternals.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000036#include <libxml/globals.h>
Daniel Veillardd5c2f922002-11-21 14:10:52 +000037#ifdef LIBXML_HTML_ENABLED
38#include <libxml/HTMLtree.h>
39#endif
Owen Taylor3473f882001-02-23 17:55:21 +000040
Daniel Veillard56a4cb82001-03-24 17:00:36 +000041xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
42
43/************************************************************************
44 * *
45 * A few static variables and macros *
46 * *
47 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +000048/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +000049const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000050/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +000051const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +000052 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000053/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +000054const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
55
Owen Taylor3473f882001-02-23 17:55:21 +000056static int xmlCompressMode = 0;
57static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000058
Owen Taylor3473f882001-02-23 17:55:21 +000059#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
60 xmlNodePtr ulccur = (n)->children; \
61 if (ulccur == NULL) { \
62 (n)->last = NULL; \
63 } else { \
64 while (ulccur->next != NULL) { \
65 ulccur->parent = (n); \
66 ulccur = ulccur->next; \
67 } \
68 ulccur->parent = (n); \
69 (n)->last = ulccur; \
70}}
71
72/* #define DEBUG_BUFFER */
73/* #define DEBUG_TREE */
74
75/************************************************************************
76 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +000077 * Functions to move to entities.c once the *
78 * API freeze is smoothen and they can be made public. *
79 * *
80 ************************************************************************/
81#include <libxml/hash.h>
82
83/**
84 * xmlGetEntityFromDtd:
85 * @dtd: A pointer to the DTD to search
86 * @name: The entity name
87 *
88 * Do an entity lookup in the DTD entity hash table and
89 * return the corresponding entity, if found.
90 *
91 * Returns A pointer to the entity structure or NULL if not found.
92 */
93static xmlEntityPtr
94xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
95 xmlEntitiesTablePtr table;
96
97 if((dtd != NULL) && (dtd->entities != NULL)) {
98 table = (xmlEntitiesTablePtr) dtd->entities;
99 return((xmlEntityPtr) xmlHashLookup(table, name));
100 /* return(xmlGetEntityFromTable(table, name)); */
101 }
102 return(NULL);
103}
104/**
105 * xmlGetParameterEntityFromDtd:
106 * @dtd: A pointer to the DTD to search
107 * @name: The entity name
108 *
109 * Do an entity lookup in the DTD pararmeter entity hash table and
110 * return the corresponding entity, if found.
111 *
112 * Returns A pointer to the entity structure or NULL if not found.
113 */
114static xmlEntityPtr
115xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
116 xmlEntitiesTablePtr table;
117
118 if ((dtd != NULL) && (dtd->pentities != NULL)) {
119 table = (xmlEntitiesTablePtr) dtd->pentities;
120 return((xmlEntityPtr) xmlHashLookup(table, name));
121 /* return(xmlGetEntityFromTable(table, name)); */
122 }
123 return(NULL);
124}
125
126/************************************************************************
127 * *
Daniel Veillardd2298792003-02-14 16:54:11 +0000128 * Check Name, NCName and QName strings *
129 * *
130 ************************************************************************/
131
132#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
133
134/**
135 * xmlValidateNCName:
136 * @value: the value to check
137 * @space: allow spaces in front and end of the string
138 *
139 * Check that a value conforms to the lexical space of NCName
140 *
141 * Returns 0 if this validates, a positive error code number otherwise
142 * and -1 in case of internal or API error.
143 */
144int
145xmlValidateNCName(const xmlChar *value, int space) {
146 const xmlChar *cur = value;
147 int c,l;
148
149 /*
150 * First quick algorithm for ASCII range
151 */
152 if (space)
153 while (IS_BLANK(*cur)) cur++;
154 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
155 (*cur == '_'))
156 cur++;
157 else
158 goto try_complex;
159 while (((*cur >= 'a') && (*cur <= 'z')) ||
160 ((*cur >= 'A') && (*cur <= 'Z')) ||
161 ((*cur >= '0') && (*cur <= '9')) ||
162 (*cur == '_') || (*cur == '-') || (*cur == '.'))
163 cur++;
164 if (space)
165 while (IS_BLANK(*cur)) cur++;
166 if (*cur == 0)
167 return(0);
168
169try_complex:
170 /*
171 * Second check for chars outside the ASCII range
172 */
173 cur = value;
174 c = CUR_SCHAR(cur, l);
175 if (space) {
176 while (IS_BLANK(c)) {
177 cur += l;
178 c = CUR_SCHAR(cur, l);
179 }
180 }
181 if ((!xmlIsLetter(c)) && (c != '_'))
182 return(1);
183 cur += l;
184 c = CUR_SCHAR(cur, l);
185 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') ||
186 (c == '-') || (c == '_') || xmlIsCombining(c) ||
187 xmlIsExtender(c)) {
188 cur += l;
189 c = CUR_SCHAR(cur, l);
190 }
191 if (space) {
192 while (IS_BLANK(c)) {
193 cur += l;
194 c = CUR_SCHAR(cur, l);
195 }
196 }
197 if (c != 0)
198 return(1);
199
200 return(0);
201}
202
203/**
204 * xmlValidateQName:
205 * @value: the value to check
206 * @space: allow spaces in front and end of the string
207 *
208 * Check that a value conforms to the lexical space of QName
209 *
210 * Returns 0 if this validates, a positive error code number otherwise
211 * and -1 in case of internal or API error.
212 */
213int
214xmlValidateQName(const xmlChar *value, int space) {
215 const xmlChar *cur = value;
216 int c,l;
217
218 /*
219 * First quick algorithm for ASCII range
220 */
221 if (space)
222 while (IS_BLANK(*cur)) cur++;
223 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
224 (*cur == '_'))
225 cur++;
226 else
227 goto try_complex;
228 while (((*cur >= 'a') && (*cur <= 'z')) ||
229 ((*cur >= 'A') && (*cur <= 'Z')) ||
230 ((*cur >= '0') && (*cur <= '9')) ||
231 (*cur == '_') || (*cur == '-') || (*cur == '.'))
232 cur++;
233 if (*cur == ':') {
234 cur++;
235 if (((*cur >= 'a') && (*cur <= 'z')) ||
236 ((*cur >= 'A') && (*cur <= 'Z')) ||
237 (*cur == '_'))
238 cur++;
239 else
240 goto try_complex;
241 while (((*cur >= 'a') && (*cur <= 'z')) ||
242 ((*cur >= 'A') && (*cur <= 'Z')) ||
243 ((*cur >= '0') && (*cur <= '9')) ||
244 (*cur == '_') || (*cur == '-') || (*cur == '.'))
245 cur++;
246 }
247 if (space)
248 while (IS_BLANK(*cur)) cur++;
249 if (*cur == 0)
250 return(0);
251
252try_complex:
253 /*
254 * Second check for chars outside the ASCII range
255 */
256 cur = value;
257 c = CUR_SCHAR(cur, l);
258 if (space) {
259 while (IS_BLANK(c)) {
260 cur += l;
261 c = CUR_SCHAR(cur, l);
262 }
263 }
264 if ((!xmlIsLetter(c)) && (c != '_'))
265 return(1);
266 cur += l;
267 c = CUR_SCHAR(cur, l);
268 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') ||
269 (c == '-') || (c == '_') || xmlIsCombining(c) ||
270 xmlIsExtender(c)) {
271 cur += l;
272 c = CUR_SCHAR(cur, l);
273 }
274 if (c == ':') {
275 cur += l;
276 c = CUR_SCHAR(cur, l);
277 if ((!xmlIsLetter(c)) && (c != '_'))
278 return(1);
279 cur += l;
280 c = CUR_SCHAR(cur, l);
281 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') ||
282 (c == '-') || (c == '_') || xmlIsCombining(c) ||
283 xmlIsExtender(c)) {
284 cur += l;
285 c = CUR_SCHAR(cur, l);
286 }
287 }
288 if (space) {
289 while (IS_BLANK(c)) {
290 cur += l;
291 c = CUR_SCHAR(cur, l);
292 }
293 }
294 if (c != 0)
295 return(1);
296 return(0);
297}
298
299/**
300 * xmlValidateName:
301 * @value: the value to check
302 * @space: allow spaces in front and end of the string
303 *
304 * Check that a value conforms to the lexical space of Name
305 *
306 * Returns 0 if this validates, a positive error code number otherwise
307 * and -1 in case of internal or API error.
308 */
309int
310xmlValidateName(const xmlChar *value, int space) {
311 const xmlChar *cur = value;
312 int c,l;
313
314 /*
315 * First quick algorithm for ASCII range
316 */
317 if (space)
318 while (IS_BLANK(*cur)) cur++;
319 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
320 (*cur == '_') || (*cur == ':'))
321 cur++;
322 else
323 goto try_complex;
324 while (((*cur >= 'a') && (*cur <= 'z')) ||
325 ((*cur >= 'A') && (*cur <= 'Z')) ||
326 ((*cur >= '0') && (*cur <= '9')) ||
327 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
328 cur++;
329 if (space)
330 while (IS_BLANK(*cur)) cur++;
331 if (*cur == 0)
332 return(0);
333
334try_complex:
335 /*
336 * Second check for chars outside the ASCII range
337 */
338 cur = value;
339 c = CUR_SCHAR(cur, l);
340 if (space) {
341 while (IS_BLANK(c)) {
342 cur += l;
343 c = CUR_SCHAR(cur, l);
344 }
345 }
346 if ((!xmlIsLetter(c)) && (c != '_') && (c != ':'))
347 return(1);
348 cur += l;
349 c = CUR_SCHAR(cur, l);
350 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') || (c == ':') ||
351 (c == '-') || (c == '_') || xmlIsCombining(c) || xmlIsExtender(c)) {
352 cur += l;
353 c = CUR_SCHAR(cur, l);
354 }
355 if (space) {
356 while (IS_BLANK(c)) {
357 cur += l;
358 c = CUR_SCHAR(cur, l);
359 }
360 }
361 if (c != 0)
362 return(1);
363 return(0);
364}
365
Daniel Veillardd4310742003-02-18 21:12:46 +0000366/**
367 * xmlValidateNMToken:
368 * @value: the value to check
369 * @space: allow spaces in front and end of the string
370 *
371 * Check that a value conforms to the lexical space of NMToken
372 *
373 * Returns 0 if this validates, a positive error code number otherwise
374 * and -1 in case of internal or API error.
375 */
376int
377xmlValidateNMToken(const xmlChar *value, int space) {
378 const xmlChar *cur = value;
379 int c,l;
380
381 /*
382 * First quick algorithm for ASCII range
383 */
384 if (space)
385 while (IS_BLANK(*cur)) cur++;
386 if (((*cur >= 'a') && (*cur <= 'z')) ||
387 ((*cur >= 'A') && (*cur <= 'Z')) ||
388 ((*cur >= '0') && (*cur <= '9')) ||
389 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
390 cur++;
391 else
392 goto try_complex;
393 while (((*cur >= 'a') && (*cur <= 'z')) ||
394 ((*cur >= 'A') && (*cur <= 'Z')) ||
395 ((*cur >= '0') && (*cur <= '9')) ||
396 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
397 cur++;
398 if (space)
399 while (IS_BLANK(*cur)) cur++;
400 if (*cur == 0)
401 return(0);
402
403try_complex:
404 /*
405 * Second check for chars outside the ASCII range
406 */
407 cur = value;
408 c = CUR_SCHAR(cur, l);
409 if (space) {
410 while (IS_BLANK(c)) {
411 cur += l;
412 c = CUR_SCHAR(cur, l);
413 }
414 }
415 if (!(xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') || (c == ':') ||
416 (c == '-') || (c == '_') || xmlIsCombining(c) || xmlIsExtender(c)))
417 return(1);
418 cur += l;
419 c = CUR_SCHAR(cur, l);
420 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') || (c == ':') ||
421 (c == '-') || (c == '_') || xmlIsCombining(c) || xmlIsExtender(c)) {
422 cur += l;
423 c = CUR_SCHAR(cur, l);
424 }
425 if (space) {
426 while (IS_BLANK(c)) {
427 cur += l;
428 c = CUR_SCHAR(cur, l);
429 }
430 }
431 if (c != 0)
432 return(1);
433 return(0);
434}
435
Daniel Veillardd2298792003-02-14 16:54:11 +0000436/************************************************************************
437 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000438 * Allocation and deallocation of basic structures *
439 * *
440 ************************************************************************/
441
442/**
443 * xmlSetBufferAllocationScheme:
444 * @scheme: allocation method to use
445 *
446 * Set the buffer allocation method. Types are
447 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
448 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
449 * improves performance
450 */
451void
452xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
453 xmlBufferAllocScheme = scheme;
454}
455
456/**
457 * xmlGetBufferAllocationScheme:
458 *
459 * Types are
460 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
461 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
462 * improves performance
463 *
464 * Returns the current allocation scheme
465 */
466xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000467xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000468 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000469}
470
471/**
472 * xmlNewNs:
473 * @node: the element carrying the namespace
474 * @href: the URI associated
475 * @prefix: the prefix for the namespace
476 *
477 * Creation of a new Namespace. This function will refuse to create
478 * a namespace with a similar prefix than an existing one present on this
479 * node.
480 * We use href==NULL in the case of an element creation where the namespace
481 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000482 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000483 */
484xmlNsPtr
485xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
486 xmlNsPtr cur;
487
488 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
489 return(NULL);
490
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000491 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
492 return(NULL);
493
Owen Taylor3473f882001-02-23 17:55:21 +0000494 /*
495 * Allocate a new Namespace and fill the fields.
496 */
497 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
498 if (cur == NULL) {
499 xmlGenericError(xmlGenericErrorContext,
500 "xmlNewNs : malloc failed\n");
501 return(NULL);
502 }
503 memset(cur, 0, sizeof(xmlNs));
504 cur->type = XML_LOCAL_NAMESPACE;
505
506 if (href != NULL)
507 cur->href = xmlStrdup(href);
508 if (prefix != NULL)
509 cur->prefix = xmlStrdup(prefix);
510
511 /*
512 * Add it at the end to preserve parsing order ...
513 * and checks for existing use of the prefix
514 */
515 if (node != NULL) {
516 if (node->nsDef == NULL) {
517 node->nsDef = cur;
518 } else {
519 xmlNsPtr prev = node->nsDef;
520
521 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
522 (xmlStrEqual(prev->prefix, cur->prefix))) {
523 xmlFreeNs(cur);
524 return(NULL);
525 }
526 while (prev->next != NULL) {
527 prev = prev->next;
528 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
529 (xmlStrEqual(prev->prefix, cur->prefix))) {
530 xmlFreeNs(cur);
531 return(NULL);
532 }
533 }
534 prev->next = cur;
535 }
536 }
537 return(cur);
538}
539
540/**
541 * xmlSetNs:
542 * @node: a node in the document
543 * @ns: a namespace pointer
544 *
545 * Associate a namespace to a node, a posteriori.
546 */
547void
548xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
549 if (node == NULL) {
550#ifdef DEBUG_TREE
551 xmlGenericError(xmlGenericErrorContext,
552 "xmlSetNs: node == NULL\n");
553#endif
554 return;
555 }
556 node->ns = ns;
557}
558
559/**
560 * xmlFreeNs:
561 * @cur: the namespace pointer
562 *
563 * Free up the structures associated to a namespace
564 */
565void
566xmlFreeNs(xmlNsPtr cur) {
567 if (cur == NULL) {
568#ifdef DEBUG_TREE
569 xmlGenericError(xmlGenericErrorContext,
570 "xmlFreeNs : ns == NULL\n");
571#endif
572 return;
573 }
574 if (cur->href != NULL) xmlFree((char *) cur->href);
575 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000576 xmlFree(cur);
577}
578
579/**
580 * xmlFreeNsList:
581 * @cur: the first namespace pointer
582 *
583 * Free up all the structures associated to the chained namespaces.
584 */
585void
586xmlFreeNsList(xmlNsPtr cur) {
587 xmlNsPtr next;
588 if (cur == NULL) {
589#ifdef DEBUG_TREE
590 xmlGenericError(xmlGenericErrorContext,
591 "xmlFreeNsList : ns == NULL\n");
592#endif
593 return;
594 }
595 while (cur != NULL) {
596 next = cur->next;
597 xmlFreeNs(cur);
598 cur = next;
599 }
600}
601
602/**
603 * xmlNewDtd:
604 * @doc: the document pointer
605 * @name: the DTD name
606 * @ExternalID: the external ID
607 * @SystemID: the system ID
608 *
609 * Creation of a new DTD for the external subset. To create an
610 * internal subset, use xmlCreateIntSubset().
611 *
612 * Returns a pointer to the new DTD structure
613 */
614xmlDtdPtr
615xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
616 const xmlChar *ExternalID, const xmlChar *SystemID) {
617 xmlDtdPtr cur;
618
619 if ((doc != NULL) && (doc->extSubset != NULL)) {
620#ifdef DEBUG_TREE
621 xmlGenericError(xmlGenericErrorContext,
622 "xmlNewDtd(%s): document %s already have a DTD %s\n",
623 /* !!! */ (char *) name, doc->name,
624 /* !!! */ (char *)doc->extSubset->name);
625#endif
626 return(NULL);
627 }
628
629 /*
630 * Allocate a new DTD and fill the fields.
631 */
632 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
633 if (cur == NULL) {
634 xmlGenericError(xmlGenericErrorContext,
635 "xmlNewDtd : malloc failed\n");
636 return(NULL);
637 }
638 memset(cur, 0 , sizeof(xmlDtd));
639 cur->type = XML_DTD_NODE;
640
641 if (name != NULL)
642 cur->name = xmlStrdup(name);
643 if (ExternalID != NULL)
644 cur->ExternalID = xmlStrdup(ExternalID);
645 if (SystemID != NULL)
646 cur->SystemID = xmlStrdup(SystemID);
647 if (doc != NULL)
648 doc->extSubset = cur;
649 cur->doc = doc;
650
Daniel Veillard5335dc52003-01-01 20:59:38 +0000651 if (xmlRegisterNodeDefaultValue)
652 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000653 return(cur);
654}
655
656/**
657 * xmlGetIntSubset:
658 * @doc: the document pointer
659 *
660 * Get the internal subset of a document
661 * Returns a pointer to the DTD structure or NULL if not found
662 */
663
664xmlDtdPtr
665xmlGetIntSubset(xmlDocPtr doc) {
666 xmlNodePtr cur;
667
668 if (doc == NULL)
669 return(NULL);
670 cur = doc->children;
671 while (cur != NULL) {
672 if (cur->type == XML_DTD_NODE)
673 return((xmlDtdPtr) cur);
674 cur = cur->next;
675 }
676 return((xmlDtdPtr) doc->intSubset);
677}
678
679/**
680 * xmlCreateIntSubset:
681 * @doc: the document pointer
682 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000683 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000684 * @SystemID: the system ID
685 *
686 * Create the internal subset of a document
687 * Returns a pointer to the new DTD structure
688 */
689xmlDtdPtr
690xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
691 const xmlChar *ExternalID, const xmlChar *SystemID) {
692 xmlDtdPtr cur;
693
694 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
695#ifdef DEBUG_TREE
696 xmlGenericError(xmlGenericErrorContext,
697
698 "xmlCreateIntSubset(): document %s already have an internal subset\n",
699 doc->name);
700#endif
701 return(NULL);
702 }
703
704 /*
705 * Allocate a new DTD and fill the fields.
706 */
707 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
708 if (cur == NULL) {
709 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000710 "xmlCreateIntSubset : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000711 return(NULL);
712 }
713 memset(cur, 0, sizeof(xmlDtd));
714 cur->type = XML_DTD_NODE;
715
716 if (name != NULL)
717 cur->name = xmlStrdup(name);
718 if (ExternalID != NULL)
719 cur->ExternalID = xmlStrdup(ExternalID);
720 if (SystemID != NULL)
721 cur->SystemID = xmlStrdup(SystemID);
722 if (doc != NULL) {
723 doc->intSubset = cur;
724 cur->parent = doc;
725 cur->doc = doc;
726 if (doc->children == NULL) {
727 doc->children = (xmlNodePtr) cur;
728 doc->last = (xmlNodePtr) cur;
729 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000730 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000731 xmlNodePtr prev;
732
Owen Taylor3473f882001-02-23 17:55:21 +0000733 prev = doc->children;
734 prev->prev = (xmlNodePtr) cur;
735 cur->next = prev;
736 doc->children = (xmlNodePtr) cur;
737 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000738 xmlNodePtr next;
739
740 next = doc->children;
741 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
742 next = next->next;
743 if (next == NULL) {
744 cur->prev = doc->last;
745 cur->prev->next = (xmlNodePtr) cur;
746 cur->next = NULL;
747 doc->last = (xmlNodePtr) cur;
748 } else {
749 cur->next = next;
750 cur->prev = next->prev;
751 if (cur->prev == NULL)
752 doc->children = (xmlNodePtr) cur;
753 else
754 cur->prev->next = (xmlNodePtr) cur;
755 next->prev = (xmlNodePtr) cur;
756 }
Owen Taylor3473f882001-02-23 17:55:21 +0000757 }
758 }
759 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000760
761 if (xmlRegisterNodeDefaultValue)
762 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000763 return(cur);
764}
765
766/**
767 * xmlFreeDtd:
768 * @cur: the DTD structure to free up
769 *
770 * Free a DTD structure.
771 */
772void
773xmlFreeDtd(xmlDtdPtr cur) {
774 if (cur == NULL) {
775#ifdef DEBUG_TREE
776 xmlGenericError(xmlGenericErrorContext,
777 "xmlFreeDtd : DTD == NULL\n");
778#endif
779 return;
780 }
Daniel Veillard5335dc52003-01-01 20:59:38 +0000781
782 if (xmlDeregisterNodeDefaultValue)
783 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
784
Owen Taylor3473f882001-02-23 17:55:21 +0000785 if (cur->children != NULL) {
786 xmlNodePtr next, c = cur->children;
787
788 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000789 * Cleanup all the DTD comments they are not in the DTD
Owen Taylor3473f882001-02-23 17:55:21 +0000790 * indexes.
791 */
792 while (c != NULL) {
793 next = c->next;
794 if (c->type == XML_COMMENT_NODE) {
795 xmlUnlinkNode(c);
796 xmlFreeNode(c);
797 }
798 c = next;
799 }
800 }
801 if (cur->name != NULL) xmlFree((char *) cur->name);
802 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
803 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
804 /* TODO !!! */
805 if (cur->notations != NULL)
806 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
807
808 if (cur->elements != NULL)
809 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
810 if (cur->attributes != NULL)
811 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
812 if (cur->entities != NULL)
813 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
814 if (cur->pentities != NULL)
815 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
816
Owen Taylor3473f882001-02-23 17:55:21 +0000817 xmlFree(cur);
818}
819
820/**
821 * xmlNewDoc:
822 * @version: xmlChar string giving the version of XML "1.0"
823 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000824 * Creates a new XML document
825 *
Owen Taylor3473f882001-02-23 17:55:21 +0000826 * Returns a new document
827 */
828xmlDocPtr
829xmlNewDoc(const xmlChar *version) {
830 xmlDocPtr cur;
831
832 if (version == NULL)
833 version = (const xmlChar *) "1.0";
834
835 /*
836 * Allocate a new document and fill the fields.
837 */
838 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
839 if (cur == NULL) {
840 xmlGenericError(xmlGenericErrorContext,
841 "xmlNewDoc : malloc failed\n");
842 return(NULL);
843 }
844 memset(cur, 0, sizeof(xmlDoc));
845 cur->type = XML_DOCUMENT_NODE;
846
847 cur->version = xmlStrdup(version);
848 cur->standalone = -1;
849 cur->compression = -1; /* not initialized */
850 cur->doc = cur;
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000851 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +0000852
853 if (xmlRegisterNodeDefaultValue)
854 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000855 return(cur);
856}
857
858/**
859 * xmlFreeDoc:
860 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +0000861 *
862 * Free up all the structures used by a document, tree included.
863 */
864void
865xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +0000866 xmlDtdPtr extSubset, intSubset;
867
Owen Taylor3473f882001-02-23 17:55:21 +0000868 if (cur == NULL) {
869#ifdef DEBUG_TREE
870 xmlGenericError(xmlGenericErrorContext,
871 "xmlFreeDoc : document == NULL\n");
872#endif
873 return;
874 }
Daniel Veillard5335dc52003-01-01 20:59:38 +0000875
876 if (xmlDeregisterNodeDefaultValue)
877 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
878
Daniel Veillard76d66f42001-05-16 21:05:17 +0000879 /*
880 * Do this before freeing the children list to avoid ID lookups
881 */
882 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
883 cur->ids = NULL;
884 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
885 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000886 extSubset = cur->extSubset;
887 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +0000888 if (intSubset == extSubset)
889 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000890 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000891 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000892 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000893 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000894 }
Daniel Veillarda9142e72001-06-19 11:07:54 +0000895 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000896 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000897 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000898 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000899 }
900
901 if (cur->children != NULL) xmlFreeNodeList(cur->children);
902
Owen Taylor3473f882001-02-23 17:55:21 +0000903 if (cur->version != NULL) xmlFree((char *) cur->version);
904 if (cur->name != NULL) xmlFree((char *) cur->name);
905 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Owen Taylor3473f882001-02-23 17:55:21 +0000906 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +0000907 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Owen Taylor3473f882001-02-23 17:55:21 +0000908 xmlFree(cur);
909}
910
911/**
912 * xmlStringLenGetNodeList:
913 * @doc: the document
914 * @value: the value of the text
915 * @len: the length of the string value
916 *
917 * Parse the value string and build the node list associated. Should
918 * produce a flat tree with only TEXTs and ENTITY_REFs.
919 * Returns a pointer to the first child
920 */
921xmlNodePtr
922xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
923 xmlNodePtr ret = NULL, last = NULL;
924 xmlNodePtr node;
925 xmlChar *val;
926 const xmlChar *cur = value;
927 const xmlChar *q;
928 xmlEntityPtr ent;
929
930 if (value == NULL) return(NULL);
931
932 q = cur;
933 while ((*cur != 0) && (cur - value < len)) {
934 if (*cur == '&') {
935 /*
936 * Save the current text.
937 */
938 if (cur != q) {
939 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
940 xmlNodeAddContentLen(last, q, cur - q);
941 } else {
942 node = xmlNewDocTextLen(doc, q, cur - q);
943 if (node == NULL) return(ret);
944 if (last == NULL)
945 last = ret = node;
946 else {
947 last->next = node;
948 node->prev = last;
949 last = node;
950 }
951 }
952 }
953 /*
954 * Read the entity string
955 */
956 cur++;
957 q = cur;
958 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
959 if ((*cur == 0) || (cur - value >= len)) {
960#ifdef DEBUG_TREE
961 xmlGenericError(xmlGenericErrorContext,
962 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
963#endif
964 return(ret);
965 }
966 if (cur != q) {
967 /*
968 * Predefined entities don't generate nodes
969 */
970 val = xmlStrndup(q, cur - q);
971 ent = xmlGetDocEntity(doc, val);
972 if ((ent != NULL) &&
973 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
974 if (last == NULL) {
975 node = xmlNewDocText(doc, ent->content);
976 last = ret = node;
977 } else
978 xmlNodeAddContent(last, ent->content);
979
980 } else {
981 /*
982 * Create a new REFERENCE_REF node
983 */
984 node = xmlNewReference(doc, val);
985 if (node == NULL) {
986 if (val != NULL) xmlFree(val);
987 return(ret);
988 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +0000989 else if ((ent != NULL) && (ent->children == NULL)) {
990 xmlNodePtr tmp;
991
992 ent->children =
993 xmlStringGetNodeList(doc, (const xmlChar*)node->content);
994 tmp = ent->children;
995 while (tmp) {
996 tmp->parent = (xmlNodePtr)ent;
997 tmp = tmp->next;
998 }
999 }
Owen Taylor3473f882001-02-23 17:55:21 +00001000 if (last == NULL)
1001 last = ret = node;
1002 else {
1003 last->next = node;
1004 node->prev = last;
1005 last = node;
1006 }
1007 }
1008 xmlFree(val);
1009 }
1010 cur++;
1011 q = cur;
1012 } else
1013 cur++;
1014 }
1015 if (cur != q) {
1016 /*
1017 * Handle the last piece of text.
1018 */
1019 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1020 xmlNodeAddContentLen(last, q, cur - q);
1021 } else {
1022 node = xmlNewDocTextLen(doc, q, cur - q);
1023 if (node == NULL) return(ret);
1024 if (last == NULL)
1025 last = ret = node;
1026 else {
1027 last->next = node;
1028 node->prev = last;
1029 last = node;
1030 }
1031 }
1032 }
1033 return(ret);
1034}
1035
1036/**
1037 * xmlStringGetNodeList:
1038 * @doc: the document
1039 * @value: the value of the attribute
1040 *
1041 * Parse the value string and build the node list associated. Should
1042 * produce a flat tree with only TEXTs and ENTITY_REFs.
1043 * Returns a pointer to the first child
1044 */
1045xmlNodePtr
1046xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1047 xmlNodePtr ret = NULL, last = NULL;
1048 xmlNodePtr node;
1049 xmlChar *val;
1050 const xmlChar *cur = value;
1051 const xmlChar *q;
1052 xmlEntityPtr ent;
1053
1054 if (value == NULL) return(NULL);
1055
1056 q = cur;
1057 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001058 if (cur[0] == '&') {
1059 int charval = 0;
1060 xmlChar tmp;
1061
Owen Taylor3473f882001-02-23 17:55:21 +00001062 /*
1063 * Save the current text.
1064 */
1065 if (cur != q) {
1066 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1067 xmlNodeAddContentLen(last, q, cur - q);
1068 } else {
1069 node = xmlNewDocTextLen(doc, q, cur - q);
1070 if (node == NULL) return(ret);
1071 if (last == NULL)
1072 last = ret = node;
1073 else {
1074 last->next = node;
1075 node->prev = last;
1076 last = node;
1077 }
1078 }
1079 }
Owen Taylor3473f882001-02-23 17:55:21 +00001080 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001081 if ((cur[1] == '#') && (cur[2] == 'x')) {
1082 cur += 3;
1083 tmp = *cur;
1084 while (tmp != ';') { /* Non input consuming loop */
1085 if ((tmp >= '0') && (tmp <= '9'))
1086 charval = charval * 16 + (tmp - '0');
1087 else if ((tmp >= 'a') && (tmp <= 'f'))
1088 charval = charval * 16 + (tmp - 'a') + 10;
1089 else if ((tmp >= 'A') && (tmp <= 'F'))
1090 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001091 else {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001092 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001093 "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001094 charval = 0;
1095 break;
1096 }
1097 cur++;
1098 tmp = *cur;
1099 }
1100 if (tmp == ';')
1101 cur++;
1102 q = cur;
1103 } else if (cur[1] == '#') {
1104 cur += 2;
1105 tmp = *cur;
1106 while (tmp != ';') { /* Non input consuming loops */
1107 if ((tmp >= '0') && (tmp <= '9'))
1108 charval = charval * 10 + (tmp - '0');
1109 else {
1110 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001111 "xmlStringGetNodeList: invalid decimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001112 charval = 0;
1113 break;
1114 }
1115 cur++;
1116 tmp = *cur;
1117 }
1118 if (tmp == ';')
1119 cur++;
1120 q = cur;
1121 } else {
1122 /*
1123 * Read the entity string
1124 */
1125 cur++;
1126 q = cur;
1127 while ((*cur != 0) && (*cur != ';')) cur++;
1128 if (*cur == 0) {
1129#ifdef DEBUG_TREE
1130 xmlGenericError(xmlGenericErrorContext,
1131 "xmlStringGetNodeList: unterminated entity %30s\n", q);
1132#endif
1133 return(ret);
1134 }
1135 if (cur != q) {
1136 /*
1137 * Predefined entities don't generate nodes
1138 */
1139 val = xmlStrndup(q, cur - q);
1140 ent = xmlGetDocEntity(doc, val);
1141 if ((ent != NULL) &&
1142 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1143 if (last == NULL) {
1144 node = xmlNewDocText(doc, ent->content);
1145 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001146 } else if (last->type != XML_TEXT_NODE) {
1147 node = xmlNewDocText(doc, ent->content);
1148 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001149 } else
1150 xmlNodeAddContent(last, ent->content);
1151
1152 } else {
1153 /*
1154 * Create a new REFERENCE_REF node
1155 */
1156 node = xmlNewReference(doc, val);
1157 if (node == NULL) {
1158 if (val != NULL) xmlFree(val);
1159 return(ret);
1160 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001161 else if ((ent != NULL) && (ent->children == NULL)) {
1162 xmlNodePtr temp;
1163
1164 ent->children = xmlStringGetNodeList(doc,
1165 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001166 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001167 temp = ent->children;
1168 while (temp) {
1169 temp->parent = (xmlNodePtr)ent;
1170 temp = temp->next;
1171 }
1172 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001173 if (last == NULL) {
1174 last = ret = node;
1175 } else {
1176 last = xmlAddNextSibling(last, node);
1177 }
1178 }
1179 xmlFree(val);
1180 }
1181 cur++;
1182 q = cur;
1183 }
1184 if (charval != 0) {
1185 xmlChar buf[10];
1186 int len;
1187
1188 len = xmlCopyCharMultiByte(buf, charval);
1189 buf[len] = 0;
1190 node = xmlNewDocText(doc, buf);
1191 if (node != NULL) {
1192 if (last == NULL) {
1193 last = ret = node;
1194 } else {
1195 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001196 }
1197 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001198
1199 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001200 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001201 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001202 cur++;
1203 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001204 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001205 /*
1206 * Handle the last piece of text.
1207 */
1208 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1209 xmlNodeAddContentLen(last, q, cur - q);
1210 } else {
1211 node = xmlNewDocTextLen(doc, q, cur - q);
1212 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001213 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001214 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001215 } else {
1216 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001217 }
1218 }
1219 }
1220 return(ret);
1221}
1222
1223/**
1224 * xmlNodeListGetString:
1225 * @doc: the document
1226 * @list: a Node list
1227 * @inLine: should we replace entity contents or show their external form
1228 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001229 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001230 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001231 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001232 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001233 */
1234xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001235xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1236{
Owen Taylor3473f882001-02-23 17:55:21 +00001237 xmlNodePtr node = list;
1238 xmlChar *ret = NULL;
1239 xmlEntityPtr ent;
1240
Daniel Veillard7646b182002-04-20 06:41:40 +00001241 if (list == NULL)
1242 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001243
1244 while (node != NULL) {
1245 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001246 (node->type == XML_CDATA_SECTION_NODE)) {
1247 if (inLine) {
1248 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001249 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001250 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001251
Daniel Veillard7646b182002-04-20 06:41:40 +00001252 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1253 if (buffer != NULL) {
1254 ret = xmlStrcat(ret, buffer);
1255 xmlFree(buffer);
1256 }
1257 }
1258 } else if (node->type == XML_ENTITY_REF_NODE) {
1259 if (inLine) {
1260 ent = xmlGetDocEntity(doc, node->name);
1261 if (ent != NULL) {
1262 xmlChar *buffer;
1263
1264 /* an entity content can be any "well balanced chunk",
1265 * i.e. the result of the content [43] production:
1266 * http://www.w3.org/TR/REC-xml#NT-content.
1267 * So it can contain text, CDATA section or nested
1268 * entity reference nodes (among others).
1269 * -> we recursive call xmlNodeListGetString()
1270 * which handles these types */
1271 buffer = xmlNodeListGetString(doc, ent->children, 1);
1272 if (buffer != NULL) {
1273 ret = xmlStrcat(ret, buffer);
1274 xmlFree(buffer);
1275 }
1276 } else {
1277 ret = xmlStrcat(ret, node->content);
1278 }
1279 } else {
1280 xmlChar buf[2];
1281
1282 buf[0] = '&';
1283 buf[1] = 0;
1284 ret = xmlStrncat(ret, buf, 1);
1285 ret = xmlStrcat(ret, node->name);
1286 buf[0] = ';';
1287 buf[1] = 0;
1288 ret = xmlStrncat(ret, buf, 1);
1289 }
1290 }
1291#if 0
1292 else {
1293 xmlGenericError(xmlGenericErrorContext,
1294 "xmlGetNodeListString : invalid node type %d\n",
1295 node->type);
1296 }
1297#endif
1298 node = node->next;
1299 }
1300 return (ret);
1301}
Owen Taylor3473f882001-02-23 17:55:21 +00001302/**
1303 * xmlNodeListGetRawString:
1304 * @doc: the document
1305 * @list: a Node list
1306 * @inLine: should we replace entity contents or show their external form
1307 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001308 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001309 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1310 * this function doesn't do any character encoding handling.
1311 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001312 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001313 */
1314xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001315xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1316{
Owen Taylor3473f882001-02-23 17:55:21 +00001317 xmlNodePtr node = list;
1318 xmlChar *ret = NULL;
1319 xmlEntityPtr ent;
1320
Daniel Veillard7646b182002-04-20 06:41:40 +00001321 if (list == NULL)
1322 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001323
1324 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001325 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001326 (node->type == XML_CDATA_SECTION_NODE)) {
1327 if (inLine) {
1328 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001329 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001330 xmlChar *buffer;
1331
1332 buffer = xmlEncodeSpecialChars(doc, node->content);
1333 if (buffer != NULL) {
1334 ret = xmlStrcat(ret, buffer);
1335 xmlFree(buffer);
1336 }
1337 }
1338 } else if (node->type == XML_ENTITY_REF_NODE) {
1339 if (inLine) {
1340 ent = xmlGetDocEntity(doc, node->name);
1341 if (ent != NULL) {
1342 xmlChar *buffer;
1343
1344 /* an entity content can be any "well balanced chunk",
1345 * i.e. the result of the content [43] production:
1346 * http://www.w3.org/TR/REC-xml#NT-content.
1347 * So it can contain text, CDATA section or nested
1348 * entity reference nodes (among others).
1349 * -> we recursive call xmlNodeListGetRawString()
1350 * which handles these types */
1351 buffer =
1352 xmlNodeListGetRawString(doc, ent->children, 1);
1353 if (buffer != NULL) {
1354 ret = xmlStrcat(ret, buffer);
1355 xmlFree(buffer);
1356 }
1357 } else {
1358 ret = xmlStrcat(ret, node->content);
1359 }
1360 } else {
1361 xmlChar buf[2];
1362
1363 buf[0] = '&';
1364 buf[1] = 0;
1365 ret = xmlStrncat(ret, buf, 1);
1366 ret = xmlStrcat(ret, node->name);
1367 buf[0] = ';';
1368 buf[1] = 0;
1369 ret = xmlStrncat(ret, buf, 1);
1370 }
1371 }
Owen Taylor3473f882001-02-23 17:55:21 +00001372#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001373 else {
1374 xmlGenericError(xmlGenericErrorContext,
1375 "xmlGetNodeListString : invalid node type %d\n",
1376 node->type);
1377 }
Owen Taylor3473f882001-02-23 17:55:21 +00001378#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001379 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001380 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001381 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001382}
1383
1384/**
1385 * xmlNewProp:
1386 * @node: the holding node
1387 * @name: the name of the attribute
1388 * @value: the value of the attribute
1389 *
1390 * Create a new property carried by a node.
1391 * Returns a pointer to the attribute
1392 */
1393xmlAttrPtr
1394xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1395 xmlAttrPtr cur;
1396 xmlDocPtr doc = NULL;
1397
1398 if (name == NULL) {
1399#ifdef DEBUG_TREE
1400 xmlGenericError(xmlGenericErrorContext,
1401 "xmlNewProp : name == NULL\n");
1402#endif
1403 return(NULL);
1404 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00001405 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
1406 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001407
1408 /*
1409 * Allocate a new property and fill the fields.
1410 */
1411 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1412 if (cur == NULL) {
1413 xmlGenericError(xmlGenericErrorContext,
1414 "xmlNewProp : malloc failed\n");
1415 return(NULL);
1416 }
1417 memset(cur, 0, sizeof(xmlAttr));
1418 cur->type = XML_ATTRIBUTE_NODE;
1419
1420 cur->parent = node;
1421 if (node != NULL) {
1422 doc = node->doc;
1423 cur->doc = doc;
1424 }
1425 cur->name = xmlStrdup(name);
1426 if (value != NULL) {
1427 xmlChar *buffer;
1428 xmlNodePtr tmp;
1429
1430 buffer = xmlEncodeEntitiesReentrant(doc, value);
1431 cur->children = xmlStringGetNodeList(doc, buffer);
1432 cur->last = NULL;
1433 tmp = cur->children;
1434 while (tmp != NULL) {
1435 tmp->parent = (xmlNodePtr) cur;
1436 tmp->doc = doc;
1437 if (tmp->next == NULL)
1438 cur->last = tmp;
1439 tmp = tmp->next;
1440 }
1441 xmlFree(buffer);
1442 }
1443
1444 /*
1445 * Add it at the end to preserve parsing order ...
1446 */
1447 if (node != NULL) {
1448 if (node->properties == NULL) {
1449 node->properties = cur;
1450 } else {
1451 xmlAttrPtr prev = node->properties;
1452
1453 while (prev->next != NULL) prev = prev->next;
1454 prev->next = cur;
1455 cur->prev = prev;
1456 }
1457 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001458
1459 if (xmlRegisterNodeDefaultValue)
1460 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001461 return(cur);
1462}
1463
1464/**
1465 * xmlNewNsProp:
1466 * @node: the holding node
1467 * @ns: the namespace
1468 * @name: the name of the attribute
1469 * @value: the value of the attribute
1470 *
1471 * Create a new property tagged with a namespace and carried by a node.
1472 * Returns a pointer to the attribute
1473 */
1474xmlAttrPtr
1475xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1476 const xmlChar *value) {
1477 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001478 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001479
1480 if (name == NULL) {
1481#ifdef DEBUG_TREE
1482 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001483 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001484#endif
1485 return(NULL);
1486 }
1487
1488 /*
1489 * Allocate a new property and fill the fields.
1490 */
1491 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1492 if (cur == NULL) {
1493 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001494 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001495 return(NULL);
1496 }
1497 memset(cur, 0, sizeof(xmlAttr));
1498 cur->type = XML_ATTRIBUTE_NODE;
1499
1500 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001501 if (node != NULL) {
1502 doc = node->doc;
1503 cur->doc = doc;
1504 }
Owen Taylor3473f882001-02-23 17:55:21 +00001505 cur->ns = ns;
1506 cur->name = xmlStrdup(name);
1507 if (value != NULL) {
1508 xmlChar *buffer;
1509 xmlNodePtr tmp;
1510
Daniel Veillarda682b212001-06-07 19:59:42 +00001511 buffer = xmlEncodeEntitiesReentrant(doc, value);
1512 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001513 cur->last = NULL;
1514 tmp = cur->children;
1515 while (tmp != NULL) {
1516 tmp->parent = (xmlNodePtr) cur;
1517 if (tmp->next == NULL)
1518 cur->last = tmp;
1519 tmp = tmp->next;
1520 }
1521 xmlFree(buffer);
1522 }
1523
1524 /*
1525 * Add it at the end to preserve parsing order ...
1526 */
1527 if (node != NULL) {
1528 if (node->properties == NULL) {
1529 node->properties = cur;
1530 } else {
1531 xmlAttrPtr prev = node->properties;
1532
1533 while (prev->next != NULL) prev = prev->next;
1534 prev->next = cur;
1535 cur->prev = prev;
1536 }
1537 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001538
1539 if (xmlRegisterNodeDefaultValue)
1540 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001541 return(cur);
1542}
1543
1544/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001545 * xmlNewNsPropEatName:
1546 * @node: the holding node
1547 * @ns: the namespace
1548 * @name: the name of the attribute
1549 * @value: the value of the attribute
1550 *
1551 * Create a new property tagged with a namespace and carried by a node.
1552 * Returns a pointer to the attribute
1553 */
1554xmlAttrPtr
1555xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1556 const xmlChar *value) {
1557 xmlAttrPtr cur;
1558 xmlDocPtr doc = NULL;
1559
1560 if (name == NULL) {
1561#ifdef DEBUG_TREE
1562 xmlGenericError(xmlGenericErrorContext,
1563 "xmlNewNsPropEatName : name == NULL\n");
1564#endif
1565 return(NULL);
1566 }
1567
1568 /*
1569 * Allocate a new property and fill the fields.
1570 */
1571 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1572 if (cur == NULL) {
1573 xmlGenericError(xmlGenericErrorContext,
1574 "xmlNewNsPropEatName : malloc failed\n");
1575 return(NULL);
1576 }
1577 memset(cur, 0, sizeof(xmlAttr));
1578 cur->type = XML_ATTRIBUTE_NODE;
1579
1580 cur->parent = node;
1581 if (node != NULL) {
1582 doc = node->doc;
1583 cur->doc = doc;
1584 }
1585 cur->ns = ns;
1586 cur->name = name;
1587 if (value != NULL) {
1588 xmlChar *buffer;
1589 xmlNodePtr tmp;
1590
1591 buffer = xmlEncodeEntitiesReentrant(doc, value);
1592 cur->children = xmlStringGetNodeList(doc, buffer);
1593 cur->last = NULL;
1594 tmp = cur->children;
1595 while (tmp != NULL) {
1596 tmp->parent = (xmlNodePtr) cur;
1597 if (tmp->next == NULL)
1598 cur->last = tmp;
1599 tmp = tmp->next;
1600 }
1601 xmlFree(buffer);
1602 }
1603
1604 /*
1605 * Add it at the end to preserve parsing order ...
1606 */
1607 if (node != NULL) {
1608 if (node->properties == NULL) {
1609 node->properties = cur;
1610 } else {
1611 xmlAttrPtr prev = node->properties;
1612
1613 while (prev->next != NULL) prev = prev->next;
1614 prev->next = cur;
1615 cur->prev = prev;
1616 }
1617 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001618
1619 if (xmlRegisterNodeDefaultValue)
1620 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001621 return(cur);
1622}
1623
1624/**
Owen Taylor3473f882001-02-23 17:55:21 +00001625 * xmlNewDocProp:
1626 * @doc: the document
1627 * @name: the name of the attribute
1628 * @value: the value of the attribute
1629 *
1630 * Create a new property carried by a document.
1631 * Returns a pointer to the attribute
1632 */
1633xmlAttrPtr
1634xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1635 xmlAttrPtr cur;
1636
1637 if (name == NULL) {
1638#ifdef DEBUG_TREE
1639 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001640 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001641#endif
1642 return(NULL);
1643 }
1644
1645 /*
1646 * Allocate a new property and fill the fields.
1647 */
1648 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1649 if (cur == NULL) {
1650 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001651 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001652 return(NULL);
1653 }
1654 memset(cur, 0, sizeof(xmlAttr));
1655 cur->type = XML_ATTRIBUTE_NODE;
1656
1657 cur->name = xmlStrdup(name);
1658 cur->doc = doc;
1659 if (value != NULL) {
1660 xmlNodePtr tmp;
1661
1662 cur->children = xmlStringGetNodeList(doc, value);
1663 cur->last = NULL;
1664
1665 tmp = cur->children;
1666 while (tmp != NULL) {
1667 tmp->parent = (xmlNodePtr) cur;
1668 if (tmp->next == NULL)
1669 cur->last = tmp;
1670 tmp = tmp->next;
1671 }
1672 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001673
1674 if (xmlRegisterNodeDefaultValue)
1675 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001676 return(cur);
1677}
1678
1679/**
1680 * xmlFreePropList:
1681 * @cur: the first property in the list
1682 *
1683 * Free a property and all its siblings, all the children are freed too.
1684 */
1685void
1686xmlFreePropList(xmlAttrPtr cur) {
1687 xmlAttrPtr next;
1688 if (cur == NULL) {
1689#ifdef DEBUG_TREE
1690 xmlGenericError(xmlGenericErrorContext,
1691 "xmlFreePropList : property == NULL\n");
1692#endif
1693 return;
1694 }
1695 while (cur != NULL) {
1696 next = cur->next;
1697 xmlFreeProp(cur);
1698 cur = next;
1699 }
1700}
1701
1702/**
1703 * xmlFreeProp:
1704 * @cur: an attribute
1705 *
1706 * Free one attribute, all the content is freed too
1707 */
1708void
1709xmlFreeProp(xmlAttrPtr cur) {
1710 if (cur == NULL) {
1711#ifdef DEBUG_TREE
1712 xmlGenericError(xmlGenericErrorContext,
1713 "xmlFreeProp : property == NULL\n");
1714#endif
1715 return;
1716 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001717
1718 if (xmlDeregisterNodeDefaultValue)
1719 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1720
Owen Taylor3473f882001-02-23 17:55:21 +00001721 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001722 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1723 ((cur->parent->doc->intSubset != NULL) ||
1724 (cur->parent->doc->extSubset != NULL))) {
1725 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1726 xmlRemoveID(cur->parent->doc, cur);
1727 }
Owen Taylor3473f882001-02-23 17:55:21 +00001728 if (cur->name != NULL) xmlFree((char *) cur->name);
1729 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001730 xmlFree(cur);
1731}
1732
1733/**
1734 * xmlRemoveProp:
1735 * @cur: an attribute
1736 *
1737 * Unlink and free one attribute, all the content is freed too
1738 * Note this doesn't work for namespace definition attributes
1739 *
1740 * Returns 0 if success and -1 in case of error.
1741 */
1742int
1743xmlRemoveProp(xmlAttrPtr cur) {
1744 xmlAttrPtr tmp;
1745 if (cur == NULL) {
1746#ifdef DEBUG_TREE
1747 xmlGenericError(xmlGenericErrorContext,
1748 "xmlRemoveProp : cur == NULL\n");
1749#endif
1750 return(-1);
1751 }
1752 if (cur->parent == NULL) {
1753#ifdef DEBUG_TREE
1754 xmlGenericError(xmlGenericErrorContext,
1755 "xmlRemoveProp : cur->parent == NULL\n");
1756#endif
1757 return(-1);
1758 }
1759 tmp = cur->parent->properties;
1760 if (tmp == cur) {
1761 cur->parent->properties = cur->next;
1762 xmlFreeProp(cur);
1763 return(0);
1764 }
1765 while (tmp != NULL) {
1766 if (tmp->next == cur) {
1767 tmp->next = cur->next;
1768 if (tmp->next != NULL)
1769 tmp->next->prev = tmp;
1770 xmlFreeProp(cur);
1771 return(0);
1772 }
1773 tmp = tmp->next;
1774 }
1775#ifdef DEBUG_TREE
1776 xmlGenericError(xmlGenericErrorContext,
1777 "xmlRemoveProp : attribute not owned by its node\n");
1778#endif
1779 return(-1);
1780}
1781
1782/**
1783 * xmlNewPI:
1784 * @name: the processing instruction name
1785 * @content: the PI content
1786 *
1787 * Creation of a processing instruction element.
1788 * Returns a pointer to the new node object.
1789 */
1790xmlNodePtr
1791xmlNewPI(const xmlChar *name, const xmlChar *content) {
1792 xmlNodePtr cur;
1793
1794 if (name == NULL) {
1795#ifdef DEBUG_TREE
1796 xmlGenericError(xmlGenericErrorContext,
1797 "xmlNewPI : name == NULL\n");
1798#endif
1799 return(NULL);
1800 }
1801
1802 /*
1803 * Allocate a new node and fill the fields.
1804 */
1805 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1806 if (cur == NULL) {
1807 xmlGenericError(xmlGenericErrorContext,
1808 "xmlNewPI : malloc failed\n");
1809 return(NULL);
1810 }
1811 memset(cur, 0, sizeof(xmlNode));
1812 cur->type = XML_PI_NODE;
1813
1814 cur->name = xmlStrdup(name);
1815 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001816 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001817 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001818
1819 if (xmlRegisterNodeDefaultValue)
1820 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001821 return(cur);
1822}
1823
1824/**
1825 * xmlNewNode:
1826 * @ns: namespace if any
1827 * @name: the node name
1828 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001829 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001830 *
1831 * Returns a pointer to the new node object.
1832 */
1833xmlNodePtr
1834xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1835 xmlNodePtr cur;
1836
1837 if (name == NULL) {
1838#ifdef DEBUG_TREE
1839 xmlGenericError(xmlGenericErrorContext,
1840 "xmlNewNode : name == NULL\n");
1841#endif
1842 return(NULL);
1843 }
1844
1845 /*
1846 * Allocate a new node and fill the fields.
1847 */
1848 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1849 if (cur == NULL) {
1850 xmlGenericError(xmlGenericErrorContext,
1851 "xmlNewNode : malloc failed\n");
1852 return(NULL);
1853 }
1854 memset(cur, 0, sizeof(xmlNode));
1855 cur->type = XML_ELEMENT_NODE;
1856
1857 cur->name = xmlStrdup(name);
1858 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001859
1860 if (xmlRegisterNodeDefaultValue)
1861 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001862 return(cur);
1863}
1864
1865/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001866 * xmlNewNodeEatName:
1867 * @ns: namespace if any
1868 * @name: the node name
1869 *
1870 * Creation of a new node element. @ns is optional (NULL).
1871 *
1872 * Returns a pointer to the new node object.
1873 */
1874xmlNodePtr
1875xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
1876 xmlNodePtr cur;
1877
1878 if (name == NULL) {
1879#ifdef DEBUG_TREE
1880 xmlGenericError(xmlGenericErrorContext,
1881 "xmlNewNode : name == NULL\n");
1882#endif
1883 return(NULL);
1884 }
1885
1886 /*
1887 * Allocate a new node and fill the fields.
1888 */
1889 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1890 if (cur == NULL) {
1891 xmlGenericError(xmlGenericErrorContext,
1892 "xmlNewNode : malloc failed\n");
1893 return(NULL);
1894 }
1895 memset(cur, 0, sizeof(xmlNode));
1896 cur->type = XML_ELEMENT_NODE;
1897
1898 cur->name = name;
1899 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001900
1901 if (xmlRegisterNodeDefaultValue)
1902 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001903 return(cur);
1904}
1905
1906/**
Owen Taylor3473f882001-02-23 17:55:21 +00001907 * xmlNewDocNode:
1908 * @doc: the document
1909 * @ns: namespace if any
1910 * @name: the node name
1911 * @content: the XML text content if any
1912 *
1913 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001914 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001915 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1916 * references, but XML special chars need to be escaped first by using
1917 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1918 * need entities support.
1919 *
1920 * Returns a pointer to the new node object.
1921 */
1922xmlNodePtr
1923xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1924 const xmlChar *name, const xmlChar *content) {
1925 xmlNodePtr cur;
1926
1927 cur = xmlNewNode(ns, name);
1928 if (cur != NULL) {
1929 cur->doc = doc;
1930 if (content != NULL) {
1931 cur->children = xmlStringGetNodeList(doc, content);
1932 UPDATE_LAST_CHILD_AND_PARENT(cur)
1933 }
1934 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001935
Owen Taylor3473f882001-02-23 17:55:21 +00001936 return(cur);
1937}
1938
Daniel Veillard46de64e2002-05-29 08:21:33 +00001939/**
1940 * xmlNewDocNodeEatName:
1941 * @doc: the document
1942 * @ns: namespace if any
1943 * @name: the node name
1944 * @content: the XML text content if any
1945 *
1946 * Creation of a new node element within a document. @ns and @content
1947 * are optional (NULL).
1948 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1949 * references, but XML special chars need to be escaped first by using
1950 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1951 * need entities support.
1952 *
1953 * Returns a pointer to the new node object.
1954 */
1955xmlNodePtr
1956xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
1957 xmlChar *name, const xmlChar *content) {
1958 xmlNodePtr cur;
1959
1960 cur = xmlNewNodeEatName(ns, name);
1961 if (cur != NULL) {
1962 cur->doc = doc;
1963 if (content != NULL) {
1964 cur->children = xmlStringGetNodeList(doc, content);
1965 UPDATE_LAST_CHILD_AND_PARENT(cur)
1966 }
1967 }
1968 return(cur);
1969}
1970
Owen Taylor3473f882001-02-23 17:55:21 +00001971
1972/**
1973 * xmlNewDocRawNode:
1974 * @doc: the document
1975 * @ns: namespace if any
1976 * @name: the node name
1977 * @content: the text content if any
1978 *
1979 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001980 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001981 *
1982 * Returns a pointer to the new node object.
1983 */
1984xmlNodePtr
1985xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1986 const xmlChar *name, const xmlChar *content) {
1987 xmlNodePtr cur;
1988
1989 cur = xmlNewNode(ns, name);
1990 if (cur != NULL) {
1991 cur->doc = doc;
1992 if (content != NULL) {
1993 cur->children = xmlNewDocText(doc, content);
1994 UPDATE_LAST_CHILD_AND_PARENT(cur)
1995 }
1996 }
1997 return(cur);
1998}
1999
2000/**
2001 * xmlNewDocFragment:
2002 * @doc: the document owning the fragment
2003 *
2004 * Creation of a new Fragment node.
2005 * Returns a pointer to the new node object.
2006 */
2007xmlNodePtr
2008xmlNewDocFragment(xmlDocPtr doc) {
2009 xmlNodePtr cur;
2010
2011 /*
2012 * Allocate a new DocumentFragment node and fill the fields.
2013 */
2014 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2015 if (cur == NULL) {
2016 xmlGenericError(xmlGenericErrorContext,
2017 "xmlNewDocFragment : malloc failed\n");
2018 return(NULL);
2019 }
2020 memset(cur, 0, sizeof(xmlNode));
2021 cur->type = XML_DOCUMENT_FRAG_NODE;
2022
2023 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002024
2025 if (xmlRegisterNodeDefaultValue)
2026 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002027 return(cur);
2028}
2029
2030/**
2031 * xmlNewText:
2032 * @content: the text content
2033 *
2034 * Creation of a new text node.
2035 * Returns a pointer to the new node object.
2036 */
2037xmlNodePtr
2038xmlNewText(const xmlChar *content) {
2039 xmlNodePtr cur;
2040
2041 /*
2042 * Allocate a new node and fill the fields.
2043 */
2044 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2045 if (cur == NULL) {
2046 xmlGenericError(xmlGenericErrorContext,
2047 "xmlNewText : malloc failed\n");
2048 return(NULL);
2049 }
2050 memset(cur, 0, sizeof(xmlNode));
2051 cur->type = XML_TEXT_NODE;
2052
2053 cur->name = xmlStringText;
2054 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002055 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002056 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002057
2058 if (xmlRegisterNodeDefaultValue)
2059 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002060 return(cur);
2061}
2062
2063/**
2064 * xmlNewTextChild:
2065 * @parent: the parent node
2066 * @ns: a namespace if any
2067 * @name: the name of the child
2068 * @content: the text content of the child if any.
2069 *
2070 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002071 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002072 * a child TEXT node will be created containing the string content.
2073 *
2074 * Returns a pointer to the new node object.
2075 */
2076xmlNodePtr
2077xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2078 const xmlChar *name, const xmlChar *content) {
2079 xmlNodePtr cur, prev;
2080
2081 if (parent == NULL) {
2082#ifdef DEBUG_TREE
2083 xmlGenericError(xmlGenericErrorContext,
2084 "xmlNewTextChild : parent == NULL\n");
2085#endif
2086 return(NULL);
2087 }
2088
2089 if (name == NULL) {
2090#ifdef DEBUG_TREE
2091 xmlGenericError(xmlGenericErrorContext,
2092 "xmlNewTextChild : name == NULL\n");
2093#endif
2094 return(NULL);
2095 }
2096
2097 /*
2098 * Allocate a new node
2099 */
2100 if (ns == NULL)
2101 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2102 else
2103 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2104 if (cur == NULL) return(NULL);
2105
2106 /*
2107 * add the new element at the end of the children list.
2108 */
2109 cur->type = XML_ELEMENT_NODE;
2110 cur->parent = parent;
2111 cur->doc = parent->doc;
2112 if (parent->children == NULL) {
2113 parent->children = cur;
2114 parent->last = cur;
2115 } else {
2116 prev = parent->last;
2117 prev->next = cur;
2118 cur->prev = prev;
2119 parent->last = cur;
2120 }
2121
2122 return(cur);
2123}
2124
2125/**
2126 * xmlNewCharRef:
2127 * @doc: the document
2128 * @name: the char ref string, starting with # or "&# ... ;"
2129 *
2130 * Creation of a new character reference node.
2131 * Returns a pointer to the new node object.
2132 */
2133xmlNodePtr
2134xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2135 xmlNodePtr cur;
2136
2137 /*
2138 * Allocate a new node and fill the fields.
2139 */
2140 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2141 if (cur == NULL) {
2142 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002143 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002144 return(NULL);
2145 }
2146 memset(cur, 0, sizeof(xmlNode));
2147 cur->type = XML_ENTITY_REF_NODE;
2148
2149 cur->doc = doc;
2150 if (name[0] == '&') {
2151 int len;
2152 name++;
2153 len = xmlStrlen(name);
2154 if (name[len - 1] == ';')
2155 cur->name = xmlStrndup(name, len - 1);
2156 else
2157 cur->name = xmlStrndup(name, len);
2158 } else
2159 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002160
2161 if (xmlRegisterNodeDefaultValue)
2162 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002163 return(cur);
2164}
2165
2166/**
2167 * xmlNewReference:
2168 * @doc: the document
2169 * @name: the reference name, or the reference string with & and ;
2170 *
2171 * Creation of a new reference node.
2172 * Returns a pointer to the new node object.
2173 */
2174xmlNodePtr
2175xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2176 xmlNodePtr cur;
2177 xmlEntityPtr ent;
2178
2179 /*
2180 * Allocate a new node and fill the fields.
2181 */
2182 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2183 if (cur == NULL) {
2184 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002185 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002186 return(NULL);
2187 }
2188 memset(cur, 0, sizeof(xmlNode));
2189 cur->type = XML_ENTITY_REF_NODE;
2190
2191 cur->doc = doc;
2192 if (name[0] == '&') {
2193 int len;
2194 name++;
2195 len = xmlStrlen(name);
2196 if (name[len - 1] == ';')
2197 cur->name = xmlStrndup(name, len - 1);
2198 else
2199 cur->name = xmlStrndup(name, len);
2200 } else
2201 cur->name = xmlStrdup(name);
2202
2203 ent = xmlGetDocEntity(doc, cur->name);
2204 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002205 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002206 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002207 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002208 * updated. Not sure if this is 100% correct.
2209 * -George
2210 */
2211 cur->children = (xmlNodePtr) ent;
2212 cur->last = (xmlNodePtr) ent;
2213 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002214
2215 if (xmlRegisterNodeDefaultValue)
2216 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002217 return(cur);
2218}
2219
2220/**
2221 * xmlNewDocText:
2222 * @doc: the document
2223 * @content: the text content
2224 *
2225 * Creation of a new text node within a document.
2226 * Returns a pointer to the new node object.
2227 */
2228xmlNodePtr
2229xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2230 xmlNodePtr cur;
2231
2232 cur = xmlNewText(content);
2233 if (cur != NULL) cur->doc = doc;
2234 return(cur);
2235}
2236
2237/**
2238 * xmlNewTextLen:
2239 * @content: the text content
2240 * @len: the text len.
2241 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002242 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002243 * Returns a pointer to the new node object.
2244 */
2245xmlNodePtr
2246xmlNewTextLen(const xmlChar *content, int len) {
2247 xmlNodePtr cur;
2248
2249 /*
2250 * Allocate a new node and fill the fields.
2251 */
2252 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2253 if (cur == NULL) {
2254 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002255 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002256 return(NULL);
2257 }
2258 memset(cur, 0, sizeof(xmlNode));
2259 cur->type = XML_TEXT_NODE;
2260
2261 cur->name = xmlStringText;
2262 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002263 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002264 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002265
2266 if (xmlRegisterNodeDefaultValue)
2267 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002268 return(cur);
2269}
2270
2271/**
2272 * xmlNewDocTextLen:
2273 * @doc: the document
2274 * @content: the text content
2275 * @len: the text len.
2276 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002277 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002278 * text node pertain to a given document.
2279 * Returns a pointer to the new node object.
2280 */
2281xmlNodePtr
2282xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2283 xmlNodePtr cur;
2284
2285 cur = xmlNewTextLen(content, len);
2286 if (cur != NULL) cur->doc = doc;
2287 return(cur);
2288}
2289
2290/**
2291 * xmlNewComment:
2292 * @content: the comment content
2293 *
2294 * Creation of a new node containing a comment.
2295 * Returns a pointer to the new node object.
2296 */
2297xmlNodePtr
2298xmlNewComment(const xmlChar *content) {
2299 xmlNodePtr cur;
2300
2301 /*
2302 * Allocate a new node and fill the fields.
2303 */
2304 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2305 if (cur == NULL) {
2306 xmlGenericError(xmlGenericErrorContext,
2307 "xmlNewComment : malloc failed\n");
2308 return(NULL);
2309 }
2310 memset(cur, 0, sizeof(xmlNode));
2311 cur->type = XML_COMMENT_NODE;
2312
2313 cur->name = xmlStringComment;
2314 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002315 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002316 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002317
2318 if (xmlRegisterNodeDefaultValue)
2319 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002320 return(cur);
2321}
2322
2323/**
2324 * xmlNewCDataBlock:
2325 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002326 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002327 * @len: the length of the block
2328 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002329 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002330 * Returns a pointer to the new node object.
2331 */
2332xmlNodePtr
2333xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2334 xmlNodePtr cur;
2335
2336 /*
2337 * Allocate a new node and fill the fields.
2338 */
2339 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2340 if (cur == NULL) {
2341 xmlGenericError(xmlGenericErrorContext,
2342 "xmlNewCDataBlock : malloc failed\n");
2343 return(NULL);
2344 }
2345 memset(cur, 0, sizeof(xmlNode));
2346 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002347 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002348
2349 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002350 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002351 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002352
2353 if (xmlRegisterNodeDefaultValue)
2354 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002355 return(cur);
2356}
2357
2358/**
2359 * xmlNewDocComment:
2360 * @doc: the document
2361 * @content: the comment content
2362 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002363 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002364 * Returns a pointer to the new node object.
2365 */
2366xmlNodePtr
2367xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2368 xmlNodePtr cur;
2369
2370 cur = xmlNewComment(content);
2371 if (cur != NULL) cur->doc = doc;
2372 return(cur);
2373}
2374
2375/**
2376 * xmlSetTreeDoc:
2377 * @tree: the top element
2378 * @doc: the document
2379 *
2380 * update all nodes under the tree to point to the right document
2381 */
2382void
2383xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002384 xmlAttrPtr prop;
2385
Owen Taylor3473f882001-02-23 17:55:21 +00002386 if (tree == NULL)
2387 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002388 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002389 if(tree->type == XML_ELEMENT_NODE) {
2390 prop = tree->properties;
2391 while (prop != NULL) {
2392 prop->doc = doc;
2393 xmlSetListDoc(prop->children, doc);
2394 prop = prop->next;
2395 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002396 }
Owen Taylor3473f882001-02-23 17:55:21 +00002397 if (tree->children != NULL)
2398 xmlSetListDoc(tree->children, doc);
2399 tree->doc = doc;
2400 }
2401}
2402
2403/**
2404 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002405 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002406 * @doc: the document
2407 *
2408 * update all nodes in the list to point to the right document
2409 */
2410void
2411xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2412 xmlNodePtr cur;
2413
2414 if (list == NULL)
2415 return;
2416 cur = list;
2417 while (cur != NULL) {
2418 if (cur->doc != doc)
2419 xmlSetTreeDoc(cur, doc);
2420 cur = cur->next;
2421 }
2422}
2423
2424
2425/**
2426 * xmlNewChild:
2427 * @parent: the parent node
2428 * @ns: a namespace if any
2429 * @name: the name of the child
2430 * @content: the XML content of the child if any.
2431 *
2432 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002433 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002434 * a child list containing the TEXTs and ENTITY_REFs node will be created.
2435 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2436 * references, but XML special chars need to be escaped first by using
2437 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
2438 * support is not needed.
2439 *
2440 * Returns a pointer to the new node object.
2441 */
2442xmlNodePtr
2443xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2444 const xmlChar *name, const xmlChar *content) {
2445 xmlNodePtr cur, prev;
2446
2447 if (parent == NULL) {
2448#ifdef DEBUG_TREE
2449 xmlGenericError(xmlGenericErrorContext,
2450 "xmlNewChild : parent == NULL\n");
2451#endif
2452 return(NULL);
2453 }
2454
2455 if (name == NULL) {
2456#ifdef DEBUG_TREE
2457 xmlGenericError(xmlGenericErrorContext,
2458 "xmlNewChild : name == NULL\n");
2459#endif
2460 return(NULL);
2461 }
2462
2463 /*
2464 * Allocate a new node
2465 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002466 if (parent->type == XML_ELEMENT_NODE) {
2467 if (ns == NULL)
2468 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2469 else
2470 cur = xmlNewDocNode(parent->doc, ns, name, content);
2471 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2472 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2473 if (ns == NULL)
2474 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2475 else
2476 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002477 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2478 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002479 } else {
2480 return(NULL);
2481 }
Owen Taylor3473f882001-02-23 17:55:21 +00002482 if (cur == NULL) return(NULL);
2483
2484 /*
2485 * add the new element at the end of the children list.
2486 */
2487 cur->type = XML_ELEMENT_NODE;
2488 cur->parent = parent;
2489 cur->doc = parent->doc;
2490 if (parent->children == NULL) {
2491 parent->children = cur;
2492 parent->last = cur;
2493 } else {
2494 prev = parent->last;
2495 prev->next = cur;
2496 cur->prev = prev;
2497 parent->last = cur;
2498 }
2499
2500 return(cur);
2501}
2502
2503/**
2504 * xmlAddNextSibling:
2505 * @cur: the child node
2506 * @elem: the new node
2507 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002508 * Add a new node @elem as the next sibling of @cur
2509 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002510 * first unlinked from its existing context.
2511 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002512 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2513 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002514 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002515 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002516 */
2517xmlNodePtr
2518xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2519 if (cur == NULL) {
2520#ifdef DEBUG_TREE
2521 xmlGenericError(xmlGenericErrorContext,
2522 "xmlAddNextSibling : cur == NULL\n");
2523#endif
2524 return(NULL);
2525 }
2526 if (elem == NULL) {
2527#ifdef DEBUG_TREE
2528 xmlGenericError(xmlGenericErrorContext,
2529 "xmlAddNextSibling : elem == NULL\n");
2530#endif
2531 return(NULL);
2532 }
2533
2534 xmlUnlinkNode(elem);
2535
2536 if (elem->type == XML_TEXT_NODE) {
2537 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002538 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002539 xmlFreeNode(elem);
2540 return(cur);
2541 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002542 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2543 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002544 xmlChar *tmp;
2545
2546 tmp = xmlStrdup(elem->content);
2547 tmp = xmlStrcat(tmp, cur->next->content);
2548 xmlNodeSetContent(cur->next, tmp);
2549 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002550 xmlFreeNode(elem);
2551 return(cur->next);
2552 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002553 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2554 /* check if an attribute with the same name exists */
2555 xmlAttrPtr attr;
2556
2557 if (elem->ns == NULL)
2558 attr = xmlHasProp(cur->parent, elem->name);
2559 else
2560 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2561 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2562 /* different instance, destroy it (attributes must be unique) */
2563 xmlFreeProp(attr);
2564 }
Owen Taylor3473f882001-02-23 17:55:21 +00002565 }
2566
2567 if (elem->doc != cur->doc) {
2568 xmlSetTreeDoc(elem, cur->doc);
2569 }
2570 elem->parent = cur->parent;
2571 elem->prev = cur;
2572 elem->next = cur->next;
2573 cur->next = elem;
2574 if (elem->next != NULL)
2575 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002576 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002577 elem->parent->last = elem;
2578 return(elem);
2579}
2580
2581/**
2582 * xmlAddPrevSibling:
2583 * @cur: the child node
2584 * @elem: the new node
2585 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002586 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002587 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002588 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002589 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002590 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2591 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002592 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002593 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002594 */
2595xmlNodePtr
2596xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2597 if (cur == NULL) {
2598#ifdef DEBUG_TREE
2599 xmlGenericError(xmlGenericErrorContext,
2600 "xmlAddPrevSibling : cur == NULL\n");
2601#endif
2602 return(NULL);
2603 }
2604 if (elem == NULL) {
2605#ifdef DEBUG_TREE
2606 xmlGenericError(xmlGenericErrorContext,
2607 "xmlAddPrevSibling : elem == NULL\n");
2608#endif
2609 return(NULL);
2610 }
2611
2612 xmlUnlinkNode(elem);
2613
2614 if (elem->type == XML_TEXT_NODE) {
2615 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002616 xmlChar *tmp;
2617
2618 tmp = xmlStrdup(elem->content);
2619 tmp = xmlStrcat(tmp, cur->content);
2620 xmlNodeSetContent(cur, tmp);
2621 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002622 xmlFreeNode(elem);
2623 return(cur);
2624 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002625 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2626 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002627 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002628 xmlFreeNode(elem);
2629 return(cur->prev);
2630 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002631 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2632 /* check if an attribute with the same name exists */
2633 xmlAttrPtr attr;
2634
2635 if (elem->ns == NULL)
2636 attr = xmlHasProp(cur->parent, elem->name);
2637 else
2638 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2639 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2640 /* different instance, destroy it (attributes must be unique) */
2641 xmlFreeProp(attr);
2642 }
Owen Taylor3473f882001-02-23 17:55:21 +00002643 }
2644
2645 if (elem->doc != cur->doc) {
2646 xmlSetTreeDoc(elem, cur->doc);
2647 }
2648 elem->parent = cur->parent;
2649 elem->next = cur;
2650 elem->prev = cur->prev;
2651 cur->prev = elem;
2652 if (elem->prev != NULL)
2653 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002654 if (elem->parent != NULL) {
2655 if (elem->type == XML_ATTRIBUTE_NODE) {
2656 if (elem->parent->properties == (xmlAttrPtr) cur) {
2657 elem->parent->properties = (xmlAttrPtr) elem;
2658 }
2659 } else {
2660 if (elem->parent->children == cur) {
2661 elem->parent->children = elem;
2662 }
2663 }
2664 }
Owen Taylor3473f882001-02-23 17:55:21 +00002665 return(elem);
2666}
2667
2668/**
2669 * xmlAddSibling:
2670 * @cur: the child node
2671 * @elem: the new node
2672 *
2673 * Add a new element @elem to the list of siblings of @cur
2674 * merging adjacent TEXT nodes (@elem may be freed)
2675 * If the new element was already inserted in a document it is
2676 * first unlinked from its existing context.
2677 *
2678 * Returns the new element or NULL in case of error.
2679 */
2680xmlNodePtr
2681xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2682 xmlNodePtr parent;
2683
2684 if (cur == NULL) {
2685#ifdef DEBUG_TREE
2686 xmlGenericError(xmlGenericErrorContext,
2687 "xmlAddSibling : cur == NULL\n");
2688#endif
2689 return(NULL);
2690 }
2691
2692 if (elem == NULL) {
2693#ifdef DEBUG_TREE
2694 xmlGenericError(xmlGenericErrorContext,
2695 "xmlAddSibling : elem == NULL\n");
2696#endif
2697 return(NULL);
2698 }
2699
2700 /*
2701 * Constant time is we can rely on the ->parent->last to find
2702 * the last sibling.
2703 */
2704 if ((cur->parent != NULL) &&
2705 (cur->parent->children != NULL) &&
2706 (cur->parent->last != NULL) &&
2707 (cur->parent->last->next == NULL)) {
2708 cur = cur->parent->last;
2709 } else {
2710 while (cur->next != NULL) cur = cur->next;
2711 }
2712
2713 xmlUnlinkNode(elem);
2714
2715 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002716 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002717 xmlFreeNode(elem);
2718 return(cur);
2719 }
2720
2721 if (elem->doc != cur->doc) {
2722 xmlSetTreeDoc(elem, cur->doc);
2723 }
2724 parent = cur->parent;
2725 elem->prev = cur;
2726 elem->next = NULL;
2727 elem->parent = parent;
2728 cur->next = elem;
2729 if (parent != NULL)
2730 parent->last = elem;
2731
2732 return(elem);
2733}
2734
2735/**
2736 * xmlAddChildList:
2737 * @parent: the parent node
2738 * @cur: the first node in the list
2739 *
2740 * Add a list of node at the end of the child list of the parent
2741 * merging adjacent TEXT nodes (@cur may be freed)
2742 *
2743 * Returns the last child or NULL in case of error.
2744 */
2745xmlNodePtr
2746xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2747 xmlNodePtr prev;
2748
2749 if (parent == NULL) {
2750#ifdef DEBUG_TREE
2751 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002752 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002753#endif
2754 return(NULL);
2755 }
2756
2757 if (cur == NULL) {
2758#ifdef DEBUG_TREE
2759 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002760 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002761#endif
2762 return(NULL);
2763 }
2764
2765 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2766 (cur->doc != parent->doc)) {
2767#ifdef DEBUG_TREE
2768 xmlGenericError(xmlGenericErrorContext,
2769 "Elements moved to a different document\n");
2770#endif
2771 }
2772
2773 /*
2774 * add the first element at the end of the children list.
2775 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00002776
Owen Taylor3473f882001-02-23 17:55:21 +00002777 if (parent->children == NULL) {
2778 parent->children = cur;
2779 } else {
2780 /*
2781 * If cur and parent->last both are TEXT nodes, then merge them.
2782 */
2783 if ((cur->type == XML_TEXT_NODE) &&
2784 (parent->last->type == XML_TEXT_NODE) &&
2785 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00002786 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002787 /*
2788 * if it's the only child, nothing more to be done.
2789 */
2790 if (cur->next == NULL) {
2791 xmlFreeNode(cur);
2792 return(parent->last);
2793 }
2794 prev = cur;
2795 cur = cur->next;
2796 xmlFreeNode(prev);
2797 }
2798 prev = parent->last;
2799 prev->next = cur;
2800 cur->prev = prev;
2801 }
2802 while (cur->next != NULL) {
2803 cur->parent = parent;
2804 if (cur->doc != parent->doc) {
2805 xmlSetTreeDoc(cur, parent->doc);
2806 }
2807 cur = cur->next;
2808 }
2809 cur->parent = parent;
2810 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2811 parent->last = cur;
2812
2813 return(cur);
2814}
2815
2816/**
2817 * xmlAddChild:
2818 * @parent: the parent node
2819 * @cur: the child node
2820 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002821 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00002822 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002823 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2824 * If there is an attribute with equal name, it is first destroyed.
2825 *
Owen Taylor3473f882001-02-23 17:55:21 +00002826 * Returns the child or NULL in case of error.
2827 */
2828xmlNodePtr
2829xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2830 xmlNodePtr prev;
2831
2832 if (parent == NULL) {
2833#ifdef DEBUG_TREE
2834 xmlGenericError(xmlGenericErrorContext,
2835 "xmlAddChild : parent == NULL\n");
2836#endif
2837 return(NULL);
2838 }
2839
2840 if (cur == NULL) {
2841#ifdef DEBUG_TREE
2842 xmlGenericError(xmlGenericErrorContext,
2843 "xmlAddChild : child == NULL\n");
2844#endif
2845 return(NULL);
2846 }
2847
Owen Taylor3473f882001-02-23 17:55:21 +00002848 /*
2849 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002850 * cur is then freed.
2851 */
2852 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002853 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002854 (parent->content != NULL) &&
2855 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002856 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002857 xmlFreeNode(cur);
2858 return(parent);
2859 }
2860 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002861 (parent->last->name == cur->name) &&
2862 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002863 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002864 xmlFreeNode(cur);
2865 return(parent->last);
2866 }
2867 }
2868
2869 /*
2870 * add the new element at the end of the children list.
2871 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00002872 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00002873 cur->parent = parent;
2874 if (cur->doc != parent->doc) {
2875 xmlSetTreeDoc(cur, parent->doc);
2876 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002877 /* this check prevents a loop on tree-traversions if a developer
2878 * tries to add a node to its parent multiple times
2879 */
2880 if (prev == parent)
2881 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002882
2883 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002884 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002885 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002886 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002887 (parent->content != NULL) &&
2888 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002889 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002890 xmlFreeNode(cur);
2891 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002892 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002893 if (cur->type == XML_ATTRIBUTE_NODE) {
2894 if (parent->properties == NULL) {
2895 parent->properties = (xmlAttrPtr) cur;
2896 } else {
2897 /* check if an attribute with the same name exists */
2898 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00002899
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002900 if (cur->ns == NULL)
2901 lastattr = xmlHasProp(parent, cur->name);
2902 else
2903 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
2904 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
2905 /* different instance, destroy it (attributes must be unique) */
2906 xmlFreeProp(lastattr);
2907 }
2908 /* find the end */
2909 lastattr = parent->properties;
2910 while (lastattr->next != NULL) {
2911 lastattr = lastattr->next;
2912 }
2913 lastattr->next = (xmlAttrPtr) cur;
2914 ((xmlAttrPtr) cur)->prev = lastattr;
2915 }
2916 } else {
2917 if (parent->children == NULL) {
2918 parent->children = cur;
2919 parent->last = cur;
2920 } else {
2921 prev = parent->last;
2922 prev->next = cur;
2923 cur->prev = prev;
2924 parent->last = cur;
2925 }
2926 }
Owen Taylor3473f882001-02-23 17:55:21 +00002927 return(cur);
2928}
2929
2930/**
2931 * xmlGetLastChild:
2932 * @parent: the parent node
2933 *
2934 * Search the last child of a node.
2935 * Returns the last child or NULL if none.
2936 */
2937xmlNodePtr
2938xmlGetLastChild(xmlNodePtr parent) {
2939 if (parent == NULL) {
2940#ifdef DEBUG_TREE
2941 xmlGenericError(xmlGenericErrorContext,
2942 "xmlGetLastChild : parent == NULL\n");
2943#endif
2944 return(NULL);
2945 }
2946 return(parent->last);
2947}
2948
2949/**
2950 * xmlFreeNodeList:
2951 * @cur: the first node in the list
2952 *
2953 * Free a node and all its siblings, this is a recursive behaviour, all
2954 * the children are freed too.
2955 */
2956void
2957xmlFreeNodeList(xmlNodePtr cur) {
2958 xmlNodePtr next;
2959 if (cur == NULL) {
2960#ifdef DEBUG_TREE
2961 xmlGenericError(xmlGenericErrorContext,
2962 "xmlFreeNodeList : node == NULL\n");
2963#endif
2964 return;
2965 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00002966 if (cur->type == XML_NAMESPACE_DECL) {
2967 xmlFreeNsList((xmlNsPtr) cur);
2968 return;
2969 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00002970 if ((cur->type == XML_DOCUMENT_NODE) ||
2971#ifdef LIBXML_DOCB_ENABLED
2972 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
2973 (cur->type == XML_HTML_DOCUMENT_NODE)) {
2974#endif
2975 xmlFreeDoc((xmlDocPtr) cur);
2976 return;
2977 }
Owen Taylor3473f882001-02-23 17:55:21 +00002978 while (cur != NULL) {
2979 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002980 /* unroll to speed up freeing the document */
2981 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00002982
2983 if (xmlDeregisterNodeDefaultValue)
2984 xmlDeregisterNodeDefaultValue(cur);
2985
Daniel Veillard02141ea2001-04-30 11:46:40 +00002986 if ((cur->children != NULL) &&
2987 (cur->type != XML_ENTITY_REF_NODE))
2988 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00002989 if (((cur->type == XML_ELEMENT_NODE) ||
2990 (cur->type == XML_XINCLUDE_START) ||
2991 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002992 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00002993 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002994 if ((cur->type != XML_ELEMENT_NODE) &&
2995 (cur->type != XML_XINCLUDE_START) &&
2996 (cur->type != XML_XINCLUDE_END) &&
2997 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002998 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002999 }
3000 if (((cur->type == XML_ELEMENT_NODE) ||
3001 (cur->type == XML_XINCLUDE_START) ||
3002 (cur->type == XML_XINCLUDE_END)) &&
3003 (cur->nsDef != NULL))
3004 xmlFreeNsList(cur->nsDef);
3005
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003006 /*
3007 * When a node is a text node or a comment, it uses a global static
3008 * variable for the name of the node.
3009 *
3010 * The xmlStrEqual comparisons need to be done when (happened with
3011 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003012 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00003013 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003014 * the string addresses compare are not sufficient.
3015 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003016 if ((cur->name != NULL) &&
3017 (cur->name != xmlStringText) &&
3018 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003019 (cur->name != xmlStringComment)) {
3020 if (cur->type == XML_TEXT_NODE) {
3021 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
3022 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
3023 xmlFree((char *) cur->name);
3024 } else if (cur->type == XML_COMMENT_NODE) {
3025 if (!xmlStrEqual(cur->name, xmlStringComment))
3026 xmlFree((char *) cur->name);
3027 } else
3028 xmlFree((char *) cur->name);
3029 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00003030 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003031 xmlFree(cur);
3032 }
Owen Taylor3473f882001-02-23 17:55:21 +00003033 cur = next;
3034 }
3035}
3036
3037/**
3038 * xmlFreeNode:
3039 * @cur: the node
3040 *
3041 * Free a node, this is a recursive behaviour, all the children are freed too.
3042 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3043 */
3044void
3045xmlFreeNode(xmlNodePtr cur) {
3046 if (cur == NULL) {
3047#ifdef DEBUG_TREE
3048 xmlGenericError(xmlGenericErrorContext,
3049 "xmlFreeNode : node == NULL\n");
3050#endif
3051 return;
3052 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003053
Daniel Veillard02141ea2001-04-30 11:46:40 +00003054 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003055 if (cur->type == XML_DTD_NODE) {
3056 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003057 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003058 }
3059 if (cur->type == XML_NAMESPACE_DECL) {
3060 xmlFreeNs((xmlNsPtr) cur);
3061 return;
3062 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003063 if (cur->type == XML_ATTRIBUTE_NODE) {
3064 xmlFreeProp((xmlAttrPtr) cur);
3065 return;
3066 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003067
3068 if (xmlDeregisterNodeDefaultValue)
3069 xmlDeregisterNodeDefaultValue(cur);
3070
Owen Taylor3473f882001-02-23 17:55:21 +00003071 if ((cur->children != NULL) &&
3072 (cur->type != XML_ENTITY_REF_NODE))
3073 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003074 if (((cur->type == XML_ELEMENT_NODE) ||
3075 (cur->type == XML_XINCLUDE_START) ||
3076 (cur->type == XML_XINCLUDE_END)) &&
3077 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003078 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003079 if ((cur->type != XML_ELEMENT_NODE) &&
3080 (cur->content != NULL) &&
3081 (cur->type != XML_ENTITY_REF_NODE) &&
3082 (cur->type != XML_XINCLUDE_END) &&
3083 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003084 xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003085 }
3086
Daniel Veillardacd370f2001-06-09 17:17:51 +00003087 /*
3088 * When a node is a text node or a comment, it uses a global static
3089 * variable for the name of the node.
3090 *
3091 * The xmlStrEqual comparisons need to be done when (happened with
3092 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003093 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00003094 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00003095 * are not sufficient.
3096 */
Owen Taylor3473f882001-02-23 17:55:21 +00003097 if ((cur->name != NULL) &&
3098 (cur->name != xmlStringText) &&
3099 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00003100 (cur->name != xmlStringComment)) {
3101 if (cur->type == XML_TEXT_NODE) {
3102 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
3103 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
3104 xmlFree((char *) cur->name);
3105 } else if (cur->type == XML_COMMENT_NODE) {
3106 if (!xmlStrEqual(cur->name, xmlStringComment))
3107 xmlFree((char *) cur->name);
3108 } else
3109 xmlFree((char *) cur->name);
3110 }
3111
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003112 if (((cur->type == XML_ELEMENT_NODE) ||
3113 (cur->type == XML_XINCLUDE_START) ||
3114 (cur->type == XML_XINCLUDE_END)) &&
3115 (cur->nsDef != NULL))
3116 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003117 xmlFree(cur);
3118}
3119
3120/**
3121 * xmlUnlinkNode:
3122 * @cur: the node
3123 *
3124 * Unlink a node from it's current context, the node is not freed
3125 */
3126void
3127xmlUnlinkNode(xmlNodePtr cur) {
3128 if (cur == NULL) {
3129#ifdef DEBUG_TREE
3130 xmlGenericError(xmlGenericErrorContext,
3131 "xmlUnlinkNode : node == NULL\n");
3132#endif
3133 return;
3134 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003135 if (cur->type == XML_DTD_NODE) {
3136 xmlDocPtr doc;
3137 doc = cur->doc;
3138 if (doc->intSubset == (xmlDtdPtr) cur)
3139 doc->intSubset = NULL;
3140 if (doc->extSubset == (xmlDtdPtr) cur)
3141 doc->extSubset = NULL;
3142 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003143 if (cur->parent != NULL) {
3144 xmlNodePtr parent;
3145 parent = cur->parent;
3146 if (cur->type == XML_ATTRIBUTE_NODE) {
3147 if (parent->properties == (xmlAttrPtr) cur)
3148 parent->properties = ((xmlAttrPtr) cur)->next;
3149 } else {
3150 if (parent->children == cur)
3151 parent->children = cur->next;
3152 if (parent->last == cur)
3153 parent->last = cur->prev;
3154 }
3155 cur->parent = NULL;
3156 }
Owen Taylor3473f882001-02-23 17:55:21 +00003157 if (cur->next != NULL)
3158 cur->next->prev = cur->prev;
3159 if (cur->prev != NULL)
3160 cur->prev->next = cur->next;
3161 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003162}
3163
3164/**
3165 * xmlReplaceNode:
3166 * @old: the old node
3167 * @cur: the node
3168 *
3169 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003170 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003171 * first unlinked from its existing context.
3172 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003173 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003174 */
3175xmlNodePtr
3176xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3177 if (old == NULL) {
3178#ifdef DEBUG_TREE
3179 xmlGenericError(xmlGenericErrorContext,
3180 "xmlReplaceNode : old == NULL\n");
3181#endif
3182 return(NULL);
3183 }
3184 if (cur == NULL) {
3185 xmlUnlinkNode(old);
3186 return(old);
3187 }
3188 if (cur == old) {
3189 return(old);
3190 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003191 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3192#ifdef DEBUG_TREE
3193 xmlGenericError(xmlGenericErrorContext,
3194 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3195#endif
3196 return(old);
3197 }
3198 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3199#ifdef DEBUG_TREE
3200 xmlGenericError(xmlGenericErrorContext,
3201 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3202#endif
3203 return(old);
3204 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003205 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3206#ifdef DEBUG_TREE
3207 xmlGenericError(xmlGenericErrorContext,
3208 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3209#endif
3210 return(old);
3211 }
3212 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3213#ifdef DEBUG_TREE
3214 xmlGenericError(xmlGenericErrorContext,
3215 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3216#endif
3217 return(old);
3218 }
Owen Taylor3473f882001-02-23 17:55:21 +00003219 xmlUnlinkNode(cur);
3220 cur->doc = old->doc;
3221 cur->parent = old->parent;
3222 cur->next = old->next;
3223 if (cur->next != NULL)
3224 cur->next->prev = cur;
3225 cur->prev = old->prev;
3226 if (cur->prev != NULL)
3227 cur->prev->next = cur;
3228 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003229 if (cur->type == XML_ATTRIBUTE_NODE) {
3230 if (cur->parent->properties == (xmlAttrPtr)old)
3231 cur->parent->properties = ((xmlAttrPtr) cur);
3232 } else {
3233 if (cur->parent->children == old)
3234 cur->parent->children = cur;
3235 if (cur->parent->last == old)
3236 cur->parent->last = cur;
3237 }
Owen Taylor3473f882001-02-23 17:55:21 +00003238 }
3239 old->next = old->prev = NULL;
3240 old->parent = NULL;
3241 return(old);
3242}
3243
3244/************************************************************************
3245 * *
3246 * Copy operations *
3247 * *
3248 ************************************************************************/
3249
3250/**
3251 * xmlCopyNamespace:
3252 * @cur: the namespace
3253 *
3254 * Do a copy of the namespace.
3255 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003256 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003257 */
3258xmlNsPtr
3259xmlCopyNamespace(xmlNsPtr cur) {
3260 xmlNsPtr ret;
3261
3262 if (cur == NULL) return(NULL);
3263 switch (cur->type) {
3264 case XML_LOCAL_NAMESPACE:
3265 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3266 break;
3267 default:
3268#ifdef DEBUG_TREE
3269 xmlGenericError(xmlGenericErrorContext,
3270 "xmlCopyNamespace: invalid type %d\n", cur->type);
3271#endif
3272 return(NULL);
3273 }
3274 return(ret);
3275}
3276
3277/**
3278 * xmlCopyNamespaceList:
3279 * @cur: the first namespace
3280 *
3281 * Do a copy of an namespace list.
3282 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003283 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003284 */
3285xmlNsPtr
3286xmlCopyNamespaceList(xmlNsPtr cur) {
3287 xmlNsPtr ret = NULL;
3288 xmlNsPtr p = NULL,q;
3289
3290 while (cur != NULL) {
3291 q = xmlCopyNamespace(cur);
3292 if (p == NULL) {
3293 ret = p = q;
3294 } else {
3295 p->next = q;
3296 p = q;
3297 }
3298 cur = cur->next;
3299 }
3300 return(ret);
3301}
3302
3303static xmlNodePtr
3304xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3305/**
3306 * xmlCopyProp:
3307 * @target: the element where the attribute will be grafted
3308 * @cur: the attribute
3309 *
3310 * Do a copy of the attribute.
3311 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003312 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003313 */
3314xmlAttrPtr
3315xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3316 xmlAttrPtr ret;
3317
3318 if (cur == NULL) return(NULL);
3319 if (target != NULL)
3320 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3321 else if (cur->parent != NULL)
3322 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3323 else if (cur->children != NULL)
3324 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3325 else
3326 ret = xmlNewDocProp(NULL, cur->name, NULL);
3327 if (ret == NULL) return(NULL);
3328 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003329
Owen Taylor3473f882001-02-23 17:55:21 +00003330 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003331 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003332/*
3333 * if (target->doc)
3334 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3335 * else if (cur->doc) / * target may not yet have a doc : KPI * /
3336 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
3337 * else
3338 * ns = NULL;
3339 * ret->ns = ns;
3340 */
3341 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3342 if (ns == NULL) {
3343 /*
3344 * Humm, we are copying an element whose namespace is defined
3345 * out of the new tree scope. Search it in the original tree
3346 * and add it at the top of the new tree
3347 */
3348 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3349 if (ns != NULL) {
3350 xmlNodePtr root = target;
3351 xmlNodePtr pred = NULL;
3352
3353 while (root->parent != NULL) {
3354 pred = root;
3355 root = root->parent;
3356 }
3357 if (root == (xmlNodePtr) target->doc) {
3358 /* correct possibly cycling above the document elt */
3359 root = pred;
3360 }
3361 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3362 }
3363 } else {
3364 /*
3365 * we have to find something appropriate here since
3366 * we cant be sure, that the namespce we found is identified
3367 * by the prefix
3368 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003369 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003370 /* this is the nice case */
3371 ret->ns = ns;
3372 } else {
3373 /*
3374 * we are in trouble: we need a new reconcilied namespace.
3375 * This is expensive
3376 */
3377 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3378 }
3379 }
3380
Owen Taylor3473f882001-02-23 17:55:21 +00003381 } else
3382 ret->ns = NULL;
3383
3384 if (cur->children != NULL) {
3385 xmlNodePtr tmp;
3386
3387 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3388 ret->last = NULL;
3389 tmp = ret->children;
3390 while (tmp != NULL) {
3391 /* tmp->parent = (xmlNodePtr)ret; */
3392 if (tmp->next == NULL)
3393 ret->last = tmp;
3394 tmp = tmp->next;
3395 }
3396 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003397 /*
3398 * Try to handle IDs
3399 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003400 if ((target!= NULL) && (cur!= NULL) &&
3401 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003402 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3403 if (xmlIsID(cur->doc, cur->parent, cur)) {
3404 xmlChar *id;
3405
3406 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3407 if (id != NULL) {
3408 xmlAddID(NULL, target->doc, id, ret);
3409 xmlFree(id);
3410 }
3411 }
3412 }
Owen Taylor3473f882001-02-23 17:55:21 +00003413 return(ret);
3414}
3415
3416/**
3417 * xmlCopyPropList:
3418 * @target: the element where the attributes will be grafted
3419 * @cur: the first attribute
3420 *
3421 * Do a copy of an attribute list.
3422 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003423 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003424 */
3425xmlAttrPtr
3426xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3427 xmlAttrPtr ret = NULL;
3428 xmlAttrPtr p = NULL,q;
3429
3430 while (cur != NULL) {
3431 q = xmlCopyProp(target, cur);
3432 if (p == NULL) {
3433 ret = p = q;
3434 } else {
3435 p->next = q;
3436 q->prev = p;
3437 p = q;
3438 }
3439 cur = cur->next;
3440 }
3441 return(ret);
3442}
3443
3444/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003445 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003446 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003447 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003448 * tricky reason: namespaces. Doing a direct copy of a node
3449 * say RPM:Copyright without changing the namespace pointer to
3450 * something else can produce stale links. One way to do it is
3451 * to keep a reference counter but this doesn't work as soon
3452 * as one move the element or the subtree out of the scope of
3453 * the existing namespace. The actual solution seems to add
3454 * a copy of the namespace at the top of the copied tree if
3455 * not available in the subtree.
3456 * Hence two functions, the public front-end call the inner ones
3457 */
3458
3459static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003460xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003461 int recursive) {
3462 xmlNodePtr ret;
3463
3464 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003465 switch (node->type) {
3466 case XML_TEXT_NODE:
3467 case XML_CDATA_SECTION_NODE:
3468 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003469 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003470 case XML_ENTITY_REF_NODE:
3471 case XML_ENTITY_NODE:
3472 case XML_PI_NODE:
3473 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003474 case XML_XINCLUDE_START:
3475 case XML_XINCLUDE_END:
3476 break;
3477 case XML_ATTRIBUTE_NODE:
3478 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3479 case XML_NAMESPACE_DECL:
3480 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3481
Daniel Veillard39196eb2001-06-19 18:09:42 +00003482 case XML_DOCUMENT_NODE:
3483 case XML_HTML_DOCUMENT_NODE:
3484#ifdef LIBXML_DOCB_ENABLED
3485 case XML_DOCB_DOCUMENT_NODE:
3486#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003487 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00003488 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003489 case XML_NOTATION_NODE:
3490 case XML_DTD_NODE:
3491 case XML_ELEMENT_DECL:
3492 case XML_ATTRIBUTE_DECL:
3493 case XML_ENTITY_DECL:
3494 return(NULL);
3495 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003496
Owen Taylor3473f882001-02-23 17:55:21 +00003497 /*
3498 * Allocate a new node and fill the fields.
3499 */
3500 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3501 if (ret == NULL) {
3502 xmlGenericError(xmlGenericErrorContext,
3503 "xmlStaticCopyNode : malloc failed\n");
3504 return(NULL);
3505 }
3506 memset(ret, 0, sizeof(xmlNode));
3507 ret->type = node->type;
3508
3509 ret->doc = doc;
3510 ret->parent = parent;
3511 if (node->name == xmlStringText)
3512 ret->name = xmlStringText;
3513 else if (node->name == xmlStringTextNoenc)
3514 ret->name = xmlStringTextNoenc;
3515 else if (node->name == xmlStringComment)
3516 ret->name = xmlStringComment;
3517 else if (node->name != NULL)
3518 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003519 if ((node->type != XML_ELEMENT_NODE) &&
3520 (node->content != NULL) &&
3521 (node->type != XML_ENTITY_REF_NODE) &&
3522 (node->type != XML_XINCLUDE_END) &&
3523 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003524 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003525 }else{
3526 if (node->type == XML_ELEMENT_NODE)
3527 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00003528 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003529 if (parent != NULL) {
3530 xmlNodePtr tmp;
3531
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003532 /*
3533 * this is a tricky part for the node register thing:
3534 * in case ret does get coalesced in xmlAddChild
3535 * the deregister-node callback is called; so we register ret now already
3536 */
3537 if (xmlRegisterNodeDefaultValue)
3538 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3539
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003540 tmp = xmlAddChild(parent, ret);
3541 /* node could have coalesced */
3542 if (tmp != ret)
3543 return(tmp);
3544 }
Owen Taylor3473f882001-02-23 17:55:21 +00003545
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003546 if (!recursive)
3547 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003548 if (node->nsDef != NULL)
3549 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3550
3551 if (node->ns != NULL) {
3552 xmlNsPtr ns;
3553
3554 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3555 if (ns == NULL) {
3556 /*
3557 * Humm, we are copying an element whose namespace is defined
3558 * out of the new tree scope. Search it in the original tree
3559 * and add it at the top of the new tree
3560 */
3561 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3562 if (ns != NULL) {
3563 xmlNodePtr root = ret;
3564
3565 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003566 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003567 }
3568 } else {
3569 /*
3570 * reference the existing namespace definition in our own tree.
3571 */
3572 ret->ns = ns;
3573 }
3574 }
3575 if (node->properties != NULL)
3576 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003577 if (node->type == XML_ENTITY_REF_NODE) {
3578 if ((doc == NULL) || (node->doc != doc)) {
3579 /*
3580 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003581 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003582 * we cannot keep the reference. Try to find it in the
3583 * target document.
3584 */
3585 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3586 } else {
3587 ret->children = node->children;
3588 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003589 ret->last = ret->children;
3590 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003591 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003592 UPDATE_LAST_CHILD_AND_PARENT(ret)
3593 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003594
3595out:
3596 /* if parent != NULL we already registered the node above */
3597 if (parent == NULL && xmlRegisterNodeDefaultValue)
3598 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003599 return(ret);
3600}
3601
3602static xmlNodePtr
3603xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3604 xmlNodePtr ret = NULL;
3605 xmlNodePtr p = NULL,q;
3606
3607 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003608 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003609 if (doc == NULL) {
3610 node = node->next;
3611 continue;
3612 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003613 if (doc->intSubset == NULL) {
3614 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3615 q->doc = doc;
3616 q->parent = parent;
3617 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003618 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003619 } else {
3620 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003621 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003622 }
3623 } else
3624 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003625 if (ret == NULL) {
3626 q->prev = NULL;
3627 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003628 } else if (p != q) {
3629 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003630 p->next = q;
3631 q->prev = p;
3632 p = q;
3633 }
3634 node = node->next;
3635 }
3636 return(ret);
3637}
3638
3639/**
3640 * xmlCopyNode:
3641 * @node: the node
3642 * @recursive: if 1 do a recursive copy.
3643 *
3644 * Do a copy of the node.
3645 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003646 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003647 */
3648xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003649xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003650 xmlNodePtr ret;
3651
3652 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3653 return(ret);
3654}
3655
3656/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003657 * xmlDocCopyNode:
3658 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003659 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003660 * @recursive: if 1 do a recursive copy.
3661 *
3662 * Do a copy of the node to a given document.
3663 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003664 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003665 */
3666xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003667xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003668 xmlNodePtr ret;
3669
3670 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3671 return(ret);
3672}
3673
3674/**
Owen Taylor3473f882001-02-23 17:55:21 +00003675 * xmlCopyNodeList:
3676 * @node: the first node in the list.
3677 *
3678 * Do a recursive copy of the node list.
3679 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003680 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003681 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003682xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003683 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3684 return(ret);
3685}
3686
3687/**
Owen Taylor3473f882001-02-23 17:55:21 +00003688 * xmlCopyDtd:
3689 * @dtd: the dtd
3690 *
3691 * Do a copy of the dtd.
3692 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003693 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003694 */
3695xmlDtdPtr
3696xmlCopyDtd(xmlDtdPtr dtd) {
3697 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003698 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003699
3700 if (dtd == NULL) return(NULL);
3701 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3702 if (ret == NULL) return(NULL);
3703 if (dtd->entities != NULL)
3704 ret->entities = (void *) xmlCopyEntitiesTable(
3705 (xmlEntitiesTablePtr) dtd->entities);
3706 if (dtd->notations != NULL)
3707 ret->notations = (void *) xmlCopyNotationTable(
3708 (xmlNotationTablePtr) dtd->notations);
3709 if (dtd->elements != NULL)
3710 ret->elements = (void *) xmlCopyElementTable(
3711 (xmlElementTablePtr) dtd->elements);
3712 if (dtd->attributes != NULL)
3713 ret->attributes = (void *) xmlCopyAttributeTable(
3714 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003715 if (dtd->pentities != NULL)
3716 ret->pentities = (void *) xmlCopyEntitiesTable(
3717 (xmlEntitiesTablePtr) dtd->pentities);
3718
3719 cur = dtd->children;
3720 while (cur != NULL) {
3721 q = NULL;
3722
3723 if (cur->type == XML_ENTITY_DECL) {
3724 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3725 switch (tmp->etype) {
3726 case XML_INTERNAL_GENERAL_ENTITY:
3727 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3728 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3729 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3730 break;
3731 case XML_INTERNAL_PARAMETER_ENTITY:
3732 case XML_EXTERNAL_PARAMETER_ENTITY:
3733 q = (xmlNodePtr)
3734 xmlGetParameterEntityFromDtd(ret, tmp->name);
3735 break;
3736 case XML_INTERNAL_PREDEFINED_ENTITY:
3737 break;
3738 }
3739 } else if (cur->type == XML_ELEMENT_DECL) {
3740 xmlElementPtr tmp = (xmlElementPtr) cur;
3741 q = (xmlNodePtr)
3742 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3743 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3744 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3745 q = (xmlNodePtr)
3746 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3747 } else if (cur->type == XML_COMMENT_NODE) {
3748 q = xmlCopyNode(cur, 0);
3749 }
3750
3751 if (q == NULL) {
3752 cur = cur->next;
3753 continue;
3754 }
3755
3756 if (p == NULL)
3757 ret->children = q;
3758 else
3759 p->next = q;
3760
3761 q->prev = p;
3762 q->parent = (xmlNodePtr) ret;
3763 q->next = NULL;
3764 ret->last = q;
3765 p = q;
3766 cur = cur->next;
3767 }
3768
Owen Taylor3473f882001-02-23 17:55:21 +00003769 return(ret);
3770}
3771
3772/**
3773 * xmlCopyDoc:
3774 * @doc: the document
3775 * @recursive: if 1 do a recursive copy.
3776 *
3777 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003778 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003779 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003780 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003781 */
3782xmlDocPtr
3783xmlCopyDoc(xmlDocPtr doc, int recursive) {
3784 xmlDocPtr ret;
3785
3786 if (doc == NULL) return(NULL);
3787 ret = xmlNewDoc(doc->version);
3788 if (ret == NULL) return(NULL);
3789 if (doc->name != NULL)
3790 ret->name = xmlMemStrdup(doc->name);
3791 if (doc->encoding != NULL)
3792 ret->encoding = xmlStrdup(doc->encoding);
3793 ret->charset = doc->charset;
3794 ret->compression = doc->compression;
3795 ret->standalone = doc->standalone;
3796 if (!recursive) return(ret);
3797
Daniel Veillardb33c2012001-04-25 12:59:04 +00003798 ret->last = NULL;
3799 ret->children = NULL;
3800 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003801 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003802 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003803 ret->intSubset->parent = ret;
3804 }
Owen Taylor3473f882001-02-23 17:55:21 +00003805 if (doc->oldNs != NULL)
3806 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3807 if (doc->children != NULL) {
3808 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003809
3810 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3811 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003812 ret->last = NULL;
3813 tmp = ret->children;
3814 while (tmp != NULL) {
3815 if (tmp->next == NULL)
3816 ret->last = tmp;
3817 tmp = tmp->next;
3818 }
3819 }
3820 return(ret);
3821}
3822
3823/************************************************************************
3824 * *
3825 * Content access functions *
3826 * *
3827 ************************************************************************/
3828
3829/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003830 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003831 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00003832 *
3833 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003834 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003835 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003836 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003837 */
3838long
3839xmlGetLineNo(xmlNodePtr node)
3840{
3841 long result = -1;
3842
3843 if (!node)
3844 return result;
3845 if (node->type == XML_ELEMENT_NODE)
3846 result = (long) node->content;
3847 else if ((node->prev != NULL) &&
3848 ((node->prev->type == XML_ELEMENT_NODE) ||
3849 (node->prev->type == XML_TEXT_NODE)))
3850 result = xmlGetLineNo(node->prev);
3851 else if ((node->parent != NULL) &&
3852 ((node->parent->type == XML_ELEMENT_NODE) ||
3853 (node->parent->type == XML_TEXT_NODE)))
3854 result = xmlGetLineNo(node->parent);
3855
3856 return result;
3857}
3858
3859/**
3860 * xmlGetNodePath:
3861 * @node: a node
3862 *
3863 * Build a structure based Path for the given node
3864 *
3865 * Returns the new path or NULL in case of error. The caller must free
3866 * the returned string
3867 */
3868xmlChar *
3869xmlGetNodePath(xmlNodePtr node)
3870{
3871 xmlNodePtr cur, tmp, next;
3872 xmlChar *buffer = NULL, *temp;
3873 size_t buf_len;
3874 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00003875 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00003876 const char *name;
3877 char nametemp[100];
3878 int occur = 0;
3879
3880 if (node == NULL)
3881 return (NULL);
3882
3883 buf_len = 500;
3884 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3885 if (buffer == NULL)
3886 return (NULL);
3887 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3888 if (buf == NULL) {
3889 xmlFree(buffer);
3890 return (NULL);
3891 }
3892
3893 buffer[0] = 0;
3894 cur = node;
3895 do {
3896 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003897 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003898 occur = 0;
3899 if ((cur->type == XML_DOCUMENT_NODE) ||
3900 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3901 if (buffer[0] == '/')
3902 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003903 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003904 next = NULL;
3905 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003906 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003907 name = (const char *) cur->name;
3908 if (cur->ns) {
3909 snprintf(nametemp, sizeof(nametemp) - 1,
3910 "%s:%s", cur->ns->prefix, cur->name);
3911 nametemp[sizeof(nametemp) - 1] = 0;
3912 name = nametemp;
3913 }
3914 next = cur->parent;
3915
3916 /*
3917 * Thumbler index computation
3918 */
3919 tmp = cur->prev;
3920 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00003921 if ((tmp->type == XML_ELEMENT_NODE) &&
3922 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00003923 occur++;
3924 tmp = tmp->prev;
3925 }
3926 if (occur == 0) {
3927 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00003928 while (tmp != NULL && occur == 0) {
3929 if ((tmp->type == XML_ELEMENT_NODE) &&
3930 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00003931 occur++;
3932 tmp = tmp->next;
3933 }
3934 if (occur != 0)
3935 occur = 1;
3936 } else
3937 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00003938 } else if (cur->type == XML_COMMENT_NODE) {
3939 sep = "/";
3940 name = "comment()";
3941 next = cur->parent;
3942
3943 /*
3944 * Thumbler index computation
3945 */
3946 tmp = cur->prev;
3947 while (tmp != NULL) {
3948 if (tmp->type == XML_COMMENT_NODE)
3949 occur++;
3950 tmp = tmp->prev;
3951 }
3952 if (occur == 0) {
3953 tmp = cur->next;
3954 while (tmp != NULL && occur == 0) {
3955 if (tmp->type == XML_COMMENT_NODE)
3956 occur++;
3957 tmp = tmp->next;
3958 }
3959 if (occur != 0)
3960 occur = 1;
3961 } else
3962 occur++;
3963 } else if ((cur->type == XML_TEXT_NODE) ||
3964 (cur->type == XML_CDATA_SECTION_NODE)) {
3965 sep = "/";
3966 name = "text()";
3967 next = cur->parent;
3968
3969 /*
3970 * Thumbler index computation
3971 */
3972 tmp = cur->prev;
3973 while (tmp != NULL) {
3974 if ((cur->type == XML_TEXT_NODE) ||
3975 (cur->type == XML_CDATA_SECTION_NODE))
3976 occur++;
3977 tmp = tmp->prev;
3978 }
3979 if (occur == 0) {
3980 tmp = cur->next;
3981 while (tmp != NULL && occur == 0) {
3982 if ((cur->type == XML_TEXT_NODE) ||
3983 (cur->type == XML_CDATA_SECTION_NODE))
3984 occur++;
3985 tmp = tmp->next;
3986 }
3987 if (occur != 0)
3988 occur = 1;
3989 } else
3990 occur++;
3991 } else if (cur->type == XML_PI_NODE) {
3992 sep = "/";
3993 snprintf(nametemp, sizeof(nametemp) - 1,
3994 "processing-instruction('%s')", cur->name);
3995 nametemp[sizeof(nametemp) - 1] = 0;
3996 name = nametemp;
3997
3998 next = cur->parent;
3999
4000 /*
4001 * Thumbler index computation
4002 */
4003 tmp = cur->prev;
4004 while (tmp != NULL) {
4005 if ((tmp->type == XML_PI_NODE) &&
4006 (xmlStrEqual(cur->name, tmp->name)))
4007 occur++;
4008 tmp = tmp->prev;
4009 }
4010 if (occur == 0) {
4011 tmp = cur->next;
4012 while (tmp != NULL && occur == 0) {
4013 if ((tmp->type == XML_PI_NODE) &&
4014 (xmlStrEqual(cur->name, tmp->name)))
4015 occur++;
4016 tmp = tmp->next;
4017 }
4018 if (occur != 0)
4019 occur = 1;
4020 } else
4021 occur++;
4022
Daniel Veillard8faa7832001-11-26 15:58:08 +00004023 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004024 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004025 name = (const char *) (((xmlAttrPtr) cur)->name);
4026 next = ((xmlAttrPtr) cur)->parent;
4027 } else {
4028 next = cur->parent;
4029 }
4030
4031 /*
4032 * Make sure there is enough room
4033 */
4034 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4035 buf_len =
4036 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4037 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4038 if (temp == NULL) {
4039 xmlFree(buf);
4040 xmlFree(buffer);
4041 return (NULL);
4042 }
4043 buffer = temp;
4044 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4045 if (temp == NULL) {
4046 xmlFree(buf);
4047 xmlFree(buffer);
4048 return (NULL);
4049 }
4050 buf = temp;
4051 }
4052 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004053 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004054 sep, name, (char *) buffer);
4055 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004056 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004057 sep, name, occur, (char *) buffer);
4058 snprintf((char *) buffer, buf_len, "%s", buf);
4059 cur = next;
4060 } while (cur != NULL);
4061 xmlFree(buf);
4062 return (buffer);
4063}
4064
4065/**
Owen Taylor3473f882001-02-23 17:55:21 +00004066 * xmlDocGetRootElement:
4067 * @doc: the document
4068 *
4069 * Get the root element of the document (doc->children is a list
4070 * containing possibly comments, PIs, etc ...).
4071 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004072 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004073 */
4074xmlNodePtr
4075xmlDocGetRootElement(xmlDocPtr doc) {
4076 xmlNodePtr ret;
4077
4078 if (doc == NULL) return(NULL);
4079 ret = doc->children;
4080 while (ret != NULL) {
4081 if (ret->type == XML_ELEMENT_NODE)
4082 return(ret);
4083 ret = ret->next;
4084 }
4085 return(ret);
4086}
4087
4088/**
4089 * xmlDocSetRootElement:
4090 * @doc: the document
4091 * @root: the new document root element
4092 *
4093 * Set the root element of the document (doc->children is a list
4094 * containing possibly comments, PIs, etc ...).
4095 *
4096 * Returns the old root element if any was found
4097 */
4098xmlNodePtr
4099xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4100 xmlNodePtr old = NULL;
4101
4102 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004103 if (root == NULL)
4104 return(NULL);
4105 xmlUnlinkNode(root);
4106 root->doc = doc;
4107 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004108 old = doc->children;
4109 while (old != NULL) {
4110 if (old->type == XML_ELEMENT_NODE)
4111 break;
4112 old = old->next;
4113 }
4114 if (old == NULL) {
4115 if (doc->children == NULL) {
4116 doc->children = root;
4117 doc->last = root;
4118 } else {
4119 xmlAddSibling(doc->children, root);
4120 }
4121 } else {
4122 xmlReplaceNode(old, root);
4123 }
4124 return(old);
4125}
4126
4127/**
4128 * xmlNodeSetLang:
4129 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004130 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004131 *
4132 * Set the language of a node, i.e. the values of the xml:lang
4133 * attribute.
4134 */
4135void
4136xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004137 xmlNsPtr ns;
4138
Owen Taylor3473f882001-02-23 17:55:21 +00004139 if (cur == NULL) return;
4140 switch(cur->type) {
4141 case XML_TEXT_NODE:
4142 case XML_CDATA_SECTION_NODE:
4143 case XML_COMMENT_NODE:
4144 case XML_DOCUMENT_NODE:
4145 case XML_DOCUMENT_TYPE_NODE:
4146 case XML_DOCUMENT_FRAG_NODE:
4147 case XML_NOTATION_NODE:
4148 case XML_HTML_DOCUMENT_NODE:
4149 case XML_DTD_NODE:
4150 case XML_ELEMENT_DECL:
4151 case XML_ATTRIBUTE_DECL:
4152 case XML_ENTITY_DECL:
4153 case XML_PI_NODE:
4154 case XML_ENTITY_REF_NODE:
4155 case XML_ENTITY_NODE:
4156 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004157#ifdef LIBXML_DOCB_ENABLED
4158 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004159#endif
4160 case XML_XINCLUDE_START:
4161 case XML_XINCLUDE_END:
4162 return;
4163 case XML_ELEMENT_NODE:
4164 case XML_ATTRIBUTE_NODE:
4165 break;
4166 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004167 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4168 if (ns == NULL)
4169 return;
4170 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004171}
4172
4173/**
4174 * xmlNodeGetLang:
4175 * @cur: the node being checked
4176 *
4177 * Searches the language of a node, i.e. the values of the xml:lang
4178 * attribute or the one carried by the nearest ancestor.
4179 *
4180 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004181 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004182 */
4183xmlChar *
4184xmlNodeGetLang(xmlNodePtr cur) {
4185 xmlChar *lang;
4186
4187 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004188 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004189 if (lang != NULL)
4190 return(lang);
4191 cur = cur->parent;
4192 }
4193 return(NULL);
4194}
4195
4196
4197/**
4198 * xmlNodeSetSpacePreserve:
4199 * @cur: the node being changed
4200 * @val: the xml:space value ("0": default, 1: "preserve")
4201 *
4202 * Set (or reset) the space preserving behaviour of a node, i.e. the
4203 * value of the xml:space attribute.
4204 */
4205void
4206xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004207 xmlNsPtr ns;
4208
Owen Taylor3473f882001-02-23 17:55:21 +00004209 if (cur == NULL) return;
4210 switch(cur->type) {
4211 case XML_TEXT_NODE:
4212 case XML_CDATA_SECTION_NODE:
4213 case XML_COMMENT_NODE:
4214 case XML_DOCUMENT_NODE:
4215 case XML_DOCUMENT_TYPE_NODE:
4216 case XML_DOCUMENT_FRAG_NODE:
4217 case XML_NOTATION_NODE:
4218 case XML_HTML_DOCUMENT_NODE:
4219 case XML_DTD_NODE:
4220 case XML_ELEMENT_DECL:
4221 case XML_ATTRIBUTE_DECL:
4222 case XML_ENTITY_DECL:
4223 case XML_PI_NODE:
4224 case XML_ENTITY_REF_NODE:
4225 case XML_ENTITY_NODE:
4226 case XML_NAMESPACE_DECL:
4227 case XML_XINCLUDE_START:
4228 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004229#ifdef LIBXML_DOCB_ENABLED
4230 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004231#endif
4232 return;
4233 case XML_ELEMENT_NODE:
4234 case XML_ATTRIBUTE_NODE:
4235 break;
4236 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004237 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4238 if (ns == NULL)
4239 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004240 switch (val) {
4241 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004242 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004243 break;
4244 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004245 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004246 break;
4247 }
4248}
4249
4250/**
4251 * xmlNodeGetSpacePreserve:
4252 * @cur: the node being checked
4253 *
4254 * Searches the space preserving behaviour of a node, i.e. the values
4255 * of the xml:space attribute or the one carried by the nearest
4256 * ancestor.
4257 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004258 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004259 */
4260int
4261xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4262 xmlChar *space;
4263
4264 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004265 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004266 if (space != NULL) {
4267 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4268 xmlFree(space);
4269 return(1);
4270 }
4271 if (xmlStrEqual(space, BAD_CAST "default")) {
4272 xmlFree(space);
4273 return(0);
4274 }
4275 xmlFree(space);
4276 }
4277 cur = cur->parent;
4278 }
4279 return(-1);
4280}
4281
4282/**
4283 * xmlNodeSetName:
4284 * @cur: the node being changed
4285 * @name: the new tag name
4286 *
4287 * Set (or reset) the name of a node.
4288 */
4289void
4290xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
4291 if (cur == NULL) return;
4292 if (name == NULL) return;
4293 switch(cur->type) {
4294 case XML_TEXT_NODE:
4295 case XML_CDATA_SECTION_NODE:
4296 case XML_COMMENT_NODE:
4297 case XML_DOCUMENT_TYPE_NODE:
4298 case XML_DOCUMENT_FRAG_NODE:
4299 case XML_NOTATION_NODE:
4300 case XML_HTML_DOCUMENT_NODE:
4301 case XML_NAMESPACE_DECL:
4302 case XML_XINCLUDE_START:
4303 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004304#ifdef LIBXML_DOCB_ENABLED
4305 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004306#endif
4307 return;
4308 case XML_ELEMENT_NODE:
4309 case XML_ATTRIBUTE_NODE:
4310 case XML_PI_NODE:
4311 case XML_ENTITY_REF_NODE:
4312 case XML_ENTITY_NODE:
4313 case XML_DTD_NODE:
4314 case XML_DOCUMENT_NODE:
4315 case XML_ELEMENT_DECL:
4316 case XML_ATTRIBUTE_DECL:
4317 case XML_ENTITY_DECL:
4318 break;
4319 }
4320 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4321 cur->name = xmlStrdup(name);
4322}
4323
4324/**
4325 * xmlNodeSetBase:
4326 * @cur: the node being changed
4327 * @uri: the new base URI
4328 *
4329 * Set (or reset) the base URI of a node, i.e. the value of the
4330 * xml:base attribute.
4331 */
4332void
4333xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004334 xmlNsPtr ns;
4335
Owen Taylor3473f882001-02-23 17:55:21 +00004336 if (cur == NULL) return;
4337 switch(cur->type) {
4338 case XML_TEXT_NODE:
4339 case XML_CDATA_SECTION_NODE:
4340 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004341 case XML_DOCUMENT_TYPE_NODE:
4342 case XML_DOCUMENT_FRAG_NODE:
4343 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004344 case XML_DTD_NODE:
4345 case XML_ELEMENT_DECL:
4346 case XML_ATTRIBUTE_DECL:
4347 case XML_ENTITY_DECL:
4348 case XML_PI_NODE:
4349 case XML_ENTITY_REF_NODE:
4350 case XML_ENTITY_NODE:
4351 case XML_NAMESPACE_DECL:
4352 case XML_XINCLUDE_START:
4353 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004354 return;
4355 case XML_ELEMENT_NODE:
4356 case XML_ATTRIBUTE_NODE:
4357 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004358 case XML_DOCUMENT_NODE:
4359#ifdef LIBXML_DOCB_ENABLED
4360 case XML_DOCB_DOCUMENT_NODE:
4361#endif
4362 case XML_HTML_DOCUMENT_NODE: {
4363 xmlDocPtr doc = (xmlDocPtr) cur;
4364
4365 if (doc->URL != NULL)
4366 xmlFree((xmlChar *) doc->URL);
4367 if (uri == NULL)
4368 doc->URL = NULL;
4369 else
4370 doc->URL = xmlStrdup(uri);
4371 return;
4372 }
Owen Taylor3473f882001-02-23 17:55:21 +00004373 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004374
4375 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4376 if (ns == NULL)
4377 return;
4378 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004379}
4380
4381/**
Owen Taylor3473f882001-02-23 17:55:21 +00004382 * xmlNodeGetBase:
4383 * @doc: the document the node pertains to
4384 * @cur: the node being checked
4385 *
4386 * Searches for the BASE URL. The code should work on both XML
4387 * and HTML document even if base mechanisms are completely different.
4388 * It returns the base as defined in RFC 2396 sections
4389 * 5.1.1. Base URI within Document Content
4390 * and
4391 * 5.1.2. Base URI from the Encapsulating Entity
4392 * However it does not return the document base (5.1.3), use
4393 * xmlDocumentGetBase() for this
4394 *
4395 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004396 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004397 */
4398xmlChar *
4399xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004400 xmlChar *oldbase = NULL;
4401 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004402
4403 if ((cur == NULL) && (doc == NULL))
4404 return(NULL);
4405 if (doc == NULL) doc = cur->doc;
4406 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4407 cur = doc->children;
4408 while ((cur != NULL) && (cur->name != NULL)) {
4409 if (cur->type != XML_ELEMENT_NODE) {
4410 cur = cur->next;
4411 continue;
4412 }
4413 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4414 cur = cur->children;
4415 continue;
4416 }
4417 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4418 cur = cur->children;
4419 continue;
4420 }
4421 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4422 return(xmlGetProp(cur, BAD_CAST "href"));
4423 }
4424 cur = cur->next;
4425 }
4426 return(NULL);
4427 }
4428 while (cur != NULL) {
4429 if (cur->type == XML_ENTITY_DECL) {
4430 xmlEntityPtr ent = (xmlEntityPtr) cur;
4431 return(xmlStrdup(ent->URI));
4432 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004433 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004434 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004435 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004436 if (oldbase != NULL) {
4437 newbase = xmlBuildURI(oldbase, base);
4438 if (newbase != NULL) {
4439 xmlFree(oldbase);
4440 xmlFree(base);
4441 oldbase = newbase;
4442 } else {
4443 xmlFree(oldbase);
4444 xmlFree(base);
4445 return(NULL);
4446 }
4447 } else {
4448 oldbase = base;
4449 }
4450 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4451 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4452 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4453 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004454 }
4455 }
Owen Taylor3473f882001-02-23 17:55:21 +00004456 cur = cur->parent;
4457 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004458 if ((doc != NULL) && (doc->URL != NULL)) {
4459 if (oldbase == NULL)
4460 return(xmlStrdup(doc->URL));
4461 newbase = xmlBuildURI(oldbase, doc->URL);
4462 xmlFree(oldbase);
4463 return(newbase);
4464 }
4465 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004466}
4467
4468/**
4469 * xmlNodeGetContent:
4470 * @cur: the node being read
4471 *
4472 * Read the value of a node, this can be either the text carried
4473 * directly by this node if it's a TEXT node or the aggregate string
4474 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004475 * Entity references are substituted.
4476 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004477 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004478 */
4479xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004480xmlNodeGetContent(xmlNodePtr cur)
4481{
4482 if (cur == NULL)
4483 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004484 switch (cur->type) {
4485 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004486 case XML_ELEMENT_NODE:{
4487 xmlNodePtr tmp = cur;
4488 xmlBufferPtr buffer;
4489 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004490
Daniel Veillard814a76d2003-01-23 18:24:20 +00004491 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004492 if (buffer == NULL)
4493 return (NULL);
4494 while (tmp != NULL) {
4495 switch (tmp->type) {
4496 case XML_CDATA_SECTION_NODE:
4497 case XML_TEXT_NODE:
4498 if (tmp->content != NULL)
4499 xmlBufferCat(buffer, tmp->content);
4500 break;
4501 case XML_ENTITY_REF_NODE:{
4502 /* recursive substitution of entity references */
4503 xmlChar *cont = xmlNodeGetContent(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00004504
Daniel Veillard7646b182002-04-20 06:41:40 +00004505 if (cont) {
4506 xmlBufferCat(buffer,
4507 (const xmlChar *) cont);
4508 xmlFree(cont);
4509 }
4510 break;
4511 }
4512 default:
4513 break;
4514 }
4515 /*
4516 * Skip to next node
4517 */
4518 if (tmp->children != NULL) {
4519 if (tmp->children->type != XML_ENTITY_DECL) {
4520 tmp = tmp->children;
4521 continue;
4522 }
4523 }
4524 if (tmp == cur)
4525 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00004526
Daniel Veillard7646b182002-04-20 06:41:40 +00004527 if (tmp->next != NULL) {
4528 tmp = tmp->next;
4529 continue;
4530 }
4531
4532 do {
4533 tmp = tmp->parent;
4534 if (tmp == NULL)
4535 break;
4536 if (tmp == cur) {
4537 tmp = NULL;
4538 break;
4539 }
4540 if (tmp->next != NULL) {
4541 tmp = tmp->next;
4542 break;
4543 }
4544 } while (tmp != NULL);
4545 }
4546 ret = buffer->content;
4547 buffer->content = NULL;
4548 xmlBufferFree(buffer);
4549 return (ret);
4550 }
4551 case XML_ATTRIBUTE_NODE:{
4552 xmlAttrPtr attr = (xmlAttrPtr) cur;
4553
4554 if (attr->parent != NULL)
4555 return (xmlNodeListGetString
4556 (attr->parent->doc, attr->children, 1));
4557 else
4558 return (xmlNodeListGetString(NULL, attr->children, 1));
4559 break;
4560 }
Owen Taylor3473f882001-02-23 17:55:21 +00004561 case XML_COMMENT_NODE:
4562 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004563 if (cur->content != NULL)
4564 return (xmlStrdup(cur->content));
4565 return (NULL);
4566 case XML_ENTITY_REF_NODE:{
4567 xmlEntityPtr ent;
4568 xmlNodePtr tmp;
4569 xmlBufferPtr buffer;
4570 xmlChar *ret;
4571
4572 /* lookup entity declaration */
4573 ent = xmlGetDocEntity(cur->doc, cur->name);
4574 if (ent == NULL)
4575 return (NULL);
4576
4577 buffer = xmlBufferCreate();
4578 if (buffer == NULL)
4579 return (NULL);
4580
4581 /* an entity content can be any "well balanced chunk",
4582 * i.e. the result of the content [43] production:
4583 * http://www.w3.org/TR/REC-xml#NT-content
4584 * -> we iterate through child nodes and recursive call
4585 * xmlNodeGetContent() which handles all possible node types */
4586 tmp = ent->children;
4587 while (tmp) {
4588 xmlChar *cont = xmlNodeGetContent(tmp);
4589
4590 if (cont) {
4591 xmlBufferCat(buffer, (const xmlChar *) cont);
4592 xmlFree(cont);
4593 }
4594 tmp = tmp->next;
4595 }
4596
4597 ret = buffer->content;
4598 buffer->content = NULL;
4599 xmlBufferFree(buffer);
4600 return (ret);
4601 }
Owen Taylor3473f882001-02-23 17:55:21 +00004602 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004603 case XML_DOCUMENT_TYPE_NODE:
4604 case XML_NOTATION_NODE:
4605 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004606 case XML_XINCLUDE_START:
4607 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00004608 return (NULL);
4609 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004610#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004611 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004612#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00004613 case XML_HTML_DOCUMENT_NODE: {
4614 xmlChar *tmp;
4615 xmlChar *res = NULL;
4616
4617 cur = cur->children;
4618 while (cur!= NULL) {
4619 if ((cur->type == XML_ELEMENT_NODE) ||
4620 (cur->type == XML_TEXT_NODE) ||
4621 (cur->type == XML_CDATA_SECTION_NODE)) {
4622 tmp = xmlNodeGetContent(cur);
4623 if (tmp != NULL) {
4624 if (res == NULL)
4625 res = tmp;
4626 else {
4627 res = xmlStrcat(res, tmp);
4628 xmlFree(tmp);
4629 }
4630 }
4631 }
4632 cur = cur->next;
4633 }
4634 return(res);
4635 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004636 case XML_NAMESPACE_DECL: {
4637 xmlChar *tmp;
4638
4639 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4640 return (tmp);
4641 }
Owen Taylor3473f882001-02-23 17:55:21 +00004642 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004643 /* TODO !!! */
4644 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004645 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004646 /* TODO !!! */
4647 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004648 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004649 /* TODO !!! */
4650 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004651 case XML_CDATA_SECTION_NODE:
4652 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004653 if (cur->content != NULL)
4654 return (xmlStrdup(cur->content));
4655 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004656 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004657 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004658}
Owen Taylor3473f882001-02-23 17:55:21 +00004659/**
4660 * xmlNodeSetContent:
4661 * @cur: the node being modified
4662 * @content: the new value of the content
4663 *
4664 * Replace the content of a node.
4665 */
4666void
4667xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4668 if (cur == NULL) {
4669#ifdef DEBUG_TREE
4670 xmlGenericError(xmlGenericErrorContext,
4671 "xmlNodeSetContent : node == NULL\n");
4672#endif
4673 return;
4674 }
4675 switch (cur->type) {
4676 case XML_DOCUMENT_FRAG_NODE:
4677 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004678 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004679 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4680 cur->children = xmlStringGetNodeList(cur->doc, content);
4681 UPDATE_LAST_CHILD_AND_PARENT(cur)
4682 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004683 case XML_TEXT_NODE:
4684 case XML_CDATA_SECTION_NODE:
4685 case XML_ENTITY_REF_NODE:
4686 case XML_ENTITY_NODE:
4687 case XML_PI_NODE:
4688 case XML_COMMENT_NODE:
4689 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004690 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004691 }
4692 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4693 cur->last = cur->children = NULL;
4694 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004695 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00004696 } else
4697 cur->content = NULL;
4698 break;
4699 case XML_DOCUMENT_NODE:
4700 case XML_HTML_DOCUMENT_NODE:
4701 case XML_DOCUMENT_TYPE_NODE:
4702 case XML_XINCLUDE_START:
4703 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004704#ifdef LIBXML_DOCB_ENABLED
4705 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004706#endif
4707 break;
4708 case XML_NOTATION_NODE:
4709 break;
4710 case XML_DTD_NODE:
4711 break;
4712 case XML_NAMESPACE_DECL:
4713 break;
4714 case XML_ELEMENT_DECL:
4715 /* TODO !!! */
4716 break;
4717 case XML_ATTRIBUTE_DECL:
4718 /* TODO !!! */
4719 break;
4720 case XML_ENTITY_DECL:
4721 /* TODO !!! */
4722 break;
4723 }
4724}
4725
4726/**
4727 * xmlNodeSetContentLen:
4728 * @cur: the node being modified
4729 * @content: the new value of the content
4730 * @len: the size of @content
4731 *
4732 * Replace the content of a node.
4733 */
4734void
4735xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4736 if (cur == NULL) {
4737#ifdef DEBUG_TREE
4738 xmlGenericError(xmlGenericErrorContext,
4739 "xmlNodeSetContentLen : node == NULL\n");
4740#endif
4741 return;
4742 }
4743 switch (cur->type) {
4744 case XML_DOCUMENT_FRAG_NODE:
4745 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004746 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004747 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4748 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
4749 UPDATE_LAST_CHILD_AND_PARENT(cur)
4750 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004751 case XML_TEXT_NODE:
4752 case XML_CDATA_SECTION_NODE:
4753 case XML_ENTITY_REF_NODE:
4754 case XML_ENTITY_NODE:
4755 case XML_PI_NODE:
4756 case XML_COMMENT_NODE:
4757 case XML_NOTATION_NODE:
4758 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004759 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004760 }
4761 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4762 cur->children = cur->last = NULL;
4763 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004764 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004765 } else
4766 cur->content = NULL;
4767 break;
4768 case XML_DOCUMENT_NODE:
4769 case XML_DTD_NODE:
4770 case XML_HTML_DOCUMENT_NODE:
4771 case XML_DOCUMENT_TYPE_NODE:
4772 case XML_NAMESPACE_DECL:
4773 case XML_XINCLUDE_START:
4774 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004775#ifdef LIBXML_DOCB_ENABLED
4776 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004777#endif
4778 break;
4779 case XML_ELEMENT_DECL:
4780 /* TODO !!! */
4781 break;
4782 case XML_ATTRIBUTE_DECL:
4783 /* TODO !!! */
4784 break;
4785 case XML_ENTITY_DECL:
4786 /* TODO !!! */
4787 break;
4788 }
4789}
4790
4791/**
4792 * xmlNodeAddContentLen:
4793 * @cur: the node being modified
4794 * @content: extra content
4795 * @len: the size of @content
4796 *
4797 * Append the extra substring to the node content.
4798 */
4799void
4800xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4801 if (cur == NULL) {
4802#ifdef DEBUG_TREE
4803 xmlGenericError(xmlGenericErrorContext,
4804 "xmlNodeAddContentLen : node == NULL\n");
4805#endif
4806 return;
4807 }
4808 if (len <= 0) return;
4809 switch (cur->type) {
4810 case XML_DOCUMENT_FRAG_NODE:
4811 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004812 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004813
Daniel Veillard7db37732001-07-12 01:20:08 +00004814 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004815 newNode = xmlNewTextLen(content, len);
4816 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004817 tmp = xmlAddChild(cur, newNode);
4818 if (tmp != newNode)
4819 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004820 if ((last != NULL) && (last->next == newNode)) {
4821 xmlTextMerge(last, newNode);
4822 }
4823 }
4824 break;
4825 }
4826 case XML_ATTRIBUTE_NODE:
4827 break;
4828 case XML_TEXT_NODE:
4829 case XML_CDATA_SECTION_NODE:
4830 case XML_ENTITY_REF_NODE:
4831 case XML_ENTITY_NODE:
4832 case XML_PI_NODE:
4833 case XML_COMMENT_NODE:
4834 case XML_NOTATION_NODE:
4835 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004836 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004837 }
4838 case XML_DOCUMENT_NODE:
4839 case XML_DTD_NODE:
4840 case XML_HTML_DOCUMENT_NODE:
4841 case XML_DOCUMENT_TYPE_NODE:
4842 case XML_NAMESPACE_DECL:
4843 case XML_XINCLUDE_START:
4844 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004845#ifdef LIBXML_DOCB_ENABLED
4846 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004847#endif
4848 break;
4849 case XML_ELEMENT_DECL:
4850 case XML_ATTRIBUTE_DECL:
4851 case XML_ENTITY_DECL:
4852 break;
4853 }
4854}
4855
4856/**
4857 * xmlNodeAddContent:
4858 * @cur: the node being modified
4859 * @content: extra content
4860 *
4861 * Append the extra substring to the node content.
4862 */
4863void
4864xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
4865 int len;
4866
4867 if (cur == NULL) {
4868#ifdef DEBUG_TREE
4869 xmlGenericError(xmlGenericErrorContext,
4870 "xmlNodeAddContent : node == NULL\n");
4871#endif
4872 return;
4873 }
4874 if (content == NULL) return;
4875 len = xmlStrlen(content);
4876 xmlNodeAddContentLen(cur, content, len);
4877}
4878
4879/**
4880 * xmlTextMerge:
4881 * @first: the first text node
4882 * @second: the second text node being merged
4883 *
4884 * Merge two text nodes into one
4885 * Returns the first text node augmented
4886 */
4887xmlNodePtr
4888xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
4889 if (first == NULL) return(second);
4890 if (second == NULL) return(first);
4891 if (first->type != XML_TEXT_NODE) return(first);
4892 if (second->type != XML_TEXT_NODE) return(first);
4893 if (second->name != first->name)
4894 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00004895 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004896 xmlUnlinkNode(second);
4897 xmlFreeNode(second);
4898 return(first);
4899}
4900
4901/**
4902 * xmlGetNsList:
4903 * @doc: the document
4904 * @node: the current node
4905 *
4906 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00004907 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00004908 * that need to be freed by the caller or NULL if no
4909 * namespace if defined
4910 */
4911xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00004912xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
4913{
Owen Taylor3473f882001-02-23 17:55:21 +00004914 xmlNsPtr cur;
4915 xmlNsPtr *ret = NULL;
4916 int nbns = 0;
4917 int maxns = 10;
4918 int i;
4919
4920 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00004921 if (node->type == XML_ELEMENT_NODE) {
4922 cur = node->nsDef;
4923 while (cur != NULL) {
4924 if (ret == NULL) {
4925 ret =
4926 (xmlNsPtr *) xmlMalloc((maxns + 1) *
4927 sizeof(xmlNsPtr));
4928 if (ret == NULL) {
4929 xmlGenericError(xmlGenericErrorContext,
4930 "xmlGetNsList : out of memory!\n");
4931 return (NULL);
4932 }
4933 ret[nbns] = NULL;
4934 }
4935 for (i = 0; i < nbns; i++) {
4936 if ((cur->prefix == ret[i]->prefix) ||
4937 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
4938 break;
4939 }
4940 if (i >= nbns) {
4941 if (nbns >= maxns) {
4942 maxns *= 2;
4943 ret = (xmlNsPtr *) xmlRealloc(ret,
4944 (maxns +
4945 1) *
4946 sizeof(xmlNsPtr));
4947 if (ret == NULL) {
4948 xmlGenericError(xmlGenericErrorContext,
4949 "xmlGetNsList : realloc failed!\n");
4950 return (NULL);
4951 }
4952 }
4953 ret[nbns++] = cur;
4954 ret[nbns] = NULL;
4955 }
Owen Taylor3473f882001-02-23 17:55:21 +00004956
Daniel Veillard77044732001-06-29 21:31:07 +00004957 cur = cur->next;
4958 }
4959 }
4960 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004961 }
Daniel Veillard77044732001-06-29 21:31:07 +00004962 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004963}
4964
4965/**
4966 * xmlSearchNs:
4967 * @doc: the document
4968 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004969 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004970 *
4971 * Search a Ns registered under a given name space for a document.
4972 * recurse on the parents until it finds the defined namespace
4973 * or return NULL otherwise.
4974 * @nameSpace can be NULL, this is a search for the default namespace.
4975 * We don't allow to cross entities boundaries. If you don't declare
4976 * the namespace within those you will be in troubles !!! A warning
4977 * is generated to cover this case.
4978 *
4979 * Returns the namespace pointer or NULL.
4980 */
4981xmlNsPtr
4982xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4983 xmlNsPtr cur;
4984
4985 if (node == NULL) return(NULL);
4986 if ((nameSpace != NULL) &&
4987 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00004988 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4989 /*
4990 * The XML-1.0 namespace is normally held on the root
4991 * element. In this case exceptionally create it on the
4992 * node element.
4993 */
4994 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4995 if (cur == NULL) {
4996 xmlGenericError(xmlGenericErrorContext,
4997 "xmlSearchNs : malloc failed\n");
4998 return(NULL);
4999 }
5000 memset(cur, 0, sizeof(xmlNs));
5001 cur->type = XML_LOCAL_NAMESPACE;
5002 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5003 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5004 cur->next = node->nsDef;
5005 node->nsDef = cur;
5006 return(cur);
5007 }
Owen Taylor3473f882001-02-23 17:55:21 +00005008 if (doc->oldNs == NULL) {
5009 /*
5010 * Allocate a new Namespace and fill the fields.
5011 */
5012 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5013 if (doc->oldNs == NULL) {
5014 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005015 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005016 return(NULL);
5017 }
5018 memset(doc->oldNs, 0, sizeof(xmlNs));
5019 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5020
5021 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5022 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5023 }
5024 return(doc->oldNs);
5025 }
5026 while (node != NULL) {
5027 if ((node->type == XML_ENTITY_REF_NODE) ||
5028 (node->type == XML_ENTITY_NODE) ||
5029 (node->type == XML_ENTITY_DECL))
5030 return(NULL);
5031 if (node->type == XML_ELEMENT_NODE) {
5032 cur = node->nsDef;
5033 while (cur != NULL) {
5034 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5035 (cur->href != NULL))
5036 return(cur);
5037 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5038 (cur->href != NULL) &&
5039 (xmlStrEqual(cur->prefix, nameSpace)))
5040 return(cur);
5041 cur = cur->next;
5042 }
5043 }
5044 node = node->parent;
5045 }
5046 return(NULL);
5047}
5048
5049/**
5050 * xmlSearchNsByHref:
5051 * @doc: the document
5052 * @node: the current node
5053 * @href: the namespace value
5054 *
5055 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5056 * the defined namespace or return NULL otherwise.
5057 * Returns the namespace pointer or NULL.
5058 */
5059xmlNsPtr
5060xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
5061 xmlNsPtr cur;
5062 xmlNodePtr orig = node;
5063
5064 if ((node == NULL) || (href == NULL)) return(NULL);
5065 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00005066 /*
5067 * Only the document can hold the XML spec namespace.
5068 */
Daniel Veillardc1a0da32002-08-14 08:32:18 +00005069 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5070 /*
5071 * The XML-1.0 namespace is normally held on the root
5072 * element. In this case exceptionally create it on the
5073 * node element.
5074 */
5075 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5076 if (cur == NULL) {
5077 xmlGenericError(xmlGenericErrorContext,
5078 "xmlSearchNs : malloc failed\n");
5079 return(NULL);
5080 }
5081 memset(cur, 0, sizeof(xmlNs));
5082 cur->type = XML_LOCAL_NAMESPACE;
5083 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5084 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5085 cur->next = node->nsDef;
5086 node->nsDef = cur;
5087 return(cur);
5088 }
Owen Taylor3473f882001-02-23 17:55:21 +00005089 if (doc->oldNs == NULL) {
5090 /*
5091 * Allocate a new Namespace and fill the fields.
5092 */
5093 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5094 if (doc->oldNs == NULL) {
5095 xmlGenericError(xmlGenericErrorContext,
5096 "xmlSearchNsByHref : malloc failed\n");
5097 return(NULL);
5098 }
5099 memset(doc->oldNs, 0, sizeof(xmlNs));
5100 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5101
5102 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5103 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5104 }
5105 return(doc->oldNs);
5106 }
5107 while (node != NULL) {
5108 cur = node->nsDef;
5109 while (cur != NULL) {
5110 if ((cur->href != NULL) && (href != NULL) &&
5111 (xmlStrEqual(cur->href, href))) {
5112 /*
5113 * Check that the prefix is not shadowed between orig and node
5114 */
5115 xmlNodePtr check = orig;
5116 xmlNsPtr tst;
5117
5118 while (check != node) {
5119 tst = check->nsDef;
5120 while (tst != NULL) {
5121 if ((tst->prefix == NULL) && (cur->prefix == NULL))
5122 goto shadowed;
5123 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
5124 (xmlStrEqual(tst->prefix, cur->prefix)))
5125 goto shadowed;
5126 tst = tst->next;
5127 }
5128 check = check->parent;
5129 }
5130 return(cur);
5131 }
5132shadowed:
5133 cur = cur->next;
5134 }
5135 node = node->parent;
5136 }
5137 return(NULL);
5138}
5139
5140/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005141 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005142 * @doc: the document
5143 * @tree: a node expected to hold the new namespace
5144 * @ns: the original namespace
5145 *
5146 * This function tries to locate a namespace definition in a tree
5147 * ancestors, or create a new namespace definition node similar to
5148 * @ns trying to reuse the same prefix. However if the given prefix is
5149 * null (default namespace) or reused within the subtree defined by
5150 * @tree or on one of its ancestors then a new prefix is generated.
5151 * Returns the (new) namespace definition or NULL in case of error
5152 */
5153xmlNsPtr
5154xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5155 xmlNsPtr def;
5156 xmlChar prefix[50];
5157 int counter = 1;
5158
5159 if (tree == NULL) {
5160#ifdef DEBUG_TREE
5161 xmlGenericError(xmlGenericErrorContext,
5162 "xmlNewReconciliedNs : tree == NULL\n");
5163#endif
5164 return(NULL);
5165 }
5166 if (ns == NULL) {
5167#ifdef DEBUG_TREE
5168 xmlGenericError(xmlGenericErrorContext,
5169 "xmlNewReconciliedNs : ns == NULL\n");
5170#endif
5171 return(NULL);
5172 }
5173 /*
5174 * Search an existing namespace definition inherited.
5175 */
5176 def = xmlSearchNsByHref(doc, tree, ns->href);
5177 if (def != NULL)
5178 return(def);
5179
5180 /*
5181 * Find a close prefix which is not already in use.
5182 * Let's strip namespace prefixes longer than 20 chars !
5183 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005184 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005185 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005186 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005187 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005188
Owen Taylor3473f882001-02-23 17:55:21 +00005189 def = xmlSearchNs(doc, tree, prefix);
5190 while (def != NULL) {
5191 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005192 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005193 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005194 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005195 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005196 def = xmlSearchNs(doc, tree, prefix);
5197 }
5198
5199 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005200 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005201 */
5202 def = xmlNewNs(tree, ns->href, prefix);
5203 return(def);
5204}
5205
5206/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005207 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005208 * @doc: the document
5209 * @tree: a node defining the subtree to reconciliate
5210 *
5211 * This function checks that all the namespaces declared within the given
5212 * tree are properly declared. This is needed for example after Copy or Cut
5213 * and then paste operations. The subtree may still hold pointers to
5214 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005215 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005216 * the new environment. If not possible the new namespaces are redeclared
5217 * on @tree at the top of the given subtree.
5218 * Returns the number of namespace declarations created or -1 in case of error.
5219 */
5220int
5221xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5222 xmlNsPtr *oldNs = NULL;
5223 xmlNsPtr *newNs = NULL;
5224 int sizeCache = 0;
5225 int nbCache = 0;
5226
5227 xmlNsPtr n;
5228 xmlNodePtr node = tree;
5229 xmlAttrPtr attr;
5230 int ret = 0, i;
5231
5232 while (node != NULL) {
5233 /*
5234 * Reconciliate the node namespace
5235 */
5236 if (node->ns != NULL) {
5237 /*
5238 * initialize the cache if needed
5239 */
5240 if (sizeCache == 0) {
5241 sizeCache = 10;
5242 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5243 sizeof(xmlNsPtr));
5244 if (oldNs == NULL) {
5245 xmlGenericError(xmlGenericErrorContext,
5246 "xmlReconciliateNs : memory pbm\n");
5247 return(-1);
5248 }
5249 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5250 sizeof(xmlNsPtr));
5251 if (newNs == NULL) {
5252 xmlGenericError(xmlGenericErrorContext,
5253 "xmlReconciliateNs : memory pbm\n");
5254 xmlFree(oldNs);
5255 return(-1);
5256 }
5257 }
5258 for (i = 0;i < nbCache;i++) {
5259 if (oldNs[i] == node->ns) {
5260 node->ns = newNs[i];
5261 break;
5262 }
5263 }
5264 if (i == nbCache) {
5265 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005266 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005267 */
5268 n = xmlNewReconciliedNs(doc, tree, node->ns);
5269 if (n != NULL) { /* :-( what if else ??? */
5270 /*
5271 * check if we need to grow the cache buffers.
5272 */
5273 if (sizeCache <= nbCache) {
5274 sizeCache *= 2;
5275 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5276 sizeof(xmlNsPtr));
5277 if (oldNs == NULL) {
5278 xmlGenericError(xmlGenericErrorContext,
5279 "xmlReconciliateNs : memory pbm\n");
5280 xmlFree(newNs);
5281 return(-1);
5282 }
5283 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5284 sizeof(xmlNsPtr));
5285 if (newNs == NULL) {
5286 xmlGenericError(xmlGenericErrorContext,
5287 "xmlReconciliateNs : memory pbm\n");
5288 xmlFree(oldNs);
5289 return(-1);
5290 }
5291 }
5292 newNs[nbCache] = n;
5293 oldNs[nbCache++] = node->ns;
5294 node->ns = n;
5295 }
5296 }
5297 }
5298 /*
5299 * now check for namespace hold by attributes on the node.
5300 */
5301 attr = node->properties;
5302 while (attr != NULL) {
5303 if (attr->ns != NULL) {
5304 /*
5305 * initialize the cache if needed
5306 */
5307 if (sizeCache == 0) {
5308 sizeCache = 10;
5309 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5310 sizeof(xmlNsPtr));
5311 if (oldNs == NULL) {
5312 xmlGenericError(xmlGenericErrorContext,
5313 "xmlReconciliateNs : memory pbm\n");
5314 return(-1);
5315 }
5316 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5317 sizeof(xmlNsPtr));
5318 if (newNs == NULL) {
5319 xmlGenericError(xmlGenericErrorContext,
5320 "xmlReconciliateNs : memory pbm\n");
5321 xmlFree(oldNs);
5322 return(-1);
5323 }
5324 }
5325 for (i = 0;i < nbCache;i++) {
5326 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005327 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005328 break;
5329 }
5330 }
5331 if (i == nbCache) {
5332 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005333 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005334 */
5335 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5336 if (n != NULL) { /* :-( what if else ??? */
5337 /*
5338 * check if we need to grow the cache buffers.
5339 */
5340 if (sizeCache <= nbCache) {
5341 sizeCache *= 2;
5342 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5343 sizeof(xmlNsPtr));
5344 if (oldNs == NULL) {
5345 xmlGenericError(xmlGenericErrorContext,
5346 "xmlReconciliateNs : memory pbm\n");
5347 xmlFree(newNs);
5348 return(-1);
5349 }
5350 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5351 sizeof(xmlNsPtr));
5352 if (newNs == NULL) {
5353 xmlGenericError(xmlGenericErrorContext,
5354 "xmlReconciliateNs : memory pbm\n");
5355 xmlFree(oldNs);
5356 return(-1);
5357 }
5358 }
5359 newNs[nbCache] = n;
5360 oldNs[nbCache++] = attr->ns;
5361 attr->ns = n;
5362 }
5363 }
5364 }
5365 attr = attr->next;
5366 }
5367
5368 /*
5369 * Browse the full subtree, deep first
5370 */
5371 if (node->children != NULL) {
5372 /* deep first */
5373 node = node->children;
5374 } else if ((node != tree) && (node->next != NULL)) {
5375 /* then siblings */
5376 node = node->next;
5377 } else if (node != tree) {
5378 /* go up to parents->next if needed */
5379 while (node != tree) {
5380 if (node->parent != NULL)
5381 node = node->parent;
5382 if ((node != tree) && (node->next != NULL)) {
5383 node = node->next;
5384 break;
5385 }
5386 if (node->parent == NULL) {
5387 node = NULL;
5388 break;
5389 }
5390 }
5391 /* exit condition */
5392 if (node == tree)
5393 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005394 } else
5395 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005396 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005397 if (oldNs != NULL)
5398 xmlFree(oldNs);
5399 if (newNs != NULL)
5400 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005401 return(ret);
5402}
5403
5404/**
5405 * xmlHasProp:
5406 * @node: the node
5407 * @name: the attribute name
5408 *
5409 * Search an attribute associated to a node
5410 * This function also looks in DTD attribute declaration for #FIXED or
5411 * default declaration values unless DTD use has been turned off.
5412 *
5413 * Returns the attribute or the attribute declaration or NULL if
5414 * neither was found.
5415 */
5416xmlAttrPtr
5417xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5418 xmlAttrPtr prop;
5419 xmlDocPtr doc;
5420
5421 if ((node == NULL) || (name == NULL)) return(NULL);
5422 /*
5423 * Check on the properties attached to the node
5424 */
5425 prop = node->properties;
5426 while (prop != NULL) {
5427 if (xmlStrEqual(prop->name, name)) {
5428 return(prop);
5429 }
5430 prop = prop->next;
5431 }
5432 if (!xmlCheckDTD) return(NULL);
5433
5434 /*
5435 * Check if there is a default declaration in the internal
5436 * or external subsets
5437 */
5438 doc = node->doc;
5439 if (doc != NULL) {
5440 xmlAttributePtr attrDecl;
5441 if (doc->intSubset != NULL) {
5442 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5443 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5444 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5445 if (attrDecl != NULL)
5446 return((xmlAttrPtr) attrDecl);
5447 }
5448 }
5449 return(NULL);
5450}
5451
5452/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005453 * xmlHasNsProp:
5454 * @node: the node
5455 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005456 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005457 *
5458 * Search for an attribute associated to a node
5459 * This attribute has to be anchored in the namespace specified.
5460 * This does the entity substitution.
5461 * This function looks in DTD attribute declaration for #FIXED or
5462 * default declaration values unless DTD use has been turned off.
5463 *
5464 * Returns the attribute or the attribute declaration or NULL
5465 * if neither was found.
5466 */
5467xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005468xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005469 xmlAttrPtr prop;
5470 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005471
5472 if (node == NULL)
5473 return(NULL);
5474
5475 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005476 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005477 return(xmlHasProp(node, name));
5478 while (prop != NULL) {
5479 /*
5480 * One need to have
5481 * - same attribute names
5482 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005483 */
5484 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005485 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5486 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005487 }
5488 prop = prop->next;
5489 }
5490 if (!xmlCheckDTD) return(NULL);
5491
5492 /*
5493 * Check if there is a default declaration in the internal
5494 * or external subsets
5495 */
5496 doc = node->doc;
5497 if (doc != NULL) {
5498 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005499 xmlAttributePtr attrDecl = NULL;
5500 xmlNsPtr *nsList, *cur;
5501 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005502
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005503 nsList = xmlGetNsList(node->doc, node);
5504 if (nsList == NULL)
5505 return(NULL);
5506 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5507 ename = xmlStrdup(node->ns->prefix);
5508 ename = xmlStrcat(ename, BAD_CAST ":");
5509 ename = xmlStrcat(ename, node->name);
5510 } else {
5511 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005512 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005513 if (ename == NULL) {
5514 xmlFree(nsList);
5515 return(NULL);
5516 }
5517
5518 cur = nsList;
5519 while (*cur != NULL) {
5520 if (xmlStrEqual((*cur)->href, nameSpace)) {
5521 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5522 name, (*cur)->prefix);
5523 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5524 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5525 name, (*cur)->prefix);
5526 }
5527 cur++;
5528 }
5529 xmlFree(nsList);
5530 xmlFree(ename);
5531 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005532 }
5533 }
5534 return(NULL);
5535}
5536
5537/**
Owen Taylor3473f882001-02-23 17:55:21 +00005538 * xmlGetProp:
5539 * @node: the node
5540 * @name: the attribute name
5541 *
5542 * Search and get the value of an attribute associated to a node
5543 * This does the entity substitution.
5544 * This function looks in DTD attribute declaration for #FIXED or
5545 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00005546 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00005547 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
5548 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00005549 *
5550 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005551 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005552 */
5553xmlChar *
5554xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5555 xmlAttrPtr prop;
5556 xmlDocPtr doc;
5557
5558 if ((node == NULL) || (name == NULL)) return(NULL);
5559 /*
5560 * Check on the properties attached to the node
5561 */
5562 prop = node->properties;
5563 while (prop != NULL) {
5564 if (xmlStrEqual(prop->name, name)) {
5565 xmlChar *ret;
5566
5567 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5568 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5569 return(ret);
5570 }
5571 prop = prop->next;
5572 }
5573 if (!xmlCheckDTD) return(NULL);
5574
5575 /*
5576 * Check if there is a default declaration in the internal
5577 * or external subsets
5578 */
5579 doc = node->doc;
5580 if (doc != NULL) {
5581 xmlAttributePtr attrDecl;
5582 if (doc->intSubset != NULL) {
5583 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5584 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5585 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5586 if (attrDecl != NULL)
5587 return(xmlStrdup(attrDecl->defaultValue));
5588 }
5589 }
5590 return(NULL);
5591}
5592
5593/**
Daniel Veillard71531f32003-02-05 13:19:53 +00005594 * xmlGetNoNsProp:
5595 * @node: the node
5596 * @name: the attribute name
5597 *
5598 * Search and get the value of an attribute associated to a node
5599 * This does the entity substitution.
5600 * This function looks in DTD attribute declaration for #FIXED or
5601 * default declaration values unless DTD use has been turned off.
5602 * This function is similar to xmlGetProp except it will accept only
5603 * an attribute in no namespace.
5604 *
5605 * Returns the attribute value or NULL if not found.
5606 * It's up to the caller to free the memory with xmlFree().
5607 */
5608xmlChar *
5609xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
5610 xmlAttrPtr prop;
5611 xmlDocPtr doc;
5612
5613 if ((node == NULL) || (name == NULL)) return(NULL);
5614 /*
5615 * Check on the properties attached to the node
5616 */
5617 prop = node->properties;
5618 while (prop != NULL) {
5619 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
5620 xmlChar *ret;
5621
5622 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5623 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5624 return(ret);
5625 }
5626 prop = prop->next;
5627 }
5628 if (!xmlCheckDTD) return(NULL);
5629
5630 /*
5631 * Check if there is a default declaration in the internal
5632 * or external subsets
5633 */
5634 doc = node->doc;
5635 if (doc != NULL) {
5636 xmlAttributePtr attrDecl;
5637 if (doc->intSubset != NULL) {
5638 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5639 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5640 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5641 if (attrDecl != NULL)
5642 return(xmlStrdup(attrDecl->defaultValue));
5643 }
5644 }
5645 return(NULL);
5646}
5647
5648/**
Owen Taylor3473f882001-02-23 17:55:21 +00005649 * xmlGetNsProp:
5650 * @node: the node
5651 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005652 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005653 *
5654 * Search and get the value of an attribute associated to a node
5655 * This attribute has to be anchored in the namespace specified.
5656 * This does the entity substitution.
5657 * This function looks in DTD attribute declaration for #FIXED or
5658 * default declaration values unless DTD use has been turned off.
5659 *
5660 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005661 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005662 */
5663xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00005664xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00005665 xmlAttrPtr prop;
5666 xmlDocPtr doc;
5667 xmlNsPtr ns;
5668
5669 if (node == NULL)
5670 return(NULL);
5671
5672 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005673 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00005674 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00005675 while (prop != NULL) {
5676 /*
5677 * One need to have
5678 * - same attribute names
5679 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005680 */
5681 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00005682 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00005683 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005684 xmlChar *ret;
5685
5686 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5687 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5688 return(ret);
5689 }
5690 prop = prop->next;
5691 }
5692 if (!xmlCheckDTD) return(NULL);
5693
5694 /*
5695 * Check if there is a default declaration in the internal
5696 * or external subsets
5697 */
5698 doc = node->doc;
5699 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005700 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00005701 xmlAttributePtr attrDecl;
5702
Owen Taylor3473f882001-02-23 17:55:21 +00005703 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5704 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5705 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5706
5707 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
5708 /*
5709 * The DTD declaration only allows a prefix search
5710 */
5711 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00005712 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00005713 return(xmlStrdup(attrDecl->defaultValue));
5714 }
5715 }
5716 }
5717 return(NULL);
5718}
5719
5720/**
5721 * xmlSetProp:
5722 * @node: the node
5723 * @name: the attribute name
5724 * @value: the attribute value
5725 *
5726 * Set (or reset) an attribute carried by a node.
5727 * Returns the attribute pointer.
5728 */
5729xmlAttrPtr
5730xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005731 xmlAttrPtr prop;
5732 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00005733
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00005734 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00005735 return(NULL);
5736 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005737 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00005738 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005739 if ((xmlStrEqual(prop->name, name)) &&
5740 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005741 xmlNodePtr oldprop = prop->children;
5742
Owen Taylor3473f882001-02-23 17:55:21 +00005743 prop->children = NULL;
5744 prop->last = NULL;
5745 if (value != NULL) {
5746 xmlChar *buffer;
5747 xmlNodePtr tmp;
5748
5749 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5750 prop->children = xmlStringGetNodeList(node->doc, buffer);
5751 prop->last = NULL;
5752 prop->doc = doc;
5753 tmp = prop->children;
5754 while (tmp != NULL) {
5755 tmp->parent = (xmlNodePtr) prop;
5756 tmp->doc = doc;
5757 if (tmp->next == NULL)
5758 prop->last = tmp;
5759 tmp = tmp->next;
5760 }
5761 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00005762 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005763 if (oldprop != NULL)
5764 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00005765 return(prop);
5766 }
5767 prop = prop->next;
5768 }
5769 prop = xmlNewProp(node, name, value);
5770 return(prop);
5771}
5772
5773/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005774 * xmlUnsetProp:
5775 * @node: the node
5776 * @name: the attribute name
5777 *
5778 * Remove an attribute carried by a node.
5779 * Returns 0 if successful, -1 if not found
5780 */
5781int
5782xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Daniel Veillard814a76d2003-01-23 18:24:20 +00005783 xmlAttrPtr prop, prev = NULL;;
Daniel Veillard75bea542001-05-11 17:41:21 +00005784
5785 if ((node == NULL) || (name == NULL))
5786 return(-1);
Daniel Veillard814a76d2003-01-23 18:24:20 +00005787 prop = node->properties;
Daniel Veillard75bea542001-05-11 17:41:21 +00005788 while (prop != NULL) {
5789 if ((xmlStrEqual(prop->name, name)) &&
5790 (prop->ns == NULL)) {
5791 if (prev == NULL)
5792 node->properties = prop->next;
5793 else
5794 prev->next = prop->next;
5795 xmlFreeProp(prop);
5796 return(0);
5797 }
5798 prev = prop;
5799 prop = prop->next;
5800 }
5801 return(-1);
5802}
5803
5804/**
Owen Taylor3473f882001-02-23 17:55:21 +00005805 * xmlSetNsProp:
5806 * @node: the node
5807 * @ns: the namespace definition
5808 * @name: the attribute name
5809 * @value: the attribute value
5810 *
5811 * Set (or reset) an attribute carried by a node.
5812 * The ns structure must be in scope, this is not checked.
5813 *
5814 * Returns the attribute pointer.
5815 */
5816xmlAttrPtr
5817xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
5818 const xmlChar *value) {
5819 xmlAttrPtr prop;
5820
5821 if ((node == NULL) || (name == NULL))
5822 return(NULL);
5823
5824 if (ns == NULL)
5825 return(xmlSetProp(node, name, value));
5826 if (ns->href == NULL)
5827 return(NULL);
5828 prop = node->properties;
5829
5830 while (prop != NULL) {
5831 /*
5832 * One need to have
5833 * - same attribute names
5834 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005835 */
5836 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00005837 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005838 if (prop->children != NULL)
5839 xmlFreeNodeList(prop->children);
5840 prop->children = NULL;
5841 prop->last = NULL;
5842 prop->ns = ns;
5843 if (value != NULL) {
5844 xmlChar *buffer;
5845 xmlNodePtr tmp;
5846
5847 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5848 prop->children = xmlStringGetNodeList(node->doc, buffer);
5849 prop->last = NULL;
5850 tmp = prop->children;
5851 while (tmp != NULL) {
5852 tmp->parent = (xmlNodePtr) prop;
5853 if (tmp->next == NULL)
5854 prop->last = tmp;
5855 tmp = tmp->next;
5856 }
5857 xmlFree(buffer);
5858 }
5859 return(prop);
5860 }
5861 prop = prop->next;
5862 }
5863 prop = xmlNewNsProp(node, ns, name, value);
5864 return(prop);
5865}
5866
5867/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005868 * xmlUnsetNsProp:
5869 * @node: the node
5870 * @ns: the namespace definition
5871 * @name: the attribute name
5872 *
5873 * Remove an attribute carried by a node.
5874 * Returns 0 if successful, -1 if not found
5875 */
5876int
5877xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
5878 xmlAttrPtr prop = node->properties, prev = NULL;;
5879
5880 if ((node == NULL) || (name == NULL))
5881 return(-1);
5882 if (ns == NULL)
5883 return(xmlUnsetProp(node, name));
5884 if (ns->href == NULL)
5885 return(-1);
5886 while (prop != NULL) {
5887 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00005888 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005889 if (prev == NULL)
5890 node->properties = prop->next;
5891 else
5892 prev->next = prop->next;
5893 xmlFreeProp(prop);
5894 return(0);
5895 }
5896 prev = prop;
5897 prop = prop->next;
5898 }
5899 return(-1);
5900}
5901
5902/**
Owen Taylor3473f882001-02-23 17:55:21 +00005903 * xmlNodeIsText:
5904 * @node: the node
5905 *
5906 * Is this node a Text node ?
5907 * Returns 1 yes, 0 no
5908 */
5909int
5910xmlNodeIsText(xmlNodePtr node) {
5911 if (node == NULL) return(0);
5912
5913 if (node->type == XML_TEXT_NODE) return(1);
5914 return(0);
5915}
5916
5917/**
5918 * xmlIsBlankNode:
5919 * @node: the node
5920 *
5921 * Checks whether this node is an empty or whitespace only
5922 * (and possibly ignorable) text-node.
5923 *
5924 * Returns 1 yes, 0 no
5925 */
5926int
5927xmlIsBlankNode(xmlNodePtr node) {
5928 const xmlChar *cur;
5929 if (node == NULL) return(0);
5930
Daniel Veillard7db37732001-07-12 01:20:08 +00005931 if ((node->type != XML_TEXT_NODE) &&
5932 (node->type != XML_CDATA_SECTION_NODE))
5933 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005934 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00005935 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00005936 while (*cur != 0) {
5937 if (!IS_BLANK(*cur)) return(0);
5938 cur++;
5939 }
5940
5941 return(1);
5942}
5943
5944/**
5945 * xmlTextConcat:
5946 * @node: the node
5947 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00005948 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00005949 *
5950 * Concat the given string at the end of the existing node content
5951 */
5952
5953void
5954xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
5955 if (node == NULL) return;
5956
5957 if ((node->type != XML_TEXT_NODE) &&
5958 (node->type != XML_CDATA_SECTION_NODE)) {
5959#ifdef DEBUG_TREE
5960 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005961 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005962#endif
5963 return;
5964 }
Owen Taylor3473f882001-02-23 17:55:21 +00005965 node->content = xmlStrncat(node->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005966}
5967
5968/************************************************************************
5969 * *
5970 * Output : to a FILE or in memory *
5971 * *
5972 ************************************************************************/
5973
Owen Taylor3473f882001-02-23 17:55:21 +00005974/**
5975 * xmlBufferCreate:
5976 *
5977 * routine to create an XML buffer.
5978 * returns the new structure.
5979 */
5980xmlBufferPtr
5981xmlBufferCreate(void) {
5982 xmlBufferPtr ret;
5983
5984 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5985 if (ret == NULL) {
5986 xmlGenericError(xmlGenericErrorContext,
5987 "xmlBufferCreate : out of memory!\n");
5988 return(NULL);
5989 }
5990 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00005991 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00005992 ret->alloc = xmlBufferAllocScheme;
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 return(ret);
6002}
6003
6004/**
6005 * xmlBufferCreateSize:
6006 * @size: initial size of buffer
6007 *
6008 * routine to create an XML buffer.
6009 * returns the new structure.
6010 */
6011xmlBufferPtr
6012xmlBufferCreateSize(size_t size) {
6013 xmlBufferPtr ret;
6014
6015 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6016 if (ret == NULL) {
6017 xmlGenericError(xmlGenericErrorContext,
6018 "xmlBufferCreate : out of memory!\n");
6019 return(NULL);
6020 }
6021 ret->use = 0;
6022 ret->alloc = xmlBufferAllocScheme;
6023 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6024 if (ret->size){
6025 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
6026 if (ret->content == NULL) {
6027 xmlGenericError(xmlGenericErrorContext,
6028 "xmlBufferCreate : out of memory!\n");
6029 xmlFree(ret);
6030 return(NULL);
6031 }
6032 ret->content[0] = 0;
6033 } else
6034 ret->content = NULL;
6035 return(ret);
6036}
6037
6038/**
6039 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006040 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006041 * @scheme: allocation scheme to use
6042 *
6043 * Sets the allocation scheme for this buffer
6044 */
6045void
6046xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6047 xmlBufferAllocationScheme scheme) {
6048 if (buf == NULL) {
6049#ifdef DEBUG_BUFFER
6050 xmlGenericError(xmlGenericErrorContext,
6051 "xmlBufferSetAllocationScheme: buf == NULL\n");
6052#endif
6053 return;
6054 }
6055
6056 buf->alloc = scheme;
6057}
6058
6059/**
6060 * xmlBufferFree:
6061 * @buf: the buffer to free
6062 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006063 * Frees an XML buffer. It frees both the content and the structure which
6064 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006065 */
6066void
6067xmlBufferFree(xmlBufferPtr buf) {
6068 if (buf == NULL) {
6069#ifdef DEBUG_BUFFER
6070 xmlGenericError(xmlGenericErrorContext,
6071 "xmlBufferFree: buf == NULL\n");
6072#endif
6073 return;
6074 }
Daniel Veillard561b7f82002-03-20 21:55:57 +00006075 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006076 xmlFree(buf->content);
6077 }
Owen Taylor3473f882001-02-23 17:55:21 +00006078 xmlFree(buf);
6079}
6080
6081/**
6082 * xmlBufferEmpty:
6083 * @buf: the buffer
6084 *
6085 * empty a buffer.
6086 */
6087void
6088xmlBufferEmpty(xmlBufferPtr buf) {
6089 if (buf->content == NULL) return;
6090 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006091 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00006092}
6093
6094/**
6095 * xmlBufferShrink:
6096 * @buf: the buffer to dump
6097 * @len: the number of xmlChar to remove
6098 *
6099 * Remove the beginning of an XML buffer.
6100 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006101 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006102 */
6103int
6104xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
6105 if (len == 0) return(0);
6106 if (len > buf->use) return(-1);
6107
6108 buf->use -= len;
6109 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6110
6111 buf->content[buf->use] = 0;
6112 return(len);
6113}
6114
6115/**
6116 * xmlBufferGrow:
6117 * @buf: the buffer
6118 * @len: the minimum free size to allocate
6119 *
6120 * Grow the available space of an XML buffer.
6121 *
6122 * Returns the new available space or -1 in case of error
6123 */
6124int
6125xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6126 int size;
6127 xmlChar *newbuf;
6128
6129 if (len + buf->use < buf->size) return(0);
6130
6131 size = buf->use + len + 100;
6132
6133 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
6134 if (newbuf == NULL) return(-1);
6135 buf->content = newbuf;
6136 buf->size = size;
6137 return(buf->size - buf->use);
6138}
6139
6140/**
6141 * xmlBufferDump:
6142 * @file: the file output
6143 * @buf: the buffer to dump
6144 *
6145 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006146 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006147 */
6148int
6149xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6150 int ret;
6151
6152 if (buf == NULL) {
6153#ifdef DEBUG_BUFFER
6154 xmlGenericError(xmlGenericErrorContext,
6155 "xmlBufferDump: buf == NULL\n");
6156#endif
6157 return(0);
6158 }
6159 if (buf->content == NULL) {
6160#ifdef DEBUG_BUFFER
6161 xmlGenericError(xmlGenericErrorContext,
6162 "xmlBufferDump: buf->content == NULL\n");
6163#endif
6164 return(0);
6165 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006166 if (file == NULL)
6167 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006168 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6169 return(ret);
6170}
6171
6172/**
6173 * xmlBufferContent:
6174 * @buf: the buffer
6175 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006176 * Function to extract the content of a buffer
6177 *
Owen Taylor3473f882001-02-23 17:55:21 +00006178 * Returns the internal content
6179 */
6180
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006181const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006182xmlBufferContent(const xmlBufferPtr buf)
6183{
6184 if(!buf)
6185 return NULL;
6186
6187 return buf->content;
6188}
6189
6190/**
6191 * xmlBufferLength:
6192 * @buf: the buffer
6193 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006194 * Function to get the length of a buffer
6195 *
Owen Taylor3473f882001-02-23 17:55:21 +00006196 * Returns the length of data in the internal content
6197 */
6198
6199int
6200xmlBufferLength(const xmlBufferPtr buf)
6201{
6202 if(!buf)
6203 return 0;
6204
6205 return buf->use;
6206}
6207
6208/**
6209 * xmlBufferResize:
6210 * @buf: the buffer to resize
6211 * @size: the desired size
6212 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006213 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006214 *
6215 * Returns 0 in case of problems, 1 otherwise
6216 */
6217int
6218xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6219{
6220 unsigned int newSize;
6221 xmlChar* rebuf = NULL;
6222
6223 /*take care of empty case*/
6224 newSize = (buf->size ? buf->size*2 : size);
6225
6226 /* Don't resize if we don't have to */
6227 if (size < buf->size)
6228 return 1;
6229
6230 /* figure out new size */
6231 switch (buf->alloc){
6232 case XML_BUFFER_ALLOC_DOUBLEIT:
6233 while (size > newSize) newSize *= 2;
6234 break;
6235 case XML_BUFFER_ALLOC_EXACT:
6236 newSize = size+10;
6237 break;
6238 default:
6239 newSize = size+10;
6240 break;
6241 }
6242
6243 if (buf->content == NULL)
6244 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
6245 else
6246 rebuf = (xmlChar *) xmlRealloc(buf->content,
6247 newSize * sizeof(xmlChar));
6248 if (rebuf == NULL) {
6249 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006250 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006251 return 0;
6252 }
6253 buf->content = rebuf;
6254 buf->size = newSize;
6255
6256 return 1;
6257}
6258
6259/**
6260 * xmlBufferAdd:
6261 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006262 * @str: the #xmlChar string
6263 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006264 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006265 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006266 * str is recomputed.
6267 */
6268void
6269xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6270 unsigned int needSize;
6271
6272 if (str == NULL) {
6273#ifdef DEBUG_BUFFER
6274 xmlGenericError(xmlGenericErrorContext,
6275 "xmlBufferAdd: str == NULL\n");
6276#endif
6277 return;
6278 }
6279 if (len < -1) {
6280#ifdef DEBUG_BUFFER
6281 xmlGenericError(xmlGenericErrorContext,
6282 "xmlBufferAdd: len < 0\n");
6283#endif
6284 return;
6285 }
6286 if (len == 0) return;
6287
6288 if (len < 0)
6289 len = xmlStrlen(str);
6290
6291 if (len <= 0) return;
6292
6293 needSize = buf->use + len + 2;
6294 if (needSize > buf->size){
6295 if (!xmlBufferResize(buf, needSize)){
6296 xmlGenericError(xmlGenericErrorContext,
6297 "xmlBufferAdd : out of memory!\n");
6298 return;
6299 }
6300 }
6301
6302 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6303 buf->use += len;
6304 buf->content[buf->use] = 0;
6305}
6306
6307/**
6308 * xmlBufferAddHead:
6309 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006310 * @str: the #xmlChar string
6311 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006312 *
6313 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006314 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00006315 */
6316void
6317xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6318 unsigned int needSize;
6319
6320 if (str == NULL) {
6321#ifdef DEBUG_BUFFER
6322 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006323 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006324#endif
6325 return;
6326 }
6327 if (len < -1) {
6328#ifdef DEBUG_BUFFER
6329 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006330 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006331#endif
6332 return;
6333 }
6334 if (len == 0) return;
6335
6336 if (len < 0)
6337 len = xmlStrlen(str);
6338
6339 if (len <= 0) return;
6340
6341 needSize = buf->use + len + 2;
6342 if (needSize > buf->size){
6343 if (!xmlBufferResize(buf, needSize)){
6344 xmlGenericError(xmlGenericErrorContext,
6345 "xmlBufferAddHead : out of memory!\n");
6346 return;
6347 }
6348 }
6349
6350 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6351 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6352 buf->use += len;
6353 buf->content[buf->use] = 0;
6354}
6355
6356/**
6357 * xmlBufferCat:
6358 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006359 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006360 *
6361 * Append a zero terminated string to an XML buffer.
6362 */
6363void
6364xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
6365 if (str != NULL)
6366 xmlBufferAdd(buf, str, -1);
6367}
6368
6369/**
6370 * xmlBufferCCat:
6371 * @buf: the buffer to dump
6372 * @str: the C char string
6373 *
6374 * Append a zero terminated C string to an XML buffer.
6375 */
6376void
6377xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6378 const char *cur;
6379
6380 if (str == NULL) {
6381#ifdef DEBUG_BUFFER
6382 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006383 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006384#endif
6385 return;
6386 }
6387 for (cur = str;*cur != 0;cur++) {
6388 if (buf->use + 10 >= buf->size) {
6389 if (!xmlBufferResize(buf, buf->use+10)){
6390 xmlGenericError(xmlGenericErrorContext,
6391 "xmlBufferCCat : out of memory!\n");
6392 return;
6393 }
6394 }
6395 buf->content[buf->use++] = *cur;
6396 }
6397 buf->content[buf->use] = 0;
6398}
6399
6400/**
6401 * xmlBufferWriteCHAR:
6402 * @buf: the XML buffer
6403 * @string: the string to add
6404 *
6405 * routine which manages and grows an output buffer. This one adds
6406 * xmlChars at the end of the buffer.
6407 */
6408void
Owen Taylor3473f882001-02-23 17:55:21 +00006409xmlBufferWriteCHAR
Owen Taylor3473f882001-02-23 17:55:21 +00006410(xmlBufferPtr buf, const xmlChar *string) {
6411 xmlBufferCat(buf, string);
6412}
6413
6414/**
6415 * xmlBufferWriteChar:
6416 * @buf: the XML buffer output
6417 * @string: the string to add
6418 *
6419 * routine which manage and grows an output buffer. This one add
6420 * C chars at the end of the array.
6421 */
6422void
6423xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
6424 xmlBufferCCat(buf, string);
6425}
6426
6427
6428/**
6429 * xmlBufferWriteQuotedString:
6430 * @buf: the XML buffer output
6431 * @string: the string to add
6432 *
6433 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00006434 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00006435 * quote or double-quotes internally
6436 */
6437void
6438xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
6439 if (xmlStrchr(string, '"')) {
6440 if (xmlStrchr(string, '\'')) {
6441#ifdef DEBUG_BUFFER
6442 xmlGenericError(xmlGenericErrorContext,
6443 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
6444#endif
6445 }
6446 xmlBufferCCat(buf, "'");
6447 xmlBufferCat(buf, string);
6448 xmlBufferCCat(buf, "'");
6449 } else {
6450 xmlBufferCCat(buf, "\"");
6451 xmlBufferCat(buf, string);
6452 xmlBufferCCat(buf, "\"");
6453 }
6454}
6455
6456
6457/************************************************************************
6458 * *
6459 * Dumping XML tree content to a simple buffer *
6460 * *
6461 ************************************************************************/
6462
Owen Taylor3473f882001-02-23 17:55:21 +00006463/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00006464 * xmlAttrSerializeContent:
6465 * @buf: the XML buffer output
6466 * @doc: the document
6467 * @attr: the attribute pointer
6468 *
6469 * Serialize the attribute in the buffer
6470 */
6471static void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006472xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr)
6473{
Daniel Veillarda6d05382002-02-13 13:07:41 +00006474 const xmlChar *cur, *base;
6475 xmlNodePtr children;
6476
6477 children = attr->children;
6478 while (children != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006479 switch (children->type) {
6480 case XML_TEXT_NODE:
6481 base = cur = children->content;
6482 while (*cur != 0) {
6483 if (*cur == '\n') {
6484 if (base != cur)
6485 xmlBufferAdd(buf, base, cur - base);
6486 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
6487 cur++;
6488 base = cur;
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006489 } else if (*cur == '\r') {
6490 if (base != cur)
6491 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006492 xmlBufferAdd(buf, BAD_CAST "&#13;", 5);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006493 cur++;
6494 base = cur;
6495 } else if (*cur == '\t') {
6496 if (base != cur)
6497 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006498 xmlBufferAdd(buf, BAD_CAST "&#9;", 4);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006499 cur++;
6500 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006501#if 0
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006502 } else if (*cur == '\'') {
6503 if (base != cur)
6504 xmlBufferAdd(buf, base, cur - base);
6505 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
6506 cur++;
6507 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006508#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006509 } else if (*cur == '"') {
6510 if (base != cur)
6511 xmlBufferAdd(buf, base, cur - base);
6512 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6513 cur++;
6514 base = cur;
6515 } else if (*cur == '<') {
6516 if (base != cur)
6517 xmlBufferAdd(buf, base, cur - base);
6518 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
6519 cur++;
6520 base = cur;
6521 } else if (*cur == '>') {
6522 if (base != cur)
6523 xmlBufferAdd(buf, base, cur - base);
6524 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
6525 cur++;
6526 base = cur;
6527 } else if (*cur == '&') {
6528 if (base != cur)
6529 xmlBufferAdd(buf, base, cur - base);
6530 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
6531 cur++;
6532 base = cur;
6533 } else if ((*cur >= 0x80) && ((doc == NULL) ||
6534 (doc->encoding ==
6535 NULL))) {
6536 /*
6537 * We assume we have UTF-8 content.
6538 */
6539 char tmp[10];
6540 int val = 0, l = 1;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006541
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006542 if (base != cur)
6543 xmlBufferAdd(buf, base, cur - base);
6544 if (*cur < 0xC0) {
6545 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6d05382002-02-13 13:07:41 +00006546 "xmlAttrSerializeContent : input not UTF-8\n");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006547 if (doc != NULL)
6548 doc->encoding =
6549 xmlStrdup(BAD_CAST "ISO-8859-1");
6550 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6551 tmp[sizeof(tmp) - 1] = 0;
6552 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6553 cur++;
6554 base = cur;
6555 continue;
6556 } else if (*cur < 0xE0) {
6557 val = (cur[0]) & 0x1F;
6558 val <<= 6;
6559 val |= (cur[1]) & 0x3F;
6560 l = 2;
6561 } else if (*cur < 0xF0) {
6562 val = (cur[0]) & 0x0F;
6563 val <<= 6;
6564 val |= (cur[1]) & 0x3F;
6565 val <<= 6;
6566 val |= (cur[2]) & 0x3F;
6567 l = 3;
6568 } else if (*cur < 0xF8) {
6569 val = (cur[0]) & 0x07;
6570 val <<= 6;
6571 val |= (cur[1]) & 0x3F;
6572 val <<= 6;
6573 val |= (cur[2]) & 0x3F;
6574 val <<= 6;
6575 val |= (cur[3]) & 0x3F;
6576 l = 4;
6577 }
6578 if ((l == 1) || (!IS_CHAR(val))) {
6579 xmlGenericError(xmlGenericErrorContext,
6580 "xmlAttrSerializeContent : char out of range\n");
6581 if (doc != NULL)
6582 doc->encoding =
6583 xmlStrdup(BAD_CAST "ISO-8859-1");
6584 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6585 tmp[sizeof(tmp) - 1] = 0;
6586 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6587 cur++;
6588 base = cur;
6589 continue;
6590 }
6591 /*
6592 * We could do multiple things here. Just save
6593 * as a char ref
6594 */
6595 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
6596 tmp[sizeof(tmp) - 1] = 0;
6597 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6598 cur += l;
6599 base = cur;
6600 } else {
6601 cur++;
6602 }
6603 }
6604 if (base != cur)
6605 xmlBufferAdd(buf, base, cur - base);
6606 break;
6607 case XML_ENTITY_REF_NODE:
6608 xmlBufferAdd(buf, BAD_CAST "&", 1);
6609 xmlBufferAdd(buf, children->name,
6610 xmlStrlen(children->name));
6611 xmlBufferAdd(buf, BAD_CAST ";", 1);
6612 break;
6613 default:
6614 /* should not happen unless we have a badly built tree */
6615 break;
6616 }
6617 children = children->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006618 }
6619}
6620
6621/**
6622 * xmlNodeDump:
6623 * @buf: the XML buffer output
6624 * @doc: the document
6625 * @cur: the current node
6626 * @level: the imbrication level for indenting
6627 * @format: is formatting allowed
6628 *
6629 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00006630 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006631 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006632 *
6633 * Returns the number of bytes written to the buffer or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00006634 */
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006635int
Owen Taylor3473f882001-02-23 17:55:21 +00006636xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006637 int format)
6638{
6639 unsigned int use;
6640 int ret;
6641 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006642
6643 if (cur == NULL) {
6644#ifdef DEBUG_TREE
6645 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006646 "xmlNodeDump : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006647#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006648 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006649 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006650 if (buf == NULL) {
6651#ifdef DEBUG_TREE
6652 xmlGenericError(xmlGenericErrorContext,
6653 "xmlNodeDump : buf == NULL\n");
6654#endif
6655 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006656 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006657 outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
6658 if (outbuf == NULL) {
6659 xmlGenericError(xmlGenericErrorContext,
6660 "xmlNodeDump: out of memory!\n");
6661 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006662 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006663 memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
6664 outbuf->buffer = buf;
6665 outbuf->encoder = NULL;
6666 outbuf->writecallback = NULL;
6667 outbuf->closecallback = NULL;
6668 outbuf->context = NULL;
6669 outbuf->written = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006670
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006671 use = buf->use;
6672 xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
6673 xmlFree(outbuf);
6674 ret = buf->use - use;
6675 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006676}
6677
6678/**
6679 * xmlElemDump:
6680 * @f: the FILE * for the output
6681 * @doc: the document
6682 * @cur: the current node
6683 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006684 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006685 */
6686void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006687xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur)
6688{
6689 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006690
6691 if (cur == NULL) {
6692#ifdef DEBUG_TREE
6693 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006694 "xmlElemDump : cur == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006695#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006696 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006697 }
Owen Taylor3473f882001-02-23 17:55:21 +00006698#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006699 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006700 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006701 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006702 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006703#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006704
6705 outbuf = xmlOutputBufferCreateFile(f, NULL);
6706 if (outbuf == NULL)
6707 return;
6708 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006709#ifdef LIBXML_HTML_ENABLED
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006710 htmlNodeDumpOutput(outbuf, doc, cur, NULL);
6711#else
6712 xmlGenericError(xmlGenericErrorContext,
6713 "HTML support not compiled in\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006714#endif /* LIBXML_HTML_ENABLED */
6715 } else
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006716 xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL);
6717 xmlOutputBufferClose(outbuf);
Owen Taylor3473f882001-02-23 17:55:21 +00006718}
6719
6720/************************************************************************
6721 * *
6722 * Dumping XML tree content to an I/O output buffer *
6723 * *
6724 ************************************************************************/
6725
Owen Taylor3473f882001-02-23 17:55:21 +00006726static void
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006727xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6728 int level, int format, const char *encoding);
6729static void
Owen Taylor3473f882001-02-23 17:55:21 +00006730xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6731 int level, int format, const char *encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006732static void
6733xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
6734 xmlNodePtr cur, int level, int format, const char *encoding);
6735
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00006736void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
6737
Owen Taylor3473f882001-02-23 17:55:21 +00006738/**
6739 * xmlNsDumpOutput:
6740 * @buf: the XML buffer output
6741 * @cur: a namespace
6742 *
6743 * Dump a local Namespace definition.
6744 * Should be called in the context of attributes dumps.
6745 */
6746static void
6747xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6748 if (cur == NULL) {
6749#ifdef DEBUG_TREE
6750 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006751 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006752#endif
6753 return;
6754 }
6755 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00006756 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
6757 return;
6758
Owen Taylor3473f882001-02-23 17:55:21 +00006759 /* Within the context of an element attributes */
6760 if (cur->prefix != NULL) {
6761 xmlOutputBufferWriteString(buf, " xmlns:");
6762 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6763 } else
6764 xmlOutputBufferWriteString(buf, " xmlns");
6765 xmlOutputBufferWriteString(buf, "=");
6766 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6767 }
6768}
6769
6770/**
6771 * xmlNsListDumpOutput:
6772 * @buf: the XML buffer output
6773 * @cur: the first namespace
6774 *
6775 * Dump a list of local Namespace definitions.
6776 * Should be called in the context of attributes dumps.
6777 */
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00006778void
Owen Taylor3473f882001-02-23 17:55:21 +00006779xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6780 while (cur != NULL) {
6781 xmlNsDumpOutput(buf, cur);
6782 cur = cur->next;
6783 }
6784}
6785
6786/**
6787 * xmlDtdDumpOutput:
6788 * @buf: the XML buffer output
6789 * @doc: the document
6790 * @encoding: an optional encoding string
6791 *
6792 * Dump the XML document DTD, if any.
6793 */
6794static void
6795xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6796 if (dtd == NULL) {
6797#ifdef DEBUG_TREE
6798 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006799 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006800#endif
6801 return;
6802 }
6803 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6804 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6805 if (dtd->ExternalID != NULL) {
6806 xmlOutputBufferWriteString(buf, " PUBLIC ");
6807 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6808 xmlOutputBufferWriteString(buf, " ");
6809 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6810 } else if (dtd->SystemID != NULL) {
6811 xmlOutputBufferWriteString(buf, " SYSTEM ");
6812 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6813 }
6814 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6815 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6816 xmlOutputBufferWriteString(buf, ">");
6817 return;
6818 }
6819 xmlOutputBufferWriteString(buf, " [\n");
6820 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6821 xmlOutputBufferWriteString(buf, "]>");
6822}
6823
6824/**
6825 * xmlAttrDumpOutput:
6826 * @buf: the XML buffer output
6827 * @doc: the document
6828 * @cur: the attribute pointer
6829 * @encoding: an optional encoding string
6830 *
6831 * Dump an XML attribute
6832 */
6833static void
6834xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006835 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006836 if (cur == NULL) {
6837#ifdef DEBUG_TREE
6838 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006839 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006840#endif
6841 return;
6842 }
6843 xmlOutputBufferWriteString(buf, " ");
6844 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6845 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6846 xmlOutputBufferWriteString(buf, ":");
6847 }
6848 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006849 xmlOutputBufferWriteString(buf, "=\"");
6850 xmlAttrSerializeContent(buf->buffer, doc, cur);
6851 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006852}
6853
6854/**
6855 * xmlAttrListDumpOutput:
6856 * @buf: the XML buffer output
6857 * @doc: the document
6858 * @cur: the first attribute pointer
6859 * @encoding: an optional encoding string
6860 *
6861 * Dump a list of XML attributes
6862 */
6863static void
6864xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6865 xmlAttrPtr cur, const char *encoding) {
6866 if (cur == NULL) {
6867#ifdef DEBUG_TREE
6868 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006869 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006870#endif
6871 return;
6872 }
6873 while (cur != NULL) {
6874 xmlAttrDumpOutput(buf, doc, cur, encoding);
6875 cur = cur->next;
6876 }
6877}
6878
6879
6880
6881/**
6882 * xmlNodeListDumpOutput:
6883 * @buf: the XML buffer output
6884 * @doc: the document
6885 * @cur: the first node
6886 * @level: the imbrication level for indenting
6887 * @format: is formatting allowed
6888 * @encoding: an optional encoding string
6889 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006890 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00006891 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006892 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006893 */
6894static void
6895xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6896 xmlNodePtr cur, int level, int format, const char *encoding) {
6897 int i;
6898
6899 if (cur == NULL) {
6900#ifdef DEBUG_TREE
6901 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006902 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006903#endif
6904 return;
6905 }
6906 while (cur != NULL) {
6907 if ((format) && (xmlIndentTreeOutput) &&
6908 (cur->type == XML_ELEMENT_NODE))
6909 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006910 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006911 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00006912 if (format) {
6913 xmlOutputBufferWriteString(buf, "\n");
6914 }
6915 cur = cur->next;
6916 }
6917}
6918
6919/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006920 * xmlNodeDumpOutputInternal:
Owen Taylor3473f882001-02-23 17:55:21 +00006921 * @buf: the XML buffer output
6922 * @doc: the document
6923 * @cur: the current node
6924 * @level: the imbrication level for indenting
6925 * @format: is formatting allowed
6926 * @encoding: an optional encoding string
6927 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006928 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00006929 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006930 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006931 */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006932static void
6933xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
6934 xmlNodePtr cur, int level, int format, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00006935 int i;
6936 xmlNodePtr tmp;
6937
6938 if (cur == NULL) {
6939#ifdef DEBUG_TREE
6940 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006941 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006942#endif
6943 return;
6944 }
6945 if (cur->type == XML_XINCLUDE_START)
6946 return;
6947 if (cur->type == XML_XINCLUDE_END)
6948 return;
6949 if (cur->type == XML_DTD_NODE) {
6950 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6951 return;
6952 }
6953 if (cur->type == XML_ELEMENT_DECL) {
6954 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6955 return;
6956 }
6957 if (cur->type == XML_ATTRIBUTE_DECL) {
6958 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6959 return;
6960 }
6961 if (cur->type == XML_ENTITY_DECL) {
6962 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6963 return;
6964 }
6965 if (cur->type == XML_TEXT_NODE) {
6966 if (cur->content != NULL) {
6967 if ((cur->name == xmlStringText) ||
6968 (cur->name != xmlStringTextNoenc)) {
6969 xmlChar *buffer;
6970
Owen Taylor3473f882001-02-23 17:55:21 +00006971 if (encoding == NULL)
6972 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6973 else
6974 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006975 if (buffer != NULL) {
6976 xmlOutputBufferWriteString(buf, (const char *)buffer);
6977 xmlFree(buffer);
6978 }
6979 } else {
6980 /*
6981 * Disable escaping, needed for XSLT
6982 */
Owen Taylor3473f882001-02-23 17:55:21 +00006983 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006984 }
6985 }
6986
6987 return;
6988 }
6989 if (cur->type == XML_PI_NODE) {
6990 if (cur->content != NULL) {
6991 xmlOutputBufferWriteString(buf, "<?");
6992 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6993 if (cur->content != NULL) {
6994 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00006995 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006996 }
6997 xmlOutputBufferWriteString(buf, "?>");
6998 } else {
6999 xmlOutputBufferWriteString(buf, "<?");
7000 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7001 xmlOutputBufferWriteString(buf, "?>");
7002 }
7003 return;
7004 }
7005 if (cur->type == XML_COMMENT_NODE) {
7006 if (cur->content != NULL) {
7007 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00007008 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007009 xmlOutputBufferWriteString(buf, "-->");
7010 }
7011 return;
7012 }
7013 if (cur->type == XML_ENTITY_REF_NODE) {
7014 xmlOutputBufferWriteString(buf, "&");
7015 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7016 xmlOutputBufferWriteString(buf, ";");
7017 return;
7018 }
7019 if (cur->type == XML_CDATA_SECTION_NODE) {
7020 xmlOutputBufferWriteString(buf, "<![CDATA[");
7021 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007022 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007023 xmlOutputBufferWriteString(buf, "]]>");
7024 return;
7025 }
Daniel Veillard7b72ee52003-02-27 23:24:53 +00007026 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillarda1a9d042003-03-18 16:53:17 +00007027 xmlAttrDumpOutput(buf,doc, (xmlAttrPtr) cur,encoding);
Daniel Veillard7b72ee52003-02-27 23:24:53 +00007028 return;
7029 }
Daniel Veillard6aa2f602003-02-10 00:01:56 +00007030 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007031 xmlNsDumpOutput(buf, (xmlNsPtr) cur);
Daniel Veillard6aa2f602003-02-10 00:01:56 +00007032 return;
7033 }
Owen Taylor3473f882001-02-23 17:55:21 +00007034
7035 if (format == 1) {
7036 tmp = cur->children;
7037 while (tmp != NULL) {
7038 if ((tmp->type == XML_TEXT_NODE) ||
7039 (tmp->type == XML_ENTITY_REF_NODE)) {
7040 format = 0;
7041 break;
7042 }
7043 tmp = tmp->next;
7044 }
7045 }
7046 xmlOutputBufferWriteString(buf, "<");
7047 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7048 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7049 xmlOutputBufferWriteString(buf, ":");
7050 }
7051
7052 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7053 if (cur->nsDef)
7054 xmlNsListDumpOutput(buf, cur->nsDef);
7055 if (cur->properties != NULL)
7056 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7057
Daniel Veillard7db37732001-07-12 01:20:08 +00007058 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
7059 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007060 xmlOutputBufferWriteString(buf, "/>");
7061 return;
7062 }
7063 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00007064 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007065 xmlChar *buffer;
7066
Owen Taylor3473f882001-02-23 17:55:21 +00007067 if (encoding == NULL)
7068 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7069 else
7070 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007071 if (buffer != NULL) {
7072 xmlOutputBufferWriteString(buf, (const char *)buffer);
7073 xmlFree(buffer);
7074 }
7075 }
7076 if (cur->children != NULL) {
7077 if (format) xmlOutputBufferWriteString(buf, "\n");
7078 xmlNodeListDumpOutput(buf, doc, cur->children,
7079 (level >= 0?level+1:-1), format, encoding);
7080 if ((xmlIndentTreeOutput) && (format))
7081 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007082 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00007083 }
7084 xmlOutputBufferWriteString(buf, "</");
7085 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7086 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7087 xmlOutputBufferWriteString(buf, ":");
7088 }
7089
7090 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7091 xmlOutputBufferWriteString(buf, ">");
7092}
7093
7094/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007095 * xmlNodeDumpOutput:
7096 * @buf: the XML buffer output
7097 * @doc: the document
7098 * @cur: the current node
7099 * @level: the imbrication level for indenting
7100 * @format: is formatting allowed
7101 * @encoding: an optional encoding string
7102 *
7103 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007104 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007105 * or xmlKeepBlanksDefault(0) was called
7106 */
7107void
7108xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007109 int level, int format, const char *encoding)
7110{
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007111#ifdef LIBXML_HTML_ENABLED
7112 xmlDtdPtr dtd;
7113 int is_xhtml = 0;
7114
7115 dtd = xmlGetIntSubset(doc);
7116 if (dtd != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007117 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7118 if (is_xhtml < 0)
7119 is_xhtml = 0;
7120 if ((is_xhtml) && (cur->parent == (xmlNodePtr) doc) &&
7121 (cur->type == XML_ELEMENT_NODE) &&
7122 (xmlStrEqual(cur->name, BAD_CAST "html"))) {
7123 if (encoding != NULL)
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007124 htmlSetMetaEncoding((htmlDocPtr) doc,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007125 (const xmlChar *) encoding);
7126 else
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007127 htmlSetMetaEncoding((htmlDocPtr) doc, BAD_CAST "UTF-8");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007128 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007129 }
7130
7131 if (is_xhtml)
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007132 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007133 else
7134#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007135 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007136}
7137
7138/**
Owen Taylor3473f882001-02-23 17:55:21 +00007139 * xmlDocContentDumpOutput:
7140 * @buf: the XML buffer output
7141 * @cur: the document
7142 * @encoding: an optional encoding string
7143 * @format: should formatting spaces been added
7144 *
7145 * Dump an XML document.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007146 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007147 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007148 */
7149static void
7150xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
7151 const char *encoding, int format) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007152#ifdef LIBXML_HTML_ENABLED
7153 xmlDtdPtr dtd;
7154 int is_xhtml = 0;
7155#endif
7156
Owen Taylor3473f882001-02-23 17:55:21 +00007157 xmlOutputBufferWriteString(buf, "<?xml version=");
7158 if (cur->version != NULL)
7159 xmlBufferWriteQuotedString(buf->buffer, cur->version);
7160 else
7161 xmlOutputBufferWriteString(buf, "\"1.0\"");
7162 if (encoding == NULL) {
7163 if (cur->encoding != NULL)
7164 encoding = (const char *) cur->encoding;
7165 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
7166 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
7167 }
7168 if (encoding != NULL) {
7169 xmlOutputBufferWriteString(buf, " encoding=");
7170 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
7171 }
7172 switch (cur->standalone) {
7173 case 0:
7174 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
7175 break;
7176 case 1:
7177 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
7178 break;
7179 }
7180 xmlOutputBufferWriteString(buf, "?>\n");
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007181
7182#ifdef LIBXML_HTML_ENABLED
7183 dtd = xmlGetIntSubset(cur);
7184 if (dtd != NULL) {
7185 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7186 if (is_xhtml < 0) is_xhtml = 0;
7187 }
7188 if (is_xhtml) {
7189 if (encoding != NULL)
7190 htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
7191 else
7192 htmlSetMetaEncoding(cur, BAD_CAST "UTF-8");
7193 }
7194#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007195 if (cur->children != NULL) {
7196 xmlNodePtr child = cur->children;
7197
7198 while (child != NULL) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007199#ifdef LIBXML_HTML_ENABLED
7200 if (is_xhtml)
7201 xhtmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
7202 else
7203#endif
7204 xmlNodeDumpOutputInternal(buf, cur, child, 0, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007205 xmlOutputBufferWriteString(buf, "\n");
7206 child = child->next;
7207 }
7208 }
7209}
7210
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007211#ifdef LIBXML_HTML_ENABLED
7212/************************************************************************
7213 * *
7214 * Functions specific to XHTML serialization *
7215 * *
7216 ************************************************************************/
7217
7218#define XHTML_STRICT_PUBLIC_ID BAD_CAST \
7219 "-//W3C//DTD XHTML 1.0 Strict//EN"
7220#define XHTML_STRICT_SYSTEM_ID BAD_CAST \
7221 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
7222#define XHTML_FRAME_PUBLIC_ID BAD_CAST \
7223 "-//W3C//DTD XHTML 1.0 Frameset//EN"
7224#define XHTML_FRAME_SYSTEM_ID BAD_CAST \
7225 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
7226#define XHTML_TRANS_PUBLIC_ID BAD_CAST \
7227 "-//W3C//DTD XHTML 1.0 Transitional//EN"
7228#define XHTML_TRANS_SYSTEM_ID BAD_CAST \
7229 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
7230
7231#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
7232/**
7233 * xmlIsXHTML:
7234 * @systemID: the system identifier
7235 * @publicID: the public identifier
7236 *
7237 * Try to find if the document correspond to an XHTML DTD
7238 *
7239 * Returns 1 if true, 0 if not and -1 in case of error
7240 */
7241int
7242xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) {
7243 if ((systemID == NULL) && (publicID == NULL))
7244 return(-1);
7245 if (publicID != NULL) {
7246 if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1);
7247 if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1);
7248 if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1);
7249 }
7250 if (systemID != NULL) {
7251 if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1);
7252 if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1);
7253 if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1);
7254 }
7255 return(0);
7256}
7257
7258/**
7259 * xhtmlIsEmpty:
7260 * @node: the node
7261 *
7262 * Check if a node is an empty xhtml node
7263 *
7264 * Returns 1 if the node is an empty node, 0 if not and -1 in case of error
7265 */
7266static int
7267xhtmlIsEmpty(xmlNodePtr node) {
7268 if (node == NULL)
7269 return(-1);
7270 if (node->type != XML_ELEMENT_NODE)
7271 return(0);
7272 if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME)))
7273 return(0);
7274 if (node->children != NULL)
7275 return(0);
7276 switch (node->name[0]) {
7277 case 'a':
7278 if (xmlStrEqual(node->name, BAD_CAST "area"))
7279 return(1);
7280 return(0);
7281 case 'b':
7282 if (xmlStrEqual(node->name, BAD_CAST "br"))
7283 return(1);
7284 if (xmlStrEqual(node->name, BAD_CAST "base"))
7285 return(1);
7286 if (xmlStrEqual(node->name, BAD_CAST "basefont"))
7287 return(1);
7288 return(0);
7289 case 'c':
7290 if (xmlStrEqual(node->name, BAD_CAST "col"))
7291 return(1);
7292 return(0);
7293 case 'f':
7294 if (xmlStrEqual(node->name, BAD_CAST "frame"))
7295 return(1);
7296 return(0);
7297 case 'h':
7298 if (xmlStrEqual(node->name, BAD_CAST "hr"))
7299 return(1);
7300 return(0);
7301 case 'i':
7302 if (xmlStrEqual(node->name, BAD_CAST "img"))
7303 return(1);
7304 if (xmlStrEqual(node->name, BAD_CAST "input"))
7305 return(1);
7306 if (xmlStrEqual(node->name, BAD_CAST "isindex"))
7307 return(1);
7308 return(0);
7309 case 'l':
7310 if (xmlStrEqual(node->name, BAD_CAST "link"))
7311 return(1);
7312 return(0);
7313 case 'm':
7314 if (xmlStrEqual(node->name, BAD_CAST "meta"))
7315 return(1);
7316 return(0);
7317 case 'p':
7318 if (xmlStrEqual(node->name, BAD_CAST "param"))
7319 return(1);
7320 return(0);
7321 }
7322 return(0);
7323}
7324
7325/**
7326 * xhtmlAttrListDumpOutput:
7327 * @buf: the XML buffer output
7328 * @doc: the document
7329 * @cur: the first attribute pointer
7330 * @encoding: an optional encoding string
7331 *
7332 * Dump a list of XML attributes
7333 */
7334static void
7335xhtmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7336 xmlAttrPtr cur, const char *encoding) {
7337 xmlAttrPtr xml_lang = NULL;
7338 xmlAttrPtr lang = NULL;
7339 xmlAttrPtr name = NULL;
7340 xmlAttrPtr id = NULL;
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007341 xmlNodePtr parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007342
7343 if (cur == NULL) {
7344#ifdef DEBUG_TREE
7345 xmlGenericError(xmlGenericErrorContext,
7346 "xmlAttrListDumpOutput : property == NULL\n");
7347#endif
7348 return;
7349 }
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007350 parent = cur->parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007351 while (cur != NULL) {
7352 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id")))
7353 id = cur;
7354 else
7355 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name")))
7356 name = cur;
7357 else
7358 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")))
7359 lang = cur;
7360 else
7361 if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) &&
7362 (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml")))
7363 xml_lang = cur;
7364 else if ((cur->ns == NULL) &&
7365 ((cur->children == NULL) ||
7366 (cur->children->content == NULL) ||
7367 (cur->children->content[0] == 0)) &&
7368 (htmlIsBooleanAttr(cur->name))) {
7369 if (cur->children != NULL)
7370 xmlFreeNode(cur->children);
7371 cur->children = xmlNewText(cur->name);
7372 if (cur->children != NULL)
7373 cur->children->parent = (xmlNodePtr) cur;
7374 }
7375 xmlAttrDumpOutput(buf, doc, cur, encoding);
7376 cur = cur->next;
7377 }
7378 /*
7379 * C.8
7380 */
7381 if ((name != NULL) && (id == NULL)) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007382 if ((parent != NULL) && (parent->name != NULL) &&
7383 ((xmlStrEqual(parent->name, BAD_CAST "a")) ||
7384 (xmlStrEqual(parent->name, BAD_CAST "p")) ||
7385 (xmlStrEqual(parent->name, BAD_CAST "div")) ||
7386 (xmlStrEqual(parent->name, BAD_CAST "img")) ||
7387 (xmlStrEqual(parent->name, BAD_CAST "map")) ||
7388 (xmlStrEqual(parent->name, BAD_CAST "applet")) ||
7389 (xmlStrEqual(parent->name, BAD_CAST "form")) ||
7390 (xmlStrEqual(parent->name, BAD_CAST "frame")) ||
7391 (xmlStrEqual(parent->name, BAD_CAST "iframe")))) {
7392 xmlOutputBufferWriteString(buf, " id=\"");
7393 xmlAttrSerializeContent(buf->buffer, doc, name);
7394 xmlOutputBufferWriteString(buf, "\"");
7395 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007396 }
7397 /*
7398 * C.7.
7399 */
7400 if ((lang != NULL) && (xml_lang == NULL)) {
7401 xmlOutputBufferWriteString(buf, " xml:lang=\"");
7402 xmlAttrSerializeContent(buf->buffer, doc, lang);
7403 xmlOutputBufferWriteString(buf, "\"");
7404 } else
7405 if ((xml_lang != NULL) && (lang == NULL)) {
7406 xmlOutputBufferWriteString(buf, " lang=\"");
7407 xmlAttrSerializeContent(buf->buffer, doc, xml_lang);
7408 xmlOutputBufferWriteString(buf, "\"");
7409 }
7410}
7411
7412/**
7413 * xhtmlNodeListDumpOutput:
7414 * @buf: the XML buffer output
7415 * @doc: the XHTML document
7416 * @cur: the first node
7417 * @level: the imbrication level for indenting
7418 * @format: is formatting allowed
7419 * @encoding: an optional encoding string
7420 *
7421 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007422 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007423 * or xmlKeepBlanksDefault(0) was called
7424 */
7425static void
7426xhtmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7427 xmlNodePtr cur, int level, int format, const char *encoding) {
7428 int i;
7429
7430 if (cur == NULL) {
7431#ifdef DEBUG_TREE
7432 xmlGenericError(xmlGenericErrorContext,
7433 "xhtmlNodeListDumpOutput : node == NULL\n");
7434#endif
7435 return;
7436 }
7437 while (cur != NULL) {
7438 if ((format) && (xmlIndentTreeOutput) &&
7439 (cur->type == XML_ELEMENT_NODE))
7440 for (i = 0;i < level;i++)
7441 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7442 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
7443 if (format) {
7444 xmlOutputBufferWriteString(buf, "\n");
7445 }
7446 cur = cur->next;
7447 }
7448}
7449
7450/**
7451 * xhtmlNodeDumpOutput:
7452 * @buf: the XML buffer output
7453 * @doc: the XHTML document
7454 * @cur: the current node
7455 * @level: the imbrication level for indenting
7456 * @format: is formatting allowed
7457 * @encoding: an optional encoding string
7458 *
7459 * Dump an XHTML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007460 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007461 * or xmlKeepBlanksDefault(0) was called
7462 */
7463static void
7464xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7465 int level, int format, const char *encoding) {
7466 int i;
7467 xmlNodePtr tmp;
7468
7469 if (cur == NULL) {
7470#ifdef DEBUG_TREE
7471 xmlGenericError(xmlGenericErrorContext,
7472 "xmlNodeDumpOutput : node == NULL\n");
7473#endif
7474 return;
7475 }
7476 if (cur->type == XML_XINCLUDE_START)
7477 return;
7478 if (cur->type == XML_XINCLUDE_END)
7479 return;
7480 if (cur->type == XML_DTD_NODE) {
7481 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7482 return;
7483 }
7484 if (cur->type == XML_ELEMENT_DECL) {
7485 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7486 return;
7487 }
7488 if (cur->type == XML_ATTRIBUTE_DECL) {
7489 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7490 return;
7491 }
7492 if (cur->type == XML_ENTITY_DECL) {
7493 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7494 return;
7495 }
7496 if (cur->type == XML_TEXT_NODE) {
7497 if (cur->content != NULL) {
7498 if ((cur->name == xmlStringText) ||
7499 (cur->name != xmlStringTextNoenc)) {
7500 xmlChar *buffer;
7501
7502 if (encoding == NULL)
7503 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7504 else
7505 buffer = xmlEncodeSpecialChars(doc, cur->content);
7506 if (buffer != NULL) {
7507 xmlOutputBufferWriteString(buf, (const char *)buffer);
7508 xmlFree(buffer);
7509 }
7510 } else {
7511 /*
7512 * Disable escaping, needed for XSLT
7513 */
7514 xmlOutputBufferWriteString(buf, (const char *) cur->content);
7515 }
7516 }
7517
7518 return;
7519 }
7520 if (cur->type == XML_PI_NODE) {
7521 if (cur->content != NULL) {
7522 xmlOutputBufferWriteString(buf, "<?");
7523 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7524 if (cur->content != NULL) {
7525 xmlOutputBufferWriteString(buf, " ");
7526 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7527 }
7528 xmlOutputBufferWriteString(buf, "?>");
7529 } else {
7530 xmlOutputBufferWriteString(buf, "<?");
7531 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7532 xmlOutputBufferWriteString(buf, "?>");
7533 }
7534 return;
7535 }
7536 if (cur->type == XML_COMMENT_NODE) {
7537 if (cur->content != NULL) {
7538 xmlOutputBufferWriteString(buf, "<!--");
7539 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7540 xmlOutputBufferWriteString(buf, "-->");
7541 }
7542 return;
7543 }
7544 if (cur->type == XML_ENTITY_REF_NODE) {
7545 xmlOutputBufferWriteString(buf, "&");
7546 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7547 xmlOutputBufferWriteString(buf, ";");
7548 return;
7549 }
7550 if (cur->type == XML_CDATA_SECTION_NODE) {
7551 xmlOutputBufferWriteString(buf, "<![CDATA[");
7552 if (cur->content != NULL)
7553 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7554 xmlOutputBufferWriteString(buf, "]]>");
7555 return;
7556 }
7557
7558 if (format == 1) {
7559 tmp = cur->children;
7560 while (tmp != NULL) {
7561 if ((tmp->type == XML_TEXT_NODE) ||
7562 (tmp->type == XML_ENTITY_REF_NODE)) {
7563 format = 0;
7564 break;
7565 }
7566 tmp = tmp->next;
7567 }
7568 }
7569 xmlOutputBufferWriteString(buf, "<");
7570 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7571 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7572 xmlOutputBufferWriteString(buf, ":");
7573 }
7574
7575 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7576 if (cur->nsDef)
7577 xmlNsListDumpOutput(buf, cur->nsDef);
7578 if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
7579 (cur->ns == NULL) && (cur->nsDef == NULL))) {
7580 /*
7581 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
7582 */
7583 xmlOutputBufferWriteString(buf,
7584 " xmlns=\"http://www.w3.org/1999/xhtml\"");
7585 }
7586 if (cur->properties != NULL)
7587 xhtmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7588
7589 if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) {
7590 if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
7591 (xhtmlIsEmpty(cur) == 1)) {
7592 /*
7593 * C.2. Empty Elements
7594 */
7595 xmlOutputBufferWriteString(buf, " />");
7596 } else {
7597 /*
7598 * C.3. Element Minimization and Empty Element Content
7599 */
7600 xmlOutputBufferWriteString(buf, "></");
7601 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7602 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7603 xmlOutputBufferWriteString(buf, ":");
7604 }
7605 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7606 xmlOutputBufferWriteString(buf, ">");
7607 }
7608 return;
7609 }
7610 xmlOutputBufferWriteString(buf, ">");
7611 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
7612 xmlChar *buffer;
7613
7614 if (encoding == NULL)
7615 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7616 else
7617 buffer = xmlEncodeSpecialChars(doc, cur->content);
7618 if (buffer != NULL) {
7619 xmlOutputBufferWriteString(buf, (const char *)buffer);
7620 xmlFree(buffer);
7621 }
7622 }
7623
7624 /*
7625 * 4.8. Script and Style elements
7626 */
7627 if ((cur->type == XML_ELEMENT_NODE) &&
7628 ((xmlStrEqual(cur->name, BAD_CAST "script")) ||
7629 (xmlStrEqual(cur->name, BAD_CAST "style"))) &&
7630 ((cur->ns == NULL) ||
7631 (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) {
7632 xmlNodePtr child = cur->children;
7633
7634 while (child != NULL) {
7635 if ((child->type == XML_TEXT_NODE) ||
7636 (child->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard64b35282002-12-04 15:10:40 +00007637 /*
7638 * Apparently CDATA escaping for style just break on IE,
7639 * mozilla and galeon, so ...
7640 */
7641 if (xmlStrEqual(cur->name, BAD_CAST "style") &&
7642 (xmlStrchr(child->content, '<') == NULL) &&
7643 (xmlStrchr(child->content, '>') == NULL) &&
7644 (xmlStrchr(child->content, '&') == NULL)) {
7645 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7646 } else {
7647 xmlOutputBufferWriteString(buf, "<![CDATA[");
7648 if (child->content != NULL)
7649 xmlOutputBufferWriteString(buf,
7650 (const char *)child->content);
7651 xmlOutputBufferWriteString(buf, "]]>");
7652 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007653 } else {
7654 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7655 }
7656 child = child->next;
7657 }
7658 } else if (cur->children != NULL) {
7659 if (format) xmlOutputBufferWriteString(buf, "\n");
7660 xhtmlNodeListDumpOutput(buf, doc, cur->children,
7661 (level >= 0?level+1:-1), format, encoding);
7662 if ((xmlIndentTreeOutput) && (format))
7663 for (i = 0;i < level;i++)
7664 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7665 }
7666 xmlOutputBufferWriteString(buf, "</");
7667 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7668 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7669 xmlOutputBufferWriteString(buf, ":");
7670 }
7671
7672 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7673 xmlOutputBufferWriteString(buf, ">");
7674}
7675#endif
7676
Owen Taylor3473f882001-02-23 17:55:21 +00007677/************************************************************************
7678 * *
7679 * Saving functions front-ends *
7680 * *
7681 ************************************************************************/
7682
7683/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00007684 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00007685 * @out_doc: Document to generate XML text from
7686 * @doc_txt_ptr: Memory pointer for allocated XML text
7687 * @doc_txt_len: Length of the generated XML text
7688 * @txt_encoding: Character encoding to use when generating XML text
7689 * @format: should formatting spaces been added
7690 *
7691 * Dump the current DOM tree into memory using the character encoding specified
7692 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007693 * allocated memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00007694 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007695 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007696 */
7697
7698void
7699xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007700 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007701 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007702 int dummy = 0;
7703
7704 xmlCharEncoding doc_charset;
7705 xmlOutputBufferPtr out_buff = NULL;
7706 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
7707
7708 if (doc_txt_len == NULL) {
7709 doc_txt_len = &dummy; /* Continue, caller just won't get length */
7710 }
7711
7712 if (doc_txt_ptr == NULL) {
7713 *doc_txt_len = 0;
7714 xmlGenericError(xmlGenericErrorContext,
7715 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
7716 return;
7717 }
7718
7719 *doc_txt_ptr = NULL;
7720 *doc_txt_len = 0;
7721
7722 if (out_doc == NULL) {
7723 /* No document, no output */
7724 xmlGenericError(xmlGenericErrorContext,
7725 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
7726 return;
7727 }
7728
7729 /*
7730 * Validate the encoding value, if provided.
7731 * This logic is copied from xmlSaveFileEnc.
7732 */
7733
7734 if (txt_encoding == NULL)
7735 txt_encoding = (const char *) out_doc->encoding;
7736 if (txt_encoding != NULL) {
7737 doc_charset = xmlParseCharEncoding(txt_encoding);
7738
7739 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
7740 xmlGenericError(xmlGenericErrorContext,
7741 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
7742 return;
7743
7744 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
7745 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
7746 if ( conv_hdlr == NULL ) {
7747 xmlGenericError(xmlGenericErrorContext,
7748 "%s: %s %s '%s'\n",
7749 "xmlDocDumpFormatMemoryEnc",
7750 "Failed to identify encoding handler for",
7751 "character set",
7752 txt_encoding);
7753 return;
7754 }
7755 }
7756 }
7757
7758 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
7759 xmlGenericError(xmlGenericErrorContext,
7760 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
7761 return;
7762 }
7763
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007764 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007765 xmlOutputBufferFlush(out_buff);
7766 if (out_buff->conv != NULL) {
7767 *doc_txt_len = out_buff->conv->use;
7768 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
7769 } else {
7770 *doc_txt_len = out_buff->buffer->use;
7771 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
7772 }
7773 (void)xmlOutputBufferClose(out_buff);
7774
7775 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
7776 *doc_txt_len = 0;
7777 xmlGenericError(xmlGenericErrorContext,
7778 "xmlDocDumpFormatMemoryEnc: %s\n",
7779 "Failed to allocate memory for document text representation.");
7780 }
7781
7782 return;
7783}
7784
7785/**
7786 * xmlDocDumpMemory:
7787 * @cur: the document
7788 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007789 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007790 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007791 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007792 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007793 */
7794void
7795xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
7796 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
7797}
7798
7799/**
7800 * xmlDocDumpFormatMemory:
7801 * @cur: the document
7802 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007803 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007804 * @format: should formatting spaces been added
7805 *
7806 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007807 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007808 * It's up to the caller to free the memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00007809 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007810 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007811 */
7812void
7813xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
7814 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
7815}
7816
7817/**
7818 * xmlDocDumpMemoryEnc:
7819 * @out_doc: Document to generate XML text from
7820 * @doc_txt_ptr: Memory pointer for allocated XML text
7821 * @doc_txt_len: Length of the generated XML text
7822 * @txt_encoding: Character encoding to use when generating XML text
7823 *
7824 * Dump the current DOM tree into memory using the character encoding specified
7825 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007826 * allocated memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007827 */
7828
7829void
7830xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
7831 int * doc_txt_len, const char * txt_encoding) {
7832 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007833 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007834}
7835
7836/**
7837 * xmlGetDocCompressMode:
7838 * @doc: the document
7839 *
7840 * get the compression ratio for a document, ZLIB based
7841 * Returns 0 (uncompressed) to 9 (max compression)
7842 */
7843int
7844xmlGetDocCompressMode (xmlDocPtr doc) {
7845 if (doc == NULL) return(-1);
7846 return(doc->compression);
7847}
7848
7849/**
7850 * xmlSetDocCompressMode:
7851 * @doc: the document
7852 * @mode: the compression ratio
7853 *
7854 * set the compression ratio for a document, ZLIB based
7855 * Correct values: 0 (uncompressed) to 9 (max compression)
7856 */
7857void
7858xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7859 if (doc == NULL) return;
7860 if (mode < 0) doc->compression = 0;
7861 else if (mode > 9) doc->compression = 9;
7862 else doc->compression = mode;
7863}
7864
7865/**
7866 * xmlGetCompressMode:
7867 *
7868 * get the default compression mode used, ZLIB based.
7869 * Returns 0 (uncompressed) to 9 (max compression)
7870 */
7871int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007872xmlGetCompressMode(void)
7873{
7874 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00007875}
7876
7877/**
7878 * xmlSetCompressMode:
7879 * @mode: the compression ratio
7880 *
7881 * set the default compression mode used, ZLIB based
7882 * Correct values: 0 (uncompressed) to 9 (max compression)
7883 */
7884void
7885xmlSetCompressMode(int mode) {
7886 if (mode < 0) xmlCompressMode = 0;
7887 else if (mode > 9) xmlCompressMode = 9;
7888 else xmlCompressMode = mode;
7889}
7890
7891/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007892 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00007893 * @f: the FILE*
7894 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00007895 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007896 *
7897 * Dump an XML document to an open FILE.
7898 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007899 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007900 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7901 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007902 */
7903int
Daniel Veillard9e412302002-06-10 15:59:44 +00007904xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007905 xmlOutputBufferPtr buf;
7906 const char * encoding;
7907 xmlCharEncodingHandlerPtr handler = NULL;
7908 int ret;
7909
7910 if (cur == NULL) {
7911#ifdef DEBUG_TREE
7912 xmlGenericError(xmlGenericErrorContext,
7913 "xmlDocDump : document == NULL\n");
7914#endif
7915 return(-1);
7916 }
7917 encoding = (const char *) cur->encoding;
7918
7919 if (encoding != NULL) {
7920 xmlCharEncoding enc;
7921
7922 enc = xmlParseCharEncoding(encoding);
7923
7924 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7925 xmlGenericError(xmlGenericErrorContext,
7926 "xmlDocDump: document not in UTF8\n");
7927 return(-1);
7928 }
7929 if (enc != XML_CHAR_ENCODING_UTF8) {
7930 handler = xmlFindCharEncodingHandler(encoding);
7931 if (handler == NULL) {
7932 xmlFree((char *) cur->encoding);
7933 cur->encoding = NULL;
7934 }
7935 }
7936 }
7937 buf = xmlOutputBufferCreateFile(f, handler);
7938 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00007939 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007940
7941 ret = xmlOutputBufferClose(buf);
7942 return(ret);
7943}
7944
7945/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007946 * xmlDocDump:
7947 * @f: the FILE*
7948 * @cur: the document
7949 *
7950 * Dump an XML document to an open FILE.
7951 *
7952 * returns: the number of bytes written or -1 in case of failure.
7953 */
7954int
7955xmlDocDump(FILE *f, xmlDocPtr cur) {
7956 return(xmlDocFormatDump (f, cur, 0));
7957}
7958
7959/**
Owen Taylor3473f882001-02-23 17:55:21 +00007960 * xmlSaveFileTo:
7961 * @buf: an output I/O buffer
7962 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007963 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00007964 *
7965 * Dump an XML document to an I/O buffer.
7966 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007967 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007968 */
7969int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007970xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007971 int ret;
7972
7973 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007974 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007975 ret = xmlOutputBufferClose(buf);
7976 return(ret);
7977}
7978
7979/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00007980 * xmlSaveFormatFileTo:
7981 * @buf: an output I/O buffer
7982 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007983 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00007984 * @format: should formatting spaces been added
7985 *
7986 * Dump an XML document to an I/O buffer.
7987 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007988 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007989 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7990 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardeefd4492001-04-28 16:55:50 +00007991 */
7992int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007993xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00007994 int ret;
7995
7996 if (buf == NULL) return(0);
7997 xmlDocContentDumpOutput(buf, cur, encoding, format);
7998 ret = xmlOutputBufferClose(buf);
7999 return(ret);
8000}
8001
8002/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00008003 * xmlSaveFormatFileEnc:
Daniel Veillardf012a642001-07-23 19:10:52 +00008004 * @filename: the filename or URL to output
8005 * @cur: the document being saved
8006 * @encoding: the name of the encoding to use or NULL.
8007 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00008008 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00008009 * Dump an XML document to a file or an URL.
8010 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008011 * Returns the number of bytes written or -1 in case of error.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008012 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8013 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008014 */
8015int
Daniel Veillardf012a642001-07-23 19:10:52 +00008016xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
8017 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00008018 xmlOutputBufferPtr buf;
8019 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00008020 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00008021 int ret;
8022
Daniel Veillard4dbe77a2003-01-14 00:17:42 +00008023 if (cur == NULL)
8024 return(-1);
8025
Daniel Veillardfb25a512002-01-13 20:32:08 +00008026 if (encoding == NULL)
8027 encoding = (const char *) cur->encoding;
8028
Owen Taylor3473f882001-02-23 17:55:21 +00008029 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00008030
8031 enc = xmlParseCharEncoding(encoding);
8032 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
8033 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00008034 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00008035 return(-1);
8036 }
8037 if (enc != XML_CHAR_ENCODING_UTF8) {
8038 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00008039 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00008040 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00008041 }
8042 }
8043
Daniel Veillardf012a642001-07-23 19:10:52 +00008044#ifdef HAVE_ZLIB_H
8045 if (cur->compression < 0) cur->compression = xmlCompressMode;
8046#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008047 /*
8048 * save the content to a temp buffer.
8049 */
Daniel Veillardf012a642001-07-23 19:10:52 +00008050 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00008051 if (buf == NULL) return(-1);
8052
Daniel Veillardf012a642001-07-23 19:10:52 +00008053 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008054
8055 ret = xmlOutputBufferClose(buf);
8056 return(ret);
8057}
8058
Daniel Veillardf012a642001-07-23 19:10:52 +00008059
8060/**
8061 * xmlSaveFileEnc:
8062 * @filename: the filename (or URL)
8063 * @cur: the document
8064 * @encoding: the name of an encoding (or NULL)
8065 *
8066 * Dump an XML document, converting it to the given encoding
8067 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008068 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00008069 */
8070int
8071xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
8072 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
8073}
8074
Owen Taylor3473f882001-02-23 17:55:21 +00008075/**
Daniel Veillard67fee942001-04-26 18:59:03 +00008076 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00008077 * @filename: the filename (or URL)
8078 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00008079 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00008080 *
8081 * Dump an XML document to a file. Will use compression if
8082 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00008083 * used. If @format is set then the document will be indented on output.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008084 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8085 * or xmlKeepBlanksDefault(0) was called
Daniel Veillard67fee942001-04-26 18:59:03 +00008086 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008087 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008088 */
8089int
Daniel Veillard67fee942001-04-26 18:59:03 +00008090xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008091 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00008092}
8093
Daniel Veillard67fee942001-04-26 18:59:03 +00008094/**
8095 * xmlSaveFile:
8096 * @filename: the filename (or URL)
8097 * @cur: the document
8098 *
8099 * Dump an XML document to a file. Will use compression if
8100 * compiled in and enabled. If @filename is "-" the stdout file is
8101 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00008102 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00008103 */
8104int
8105xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008106 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00008107}
8108