blob: 8bb062548fca556f47b414a044dbdddf26c9ecb7 [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
366/************************************************************************
367 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000368 * Allocation and deallocation of basic structures *
369 * *
370 ************************************************************************/
371
372/**
373 * xmlSetBufferAllocationScheme:
374 * @scheme: allocation method to use
375 *
376 * Set the buffer allocation method. Types are
377 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
378 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
379 * improves performance
380 */
381void
382xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
383 xmlBufferAllocScheme = scheme;
384}
385
386/**
387 * xmlGetBufferAllocationScheme:
388 *
389 * Types are
390 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
391 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
392 * improves performance
393 *
394 * Returns the current allocation scheme
395 */
396xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000397xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000398 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000399}
400
401/**
402 * xmlNewNs:
403 * @node: the element carrying the namespace
404 * @href: the URI associated
405 * @prefix: the prefix for the namespace
406 *
407 * Creation of a new Namespace. This function will refuse to create
408 * a namespace with a similar prefix than an existing one present on this
409 * node.
410 * We use href==NULL in the case of an element creation where the namespace
411 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000412 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000413 */
414xmlNsPtr
415xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
416 xmlNsPtr cur;
417
418 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
419 return(NULL);
420
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000421 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
422 return(NULL);
423
Owen Taylor3473f882001-02-23 17:55:21 +0000424 /*
425 * Allocate a new Namespace and fill the fields.
426 */
427 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
428 if (cur == NULL) {
429 xmlGenericError(xmlGenericErrorContext,
430 "xmlNewNs : malloc failed\n");
431 return(NULL);
432 }
433 memset(cur, 0, sizeof(xmlNs));
434 cur->type = XML_LOCAL_NAMESPACE;
435
436 if (href != NULL)
437 cur->href = xmlStrdup(href);
438 if (prefix != NULL)
439 cur->prefix = xmlStrdup(prefix);
440
441 /*
442 * Add it at the end to preserve parsing order ...
443 * and checks for existing use of the prefix
444 */
445 if (node != NULL) {
446 if (node->nsDef == NULL) {
447 node->nsDef = cur;
448 } else {
449 xmlNsPtr prev = node->nsDef;
450
451 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
452 (xmlStrEqual(prev->prefix, cur->prefix))) {
453 xmlFreeNs(cur);
454 return(NULL);
455 }
456 while (prev->next != NULL) {
457 prev = prev->next;
458 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
459 (xmlStrEqual(prev->prefix, cur->prefix))) {
460 xmlFreeNs(cur);
461 return(NULL);
462 }
463 }
464 prev->next = cur;
465 }
466 }
467 return(cur);
468}
469
470/**
471 * xmlSetNs:
472 * @node: a node in the document
473 * @ns: a namespace pointer
474 *
475 * Associate a namespace to a node, a posteriori.
476 */
477void
478xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
479 if (node == NULL) {
480#ifdef DEBUG_TREE
481 xmlGenericError(xmlGenericErrorContext,
482 "xmlSetNs: node == NULL\n");
483#endif
484 return;
485 }
486 node->ns = ns;
487}
488
489/**
490 * xmlFreeNs:
491 * @cur: the namespace pointer
492 *
493 * Free up the structures associated to a namespace
494 */
495void
496xmlFreeNs(xmlNsPtr cur) {
497 if (cur == NULL) {
498#ifdef DEBUG_TREE
499 xmlGenericError(xmlGenericErrorContext,
500 "xmlFreeNs : ns == NULL\n");
501#endif
502 return;
503 }
504 if (cur->href != NULL) xmlFree((char *) cur->href);
505 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000506 xmlFree(cur);
507}
508
509/**
510 * xmlFreeNsList:
511 * @cur: the first namespace pointer
512 *
513 * Free up all the structures associated to the chained namespaces.
514 */
515void
516xmlFreeNsList(xmlNsPtr cur) {
517 xmlNsPtr next;
518 if (cur == NULL) {
519#ifdef DEBUG_TREE
520 xmlGenericError(xmlGenericErrorContext,
521 "xmlFreeNsList : ns == NULL\n");
522#endif
523 return;
524 }
525 while (cur != NULL) {
526 next = cur->next;
527 xmlFreeNs(cur);
528 cur = next;
529 }
530}
531
532/**
533 * xmlNewDtd:
534 * @doc: the document pointer
535 * @name: the DTD name
536 * @ExternalID: the external ID
537 * @SystemID: the system ID
538 *
539 * Creation of a new DTD for the external subset. To create an
540 * internal subset, use xmlCreateIntSubset().
541 *
542 * Returns a pointer to the new DTD structure
543 */
544xmlDtdPtr
545xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
546 const xmlChar *ExternalID, const xmlChar *SystemID) {
547 xmlDtdPtr cur;
548
549 if ((doc != NULL) && (doc->extSubset != NULL)) {
550#ifdef DEBUG_TREE
551 xmlGenericError(xmlGenericErrorContext,
552 "xmlNewDtd(%s): document %s already have a DTD %s\n",
553 /* !!! */ (char *) name, doc->name,
554 /* !!! */ (char *)doc->extSubset->name);
555#endif
556 return(NULL);
557 }
558
559 /*
560 * Allocate a new DTD and fill the fields.
561 */
562 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
563 if (cur == NULL) {
564 xmlGenericError(xmlGenericErrorContext,
565 "xmlNewDtd : malloc failed\n");
566 return(NULL);
567 }
568 memset(cur, 0 , sizeof(xmlDtd));
569 cur->type = XML_DTD_NODE;
570
571 if (name != NULL)
572 cur->name = xmlStrdup(name);
573 if (ExternalID != NULL)
574 cur->ExternalID = xmlStrdup(ExternalID);
575 if (SystemID != NULL)
576 cur->SystemID = xmlStrdup(SystemID);
577 if (doc != NULL)
578 doc->extSubset = cur;
579 cur->doc = doc;
580
Daniel Veillard5335dc52003-01-01 20:59:38 +0000581 if (xmlRegisterNodeDefaultValue)
582 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000583 return(cur);
584}
585
586/**
587 * xmlGetIntSubset:
588 * @doc: the document pointer
589 *
590 * Get the internal subset of a document
591 * Returns a pointer to the DTD structure or NULL if not found
592 */
593
594xmlDtdPtr
595xmlGetIntSubset(xmlDocPtr doc) {
596 xmlNodePtr cur;
597
598 if (doc == NULL)
599 return(NULL);
600 cur = doc->children;
601 while (cur != NULL) {
602 if (cur->type == XML_DTD_NODE)
603 return((xmlDtdPtr) cur);
604 cur = cur->next;
605 }
606 return((xmlDtdPtr) doc->intSubset);
607}
608
609/**
610 * xmlCreateIntSubset:
611 * @doc: the document pointer
612 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000613 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000614 * @SystemID: the system ID
615 *
616 * Create the internal subset of a document
617 * Returns a pointer to the new DTD structure
618 */
619xmlDtdPtr
620xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
621 const xmlChar *ExternalID, const xmlChar *SystemID) {
622 xmlDtdPtr cur;
623
624 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
625#ifdef DEBUG_TREE
626 xmlGenericError(xmlGenericErrorContext,
627
628 "xmlCreateIntSubset(): document %s already have an internal subset\n",
629 doc->name);
630#endif
631 return(NULL);
632 }
633
634 /*
635 * Allocate a new DTD and fill the fields.
636 */
637 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
638 if (cur == NULL) {
639 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000640 "xmlCreateIntSubset : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000641 return(NULL);
642 }
643 memset(cur, 0, sizeof(xmlDtd));
644 cur->type = XML_DTD_NODE;
645
646 if (name != NULL)
647 cur->name = xmlStrdup(name);
648 if (ExternalID != NULL)
649 cur->ExternalID = xmlStrdup(ExternalID);
650 if (SystemID != NULL)
651 cur->SystemID = xmlStrdup(SystemID);
652 if (doc != NULL) {
653 doc->intSubset = cur;
654 cur->parent = doc;
655 cur->doc = doc;
656 if (doc->children == NULL) {
657 doc->children = (xmlNodePtr) cur;
658 doc->last = (xmlNodePtr) cur;
659 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000660 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000661 xmlNodePtr prev;
662
Owen Taylor3473f882001-02-23 17:55:21 +0000663 prev = doc->children;
664 prev->prev = (xmlNodePtr) cur;
665 cur->next = prev;
666 doc->children = (xmlNodePtr) cur;
667 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000668 xmlNodePtr next;
669
670 next = doc->children;
671 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
672 next = next->next;
673 if (next == NULL) {
674 cur->prev = doc->last;
675 cur->prev->next = (xmlNodePtr) cur;
676 cur->next = NULL;
677 doc->last = (xmlNodePtr) cur;
678 } else {
679 cur->next = next;
680 cur->prev = next->prev;
681 if (cur->prev == NULL)
682 doc->children = (xmlNodePtr) cur;
683 else
684 cur->prev->next = (xmlNodePtr) cur;
685 next->prev = (xmlNodePtr) cur;
686 }
Owen Taylor3473f882001-02-23 17:55:21 +0000687 }
688 }
689 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000690
691 if (xmlRegisterNodeDefaultValue)
692 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000693 return(cur);
694}
695
696/**
697 * xmlFreeDtd:
698 * @cur: the DTD structure to free up
699 *
700 * Free a DTD structure.
701 */
702void
703xmlFreeDtd(xmlDtdPtr cur) {
704 if (cur == NULL) {
705#ifdef DEBUG_TREE
706 xmlGenericError(xmlGenericErrorContext,
707 "xmlFreeDtd : DTD == NULL\n");
708#endif
709 return;
710 }
Daniel Veillard5335dc52003-01-01 20:59:38 +0000711
712 if (xmlDeregisterNodeDefaultValue)
713 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
714
Owen Taylor3473f882001-02-23 17:55:21 +0000715 if (cur->children != NULL) {
716 xmlNodePtr next, c = cur->children;
717
718 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000719 * Cleanup all the DTD comments they are not in the DTD
Owen Taylor3473f882001-02-23 17:55:21 +0000720 * indexes.
721 */
722 while (c != NULL) {
723 next = c->next;
724 if (c->type == XML_COMMENT_NODE) {
725 xmlUnlinkNode(c);
726 xmlFreeNode(c);
727 }
728 c = next;
729 }
730 }
731 if (cur->name != NULL) xmlFree((char *) cur->name);
732 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
733 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
734 /* TODO !!! */
735 if (cur->notations != NULL)
736 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
737
738 if (cur->elements != NULL)
739 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
740 if (cur->attributes != NULL)
741 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
742 if (cur->entities != NULL)
743 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
744 if (cur->pentities != NULL)
745 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
746
Owen Taylor3473f882001-02-23 17:55:21 +0000747 xmlFree(cur);
748}
749
750/**
751 * xmlNewDoc:
752 * @version: xmlChar string giving the version of XML "1.0"
753 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000754 * Creates a new XML document
755 *
Owen Taylor3473f882001-02-23 17:55:21 +0000756 * Returns a new document
757 */
758xmlDocPtr
759xmlNewDoc(const xmlChar *version) {
760 xmlDocPtr cur;
761
762 if (version == NULL)
763 version = (const xmlChar *) "1.0";
764
765 /*
766 * Allocate a new document and fill the fields.
767 */
768 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
769 if (cur == NULL) {
770 xmlGenericError(xmlGenericErrorContext,
771 "xmlNewDoc : malloc failed\n");
772 return(NULL);
773 }
774 memset(cur, 0, sizeof(xmlDoc));
775 cur->type = XML_DOCUMENT_NODE;
776
777 cur->version = xmlStrdup(version);
778 cur->standalone = -1;
779 cur->compression = -1; /* not initialized */
780 cur->doc = cur;
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000781 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +0000782
783 if (xmlRegisterNodeDefaultValue)
784 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000785 return(cur);
786}
787
788/**
789 * xmlFreeDoc:
790 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +0000791 *
792 * Free up all the structures used by a document, tree included.
793 */
794void
795xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +0000796 xmlDtdPtr extSubset, intSubset;
797
Owen Taylor3473f882001-02-23 17:55:21 +0000798 if (cur == NULL) {
799#ifdef DEBUG_TREE
800 xmlGenericError(xmlGenericErrorContext,
801 "xmlFreeDoc : document == NULL\n");
802#endif
803 return;
804 }
Daniel Veillard5335dc52003-01-01 20:59:38 +0000805
806 if (xmlDeregisterNodeDefaultValue)
807 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
808
Daniel Veillard76d66f42001-05-16 21:05:17 +0000809 /*
810 * Do this before freeing the children list to avoid ID lookups
811 */
812 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
813 cur->ids = NULL;
814 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
815 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000816 extSubset = cur->extSubset;
817 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +0000818 if (intSubset == extSubset)
819 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000820 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000821 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000822 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000823 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000824 }
Daniel Veillarda9142e72001-06-19 11:07:54 +0000825 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000826 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000827 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000828 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000829 }
830
831 if (cur->children != NULL) xmlFreeNodeList(cur->children);
832
Owen Taylor3473f882001-02-23 17:55:21 +0000833 if (cur->version != NULL) xmlFree((char *) cur->version);
834 if (cur->name != NULL) xmlFree((char *) cur->name);
835 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Owen Taylor3473f882001-02-23 17:55:21 +0000836 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +0000837 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Owen Taylor3473f882001-02-23 17:55:21 +0000838 xmlFree(cur);
839}
840
841/**
842 * xmlStringLenGetNodeList:
843 * @doc: the document
844 * @value: the value of the text
845 * @len: the length of the string value
846 *
847 * Parse the value string and build the node list associated. Should
848 * produce a flat tree with only TEXTs and ENTITY_REFs.
849 * Returns a pointer to the first child
850 */
851xmlNodePtr
852xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
853 xmlNodePtr ret = NULL, last = NULL;
854 xmlNodePtr node;
855 xmlChar *val;
856 const xmlChar *cur = value;
857 const xmlChar *q;
858 xmlEntityPtr ent;
859
860 if (value == NULL) return(NULL);
861
862 q = cur;
863 while ((*cur != 0) && (cur - value < len)) {
864 if (*cur == '&') {
865 /*
866 * Save the current text.
867 */
868 if (cur != q) {
869 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
870 xmlNodeAddContentLen(last, q, cur - q);
871 } else {
872 node = xmlNewDocTextLen(doc, q, cur - q);
873 if (node == NULL) return(ret);
874 if (last == NULL)
875 last = ret = node;
876 else {
877 last->next = node;
878 node->prev = last;
879 last = node;
880 }
881 }
882 }
883 /*
884 * Read the entity string
885 */
886 cur++;
887 q = cur;
888 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
889 if ((*cur == 0) || (cur - value >= len)) {
890#ifdef DEBUG_TREE
891 xmlGenericError(xmlGenericErrorContext,
892 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
893#endif
894 return(ret);
895 }
896 if (cur != q) {
897 /*
898 * Predefined entities don't generate nodes
899 */
900 val = xmlStrndup(q, cur - q);
901 ent = xmlGetDocEntity(doc, val);
902 if ((ent != NULL) &&
903 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
904 if (last == NULL) {
905 node = xmlNewDocText(doc, ent->content);
906 last = ret = node;
907 } else
908 xmlNodeAddContent(last, ent->content);
909
910 } else {
911 /*
912 * Create a new REFERENCE_REF node
913 */
914 node = xmlNewReference(doc, val);
915 if (node == NULL) {
916 if (val != NULL) xmlFree(val);
917 return(ret);
918 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +0000919 else if ((ent != NULL) && (ent->children == NULL)) {
920 xmlNodePtr tmp;
921
922 ent->children =
923 xmlStringGetNodeList(doc, (const xmlChar*)node->content);
924 tmp = ent->children;
925 while (tmp) {
926 tmp->parent = (xmlNodePtr)ent;
927 tmp = tmp->next;
928 }
929 }
Owen Taylor3473f882001-02-23 17:55:21 +0000930 if (last == NULL)
931 last = ret = node;
932 else {
933 last->next = node;
934 node->prev = last;
935 last = node;
936 }
937 }
938 xmlFree(val);
939 }
940 cur++;
941 q = cur;
942 } else
943 cur++;
944 }
945 if (cur != q) {
946 /*
947 * Handle the last piece of text.
948 */
949 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
950 xmlNodeAddContentLen(last, q, cur - q);
951 } else {
952 node = xmlNewDocTextLen(doc, q, cur - q);
953 if (node == NULL) return(ret);
954 if (last == NULL)
955 last = ret = node;
956 else {
957 last->next = node;
958 node->prev = last;
959 last = node;
960 }
961 }
962 }
963 return(ret);
964}
965
966/**
967 * xmlStringGetNodeList:
968 * @doc: the document
969 * @value: the value of the attribute
970 *
971 * Parse the value string and build the node list associated. Should
972 * produce a flat tree with only TEXTs and ENTITY_REFs.
973 * Returns a pointer to the first child
974 */
975xmlNodePtr
976xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
977 xmlNodePtr ret = NULL, last = NULL;
978 xmlNodePtr node;
979 xmlChar *val;
980 const xmlChar *cur = value;
981 const xmlChar *q;
982 xmlEntityPtr ent;
983
984 if (value == NULL) return(NULL);
985
986 q = cur;
987 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000988 if (cur[0] == '&') {
989 int charval = 0;
990 xmlChar tmp;
991
Owen Taylor3473f882001-02-23 17:55:21 +0000992 /*
993 * Save the current text.
994 */
995 if (cur != q) {
996 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
997 xmlNodeAddContentLen(last, q, cur - q);
998 } else {
999 node = xmlNewDocTextLen(doc, q, cur - q);
1000 if (node == NULL) return(ret);
1001 if (last == NULL)
1002 last = ret = node;
1003 else {
1004 last->next = node;
1005 node->prev = last;
1006 last = node;
1007 }
1008 }
1009 }
Owen Taylor3473f882001-02-23 17:55:21 +00001010 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001011 if ((cur[1] == '#') && (cur[2] == 'x')) {
1012 cur += 3;
1013 tmp = *cur;
1014 while (tmp != ';') { /* Non input consuming loop */
1015 if ((tmp >= '0') && (tmp <= '9'))
1016 charval = charval * 16 + (tmp - '0');
1017 else if ((tmp >= 'a') && (tmp <= 'f'))
1018 charval = charval * 16 + (tmp - 'a') + 10;
1019 else if ((tmp >= 'A') && (tmp <= 'F'))
1020 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001021 else {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001022 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001023 "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001024 charval = 0;
1025 break;
1026 }
1027 cur++;
1028 tmp = *cur;
1029 }
1030 if (tmp == ';')
1031 cur++;
1032 q = cur;
1033 } else if (cur[1] == '#') {
1034 cur += 2;
1035 tmp = *cur;
1036 while (tmp != ';') { /* Non input consuming loops */
1037 if ((tmp >= '0') && (tmp <= '9'))
1038 charval = charval * 10 + (tmp - '0');
1039 else {
1040 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001041 "xmlStringGetNodeList: invalid decimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001042 charval = 0;
1043 break;
1044 }
1045 cur++;
1046 tmp = *cur;
1047 }
1048 if (tmp == ';')
1049 cur++;
1050 q = cur;
1051 } else {
1052 /*
1053 * Read the entity string
1054 */
1055 cur++;
1056 q = cur;
1057 while ((*cur != 0) && (*cur != ';')) cur++;
1058 if (*cur == 0) {
1059#ifdef DEBUG_TREE
1060 xmlGenericError(xmlGenericErrorContext,
1061 "xmlStringGetNodeList: unterminated entity %30s\n", q);
1062#endif
1063 return(ret);
1064 }
1065 if (cur != q) {
1066 /*
1067 * Predefined entities don't generate nodes
1068 */
1069 val = xmlStrndup(q, cur - q);
1070 ent = xmlGetDocEntity(doc, val);
1071 if ((ent != NULL) &&
1072 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1073 if (last == NULL) {
1074 node = xmlNewDocText(doc, ent->content);
1075 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001076 } else if (last->type != XML_TEXT_NODE) {
1077 node = xmlNewDocText(doc, ent->content);
1078 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001079 } else
1080 xmlNodeAddContent(last, ent->content);
1081
1082 } else {
1083 /*
1084 * Create a new REFERENCE_REF node
1085 */
1086 node = xmlNewReference(doc, val);
1087 if (node == NULL) {
1088 if (val != NULL) xmlFree(val);
1089 return(ret);
1090 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001091 else if ((ent != NULL) && (ent->children == NULL)) {
1092 xmlNodePtr temp;
1093
1094 ent->children = xmlStringGetNodeList(doc,
1095 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001096 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001097 temp = ent->children;
1098 while (temp) {
1099 temp->parent = (xmlNodePtr)ent;
1100 temp = temp->next;
1101 }
1102 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001103 if (last == NULL) {
1104 last = ret = node;
1105 } else {
1106 last = xmlAddNextSibling(last, node);
1107 }
1108 }
1109 xmlFree(val);
1110 }
1111 cur++;
1112 q = cur;
1113 }
1114 if (charval != 0) {
1115 xmlChar buf[10];
1116 int len;
1117
1118 len = xmlCopyCharMultiByte(buf, charval);
1119 buf[len] = 0;
1120 node = xmlNewDocText(doc, buf);
1121 if (node != NULL) {
1122 if (last == NULL) {
1123 last = ret = node;
1124 } else {
1125 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001126 }
1127 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001128
1129 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001130 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001131 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001132 cur++;
1133 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001134 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001135 /*
1136 * Handle the last piece of text.
1137 */
1138 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1139 xmlNodeAddContentLen(last, q, cur - q);
1140 } else {
1141 node = xmlNewDocTextLen(doc, q, cur - q);
1142 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001143 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001144 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001145 } else {
1146 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001147 }
1148 }
1149 }
1150 return(ret);
1151}
1152
1153/**
1154 * xmlNodeListGetString:
1155 * @doc: the document
1156 * @list: a Node list
1157 * @inLine: should we replace entity contents or show their external form
1158 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001159 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001160 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001161 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001162 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001163 */
1164xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001165xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1166{
Owen Taylor3473f882001-02-23 17:55:21 +00001167 xmlNodePtr node = list;
1168 xmlChar *ret = NULL;
1169 xmlEntityPtr ent;
1170
Daniel Veillard7646b182002-04-20 06:41:40 +00001171 if (list == NULL)
1172 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001173
1174 while (node != NULL) {
1175 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001176 (node->type == XML_CDATA_SECTION_NODE)) {
1177 if (inLine) {
1178 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001179 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001180 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001181
Daniel Veillard7646b182002-04-20 06:41:40 +00001182 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1183 if (buffer != NULL) {
1184 ret = xmlStrcat(ret, buffer);
1185 xmlFree(buffer);
1186 }
1187 }
1188 } else if (node->type == XML_ENTITY_REF_NODE) {
1189 if (inLine) {
1190 ent = xmlGetDocEntity(doc, node->name);
1191 if (ent != NULL) {
1192 xmlChar *buffer;
1193
1194 /* an entity content can be any "well balanced chunk",
1195 * i.e. the result of the content [43] production:
1196 * http://www.w3.org/TR/REC-xml#NT-content.
1197 * So it can contain text, CDATA section or nested
1198 * entity reference nodes (among others).
1199 * -> we recursive call xmlNodeListGetString()
1200 * which handles these types */
1201 buffer = xmlNodeListGetString(doc, ent->children, 1);
1202 if (buffer != NULL) {
1203 ret = xmlStrcat(ret, buffer);
1204 xmlFree(buffer);
1205 }
1206 } else {
1207 ret = xmlStrcat(ret, node->content);
1208 }
1209 } else {
1210 xmlChar buf[2];
1211
1212 buf[0] = '&';
1213 buf[1] = 0;
1214 ret = xmlStrncat(ret, buf, 1);
1215 ret = xmlStrcat(ret, node->name);
1216 buf[0] = ';';
1217 buf[1] = 0;
1218 ret = xmlStrncat(ret, buf, 1);
1219 }
1220 }
1221#if 0
1222 else {
1223 xmlGenericError(xmlGenericErrorContext,
1224 "xmlGetNodeListString : invalid node type %d\n",
1225 node->type);
1226 }
1227#endif
1228 node = node->next;
1229 }
1230 return (ret);
1231}
Owen Taylor3473f882001-02-23 17:55:21 +00001232/**
1233 * xmlNodeListGetRawString:
1234 * @doc: the document
1235 * @list: a Node list
1236 * @inLine: should we replace entity contents or show their external form
1237 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001238 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001239 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1240 * this function doesn't do any character encoding handling.
1241 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001242 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001243 */
1244xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001245xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1246{
Owen Taylor3473f882001-02-23 17:55:21 +00001247 xmlNodePtr node = list;
1248 xmlChar *ret = NULL;
1249 xmlEntityPtr ent;
1250
Daniel Veillard7646b182002-04-20 06:41:40 +00001251 if (list == NULL)
1252 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001253
1254 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001255 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001256 (node->type == XML_CDATA_SECTION_NODE)) {
1257 if (inLine) {
1258 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001259 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001260 xmlChar *buffer;
1261
1262 buffer = xmlEncodeSpecialChars(doc, node->content);
1263 if (buffer != NULL) {
1264 ret = xmlStrcat(ret, buffer);
1265 xmlFree(buffer);
1266 }
1267 }
1268 } else if (node->type == XML_ENTITY_REF_NODE) {
1269 if (inLine) {
1270 ent = xmlGetDocEntity(doc, node->name);
1271 if (ent != NULL) {
1272 xmlChar *buffer;
1273
1274 /* an entity content can be any "well balanced chunk",
1275 * i.e. the result of the content [43] production:
1276 * http://www.w3.org/TR/REC-xml#NT-content.
1277 * So it can contain text, CDATA section or nested
1278 * entity reference nodes (among others).
1279 * -> we recursive call xmlNodeListGetRawString()
1280 * which handles these types */
1281 buffer =
1282 xmlNodeListGetRawString(doc, ent->children, 1);
1283 if (buffer != NULL) {
1284 ret = xmlStrcat(ret, buffer);
1285 xmlFree(buffer);
1286 }
1287 } else {
1288 ret = xmlStrcat(ret, node->content);
1289 }
1290 } else {
1291 xmlChar buf[2];
1292
1293 buf[0] = '&';
1294 buf[1] = 0;
1295 ret = xmlStrncat(ret, buf, 1);
1296 ret = xmlStrcat(ret, node->name);
1297 buf[0] = ';';
1298 buf[1] = 0;
1299 ret = xmlStrncat(ret, buf, 1);
1300 }
1301 }
Owen Taylor3473f882001-02-23 17:55:21 +00001302#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001303 else {
1304 xmlGenericError(xmlGenericErrorContext,
1305 "xmlGetNodeListString : invalid node type %d\n",
1306 node->type);
1307 }
Owen Taylor3473f882001-02-23 17:55:21 +00001308#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001309 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001310 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001311 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001312}
1313
1314/**
1315 * xmlNewProp:
1316 * @node: the holding node
1317 * @name: the name of the attribute
1318 * @value: the value of the attribute
1319 *
1320 * Create a new property carried by a node.
1321 * Returns a pointer to the attribute
1322 */
1323xmlAttrPtr
1324xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1325 xmlAttrPtr cur;
1326 xmlDocPtr doc = NULL;
1327
1328 if (name == NULL) {
1329#ifdef DEBUG_TREE
1330 xmlGenericError(xmlGenericErrorContext,
1331 "xmlNewProp : name == NULL\n");
1332#endif
1333 return(NULL);
1334 }
1335
1336 /*
1337 * Allocate a new property and fill the fields.
1338 */
1339 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1340 if (cur == NULL) {
1341 xmlGenericError(xmlGenericErrorContext,
1342 "xmlNewProp : malloc failed\n");
1343 return(NULL);
1344 }
1345 memset(cur, 0, sizeof(xmlAttr));
1346 cur->type = XML_ATTRIBUTE_NODE;
1347
1348 cur->parent = node;
1349 if (node != NULL) {
1350 doc = node->doc;
1351 cur->doc = doc;
1352 }
1353 cur->name = xmlStrdup(name);
1354 if (value != NULL) {
1355 xmlChar *buffer;
1356 xmlNodePtr tmp;
1357
1358 buffer = xmlEncodeEntitiesReentrant(doc, value);
1359 cur->children = xmlStringGetNodeList(doc, buffer);
1360 cur->last = NULL;
1361 tmp = cur->children;
1362 while (tmp != NULL) {
1363 tmp->parent = (xmlNodePtr) cur;
1364 tmp->doc = doc;
1365 if (tmp->next == NULL)
1366 cur->last = tmp;
1367 tmp = tmp->next;
1368 }
1369 xmlFree(buffer);
1370 }
1371
1372 /*
1373 * Add it at the end to preserve parsing order ...
1374 */
1375 if (node != NULL) {
1376 if (node->properties == NULL) {
1377 node->properties = cur;
1378 } else {
1379 xmlAttrPtr prev = node->properties;
1380
1381 while (prev->next != NULL) prev = prev->next;
1382 prev->next = cur;
1383 cur->prev = prev;
1384 }
1385 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001386
1387 if (xmlRegisterNodeDefaultValue)
1388 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001389 return(cur);
1390}
1391
1392/**
1393 * xmlNewNsProp:
1394 * @node: the holding node
1395 * @ns: the namespace
1396 * @name: the name of the attribute
1397 * @value: the value of the attribute
1398 *
1399 * Create a new property tagged with a namespace and carried by a node.
1400 * Returns a pointer to the attribute
1401 */
1402xmlAttrPtr
1403xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1404 const xmlChar *value) {
1405 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001406 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001407
1408 if (name == NULL) {
1409#ifdef DEBUG_TREE
1410 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001411 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001412#endif
1413 return(NULL);
1414 }
1415
1416 /*
1417 * Allocate a new property and fill the fields.
1418 */
1419 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1420 if (cur == NULL) {
1421 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001422 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001423 return(NULL);
1424 }
1425 memset(cur, 0, sizeof(xmlAttr));
1426 cur->type = XML_ATTRIBUTE_NODE;
1427
1428 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001429 if (node != NULL) {
1430 doc = node->doc;
1431 cur->doc = doc;
1432 }
Owen Taylor3473f882001-02-23 17:55:21 +00001433 cur->ns = ns;
1434 cur->name = xmlStrdup(name);
1435 if (value != NULL) {
1436 xmlChar *buffer;
1437 xmlNodePtr tmp;
1438
Daniel Veillarda682b212001-06-07 19:59:42 +00001439 buffer = xmlEncodeEntitiesReentrant(doc, value);
1440 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001441 cur->last = NULL;
1442 tmp = cur->children;
1443 while (tmp != NULL) {
1444 tmp->parent = (xmlNodePtr) cur;
1445 if (tmp->next == NULL)
1446 cur->last = tmp;
1447 tmp = tmp->next;
1448 }
1449 xmlFree(buffer);
1450 }
1451
1452 /*
1453 * Add it at the end to preserve parsing order ...
1454 */
1455 if (node != NULL) {
1456 if (node->properties == NULL) {
1457 node->properties = cur;
1458 } else {
1459 xmlAttrPtr prev = node->properties;
1460
1461 while (prev->next != NULL) prev = prev->next;
1462 prev->next = cur;
1463 cur->prev = prev;
1464 }
1465 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001466
1467 if (xmlRegisterNodeDefaultValue)
1468 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001469 return(cur);
1470}
1471
1472/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001473 * xmlNewNsPropEatName:
1474 * @node: the holding node
1475 * @ns: the namespace
1476 * @name: the name of the attribute
1477 * @value: the value of the attribute
1478 *
1479 * Create a new property tagged with a namespace and carried by a node.
1480 * Returns a pointer to the attribute
1481 */
1482xmlAttrPtr
1483xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1484 const xmlChar *value) {
1485 xmlAttrPtr cur;
1486 xmlDocPtr doc = NULL;
1487
1488 if (name == NULL) {
1489#ifdef DEBUG_TREE
1490 xmlGenericError(xmlGenericErrorContext,
1491 "xmlNewNsPropEatName : name == NULL\n");
1492#endif
1493 return(NULL);
1494 }
1495
1496 /*
1497 * Allocate a new property and fill the fields.
1498 */
1499 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1500 if (cur == NULL) {
1501 xmlGenericError(xmlGenericErrorContext,
1502 "xmlNewNsPropEatName : malloc failed\n");
1503 return(NULL);
1504 }
1505 memset(cur, 0, sizeof(xmlAttr));
1506 cur->type = XML_ATTRIBUTE_NODE;
1507
1508 cur->parent = node;
1509 if (node != NULL) {
1510 doc = node->doc;
1511 cur->doc = doc;
1512 }
1513 cur->ns = ns;
1514 cur->name = name;
1515 if (value != NULL) {
1516 xmlChar *buffer;
1517 xmlNodePtr tmp;
1518
1519 buffer = xmlEncodeEntitiesReentrant(doc, value);
1520 cur->children = xmlStringGetNodeList(doc, buffer);
1521 cur->last = NULL;
1522 tmp = cur->children;
1523 while (tmp != NULL) {
1524 tmp->parent = (xmlNodePtr) cur;
1525 if (tmp->next == NULL)
1526 cur->last = tmp;
1527 tmp = tmp->next;
1528 }
1529 xmlFree(buffer);
1530 }
1531
1532 /*
1533 * Add it at the end to preserve parsing order ...
1534 */
1535 if (node != NULL) {
1536 if (node->properties == NULL) {
1537 node->properties = cur;
1538 } else {
1539 xmlAttrPtr prev = node->properties;
1540
1541 while (prev->next != NULL) prev = prev->next;
1542 prev->next = cur;
1543 cur->prev = prev;
1544 }
1545 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001546
1547 if (xmlRegisterNodeDefaultValue)
1548 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001549 return(cur);
1550}
1551
1552/**
Owen Taylor3473f882001-02-23 17:55:21 +00001553 * xmlNewDocProp:
1554 * @doc: the document
1555 * @name: the name of the attribute
1556 * @value: the value of the attribute
1557 *
1558 * Create a new property carried by a document.
1559 * Returns a pointer to the attribute
1560 */
1561xmlAttrPtr
1562xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1563 xmlAttrPtr cur;
1564
1565 if (name == NULL) {
1566#ifdef DEBUG_TREE
1567 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001568 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001569#endif
1570 return(NULL);
1571 }
1572
1573 /*
1574 * Allocate a new property and fill the fields.
1575 */
1576 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1577 if (cur == NULL) {
1578 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001579 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001580 return(NULL);
1581 }
1582 memset(cur, 0, sizeof(xmlAttr));
1583 cur->type = XML_ATTRIBUTE_NODE;
1584
1585 cur->name = xmlStrdup(name);
1586 cur->doc = doc;
1587 if (value != NULL) {
1588 xmlNodePtr tmp;
1589
1590 cur->children = xmlStringGetNodeList(doc, value);
1591 cur->last = NULL;
1592
1593 tmp = cur->children;
1594 while (tmp != NULL) {
1595 tmp->parent = (xmlNodePtr) cur;
1596 if (tmp->next == NULL)
1597 cur->last = tmp;
1598 tmp = tmp->next;
1599 }
1600 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001601
1602 if (xmlRegisterNodeDefaultValue)
1603 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001604 return(cur);
1605}
1606
1607/**
1608 * xmlFreePropList:
1609 * @cur: the first property in the list
1610 *
1611 * Free a property and all its siblings, all the children are freed too.
1612 */
1613void
1614xmlFreePropList(xmlAttrPtr cur) {
1615 xmlAttrPtr next;
1616 if (cur == NULL) {
1617#ifdef DEBUG_TREE
1618 xmlGenericError(xmlGenericErrorContext,
1619 "xmlFreePropList : property == NULL\n");
1620#endif
1621 return;
1622 }
1623 while (cur != NULL) {
1624 next = cur->next;
1625 xmlFreeProp(cur);
1626 cur = next;
1627 }
1628}
1629
1630/**
1631 * xmlFreeProp:
1632 * @cur: an attribute
1633 *
1634 * Free one attribute, all the content is freed too
1635 */
1636void
1637xmlFreeProp(xmlAttrPtr cur) {
1638 if (cur == NULL) {
1639#ifdef DEBUG_TREE
1640 xmlGenericError(xmlGenericErrorContext,
1641 "xmlFreeProp : property == NULL\n");
1642#endif
1643 return;
1644 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001645
1646 if (xmlDeregisterNodeDefaultValue)
1647 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1648
Owen Taylor3473f882001-02-23 17:55:21 +00001649 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001650 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1651 ((cur->parent->doc->intSubset != NULL) ||
1652 (cur->parent->doc->extSubset != NULL))) {
1653 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1654 xmlRemoveID(cur->parent->doc, cur);
1655 }
Owen Taylor3473f882001-02-23 17:55:21 +00001656 if (cur->name != NULL) xmlFree((char *) cur->name);
1657 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001658 xmlFree(cur);
1659}
1660
1661/**
1662 * xmlRemoveProp:
1663 * @cur: an attribute
1664 *
1665 * Unlink and free one attribute, all the content is freed too
1666 * Note this doesn't work for namespace definition attributes
1667 *
1668 * Returns 0 if success and -1 in case of error.
1669 */
1670int
1671xmlRemoveProp(xmlAttrPtr cur) {
1672 xmlAttrPtr tmp;
1673 if (cur == NULL) {
1674#ifdef DEBUG_TREE
1675 xmlGenericError(xmlGenericErrorContext,
1676 "xmlRemoveProp : cur == NULL\n");
1677#endif
1678 return(-1);
1679 }
1680 if (cur->parent == NULL) {
1681#ifdef DEBUG_TREE
1682 xmlGenericError(xmlGenericErrorContext,
1683 "xmlRemoveProp : cur->parent == NULL\n");
1684#endif
1685 return(-1);
1686 }
1687 tmp = cur->parent->properties;
1688 if (tmp == cur) {
1689 cur->parent->properties = cur->next;
1690 xmlFreeProp(cur);
1691 return(0);
1692 }
1693 while (tmp != NULL) {
1694 if (tmp->next == cur) {
1695 tmp->next = cur->next;
1696 if (tmp->next != NULL)
1697 tmp->next->prev = tmp;
1698 xmlFreeProp(cur);
1699 return(0);
1700 }
1701 tmp = tmp->next;
1702 }
1703#ifdef DEBUG_TREE
1704 xmlGenericError(xmlGenericErrorContext,
1705 "xmlRemoveProp : attribute not owned by its node\n");
1706#endif
1707 return(-1);
1708}
1709
1710/**
1711 * xmlNewPI:
1712 * @name: the processing instruction name
1713 * @content: the PI content
1714 *
1715 * Creation of a processing instruction element.
1716 * Returns a pointer to the new node object.
1717 */
1718xmlNodePtr
1719xmlNewPI(const xmlChar *name, const xmlChar *content) {
1720 xmlNodePtr cur;
1721
1722 if (name == NULL) {
1723#ifdef DEBUG_TREE
1724 xmlGenericError(xmlGenericErrorContext,
1725 "xmlNewPI : name == NULL\n");
1726#endif
1727 return(NULL);
1728 }
1729
1730 /*
1731 * Allocate a new node and fill the fields.
1732 */
1733 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1734 if (cur == NULL) {
1735 xmlGenericError(xmlGenericErrorContext,
1736 "xmlNewPI : malloc failed\n");
1737 return(NULL);
1738 }
1739 memset(cur, 0, sizeof(xmlNode));
1740 cur->type = XML_PI_NODE;
1741
1742 cur->name = xmlStrdup(name);
1743 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001744 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001745 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001746
1747 if (xmlRegisterNodeDefaultValue)
1748 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001749 return(cur);
1750}
1751
1752/**
1753 * xmlNewNode:
1754 * @ns: namespace if any
1755 * @name: the node name
1756 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001757 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001758 *
1759 * Returns a pointer to the new node object.
1760 */
1761xmlNodePtr
1762xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1763 xmlNodePtr cur;
1764
1765 if (name == NULL) {
1766#ifdef DEBUG_TREE
1767 xmlGenericError(xmlGenericErrorContext,
1768 "xmlNewNode : name == NULL\n");
1769#endif
1770 return(NULL);
1771 }
1772
1773 /*
1774 * Allocate a new node and fill the fields.
1775 */
1776 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1777 if (cur == NULL) {
1778 xmlGenericError(xmlGenericErrorContext,
1779 "xmlNewNode : malloc failed\n");
1780 return(NULL);
1781 }
1782 memset(cur, 0, sizeof(xmlNode));
1783 cur->type = XML_ELEMENT_NODE;
1784
1785 cur->name = xmlStrdup(name);
1786 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001787
1788 if (xmlRegisterNodeDefaultValue)
1789 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001790 return(cur);
1791}
1792
1793/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001794 * xmlNewNodeEatName:
1795 * @ns: namespace if any
1796 * @name: the node name
1797 *
1798 * Creation of a new node element. @ns is optional (NULL).
1799 *
1800 * Returns a pointer to the new node object.
1801 */
1802xmlNodePtr
1803xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
1804 xmlNodePtr cur;
1805
1806 if (name == NULL) {
1807#ifdef DEBUG_TREE
1808 xmlGenericError(xmlGenericErrorContext,
1809 "xmlNewNode : name == NULL\n");
1810#endif
1811 return(NULL);
1812 }
1813
1814 /*
1815 * Allocate a new node and fill the fields.
1816 */
1817 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1818 if (cur == NULL) {
1819 xmlGenericError(xmlGenericErrorContext,
1820 "xmlNewNode : malloc failed\n");
1821 return(NULL);
1822 }
1823 memset(cur, 0, sizeof(xmlNode));
1824 cur->type = XML_ELEMENT_NODE;
1825
1826 cur->name = name;
1827 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001828
1829 if (xmlRegisterNodeDefaultValue)
1830 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001831 return(cur);
1832}
1833
1834/**
Owen Taylor3473f882001-02-23 17:55:21 +00001835 * xmlNewDocNode:
1836 * @doc: the document
1837 * @ns: namespace if any
1838 * @name: the node name
1839 * @content: the XML text content if any
1840 *
1841 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001842 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001843 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1844 * references, but XML special chars need to be escaped first by using
1845 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1846 * need entities support.
1847 *
1848 * Returns a pointer to the new node object.
1849 */
1850xmlNodePtr
1851xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1852 const xmlChar *name, const xmlChar *content) {
1853 xmlNodePtr cur;
1854
1855 cur = xmlNewNode(ns, name);
1856 if (cur != NULL) {
1857 cur->doc = doc;
1858 if (content != NULL) {
1859 cur->children = xmlStringGetNodeList(doc, content);
1860 UPDATE_LAST_CHILD_AND_PARENT(cur)
1861 }
1862 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001863
Owen Taylor3473f882001-02-23 17:55:21 +00001864 return(cur);
1865}
1866
Daniel Veillard46de64e2002-05-29 08:21:33 +00001867/**
1868 * xmlNewDocNodeEatName:
1869 * @doc: the document
1870 * @ns: namespace if any
1871 * @name: the node name
1872 * @content: the XML text content if any
1873 *
1874 * Creation of a new node element within a document. @ns and @content
1875 * are optional (NULL).
1876 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1877 * references, but XML special chars need to be escaped first by using
1878 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1879 * need entities support.
1880 *
1881 * Returns a pointer to the new node object.
1882 */
1883xmlNodePtr
1884xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
1885 xmlChar *name, const xmlChar *content) {
1886 xmlNodePtr cur;
1887
1888 cur = xmlNewNodeEatName(ns, name);
1889 if (cur != NULL) {
1890 cur->doc = doc;
1891 if (content != NULL) {
1892 cur->children = xmlStringGetNodeList(doc, content);
1893 UPDATE_LAST_CHILD_AND_PARENT(cur)
1894 }
1895 }
1896 return(cur);
1897}
1898
Owen Taylor3473f882001-02-23 17:55:21 +00001899
1900/**
1901 * xmlNewDocRawNode:
1902 * @doc: the document
1903 * @ns: namespace if any
1904 * @name: the node name
1905 * @content: the text content if any
1906 *
1907 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001908 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001909 *
1910 * Returns a pointer to the new node object.
1911 */
1912xmlNodePtr
1913xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1914 const xmlChar *name, const xmlChar *content) {
1915 xmlNodePtr cur;
1916
1917 cur = xmlNewNode(ns, name);
1918 if (cur != NULL) {
1919 cur->doc = doc;
1920 if (content != NULL) {
1921 cur->children = xmlNewDocText(doc, content);
1922 UPDATE_LAST_CHILD_AND_PARENT(cur)
1923 }
1924 }
1925 return(cur);
1926}
1927
1928/**
1929 * xmlNewDocFragment:
1930 * @doc: the document owning the fragment
1931 *
1932 * Creation of a new Fragment node.
1933 * Returns a pointer to the new node object.
1934 */
1935xmlNodePtr
1936xmlNewDocFragment(xmlDocPtr doc) {
1937 xmlNodePtr cur;
1938
1939 /*
1940 * Allocate a new DocumentFragment node and fill the fields.
1941 */
1942 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1943 if (cur == NULL) {
1944 xmlGenericError(xmlGenericErrorContext,
1945 "xmlNewDocFragment : malloc failed\n");
1946 return(NULL);
1947 }
1948 memset(cur, 0, sizeof(xmlNode));
1949 cur->type = XML_DOCUMENT_FRAG_NODE;
1950
1951 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001952
1953 if (xmlRegisterNodeDefaultValue)
1954 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001955 return(cur);
1956}
1957
1958/**
1959 * xmlNewText:
1960 * @content: the text content
1961 *
1962 * Creation of a new text node.
1963 * Returns a pointer to the new node object.
1964 */
1965xmlNodePtr
1966xmlNewText(const xmlChar *content) {
1967 xmlNodePtr cur;
1968
1969 /*
1970 * Allocate a new node and fill the fields.
1971 */
1972 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1973 if (cur == NULL) {
1974 xmlGenericError(xmlGenericErrorContext,
1975 "xmlNewText : malloc failed\n");
1976 return(NULL);
1977 }
1978 memset(cur, 0, sizeof(xmlNode));
1979 cur->type = XML_TEXT_NODE;
1980
1981 cur->name = xmlStringText;
1982 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001983 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001984 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001985
1986 if (xmlRegisterNodeDefaultValue)
1987 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001988 return(cur);
1989}
1990
1991/**
1992 * xmlNewTextChild:
1993 * @parent: the parent node
1994 * @ns: a namespace if any
1995 * @name: the name of the child
1996 * @content: the text content of the child if any.
1997 *
1998 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001999 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002000 * a child TEXT node will be created containing the string content.
2001 *
2002 * Returns a pointer to the new node object.
2003 */
2004xmlNodePtr
2005xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2006 const xmlChar *name, const xmlChar *content) {
2007 xmlNodePtr cur, prev;
2008
2009 if (parent == NULL) {
2010#ifdef DEBUG_TREE
2011 xmlGenericError(xmlGenericErrorContext,
2012 "xmlNewTextChild : parent == NULL\n");
2013#endif
2014 return(NULL);
2015 }
2016
2017 if (name == NULL) {
2018#ifdef DEBUG_TREE
2019 xmlGenericError(xmlGenericErrorContext,
2020 "xmlNewTextChild : name == NULL\n");
2021#endif
2022 return(NULL);
2023 }
2024
2025 /*
2026 * Allocate a new node
2027 */
2028 if (ns == NULL)
2029 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2030 else
2031 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2032 if (cur == NULL) return(NULL);
2033
2034 /*
2035 * add the new element at the end of the children list.
2036 */
2037 cur->type = XML_ELEMENT_NODE;
2038 cur->parent = parent;
2039 cur->doc = parent->doc;
2040 if (parent->children == NULL) {
2041 parent->children = cur;
2042 parent->last = cur;
2043 } else {
2044 prev = parent->last;
2045 prev->next = cur;
2046 cur->prev = prev;
2047 parent->last = cur;
2048 }
2049
2050 return(cur);
2051}
2052
2053/**
2054 * xmlNewCharRef:
2055 * @doc: the document
2056 * @name: the char ref string, starting with # or "&# ... ;"
2057 *
2058 * Creation of a new character reference node.
2059 * Returns a pointer to the new node object.
2060 */
2061xmlNodePtr
2062xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2063 xmlNodePtr cur;
2064
2065 /*
2066 * Allocate a new node and fill the fields.
2067 */
2068 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2069 if (cur == NULL) {
2070 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002071 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002072 return(NULL);
2073 }
2074 memset(cur, 0, sizeof(xmlNode));
2075 cur->type = XML_ENTITY_REF_NODE;
2076
2077 cur->doc = doc;
2078 if (name[0] == '&') {
2079 int len;
2080 name++;
2081 len = xmlStrlen(name);
2082 if (name[len - 1] == ';')
2083 cur->name = xmlStrndup(name, len - 1);
2084 else
2085 cur->name = xmlStrndup(name, len);
2086 } else
2087 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002088
2089 if (xmlRegisterNodeDefaultValue)
2090 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002091 return(cur);
2092}
2093
2094/**
2095 * xmlNewReference:
2096 * @doc: the document
2097 * @name: the reference name, or the reference string with & and ;
2098 *
2099 * Creation of a new reference node.
2100 * Returns a pointer to the new node object.
2101 */
2102xmlNodePtr
2103xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2104 xmlNodePtr cur;
2105 xmlEntityPtr ent;
2106
2107 /*
2108 * Allocate a new node and fill the fields.
2109 */
2110 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2111 if (cur == NULL) {
2112 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002113 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002114 return(NULL);
2115 }
2116 memset(cur, 0, sizeof(xmlNode));
2117 cur->type = XML_ENTITY_REF_NODE;
2118
2119 cur->doc = doc;
2120 if (name[0] == '&') {
2121 int len;
2122 name++;
2123 len = xmlStrlen(name);
2124 if (name[len - 1] == ';')
2125 cur->name = xmlStrndup(name, len - 1);
2126 else
2127 cur->name = xmlStrndup(name, len);
2128 } else
2129 cur->name = xmlStrdup(name);
2130
2131 ent = xmlGetDocEntity(doc, cur->name);
2132 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002133 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002134 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002135 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002136 * updated. Not sure if this is 100% correct.
2137 * -George
2138 */
2139 cur->children = (xmlNodePtr) ent;
2140 cur->last = (xmlNodePtr) ent;
2141 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002142
2143 if (xmlRegisterNodeDefaultValue)
2144 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002145 return(cur);
2146}
2147
2148/**
2149 * xmlNewDocText:
2150 * @doc: the document
2151 * @content: the text content
2152 *
2153 * Creation of a new text node within a document.
2154 * Returns a pointer to the new node object.
2155 */
2156xmlNodePtr
2157xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2158 xmlNodePtr cur;
2159
2160 cur = xmlNewText(content);
2161 if (cur != NULL) cur->doc = doc;
2162 return(cur);
2163}
2164
2165/**
2166 * xmlNewTextLen:
2167 * @content: the text content
2168 * @len: the text len.
2169 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002170 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002171 * Returns a pointer to the new node object.
2172 */
2173xmlNodePtr
2174xmlNewTextLen(const xmlChar *content, int len) {
2175 xmlNodePtr cur;
2176
2177 /*
2178 * Allocate a new node and fill the fields.
2179 */
2180 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2181 if (cur == NULL) {
2182 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002183 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002184 return(NULL);
2185 }
2186 memset(cur, 0, sizeof(xmlNode));
2187 cur->type = XML_TEXT_NODE;
2188
2189 cur->name = xmlStringText;
2190 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002191 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002192 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002193
2194 if (xmlRegisterNodeDefaultValue)
2195 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002196 return(cur);
2197}
2198
2199/**
2200 * xmlNewDocTextLen:
2201 * @doc: the document
2202 * @content: the text content
2203 * @len: the text len.
2204 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002205 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002206 * text node pertain to a given document.
2207 * Returns a pointer to the new node object.
2208 */
2209xmlNodePtr
2210xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2211 xmlNodePtr cur;
2212
2213 cur = xmlNewTextLen(content, len);
2214 if (cur != NULL) cur->doc = doc;
2215 return(cur);
2216}
2217
2218/**
2219 * xmlNewComment:
2220 * @content: the comment content
2221 *
2222 * Creation of a new node containing a comment.
2223 * Returns a pointer to the new node object.
2224 */
2225xmlNodePtr
2226xmlNewComment(const xmlChar *content) {
2227 xmlNodePtr cur;
2228
2229 /*
2230 * Allocate a new node and fill the fields.
2231 */
2232 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2233 if (cur == NULL) {
2234 xmlGenericError(xmlGenericErrorContext,
2235 "xmlNewComment : malloc failed\n");
2236 return(NULL);
2237 }
2238 memset(cur, 0, sizeof(xmlNode));
2239 cur->type = XML_COMMENT_NODE;
2240
2241 cur->name = xmlStringComment;
2242 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002243 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002244 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002245
2246 if (xmlRegisterNodeDefaultValue)
2247 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002248 return(cur);
2249}
2250
2251/**
2252 * xmlNewCDataBlock:
2253 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002254 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002255 * @len: the length of the block
2256 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002257 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002258 * Returns a pointer to the new node object.
2259 */
2260xmlNodePtr
2261xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2262 xmlNodePtr cur;
2263
2264 /*
2265 * Allocate a new node and fill the fields.
2266 */
2267 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2268 if (cur == NULL) {
2269 xmlGenericError(xmlGenericErrorContext,
2270 "xmlNewCDataBlock : malloc failed\n");
2271 return(NULL);
2272 }
2273 memset(cur, 0, sizeof(xmlNode));
2274 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002275 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002276
2277 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002278 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002279 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002280
2281 if (xmlRegisterNodeDefaultValue)
2282 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002283 return(cur);
2284}
2285
2286/**
2287 * xmlNewDocComment:
2288 * @doc: the document
2289 * @content: the comment content
2290 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002291 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002292 * Returns a pointer to the new node object.
2293 */
2294xmlNodePtr
2295xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2296 xmlNodePtr cur;
2297
2298 cur = xmlNewComment(content);
2299 if (cur != NULL) cur->doc = doc;
2300 return(cur);
2301}
2302
2303/**
2304 * xmlSetTreeDoc:
2305 * @tree: the top element
2306 * @doc: the document
2307 *
2308 * update all nodes under the tree to point to the right document
2309 */
2310void
2311xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002312 xmlAttrPtr prop;
2313
Owen Taylor3473f882001-02-23 17:55:21 +00002314 if (tree == NULL)
2315 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002316 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002317 if(tree->type == XML_ELEMENT_NODE) {
2318 prop = tree->properties;
2319 while (prop != NULL) {
2320 prop->doc = doc;
2321 xmlSetListDoc(prop->children, doc);
2322 prop = prop->next;
2323 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002324 }
Owen Taylor3473f882001-02-23 17:55:21 +00002325 if (tree->children != NULL)
2326 xmlSetListDoc(tree->children, doc);
2327 tree->doc = doc;
2328 }
2329}
2330
2331/**
2332 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002333 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002334 * @doc: the document
2335 *
2336 * update all nodes in the list to point to the right document
2337 */
2338void
2339xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2340 xmlNodePtr cur;
2341
2342 if (list == NULL)
2343 return;
2344 cur = list;
2345 while (cur != NULL) {
2346 if (cur->doc != doc)
2347 xmlSetTreeDoc(cur, doc);
2348 cur = cur->next;
2349 }
2350}
2351
2352
2353/**
2354 * xmlNewChild:
2355 * @parent: the parent node
2356 * @ns: a namespace if any
2357 * @name: the name of the child
2358 * @content: the XML content of the child if any.
2359 *
2360 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002361 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002362 * a child list containing the TEXTs and ENTITY_REFs node will be created.
2363 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2364 * references, but XML special chars need to be escaped first by using
2365 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
2366 * support is not needed.
2367 *
2368 * Returns a pointer to the new node object.
2369 */
2370xmlNodePtr
2371xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2372 const xmlChar *name, const xmlChar *content) {
2373 xmlNodePtr cur, prev;
2374
2375 if (parent == NULL) {
2376#ifdef DEBUG_TREE
2377 xmlGenericError(xmlGenericErrorContext,
2378 "xmlNewChild : parent == NULL\n");
2379#endif
2380 return(NULL);
2381 }
2382
2383 if (name == NULL) {
2384#ifdef DEBUG_TREE
2385 xmlGenericError(xmlGenericErrorContext,
2386 "xmlNewChild : name == NULL\n");
2387#endif
2388 return(NULL);
2389 }
2390
2391 /*
2392 * Allocate a new node
2393 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002394 if (parent->type == XML_ELEMENT_NODE) {
2395 if (ns == NULL)
2396 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2397 else
2398 cur = xmlNewDocNode(parent->doc, ns, name, content);
2399 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2400 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2401 if (ns == NULL)
2402 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2403 else
2404 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002405 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2406 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002407 } else {
2408 return(NULL);
2409 }
Owen Taylor3473f882001-02-23 17:55:21 +00002410 if (cur == NULL) return(NULL);
2411
2412 /*
2413 * add the new element at the end of the children list.
2414 */
2415 cur->type = XML_ELEMENT_NODE;
2416 cur->parent = parent;
2417 cur->doc = parent->doc;
2418 if (parent->children == NULL) {
2419 parent->children = cur;
2420 parent->last = cur;
2421 } else {
2422 prev = parent->last;
2423 prev->next = cur;
2424 cur->prev = prev;
2425 parent->last = cur;
2426 }
2427
2428 return(cur);
2429}
2430
2431/**
2432 * xmlAddNextSibling:
2433 * @cur: the child node
2434 * @elem: the new node
2435 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002436 * Add a new node @elem as the next sibling of @cur
2437 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002438 * first unlinked from its existing context.
2439 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002440 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2441 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002442 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002443 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002444 */
2445xmlNodePtr
2446xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2447 if (cur == NULL) {
2448#ifdef DEBUG_TREE
2449 xmlGenericError(xmlGenericErrorContext,
2450 "xmlAddNextSibling : cur == NULL\n");
2451#endif
2452 return(NULL);
2453 }
2454 if (elem == NULL) {
2455#ifdef DEBUG_TREE
2456 xmlGenericError(xmlGenericErrorContext,
2457 "xmlAddNextSibling : elem == NULL\n");
2458#endif
2459 return(NULL);
2460 }
2461
2462 xmlUnlinkNode(elem);
2463
2464 if (elem->type == XML_TEXT_NODE) {
2465 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002466 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002467 xmlFreeNode(elem);
2468 return(cur);
2469 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002470 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2471 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002472 xmlChar *tmp;
2473
2474 tmp = xmlStrdup(elem->content);
2475 tmp = xmlStrcat(tmp, cur->next->content);
2476 xmlNodeSetContent(cur->next, tmp);
2477 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002478 xmlFreeNode(elem);
2479 return(cur->next);
2480 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002481 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2482 /* check if an attribute with the same name exists */
2483 xmlAttrPtr attr;
2484
2485 if (elem->ns == NULL)
2486 attr = xmlHasProp(cur->parent, elem->name);
2487 else
2488 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2489 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2490 /* different instance, destroy it (attributes must be unique) */
2491 xmlFreeProp(attr);
2492 }
Owen Taylor3473f882001-02-23 17:55:21 +00002493 }
2494
2495 if (elem->doc != cur->doc) {
2496 xmlSetTreeDoc(elem, cur->doc);
2497 }
2498 elem->parent = cur->parent;
2499 elem->prev = cur;
2500 elem->next = cur->next;
2501 cur->next = elem;
2502 if (elem->next != NULL)
2503 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002504 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002505 elem->parent->last = elem;
2506 return(elem);
2507}
2508
2509/**
2510 * xmlAddPrevSibling:
2511 * @cur: the child node
2512 * @elem: the new node
2513 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002514 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002515 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002516 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002517 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002518 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2519 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002520 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002521 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002522 */
2523xmlNodePtr
2524xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2525 if (cur == NULL) {
2526#ifdef DEBUG_TREE
2527 xmlGenericError(xmlGenericErrorContext,
2528 "xmlAddPrevSibling : cur == NULL\n");
2529#endif
2530 return(NULL);
2531 }
2532 if (elem == NULL) {
2533#ifdef DEBUG_TREE
2534 xmlGenericError(xmlGenericErrorContext,
2535 "xmlAddPrevSibling : elem == NULL\n");
2536#endif
2537 return(NULL);
2538 }
2539
2540 xmlUnlinkNode(elem);
2541
2542 if (elem->type == XML_TEXT_NODE) {
2543 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002544 xmlChar *tmp;
2545
2546 tmp = xmlStrdup(elem->content);
2547 tmp = xmlStrcat(tmp, cur->content);
2548 xmlNodeSetContent(cur, tmp);
2549 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002550 xmlFreeNode(elem);
2551 return(cur);
2552 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002553 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2554 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002555 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002556 xmlFreeNode(elem);
2557 return(cur->prev);
2558 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002559 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2560 /* check if an attribute with the same name exists */
2561 xmlAttrPtr attr;
2562
2563 if (elem->ns == NULL)
2564 attr = xmlHasProp(cur->parent, elem->name);
2565 else
2566 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2567 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2568 /* different instance, destroy it (attributes must be unique) */
2569 xmlFreeProp(attr);
2570 }
Owen Taylor3473f882001-02-23 17:55:21 +00002571 }
2572
2573 if (elem->doc != cur->doc) {
2574 xmlSetTreeDoc(elem, cur->doc);
2575 }
2576 elem->parent = cur->parent;
2577 elem->next = cur;
2578 elem->prev = cur->prev;
2579 cur->prev = elem;
2580 if (elem->prev != NULL)
2581 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002582 if (elem->parent != NULL) {
2583 if (elem->type == XML_ATTRIBUTE_NODE) {
2584 if (elem->parent->properties == (xmlAttrPtr) cur) {
2585 elem->parent->properties = (xmlAttrPtr) elem;
2586 }
2587 } else {
2588 if (elem->parent->children == cur) {
2589 elem->parent->children = elem;
2590 }
2591 }
2592 }
Owen Taylor3473f882001-02-23 17:55:21 +00002593 return(elem);
2594}
2595
2596/**
2597 * xmlAddSibling:
2598 * @cur: the child node
2599 * @elem: the new node
2600 *
2601 * Add a new element @elem to the list of siblings of @cur
2602 * merging adjacent TEXT nodes (@elem may be freed)
2603 * If the new element was already inserted in a document it is
2604 * first unlinked from its existing context.
2605 *
2606 * Returns the new element or NULL in case of error.
2607 */
2608xmlNodePtr
2609xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2610 xmlNodePtr parent;
2611
2612 if (cur == NULL) {
2613#ifdef DEBUG_TREE
2614 xmlGenericError(xmlGenericErrorContext,
2615 "xmlAddSibling : cur == NULL\n");
2616#endif
2617 return(NULL);
2618 }
2619
2620 if (elem == NULL) {
2621#ifdef DEBUG_TREE
2622 xmlGenericError(xmlGenericErrorContext,
2623 "xmlAddSibling : elem == NULL\n");
2624#endif
2625 return(NULL);
2626 }
2627
2628 /*
2629 * Constant time is we can rely on the ->parent->last to find
2630 * the last sibling.
2631 */
2632 if ((cur->parent != NULL) &&
2633 (cur->parent->children != NULL) &&
2634 (cur->parent->last != NULL) &&
2635 (cur->parent->last->next == NULL)) {
2636 cur = cur->parent->last;
2637 } else {
2638 while (cur->next != NULL) cur = cur->next;
2639 }
2640
2641 xmlUnlinkNode(elem);
2642
2643 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002644 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002645 xmlFreeNode(elem);
2646 return(cur);
2647 }
2648
2649 if (elem->doc != cur->doc) {
2650 xmlSetTreeDoc(elem, cur->doc);
2651 }
2652 parent = cur->parent;
2653 elem->prev = cur;
2654 elem->next = NULL;
2655 elem->parent = parent;
2656 cur->next = elem;
2657 if (parent != NULL)
2658 parent->last = elem;
2659
2660 return(elem);
2661}
2662
2663/**
2664 * xmlAddChildList:
2665 * @parent: the parent node
2666 * @cur: the first node in the list
2667 *
2668 * Add a list of node at the end of the child list of the parent
2669 * merging adjacent TEXT nodes (@cur may be freed)
2670 *
2671 * Returns the last child or NULL in case of error.
2672 */
2673xmlNodePtr
2674xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2675 xmlNodePtr prev;
2676
2677 if (parent == NULL) {
2678#ifdef DEBUG_TREE
2679 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002680 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002681#endif
2682 return(NULL);
2683 }
2684
2685 if (cur == NULL) {
2686#ifdef DEBUG_TREE
2687 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002688 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002689#endif
2690 return(NULL);
2691 }
2692
2693 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2694 (cur->doc != parent->doc)) {
2695#ifdef DEBUG_TREE
2696 xmlGenericError(xmlGenericErrorContext,
2697 "Elements moved to a different document\n");
2698#endif
2699 }
2700
2701 /*
2702 * add the first element at the end of the children list.
2703 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00002704
Owen Taylor3473f882001-02-23 17:55:21 +00002705 if (parent->children == NULL) {
2706 parent->children = cur;
2707 } else {
2708 /*
2709 * If cur and parent->last both are TEXT nodes, then merge them.
2710 */
2711 if ((cur->type == XML_TEXT_NODE) &&
2712 (parent->last->type == XML_TEXT_NODE) &&
2713 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00002714 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002715 /*
2716 * if it's the only child, nothing more to be done.
2717 */
2718 if (cur->next == NULL) {
2719 xmlFreeNode(cur);
2720 return(parent->last);
2721 }
2722 prev = cur;
2723 cur = cur->next;
2724 xmlFreeNode(prev);
2725 }
2726 prev = parent->last;
2727 prev->next = cur;
2728 cur->prev = prev;
2729 }
2730 while (cur->next != NULL) {
2731 cur->parent = parent;
2732 if (cur->doc != parent->doc) {
2733 xmlSetTreeDoc(cur, parent->doc);
2734 }
2735 cur = cur->next;
2736 }
2737 cur->parent = parent;
2738 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2739 parent->last = cur;
2740
2741 return(cur);
2742}
2743
2744/**
2745 * xmlAddChild:
2746 * @parent: the parent node
2747 * @cur: the child node
2748 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002749 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00002750 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002751 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2752 * If there is an attribute with equal name, it is first destroyed.
2753 *
Owen Taylor3473f882001-02-23 17:55:21 +00002754 * Returns the child or NULL in case of error.
2755 */
2756xmlNodePtr
2757xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2758 xmlNodePtr prev;
2759
2760 if (parent == NULL) {
2761#ifdef DEBUG_TREE
2762 xmlGenericError(xmlGenericErrorContext,
2763 "xmlAddChild : parent == NULL\n");
2764#endif
2765 return(NULL);
2766 }
2767
2768 if (cur == NULL) {
2769#ifdef DEBUG_TREE
2770 xmlGenericError(xmlGenericErrorContext,
2771 "xmlAddChild : child == NULL\n");
2772#endif
2773 return(NULL);
2774 }
2775
Owen Taylor3473f882001-02-23 17:55:21 +00002776 /*
2777 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002778 * cur is then freed.
2779 */
2780 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002781 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002782 (parent->content != NULL) &&
2783 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002784 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002785 xmlFreeNode(cur);
2786 return(parent);
2787 }
2788 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002789 (parent->last->name == cur->name) &&
2790 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002791 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002792 xmlFreeNode(cur);
2793 return(parent->last);
2794 }
2795 }
2796
2797 /*
2798 * add the new element at the end of the children list.
2799 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00002800 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00002801 cur->parent = parent;
2802 if (cur->doc != parent->doc) {
2803 xmlSetTreeDoc(cur, parent->doc);
2804 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002805 /* this check prevents a loop on tree-traversions if a developer
2806 * tries to add a node to its parent multiple times
2807 */
2808 if (prev == parent)
2809 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002810
2811 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002812 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002813 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002814 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002815 (parent->content != NULL) &&
2816 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002817 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002818 xmlFreeNode(cur);
2819 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002820 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002821 if (cur->type == XML_ATTRIBUTE_NODE) {
2822 if (parent->properties == NULL) {
2823 parent->properties = (xmlAttrPtr) cur;
2824 } else {
2825 /* check if an attribute with the same name exists */
2826 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00002827
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002828 if (cur->ns == NULL)
2829 lastattr = xmlHasProp(parent, cur->name);
2830 else
2831 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
2832 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
2833 /* different instance, destroy it (attributes must be unique) */
2834 xmlFreeProp(lastattr);
2835 }
2836 /* find the end */
2837 lastattr = parent->properties;
2838 while (lastattr->next != NULL) {
2839 lastattr = lastattr->next;
2840 }
2841 lastattr->next = (xmlAttrPtr) cur;
2842 ((xmlAttrPtr) cur)->prev = lastattr;
2843 }
2844 } else {
2845 if (parent->children == NULL) {
2846 parent->children = cur;
2847 parent->last = cur;
2848 } else {
2849 prev = parent->last;
2850 prev->next = cur;
2851 cur->prev = prev;
2852 parent->last = cur;
2853 }
2854 }
Owen Taylor3473f882001-02-23 17:55:21 +00002855 return(cur);
2856}
2857
2858/**
2859 * xmlGetLastChild:
2860 * @parent: the parent node
2861 *
2862 * Search the last child of a node.
2863 * Returns the last child or NULL if none.
2864 */
2865xmlNodePtr
2866xmlGetLastChild(xmlNodePtr parent) {
2867 if (parent == NULL) {
2868#ifdef DEBUG_TREE
2869 xmlGenericError(xmlGenericErrorContext,
2870 "xmlGetLastChild : parent == NULL\n");
2871#endif
2872 return(NULL);
2873 }
2874 return(parent->last);
2875}
2876
2877/**
2878 * xmlFreeNodeList:
2879 * @cur: the first node in the list
2880 *
2881 * Free a node and all its siblings, this is a recursive behaviour, all
2882 * the children are freed too.
2883 */
2884void
2885xmlFreeNodeList(xmlNodePtr cur) {
2886 xmlNodePtr next;
2887 if (cur == NULL) {
2888#ifdef DEBUG_TREE
2889 xmlGenericError(xmlGenericErrorContext,
2890 "xmlFreeNodeList : node == NULL\n");
2891#endif
2892 return;
2893 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00002894 if (cur->type == XML_NAMESPACE_DECL) {
2895 xmlFreeNsList((xmlNsPtr) cur);
2896 return;
2897 }
Owen Taylor3473f882001-02-23 17:55:21 +00002898 while (cur != NULL) {
2899 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002900 /* unroll to speed up freeing the document */
2901 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00002902
2903 if (xmlDeregisterNodeDefaultValue)
2904 xmlDeregisterNodeDefaultValue(cur);
2905
Daniel Veillard02141ea2001-04-30 11:46:40 +00002906 if ((cur->children != NULL) &&
2907 (cur->type != XML_ENTITY_REF_NODE))
2908 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00002909 if (((cur->type == XML_ELEMENT_NODE) ||
2910 (cur->type == XML_XINCLUDE_START) ||
2911 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002912 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00002913 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002914 if ((cur->type != XML_ELEMENT_NODE) &&
2915 (cur->type != XML_XINCLUDE_START) &&
2916 (cur->type != XML_XINCLUDE_END) &&
2917 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002918 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002919 }
2920 if (((cur->type == XML_ELEMENT_NODE) ||
2921 (cur->type == XML_XINCLUDE_START) ||
2922 (cur->type == XML_XINCLUDE_END)) &&
2923 (cur->nsDef != NULL))
2924 xmlFreeNsList(cur->nsDef);
2925
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002926 /*
2927 * When a node is a text node or a comment, it uses a global static
2928 * variable for the name of the node.
2929 *
2930 * The xmlStrEqual comparisons need to be done when (happened with
2931 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002932 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00002933 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002934 * the string addresses compare are not sufficient.
2935 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002936 if ((cur->name != NULL) &&
2937 (cur->name != xmlStringText) &&
2938 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002939 (cur->name != xmlStringComment)) {
2940 if (cur->type == XML_TEXT_NODE) {
2941 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2942 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2943 xmlFree((char *) cur->name);
2944 } else if (cur->type == XML_COMMENT_NODE) {
2945 if (!xmlStrEqual(cur->name, xmlStringComment))
2946 xmlFree((char *) cur->name);
2947 } else
2948 xmlFree((char *) cur->name);
2949 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002950 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002951 xmlFree(cur);
2952 }
Owen Taylor3473f882001-02-23 17:55:21 +00002953 cur = next;
2954 }
2955}
2956
2957/**
2958 * xmlFreeNode:
2959 * @cur: the node
2960 *
2961 * Free a node, this is a recursive behaviour, all the children are freed too.
2962 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2963 */
2964void
2965xmlFreeNode(xmlNodePtr cur) {
2966 if (cur == NULL) {
2967#ifdef DEBUG_TREE
2968 xmlGenericError(xmlGenericErrorContext,
2969 "xmlFreeNode : node == NULL\n");
2970#endif
2971 return;
2972 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002973
Daniel Veillard02141ea2001-04-30 11:46:40 +00002974 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00002975 if (cur->type == XML_DTD_NODE) {
2976 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002977 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00002978 }
2979 if (cur->type == XML_NAMESPACE_DECL) {
2980 xmlFreeNs((xmlNsPtr) cur);
2981 return;
2982 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00002983 if (cur->type == XML_ATTRIBUTE_NODE) {
2984 xmlFreeProp((xmlAttrPtr) cur);
2985 return;
2986 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002987
2988 if (xmlDeregisterNodeDefaultValue)
2989 xmlDeregisterNodeDefaultValue(cur);
2990
Owen Taylor3473f882001-02-23 17:55:21 +00002991 if ((cur->children != NULL) &&
2992 (cur->type != XML_ENTITY_REF_NODE))
2993 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00002994 if (((cur->type == XML_ELEMENT_NODE) ||
2995 (cur->type == XML_XINCLUDE_START) ||
2996 (cur->type == XML_XINCLUDE_END)) &&
2997 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00002998 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002999 if ((cur->type != XML_ELEMENT_NODE) &&
3000 (cur->content != NULL) &&
3001 (cur->type != XML_ENTITY_REF_NODE) &&
3002 (cur->type != XML_XINCLUDE_END) &&
3003 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003004 xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003005 }
3006
Daniel Veillardacd370f2001-06-09 17:17:51 +00003007 /*
3008 * When a node is a text node or a comment, it uses a global static
3009 * variable for the name of the node.
3010 *
3011 * The xmlStrEqual comparisons need to be done when (happened with
3012 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003013 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00003014 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00003015 * are not sufficient.
3016 */
Owen Taylor3473f882001-02-23 17:55:21 +00003017 if ((cur->name != NULL) &&
3018 (cur->name != xmlStringText) &&
3019 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00003020 (cur->name != xmlStringComment)) {
3021 if (cur->type == XML_TEXT_NODE) {
3022 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
3023 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
3024 xmlFree((char *) cur->name);
3025 } else if (cur->type == XML_COMMENT_NODE) {
3026 if (!xmlStrEqual(cur->name, xmlStringComment))
3027 xmlFree((char *) cur->name);
3028 } else
3029 xmlFree((char *) cur->name);
3030 }
3031
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003032 if (((cur->type == XML_ELEMENT_NODE) ||
3033 (cur->type == XML_XINCLUDE_START) ||
3034 (cur->type == XML_XINCLUDE_END)) &&
3035 (cur->nsDef != NULL))
3036 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003037 xmlFree(cur);
3038}
3039
3040/**
3041 * xmlUnlinkNode:
3042 * @cur: the node
3043 *
3044 * Unlink a node from it's current context, the node is not freed
3045 */
3046void
3047xmlUnlinkNode(xmlNodePtr cur) {
3048 if (cur == NULL) {
3049#ifdef DEBUG_TREE
3050 xmlGenericError(xmlGenericErrorContext,
3051 "xmlUnlinkNode : node == NULL\n");
3052#endif
3053 return;
3054 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003055 if (cur->type == XML_DTD_NODE) {
3056 xmlDocPtr doc;
3057 doc = cur->doc;
3058 if (doc->intSubset == (xmlDtdPtr) cur)
3059 doc->intSubset = NULL;
3060 if (doc->extSubset == (xmlDtdPtr) cur)
3061 doc->extSubset = NULL;
3062 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003063 if (cur->parent != NULL) {
3064 xmlNodePtr parent;
3065 parent = cur->parent;
3066 if (cur->type == XML_ATTRIBUTE_NODE) {
3067 if (parent->properties == (xmlAttrPtr) cur)
3068 parent->properties = ((xmlAttrPtr) cur)->next;
3069 } else {
3070 if (parent->children == cur)
3071 parent->children = cur->next;
3072 if (parent->last == cur)
3073 parent->last = cur->prev;
3074 }
3075 cur->parent = NULL;
3076 }
Owen Taylor3473f882001-02-23 17:55:21 +00003077 if (cur->next != NULL)
3078 cur->next->prev = cur->prev;
3079 if (cur->prev != NULL)
3080 cur->prev->next = cur->next;
3081 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003082}
3083
3084/**
3085 * xmlReplaceNode:
3086 * @old: the old node
3087 * @cur: the node
3088 *
3089 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003090 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003091 * first unlinked from its existing context.
3092 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003093 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003094 */
3095xmlNodePtr
3096xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3097 if (old == NULL) {
3098#ifdef DEBUG_TREE
3099 xmlGenericError(xmlGenericErrorContext,
3100 "xmlReplaceNode : old == NULL\n");
3101#endif
3102 return(NULL);
3103 }
3104 if (cur == NULL) {
3105 xmlUnlinkNode(old);
3106 return(old);
3107 }
3108 if (cur == old) {
3109 return(old);
3110 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003111 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3112#ifdef DEBUG_TREE
3113 xmlGenericError(xmlGenericErrorContext,
3114 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3115#endif
3116 return(old);
3117 }
3118 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3119#ifdef DEBUG_TREE
3120 xmlGenericError(xmlGenericErrorContext,
3121 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3122#endif
3123 return(old);
3124 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003125 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3126#ifdef DEBUG_TREE
3127 xmlGenericError(xmlGenericErrorContext,
3128 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3129#endif
3130 return(old);
3131 }
3132 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3133#ifdef DEBUG_TREE
3134 xmlGenericError(xmlGenericErrorContext,
3135 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3136#endif
3137 return(old);
3138 }
Owen Taylor3473f882001-02-23 17:55:21 +00003139 xmlUnlinkNode(cur);
3140 cur->doc = old->doc;
3141 cur->parent = old->parent;
3142 cur->next = old->next;
3143 if (cur->next != NULL)
3144 cur->next->prev = cur;
3145 cur->prev = old->prev;
3146 if (cur->prev != NULL)
3147 cur->prev->next = cur;
3148 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003149 if (cur->type == XML_ATTRIBUTE_NODE) {
3150 if (cur->parent->properties == (xmlAttrPtr)old)
3151 cur->parent->properties = ((xmlAttrPtr) cur);
3152 } else {
3153 if (cur->parent->children == old)
3154 cur->parent->children = cur;
3155 if (cur->parent->last == old)
3156 cur->parent->last = cur;
3157 }
Owen Taylor3473f882001-02-23 17:55:21 +00003158 }
3159 old->next = old->prev = NULL;
3160 old->parent = NULL;
3161 return(old);
3162}
3163
3164/************************************************************************
3165 * *
3166 * Copy operations *
3167 * *
3168 ************************************************************************/
3169
3170/**
3171 * xmlCopyNamespace:
3172 * @cur: the namespace
3173 *
3174 * Do a copy of the namespace.
3175 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003176 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003177 */
3178xmlNsPtr
3179xmlCopyNamespace(xmlNsPtr cur) {
3180 xmlNsPtr ret;
3181
3182 if (cur == NULL) return(NULL);
3183 switch (cur->type) {
3184 case XML_LOCAL_NAMESPACE:
3185 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3186 break;
3187 default:
3188#ifdef DEBUG_TREE
3189 xmlGenericError(xmlGenericErrorContext,
3190 "xmlCopyNamespace: invalid type %d\n", cur->type);
3191#endif
3192 return(NULL);
3193 }
3194 return(ret);
3195}
3196
3197/**
3198 * xmlCopyNamespaceList:
3199 * @cur: the first namespace
3200 *
3201 * Do a copy of an namespace list.
3202 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003203 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003204 */
3205xmlNsPtr
3206xmlCopyNamespaceList(xmlNsPtr cur) {
3207 xmlNsPtr ret = NULL;
3208 xmlNsPtr p = NULL,q;
3209
3210 while (cur != NULL) {
3211 q = xmlCopyNamespace(cur);
3212 if (p == NULL) {
3213 ret = p = q;
3214 } else {
3215 p->next = q;
3216 p = q;
3217 }
3218 cur = cur->next;
3219 }
3220 return(ret);
3221}
3222
3223static xmlNodePtr
3224xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3225/**
3226 * xmlCopyProp:
3227 * @target: the element where the attribute will be grafted
3228 * @cur: the attribute
3229 *
3230 * Do a copy of the attribute.
3231 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003232 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003233 */
3234xmlAttrPtr
3235xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3236 xmlAttrPtr ret;
3237
3238 if (cur == NULL) return(NULL);
3239 if (target != NULL)
3240 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3241 else if (cur->parent != NULL)
3242 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3243 else if (cur->children != NULL)
3244 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3245 else
3246 ret = xmlNewDocProp(NULL, cur->name, NULL);
3247 if (ret == NULL) return(NULL);
3248 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003249
Owen Taylor3473f882001-02-23 17:55:21 +00003250 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003251 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003252/*
3253 * if (target->doc)
3254 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3255 * else if (cur->doc) / * target may not yet have a doc : KPI * /
3256 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
3257 * else
3258 * ns = NULL;
3259 * ret->ns = ns;
3260 */
3261 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3262 if (ns == NULL) {
3263 /*
3264 * Humm, we are copying an element whose namespace is defined
3265 * out of the new tree scope. Search it in the original tree
3266 * and add it at the top of the new tree
3267 */
3268 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3269 if (ns != NULL) {
3270 xmlNodePtr root = target;
3271 xmlNodePtr pred = NULL;
3272
3273 while (root->parent != NULL) {
3274 pred = root;
3275 root = root->parent;
3276 }
3277 if (root == (xmlNodePtr) target->doc) {
3278 /* correct possibly cycling above the document elt */
3279 root = pred;
3280 }
3281 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3282 }
3283 } else {
3284 /*
3285 * we have to find something appropriate here since
3286 * we cant be sure, that the namespce we found is identified
3287 * by the prefix
3288 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003289 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003290 /* this is the nice case */
3291 ret->ns = ns;
3292 } else {
3293 /*
3294 * we are in trouble: we need a new reconcilied namespace.
3295 * This is expensive
3296 */
3297 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3298 }
3299 }
3300
Owen Taylor3473f882001-02-23 17:55:21 +00003301 } else
3302 ret->ns = NULL;
3303
3304 if (cur->children != NULL) {
3305 xmlNodePtr tmp;
3306
3307 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3308 ret->last = NULL;
3309 tmp = ret->children;
3310 while (tmp != NULL) {
3311 /* tmp->parent = (xmlNodePtr)ret; */
3312 if (tmp->next == NULL)
3313 ret->last = tmp;
3314 tmp = tmp->next;
3315 }
3316 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003317 /*
3318 * Try to handle IDs
3319 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003320 if ((target!= NULL) && (cur!= NULL) &&
3321 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003322 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3323 if (xmlIsID(cur->doc, cur->parent, cur)) {
3324 xmlChar *id;
3325
3326 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3327 if (id != NULL) {
3328 xmlAddID(NULL, target->doc, id, ret);
3329 xmlFree(id);
3330 }
3331 }
3332 }
Owen Taylor3473f882001-02-23 17:55:21 +00003333 return(ret);
3334}
3335
3336/**
3337 * xmlCopyPropList:
3338 * @target: the element where the attributes will be grafted
3339 * @cur: the first attribute
3340 *
3341 * Do a copy of an attribute list.
3342 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003343 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003344 */
3345xmlAttrPtr
3346xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3347 xmlAttrPtr ret = NULL;
3348 xmlAttrPtr p = NULL,q;
3349
3350 while (cur != NULL) {
3351 q = xmlCopyProp(target, cur);
3352 if (p == NULL) {
3353 ret = p = q;
3354 } else {
3355 p->next = q;
3356 q->prev = p;
3357 p = q;
3358 }
3359 cur = cur->next;
3360 }
3361 return(ret);
3362}
3363
3364/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003365 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003366 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003367 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003368 * tricky reason: namespaces. Doing a direct copy of a node
3369 * say RPM:Copyright without changing the namespace pointer to
3370 * something else can produce stale links. One way to do it is
3371 * to keep a reference counter but this doesn't work as soon
3372 * as one move the element or the subtree out of the scope of
3373 * the existing namespace. The actual solution seems to add
3374 * a copy of the namespace at the top of the copied tree if
3375 * not available in the subtree.
3376 * Hence two functions, the public front-end call the inner ones
3377 */
3378
3379static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003380xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003381 int recursive) {
3382 xmlNodePtr ret;
3383
3384 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003385 switch (node->type) {
3386 case XML_TEXT_NODE:
3387 case XML_CDATA_SECTION_NODE:
3388 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003389 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003390 case XML_ENTITY_REF_NODE:
3391 case XML_ENTITY_NODE:
3392 case XML_PI_NODE:
3393 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003394 case XML_XINCLUDE_START:
3395 case XML_XINCLUDE_END:
3396 break;
3397 case XML_ATTRIBUTE_NODE:
3398 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3399 case XML_NAMESPACE_DECL:
3400 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3401
Daniel Veillard39196eb2001-06-19 18:09:42 +00003402 case XML_DOCUMENT_NODE:
3403 case XML_HTML_DOCUMENT_NODE:
3404#ifdef LIBXML_DOCB_ENABLED
3405 case XML_DOCB_DOCUMENT_NODE:
3406#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003407 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00003408 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003409 case XML_NOTATION_NODE:
3410 case XML_DTD_NODE:
3411 case XML_ELEMENT_DECL:
3412 case XML_ATTRIBUTE_DECL:
3413 case XML_ENTITY_DECL:
3414 return(NULL);
3415 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003416
Owen Taylor3473f882001-02-23 17:55:21 +00003417 /*
3418 * Allocate a new node and fill the fields.
3419 */
3420 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3421 if (ret == NULL) {
3422 xmlGenericError(xmlGenericErrorContext,
3423 "xmlStaticCopyNode : malloc failed\n");
3424 return(NULL);
3425 }
3426 memset(ret, 0, sizeof(xmlNode));
3427 ret->type = node->type;
3428
3429 ret->doc = doc;
3430 ret->parent = parent;
3431 if (node->name == xmlStringText)
3432 ret->name = xmlStringText;
3433 else if (node->name == xmlStringTextNoenc)
3434 ret->name = xmlStringTextNoenc;
3435 else if (node->name == xmlStringComment)
3436 ret->name = xmlStringComment;
3437 else if (node->name != NULL)
3438 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003439 if ((node->type != XML_ELEMENT_NODE) &&
3440 (node->content != NULL) &&
3441 (node->type != XML_ENTITY_REF_NODE) &&
3442 (node->type != XML_XINCLUDE_END) &&
3443 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003444 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003445 }else{
3446 if (node->type == XML_ELEMENT_NODE)
3447 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00003448 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003449 if (parent != NULL) {
3450 xmlNodePtr tmp;
3451
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003452 /*
3453 * this is a tricky part for the node register thing:
3454 * in case ret does get coalesced in xmlAddChild
3455 * the deregister-node callback is called; so we register ret now already
3456 */
3457 if (xmlRegisterNodeDefaultValue)
3458 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3459
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003460 tmp = xmlAddChild(parent, ret);
3461 /* node could have coalesced */
3462 if (tmp != ret)
3463 return(tmp);
3464 }
Owen Taylor3473f882001-02-23 17:55:21 +00003465
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003466 if (!recursive)
3467 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003468 if (node->nsDef != NULL)
3469 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3470
3471 if (node->ns != NULL) {
3472 xmlNsPtr ns;
3473
3474 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3475 if (ns == NULL) {
3476 /*
3477 * Humm, we are copying an element whose namespace is defined
3478 * out of the new tree scope. Search it in the original tree
3479 * and add it at the top of the new tree
3480 */
3481 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3482 if (ns != NULL) {
3483 xmlNodePtr root = ret;
3484
3485 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003486 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003487 }
3488 } else {
3489 /*
3490 * reference the existing namespace definition in our own tree.
3491 */
3492 ret->ns = ns;
3493 }
3494 }
3495 if (node->properties != NULL)
3496 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003497 if (node->type == XML_ENTITY_REF_NODE) {
3498 if ((doc == NULL) || (node->doc != doc)) {
3499 /*
3500 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003501 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003502 * we cannot keep the reference. Try to find it in the
3503 * target document.
3504 */
3505 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3506 } else {
3507 ret->children = node->children;
3508 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003509 ret->last = ret->children;
3510 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003511 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003512 UPDATE_LAST_CHILD_AND_PARENT(ret)
3513 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003514
3515out:
3516 /* if parent != NULL we already registered the node above */
3517 if (parent == NULL && xmlRegisterNodeDefaultValue)
3518 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003519 return(ret);
3520}
3521
3522static xmlNodePtr
3523xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3524 xmlNodePtr ret = NULL;
3525 xmlNodePtr p = NULL,q;
3526
3527 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003528 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003529 if (doc == NULL) {
3530 node = node->next;
3531 continue;
3532 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003533 if (doc->intSubset == NULL) {
3534 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3535 q->doc = doc;
3536 q->parent = parent;
3537 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003538 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003539 } else {
3540 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003541 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003542 }
3543 } else
3544 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003545 if (ret == NULL) {
3546 q->prev = NULL;
3547 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003548 } else if (p != q) {
3549 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003550 p->next = q;
3551 q->prev = p;
3552 p = q;
3553 }
3554 node = node->next;
3555 }
3556 return(ret);
3557}
3558
3559/**
3560 * xmlCopyNode:
3561 * @node: the node
3562 * @recursive: if 1 do a recursive copy.
3563 *
3564 * Do a copy of the node.
3565 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003566 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003567 */
3568xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003569xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003570 xmlNodePtr ret;
3571
3572 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3573 return(ret);
3574}
3575
3576/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003577 * xmlDocCopyNode:
3578 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003579 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003580 * @recursive: if 1 do a recursive copy.
3581 *
3582 * Do a copy of the node to a given document.
3583 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003584 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003585 */
3586xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003587xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003588 xmlNodePtr ret;
3589
3590 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3591 return(ret);
3592}
3593
3594/**
Owen Taylor3473f882001-02-23 17:55:21 +00003595 * xmlCopyNodeList:
3596 * @node: the first node in the list.
3597 *
3598 * Do a recursive copy of the node list.
3599 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003600 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003601 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003602xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003603 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3604 return(ret);
3605}
3606
3607/**
Owen Taylor3473f882001-02-23 17:55:21 +00003608 * xmlCopyDtd:
3609 * @dtd: the dtd
3610 *
3611 * Do a copy of the dtd.
3612 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003613 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003614 */
3615xmlDtdPtr
3616xmlCopyDtd(xmlDtdPtr dtd) {
3617 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003618 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003619
3620 if (dtd == NULL) return(NULL);
3621 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3622 if (ret == NULL) return(NULL);
3623 if (dtd->entities != NULL)
3624 ret->entities = (void *) xmlCopyEntitiesTable(
3625 (xmlEntitiesTablePtr) dtd->entities);
3626 if (dtd->notations != NULL)
3627 ret->notations = (void *) xmlCopyNotationTable(
3628 (xmlNotationTablePtr) dtd->notations);
3629 if (dtd->elements != NULL)
3630 ret->elements = (void *) xmlCopyElementTable(
3631 (xmlElementTablePtr) dtd->elements);
3632 if (dtd->attributes != NULL)
3633 ret->attributes = (void *) xmlCopyAttributeTable(
3634 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003635 if (dtd->pentities != NULL)
3636 ret->pentities = (void *) xmlCopyEntitiesTable(
3637 (xmlEntitiesTablePtr) dtd->pentities);
3638
3639 cur = dtd->children;
3640 while (cur != NULL) {
3641 q = NULL;
3642
3643 if (cur->type == XML_ENTITY_DECL) {
3644 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3645 switch (tmp->etype) {
3646 case XML_INTERNAL_GENERAL_ENTITY:
3647 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3648 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3649 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3650 break;
3651 case XML_INTERNAL_PARAMETER_ENTITY:
3652 case XML_EXTERNAL_PARAMETER_ENTITY:
3653 q = (xmlNodePtr)
3654 xmlGetParameterEntityFromDtd(ret, tmp->name);
3655 break;
3656 case XML_INTERNAL_PREDEFINED_ENTITY:
3657 break;
3658 }
3659 } else if (cur->type == XML_ELEMENT_DECL) {
3660 xmlElementPtr tmp = (xmlElementPtr) cur;
3661 q = (xmlNodePtr)
3662 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3663 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3664 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3665 q = (xmlNodePtr)
3666 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3667 } else if (cur->type == XML_COMMENT_NODE) {
3668 q = xmlCopyNode(cur, 0);
3669 }
3670
3671 if (q == NULL) {
3672 cur = cur->next;
3673 continue;
3674 }
3675
3676 if (p == NULL)
3677 ret->children = q;
3678 else
3679 p->next = q;
3680
3681 q->prev = p;
3682 q->parent = (xmlNodePtr) ret;
3683 q->next = NULL;
3684 ret->last = q;
3685 p = q;
3686 cur = cur->next;
3687 }
3688
Owen Taylor3473f882001-02-23 17:55:21 +00003689 return(ret);
3690}
3691
3692/**
3693 * xmlCopyDoc:
3694 * @doc: the document
3695 * @recursive: if 1 do a recursive copy.
3696 *
3697 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003698 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003699 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003700 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003701 */
3702xmlDocPtr
3703xmlCopyDoc(xmlDocPtr doc, int recursive) {
3704 xmlDocPtr ret;
3705
3706 if (doc == NULL) return(NULL);
3707 ret = xmlNewDoc(doc->version);
3708 if (ret == NULL) return(NULL);
3709 if (doc->name != NULL)
3710 ret->name = xmlMemStrdup(doc->name);
3711 if (doc->encoding != NULL)
3712 ret->encoding = xmlStrdup(doc->encoding);
3713 ret->charset = doc->charset;
3714 ret->compression = doc->compression;
3715 ret->standalone = doc->standalone;
3716 if (!recursive) return(ret);
3717
Daniel Veillardb33c2012001-04-25 12:59:04 +00003718 ret->last = NULL;
3719 ret->children = NULL;
3720 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003721 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003722 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003723 ret->intSubset->parent = ret;
3724 }
Owen Taylor3473f882001-02-23 17:55:21 +00003725 if (doc->oldNs != NULL)
3726 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3727 if (doc->children != NULL) {
3728 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003729
3730 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3731 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003732 ret->last = NULL;
3733 tmp = ret->children;
3734 while (tmp != NULL) {
3735 if (tmp->next == NULL)
3736 ret->last = tmp;
3737 tmp = tmp->next;
3738 }
3739 }
3740 return(ret);
3741}
3742
3743/************************************************************************
3744 * *
3745 * Content access functions *
3746 * *
3747 ************************************************************************/
3748
3749/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003750 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003751 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00003752 *
3753 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003754 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003755 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003756 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003757 */
3758long
3759xmlGetLineNo(xmlNodePtr node)
3760{
3761 long result = -1;
3762
3763 if (!node)
3764 return result;
3765 if (node->type == XML_ELEMENT_NODE)
3766 result = (long) node->content;
3767 else if ((node->prev != NULL) &&
3768 ((node->prev->type == XML_ELEMENT_NODE) ||
3769 (node->prev->type == XML_TEXT_NODE)))
3770 result = xmlGetLineNo(node->prev);
3771 else if ((node->parent != NULL) &&
3772 ((node->parent->type == XML_ELEMENT_NODE) ||
3773 (node->parent->type == XML_TEXT_NODE)))
3774 result = xmlGetLineNo(node->parent);
3775
3776 return result;
3777}
3778
3779/**
3780 * xmlGetNodePath:
3781 * @node: a node
3782 *
3783 * Build a structure based Path for the given node
3784 *
3785 * Returns the new path or NULL in case of error. The caller must free
3786 * the returned string
3787 */
3788xmlChar *
3789xmlGetNodePath(xmlNodePtr node)
3790{
3791 xmlNodePtr cur, tmp, next;
3792 xmlChar *buffer = NULL, *temp;
3793 size_t buf_len;
3794 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00003795 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00003796 const char *name;
3797 char nametemp[100];
3798 int occur = 0;
3799
3800 if (node == NULL)
3801 return (NULL);
3802
3803 buf_len = 500;
3804 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3805 if (buffer == NULL)
3806 return (NULL);
3807 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3808 if (buf == NULL) {
3809 xmlFree(buffer);
3810 return (NULL);
3811 }
3812
3813 buffer[0] = 0;
3814 cur = node;
3815 do {
3816 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003817 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003818 occur = 0;
3819 if ((cur->type == XML_DOCUMENT_NODE) ||
3820 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3821 if (buffer[0] == '/')
3822 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003823 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003824 next = NULL;
3825 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003826 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003827 name = (const char *) cur->name;
3828 if (cur->ns) {
3829 snprintf(nametemp, sizeof(nametemp) - 1,
3830 "%s:%s", cur->ns->prefix, cur->name);
3831 nametemp[sizeof(nametemp) - 1] = 0;
3832 name = nametemp;
3833 }
3834 next = cur->parent;
3835
3836 /*
3837 * Thumbler index computation
3838 */
3839 tmp = cur->prev;
3840 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00003841 if ((tmp->type == XML_ELEMENT_NODE) &&
3842 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00003843 occur++;
3844 tmp = tmp->prev;
3845 }
3846 if (occur == 0) {
3847 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00003848 while (tmp != NULL && occur == 0) {
3849 if ((tmp->type == XML_ELEMENT_NODE) &&
3850 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00003851 occur++;
3852 tmp = tmp->next;
3853 }
3854 if (occur != 0)
3855 occur = 1;
3856 } else
3857 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00003858 } else if (cur->type == XML_COMMENT_NODE) {
3859 sep = "/";
3860 name = "comment()";
3861 next = cur->parent;
3862
3863 /*
3864 * Thumbler index computation
3865 */
3866 tmp = cur->prev;
3867 while (tmp != NULL) {
3868 if (tmp->type == XML_COMMENT_NODE)
3869 occur++;
3870 tmp = tmp->prev;
3871 }
3872 if (occur == 0) {
3873 tmp = cur->next;
3874 while (tmp != NULL && occur == 0) {
3875 if (tmp->type == XML_COMMENT_NODE)
3876 occur++;
3877 tmp = tmp->next;
3878 }
3879 if (occur != 0)
3880 occur = 1;
3881 } else
3882 occur++;
3883 } else if ((cur->type == XML_TEXT_NODE) ||
3884 (cur->type == XML_CDATA_SECTION_NODE)) {
3885 sep = "/";
3886 name = "text()";
3887 next = cur->parent;
3888
3889 /*
3890 * Thumbler index computation
3891 */
3892 tmp = cur->prev;
3893 while (tmp != NULL) {
3894 if ((cur->type == XML_TEXT_NODE) ||
3895 (cur->type == XML_CDATA_SECTION_NODE))
3896 occur++;
3897 tmp = tmp->prev;
3898 }
3899 if (occur == 0) {
3900 tmp = cur->next;
3901 while (tmp != NULL && occur == 0) {
3902 if ((cur->type == XML_TEXT_NODE) ||
3903 (cur->type == XML_CDATA_SECTION_NODE))
3904 occur++;
3905 tmp = tmp->next;
3906 }
3907 if (occur != 0)
3908 occur = 1;
3909 } else
3910 occur++;
3911 } else if (cur->type == XML_PI_NODE) {
3912 sep = "/";
3913 snprintf(nametemp, sizeof(nametemp) - 1,
3914 "processing-instruction('%s')", cur->name);
3915 nametemp[sizeof(nametemp) - 1] = 0;
3916 name = nametemp;
3917
3918 next = cur->parent;
3919
3920 /*
3921 * Thumbler index computation
3922 */
3923 tmp = cur->prev;
3924 while (tmp != NULL) {
3925 if ((tmp->type == XML_PI_NODE) &&
3926 (xmlStrEqual(cur->name, tmp->name)))
3927 occur++;
3928 tmp = tmp->prev;
3929 }
3930 if (occur == 0) {
3931 tmp = cur->next;
3932 while (tmp != NULL && occur == 0) {
3933 if ((tmp->type == XML_PI_NODE) &&
3934 (xmlStrEqual(cur->name, tmp->name)))
3935 occur++;
3936 tmp = tmp->next;
3937 }
3938 if (occur != 0)
3939 occur = 1;
3940 } else
3941 occur++;
3942
Daniel Veillard8faa7832001-11-26 15:58:08 +00003943 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003944 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003945 name = (const char *) (((xmlAttrPtr) cur)->name);
3946 next = ((xmlAttrPtr) cur)->parent;
3947 } else {
3948 next = cur->parent;
3949 }
3950
3951 /*
3952 * Make sure there is enough room
3953 */
3954 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
3955 buf_len =
3956 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
3957 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
3958 if (temp == NULL) {
3959 xmlFree(buf);
3960 xmlFree(buffer);
3961 return (NULL);
3962 }
3963 buffer = temp;
3964 temp = (xmlChar *) xmlRealloc(buf, buf_len);
3965 if (temp == NULL) {
3966 xmlFree(buf);
3967 xmlFree(buffer);
3968 return (NULL);
3969 }
3970 buf = temp;
3971 }
3972 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003973 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00003974 sep, name, (char *) buffer);
3975 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003976 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00003977 sep, name, occur, (char *) buffer);
3978 snprintf((char *) buffer, buf_len, "%s", buf);
3979 cur = next;
3980 } while (cur != NULL);
3981 xmlFree(buf);
3982 return (buffer);
3983}
3984
3985/**
Owen Taylor3473f882001-02-23 17:55:21 +00003986 * xmlDocGetRootElement:
3987 * @doc: the document
3988 *
3989 * Get the root element of the document (doc->children is a list
3990 * containing possibly comments, PIs, etc ...).
3991 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003992 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00003993 */
3994xmlNodePtr
3995xmlDocGetRootElement(xmlDocPtr doc) {
3996 xmlNodePtr ret;
3997
3998 if (doc == NULL) return(NULL);
3999 ret = doc->children;
4000 while (ret != NULL) {
4001 if (ret->type == XML_ELEMENT_NODE)
4002 return(ret);
4003 ret = ret->next;
4004 }
4005 return(ret);
4006}
4007
4008/**
4009 * xmlDocSetRootElement:
4010 * @doc: the document
4011 * @root: the new document root element
4012 *
4013 * Set the root element of the document (doc->children is a list
4014 * containing possibly comments, PIs, etc ...).
4015 *
4016 * Returns the old root element if any was found
4017 */
4018xmlNodePtr
4019xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4020 xmlNodePtr old = NULL;
4021
4022 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004023 if (root == NULL)
4024 return(NULL);
4025 xmlUnlinkNode(root);
4026 root->doc = doc;
4027 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004028 old = doc->children;
4029 while (old != NULL) {
4030 if (old->type == XML_ELEMENT_NODE)
4031 break;
4032 old = old->next;
4033 }
4034 if (old == NULL) {
4035 if (doc->children == NULL) {
4036 doc->children = root;
4037 doc->last = root;
4038 } else {
4039 xmlAddSibling(doc->children, root);
4040 }
4041 } else {
4042 xmlReplaceNode(old, root);
4043 }
4044 return(old);
4045}
4046
4047/**
4048 * xmlNodeSetLang:
4049 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004050 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004051 *
4052 * Set the language of a node, i.e. the values of the xml:lang
4053 * attribute.
4054 */
4055void
4056xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004057 xmlNsPtr ns;
4058
Owen Taylor3473f882001-02-23 17:55:21 +00004059 if (cur == NULL) return;
4060 switch(cur->type) {
4061 case XML_TEXT_NODE:
4062 case XML_CDATA_SECTION_NODE:
4063 case XML_COMMENT_NODE:
4064 case XML_DOCUMENT_NODE:
4065 case XML_DOCUMENT_TYPE_NODE:
4066 case XML_DOCUMENT_FRAG_NODE:
4067 case XML_NOTATION_NODE:
4068 case XML_HTML_DOCUMENT_NODE:
4069 case XML_DTD_NODE:
4070 case XML_ELEMENT_DECL:
4071 case XML_ATTRIBUTE_DECL:
4072 case XML_ENTITY_DECL:
4073 case XML_PI_NODE:
4074 case XML_ENTITY_REF_NODE:
4075 case XML_ENTITY_NODE:
4076 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004077#ifdef LIBXML_DOCB_ENABLED
4078 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004079#endif
4080 case XML_XINCLUDE_START:
4081 case XML_XINCLUDE_END:
4082 return;
4083 case XML_ELEMENT_NODE:
4084 case XML_ATTRIBUTE_NODE:
4085 break;
4086 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004087 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4088 if (ns == NULL)
4089 return;
4090 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004091}
4092
4093/**
4094 * xmlNodeGetLang:
4095 * @cur: the node being checked
4096 *
4097 * Searches the language of a node, i.e. the values of the xml:lang
4098 * attribute or the one carried by the nearest ancestor.
4099 *
4100 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004101 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004102 */
4103xmlChar *
4104xmlNodeGetLang(xmlNodePtr cur) {
4105 xmlChar *lang;
4106
4107 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004108 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004109 if (lang != NULL)
4110 return(lang);
4111 cur = cur->parent;
4112 }
4113 return(NULL);
4114}
4115
4116
4117/**
4118 * xmlNodeSetSpacePreserve:
4119 * @cur: the node being changed
4120 * @val: the xml:space value ("0": default, 1: "preserve")
4121 *
4122 * Set (or reset) the space preserving behaviour of a node, i.e. the
4123 * value of the xml:space attribute.
4124 */
4125void
4126xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004127 xmlNsPtr ns;
4128
Owen Taylor3473f882001-02-23 17:55:21 +00004129 if (cur == NULL) return;
4130 switch(cur->type) {
4131 case XML_TEXT_NODE:
4132 case XML_CDATA_SECTION_NODE:
4133 case XML_COMMENT_NODE:
4134 case XML_DOCUMENT_NODE:
4135 case XML_DOCUMENT_TYPE_NODE:
4136 case XML_DOCUMENT_FRAG_NODE:
4137 case XML_NOTATION_NODE:
4138 case XML_HTML_DOCUMENT_NODE:
4139 case XML_DTD_NODE:
4140 case XML_ELEMENT_DECL:
4141 case XML_ATTRIBUTE_DECL:
4142 case XML_ENTITY_DECL:
4143 case XML_PI_NODE:
4144 case XML_ENTITY_REF_NODE:
4145 case XML_ENTITY_NODE:
4146 case XML_NAMESPACE_DECL:
4147 case XML_XINCLUDE_START:
4148 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004149#ifdef LIBXML_DOCB_ENABLED
4150 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004151#endif
4152 return;
4153 case XML_ELEMENT_NODE:
4154 case XML_ATTRIBUTE_NODE:
4155 break;
4156 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004157 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4158 if (ns == NULL)
4159 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004160 switch (val) {
4161 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004162 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004163 break;
4164 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004165 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004166 break;
4167 }
4168}
4169
4170/**
4171 * xmlNodeGetSpacePreserve:
4172 * @cur: the node being checked
4173 *
4174 * Searches the space preserving behaviour of a node, i.e. the values
4175 * of the xml:space attribute or the one carried by the nearest
4176 * ancestor.
4177 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004178 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004179 */
4180int
4181xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4182 xmlChar *space;
4183
4184 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004185 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004186 if (space != NULL) {
4187 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4188 xmlFree(space);
4189 return(1);
4190 }
4191 if (xmlStrEqual(space, BAD_CAST "default")) {
4192 xmlFree(space);
4193 return(0);
4194 }
4195 xmlFree(space);
4196 }
4197 cur = cur->parent;
4198 }
4199 return(-1);
4200}
4201
4202/**
4203 * xmlNodeSetName:
4204 * @cur: the node being changed
4205 * @name: the new tag name
4206 *
4207 * Set (or reset) the name of a node.
4208 */
4209void
4210xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
4211 if (cur == NULL) return;
4212 if (name == NULL) return;
4213 switch(cur->type) {
4214 case XML_TEXT_NODE:
4215 case XML_CDATA_SECTION_NODE:
4216 case XML_COMMENT_NODE:
4217 case XML_DOCUMENT_TYPE_NODE:
4218 case XML_DOCUMENT_FRAG_NODE:
4219 case XML_NOTATION_NODE:
4220 case XML_HTML_DOCUMENT_NODE:
4221 case XML_NAMESPACE_DECL:
4222 case XML_XINCLUDE_START:
4223 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004224#ifdef LIBXML_DOCB_ENABLED
4225 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004226#endif
4227 return;
4228 case XML_ELEMENT_NODE:
4229 case XML_ATTRIBUTE_NODE:
4230 case XML_PI_NODE:
4231 case XML_ENTITY_REF_NODE:
4232 case XML_ENTITY_NODE:
4233 case XML_DTD_NODE:
4234 case XML_DOCUMENT_NODE:
4235 case XML_ELEMENT_DECL:
4236 case XML_ATTRIBUTE_DECL:
4237 case XML_ENTITY_DECL:
4238 break;
4239 }
4240 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4241 cur->name = xmlStrdup(name);
4242}
4243
4244/**
4245 * xmlNodeSetBase:
4246 * @cur: the node being changed
4247 * @uri: the new base URI
4248 *
4249 * Set (or reset) the base URI of a node, i.e. the value of the
4250 * xml:base attribute.
4251 */
4252void
4253xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004254 xmlNsPtr ns;
4255
Owen Taylor3473f882001-02-23 17:55:21 +00004256 if (cur == NULL) return;
4257 switch(cur->type) {
4258 case XML_TEXT_NODE:
4259 case XML_CDATA_SECTION_NODE:
4260 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004261 case XML_DOCUMENT_TYPE_NODE:
4262 case XML_DOCUMENT_FRAG_NODE:
4263 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004264 case XML_DTD_NODE:
4265 case XML_ELEMENT_DECL:
4266 case XML_ATTRIBUTE_DECL:
4267 case XML_ENTITY_DECL:
4268 case XML_PI_NODE:
4269 case XML_ENTITY_REF_NODE:
4270 case XML_ENTITY_NODE:
4271 case XML_NAMESPACE_DECL:
4272 case XML_XINCLUDE_START:
4273 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004274 return;
4275 case XML_ELEMENT_NODE:
4276 case XML_ATTRIBUTE_NODE:
4277 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004278 case XML_DOCUMENT_NODE:
4279#ifdef LIBXML_DOCB_ENABLED
4280 case XML_DOCB_DOCUMENT_NODE:
4281#endif
4282 case XML_HTML_DOCUMENT_NODE: {
4283 xmlDocPtr doc = (xmlDocPtr) cur;
4284
4285 if (doc->URL != NULL)
4286 xmlFree((xmlChar *) doc->URL);
4287 if (uri == NULL)
4288 doc->URL = NULL;
4289 else
4290 doc->URL = xmlStrdup(uri);
4291 return;
4292 }
Owen Taylor3473f882001-02-23 17:55:21 +00004293 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004294
4295 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4296 if (ns == NULL)
4297 return;
4298 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004299}
4300
4301/**
Owen Taylor3473f882001-02-23 17:55:21 +00004302 * xmlNodeGetBase:
4303 * @doc: the document the node pertains to
4304 * @cur: the node being checked
4305 *
4306 * Searches for the BASE URL. The code should work on both XML
4307 * and HTML document even if base mechanisms are completely different.
4308 * It returns the base as defined in RFC 2396 sections
4309 * 5.1.1. Base URI within Document Content
4310 * and
4311 * 5.1.2. Base URI from the Encapsulating Entity
4312 * However it does not return the document base (5.1.3), use
4313 * xmlDocumentGetBase() for this
4314 *
4315 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004316 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004317 */
4318xmlChar *
4319xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004320 xmlChar *oldbase = NULL;
4321 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004322
4323 if ((cur == NULL) && (doc == NULL))
4324 return(NULL);
4325 if (doc == NULL) doc = cur->doc;
4326 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4327 cur = doc->children;
4328 while ((cur != NULL) && (cur->name != NULL)) {
4329 if (cur->type != XML_ELEMENT_NODE) {
4330 cur = cur->next;
4331 continue;
4332 }
4333 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4334 cur = cur->children;
4335 continue;
4336 }
4337 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4338 cur = cur->children;
4339 continue;
4340 }
4341 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4342 return(xmlGetProp(cur, BAD_CAST "href"));
4343 }
4344 cur = cur->next;
4345 }
4346 return(NULL);
4347 }
4348 while (cur != NULL) {
4349 if (cur->type == XML_ENTITY_DECL) {
4350 xmlEntityPtr ent = (xmlEntityPtr) cur;
4351 return(xmlStrdup(ent->URI));
4352 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004353 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004354 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004355 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004356 if (oldbase != NULL) {
4357 newbase = xmlBuildURI(oldbase, base);
4358 if (newbase != NULL) {
4359 xmlFree(oldbase);
4360 xmlFree(base);
4361 oldbase = newbase;
4362 } else {
4363 xmlFree(oldbase);
4364 xmlFree(base);
4365 return(NULL);
4366 }
4367 } else {
4368 oldbase = base;
4369 }
4370 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4371 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4372 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4373 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004374 }
4375 }
Owen Taylor3473f882001-02-23 17:55:21 +00004376 cur = cur->parent;
4377 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004378 if ((doc != NULL) && (doc->URL != NULL)) {
4379 if (oldbase == NULL)
4380 return(xmlStrdup(doc->URL));
4381 newbase = xmlBuildURI(oldbase, doc->URL);
4382 xmlFree(oldbase);
4383 return(newbase);
4384 }
4385 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004386}
4387
4388/**
4389 * xmlNodeGetContent:
4390 * @cur: the node being read
4391 *
4392 * Read the value of a node, this can be either the text carried
4393 * directly by this node if it's a TEXT node or the aggregate string
4394 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004395 * Entity references are substituted.
4396 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004397 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004398 */
4399xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004400xmlNodeGetContent(xmlNodePtr cur)
4401{
4402 if (cur == NULL)
4403 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004404 switch (cur->type) {
4405 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004406 case XML_ELEMENT_NODE:{
4407 xmlNodePtr tmp = cur;
4408 xmlBufferPtr buffer;
4409 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004410
Daniel Veillard814a76d2003-01-23 18:24:20 +00004411 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004412 if (buffer == NULL)
4413 return (NULL);
4414 while (tmp != NULL) {
4415 switch (tmp->type) {
4416 case XML_CDATA_SECTION_NODE:
4417 case XML_TEXT_NODE:
4418 if (tmp->content != NULL)
4419 xmlBufferCat(buffer, tmp->content);
4420 break;
4421 case XML_ENTITY_REF_NODE:{
4422 /* recursive substitution of entity references */
4423 xmlChar *cont = xmlNodeGetContent(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00004424
Daniel Veillard7646b182002-04-20 06:41:40 +00004425 if (cont) {
4426 xmlBufferCat(buffer,
4427 (const xmlChar *) cont);
4428 xmlFree(cont);
4429 }
4430 break;
4431 }
4432 default:
4433 break;
4434 }
4435 /*
4436 * Skip to next node
4437 */
4438 if (tmp->children != NULL) {
4439 if (tmp->children->type != XML_ENTITY_DECL) {
4440 tmp = tmp->children;
4441 continue;
4442 }
4443 }
4444 if (tmp == cur)
4445 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00004446
Daniel Veillard7646b182002-04-20 06:41:40 +00004447 if (tmp->next != NULL) {
4448 tmp = tmp->next;
4449 continue;
4450 }
4451
4452 do {
4453 tmp = tmp->parent;
4454 if (tmp == NULL)
4455 break;
4456 if (tmp == cur) {
4457 tmp = NULL;
4458 break;
4459 }
4460 if (tmp->next != NULL) {
4461 tmp = tmp->next;
4462 break;
4463 }
4464 } while (tmp != NULL);
4465 }
4466 ret = buffer->content;
4467 buffer->content = NULL;
4468 xmlBufferFree(buffer);
4469 return (ret);
4470 }
4471 case XML_ATTRIBUTE_NODE:{
4472 xmlAttrPtr attr = (xmlAttrPtr) cur;
4473
4474 if (attr->parent != NULL)
4475 return (xmlNodeListGetString
4476 (attr->parent->doc, attr->children, 1));
4477 else
4478 return (xmlNodeListGetString(NULL, attr->children, 1));
4479 break;
4480 }
Owen Taylor3473f882001-02-23 17:55:21 +00004481 case XML_COMMENT_NODE:
4482 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004483 if (cur->content != NULL)
4484 return (xmlStrdup(cur->content));
4485 return (NULL);
4486 case XML_ENTITY_REF_NODE:{
4487 xmlEntityPtr ent;
4488 xmlNodePtr tmp;
4489 xmlBufferPtr buffer;
4490 xmlChar *ret;
4491
4492 /* lookup entity declaration */
4493 ent = xmlGetDocEntity(cur->doc, cur->name);
4494 if (ent == NULL)
4495 return (NULL);
4496
4497 buffer = xmlBufferCreate();
4498 if (buffer == NULL)
4499 return (NULL);
4500
4501 /* an entity content can be any "well balanced chunk",
4502 * i.e. the result of the content [43] production:
4503 * http://www.w3.org/TR/REC-xml#NT-content
4504 * -> we iterate through child nodes and recursive call
4505 * xmlNodeGetContent() which handles all possible node types */
4506 tmp = ent->children;
4507 while (tmp) {
4508 xmlChar *cont = xmlNodeGetContent(tmp);
4509
4510 if (cont) {
4511 xmlBufferCat(buffer, (const xmlChar *) cont);
4512 xmlFree(cont);
4513 }
4514 tmp = tmp->next;
4515 }
4516
4517 ret = buffer->content;
4518 buffer->content = NULL;
4519 xmlBufferFree(buffer);
4520 return (ret);
4521 }
Owen Taylor3473f882001-02-23 17:55:21 +00004522 case XML_ENTITY_NODE:
4523 case XML_DOCUMENT_NODE:
4524 case XML_HTML_DOCUMENT_NODE:
4525 case XML_DOCUMENT_TYPE_NODE:
4526 case XML_NOTATION_NODE:
4527 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004528 case XML_XINCLUDE_START:
4529 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004530#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004531 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004532#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00004533 return (NULL);
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004534 case XML_NAMESPACE_DECL: {
4535 xmlChar *tmp;
4536
4537 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4538 return (tmp);
4539 }
Owen Taylor3473f882001-02-23 17:55:21 +00004540 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004541 /* TODO !!! */
4542 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004543 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004544 /* TODO !!! */
4545 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004546 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004547 /* TODO !!! */
4548 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004549 case XML_CDATA_SECTION_NODE:
4550 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004551 if (cur->content != NULL)
4552 return (xmlStrdup(cur->content));
4553 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004554 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004555 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004556}
Owen Taylor3473f882001-02-23 17:55:21 +00004557/**
4558 * xmlNodeSetContent:
4559 * @cur: the node being modified
4560 * @content: the new value of the content
4561 *
4562 * Replace the content of a node.
4563 */
4564void
4565xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4566 if (cur == NULL) {
4567#ifdef DEBUG_TREE
4568 xmlGenericError(xmlGenericErrorContext,
4569 "xmlNodeSetContent : node == NULL\n");
4570#endif
4571 return;
4572 }
4573 switch (cur->type) {
4574 case XML_DOCUMENT_FRAG_NODE:
4575 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004576 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004577 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4578 cur->children = xmlStringGetNodeList(cur->doc, content);
4579 UPDATE_LAST_CHILD_AND_PARENT(cur)
4580 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004581 case XML_TEXT_NODE:
4582 case XML_CDATA_SECTION_NODE:
4583 case XML_ENTITY_REF_NODE:
4584 case XML_ENTITY_NODE:
4585 case XML_PI_NODE:
4586 case XML_COMMENT_NODE:
4587 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004588 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004589 }
4590 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4591 cur->last = cur->children = NULL;
4592 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004593 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00004594 } else
4595 cur->content = NULL;
4596 break;
4597 case XML_DOCUMENT_NODE:
4598 case XML_HTML_DOCUMENT_NODE:
4599 case XML_DOCUMENT_TYPE_NODE:
4600 case XML_XINCLUDE_START:
4601 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004602#ifdef LIBXML_DOCB_ENABLED
4603 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004604#endif
4605 break;
4606 case XML_NOTATION_NODE:
4607 break;
4608 case XML_DTD_NODE:
4609 break;
4610 case XML_NAMESPACE_DECL:
4611 break;
4612 case XML_ELEMENT_DECL:
4613 /* TODO !!! */
4614 break;
4615 case XML_ATTRIBUTE_DECL:
4616 /* TODO !!! */
4617 break;
4618 case XML_ENTITY_DECL:
4619 /* TODO !!! */
4620 break;
4621 }
4622}
4623
4624/**
4625 * xmlNodeSetContentLen:
4626 * @cur: the node being modified
4627 * @content: the new value of the content
4628 * @len: the size of @content
4629 *
4630 * Replace the content of a node.
4631 */
4632void
4633xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4634 if (cur == NULL) {
4635#ifdef DEBUG_TREE
4636 xmlGenericError(xmlGenericErrorContext,
4637 "xmlNodeSetContentLen : node == NULL\n");
4638#endif
4639 return;
4640 }
4641 switch (cur->type) {
4642 case XML_DOCUMENT_FRAG_NODE:
4643 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004644 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004645 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4646 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
4647 UPDATE_LAST_CHILD_AND_PARENT(cur)
4648 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004649 case XML_TEXT_NODE:
4650 case XML_CDATA_SECTION_NODE:
4651 case XML_ENTITY_REF_NODE:
4652 case XML_ENTITY_NODE:
4653 case XML_PI_NODE:
4654 case XML_COMMENT_NODE:
4655 case XML_NOTATION_NODE:
4656 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004657 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004658 }
4659 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4660 cur->children = cur->last = NULL;
4661 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004662 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004663 } else
4664 cur->content = NULL;
4665 break;
4666 case XML_DOCUMENT_NODE:
4667 case XML_DTD_NODE:
4668 case XML_HTML_DOCUMENT_NODE:
4669 case XML_DOCUMENT_TYPE_NODE:
4670 case XML_NAMESPACE_DECL:
4671 case XML_XINCLUDE_START:
4672 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004673#ifdef LIBXML_DOCB_ENABLED
4674 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004675#endif
4676 break;
4677 case XML_ELEMENT_DECL:
4678 /* TODO !!! */
4679 break;
4680 case XML_ATTRIBUTE_DECL:
4681 /* TODO !!! */
4682 break;
4683 case XML_ENTITY_DECL:
4684 /* TODO !!! */
4685 break;
4686 }
4687}
4688
4689/**
4690 * xmlNodeAddContentLen:
4691 * @cur: the node being modified
4692 * @content: extra content
4693 * @len: the size of @content
4694 *
4695 * Append the extra substring to the node content.
4696 */
4697void
4698xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4699 if (cur == NULL) {
4700#ifdef DEBUG_TREE
4701 xmlGenericError(xmlGenericErrorContext,
4702 "xmlNodeAddContentLen : node == NULL\n");
4703#endif
4704 return;
4705 }
4706 if (len <= 0) return;
4707 switch (cur->type) {
4708 case XML_DOCUMENT_FRAG_NODE:
4709 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004710 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004711
Daniel Veillard7db37732001-07-12 01:20:08 +00004712 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004713 newNode = xmlNewTextLen(content, len);
4714 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004715 tmp = xmlAddChild(cur, newNode);
4716 if (tmp != newNode)
4717 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004718 if ((last != NULL) && (last->next == newNode)) {
4719 xmlTextMerge(last, newNode);
4720 }
4721 }
4722 break;
4723 }
4724 case XML_ATTRIBUTE_NODE:
4725 break;
4726 case XML_TEXT_NODE:
4727 case XML_CDATA_SECTION_NODE:
4728 case XML_ENTITY_REF_NODE:
4729 case XML_ENTITY_NODE:
4730 case XML_PI_NODE:
4731 case XML_COMMENT_NODE:
4732 case XML_NOTATION_NODE:
4733 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004734 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004735 }
4736 case XML_DOCUMENT_NODE:
4737 case XML_DTD_NODE:
4738 case XML_HTML_DOCUMENT_NODE:
4739 case XML_DOCUMENT_TYPE_NODE:
4740 case XML_NAMESPACE_DECL:
4741 case XML_XINCLUDE_START:
4742 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004743#ifdef LIBXML_DOCB_ENABLED
4744 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004745#endif
4746 break;
4747 case XML_ELEMENT_DECL:
4748 case XML_ATTRIBUTE_DECL:
4749 case XML_ENTITY_DECL:
4750 break;
4751 }
4752}
4753
4754/**
4755 * xmlNodeAddContent:
4756 * @cur: the node being modified
4757 * @content: extra content
4758 *
4759 * Append the extra substring to the node content.
4760 */
4761void
4762xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
4763 int len;
4764
4765 if (cur == NULL) {
4766#ifdef DEBUG_TREE
4767 xmlGenericError(xmlGenericErrorContext,
4768 "xmlNodeAddContent : node == NULL\n");
4769#endif
4770 return;
4771 }
4772 if (content == NULL) return;
4773 len = xmlStrlen(content);
4774 xmlNodeAddContentLen(cur, content, len);
4775}
4776
4777/**
4778 * xmlTextMerge:
4779 * @first: the first text node
4780 * @second: the second text node being merged
4781 *
4782 * Merge two text nodes into one
4783 * Returns the first text node augmented
4784 */
4785xmlNodePtr
4786xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
4787 if (first == NULL) return(second);
4788 if (second == NULL) return(first);
4789 if (first->type != XML_TEXT_NODE) return(first);
4790 if (second->type != XML_TEXT_NODE) return(first);
4791 if (second->name != first->name)
4792 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00004793 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004794 xmlUnlinkNode(second);
4795 xmlFreeNode(second);
4796 return(first);
4797}
4798
4799/**
4800 * xmlGetNsList:
4801 * @doc: the document
4802 * @node: the current node
4803 *
4804 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00004805 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00004806 * that need to be freed by the caller or NULL if no
4807 * namespace if defined
4808 */
4809xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00004810xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
4811{
Owen Taylor3473f882001-02-23 17:55:21 +00004812 xmlNsPtr cur;
4813 xmlNsPtr *ret = NULL;
4814 int nbns = 0;
4815 int maxns = 10;
4816 int i;
4817
4818 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00004819 if (node->type == XML_ELEMENT_NODE) {
4820 cur = node->nsDef;
4821 while (cur != NULL) {
4822 if (ret == NULL) {
4823 ret =
4824 (xmlNsPtr *) xmlMalloc((maxns + 1) *
4825 sizeof(xmlNsPtr));
4826 if (ret == NULL) {
4827 xmlGenericError(xmlGenericErrorContext,
4828 "xmlGetNsList : out of memory!\n");
4829 return (NULL);
4830 }
4831 ret[nbns] = NULL;
4832 }
4833 for (i = 0; i < nbns; i++) {
4834 if ((cur->prefix == ret[i]->prefix) ||
4835 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
4836 break;
4837 }
4838 if (i >= nbns) {
4839 if (nbns >= maxns) {
4840 maxns *= 2;
4841 ret = (xmlNsPtr *) xmlRealloc(ret,
4842 (maxns +
4843 1) *
4844 sizeof(xmlNsPtr));
4845 if (ret == NULL) {
4846 xmlGenericError(xmlGenericErrorContext,
4847 "xmlGetNsList : realloc failed!\n");
4848 return (NULL);
4849 }
4850 }
4851 ret[nbns++] = cur;
4852 ret[nbns] = NULL;
4853 }
Owen Taylor3473f882001-02-23 17:55:21 +00004854
Daniel Veillard77044732001-06-29 21:31:07 +00004855 cur = cur->next;
4856 }
4857 }
4858 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004859 }
Daniel Veillard77044732001-06-29 21:31:07 +00004860 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004861}
4862
4863/**
4864 * xmlSearchNs:
4865 * @doc: the document
4866 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004867 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004868 *
4869 * Search a Ns registered under a given name space for a document.
4870 * recurse on the parents until it finds the defined namespace
4871 * or return NULL otherwise.
4872 * @nameSpace can be NULL, this is a search for the default namespace.
4873 * We don't allow to cross entities boundaries. If you don't declare
4874 * the namespace within those you will be in troubles !!! A warning
4875 * is generated to cover this case.
4876 *
4877 * Returns the namespace pointer or NULL.
4878 */
4879xmlNsPtr
4880xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4881 xmlNsPtr cur;
4882
4883 if (node == NULL) return(NULL);
4884 if ((nameSpace != NULL) &&
4885 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00004886 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4887 /*
4888 * The XML-1.0 namespace is normally held on the root
4889 * element. In this case exceptionally create it on the
4890 * node element.
4891 */
4892 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4893 if (cur == NULL) {
4894 xmlGenericError(xmlGenericErrorContext,
4895 "xmlSearchNs : malloc failed\n");
4896 return(NULL);
4897 }
4898 memset(cur, 0, sizeof(xmlNs));
4899 cur->type = XML_LOCAL_NAMESPACE;
4900 cur->href = xmlStrdup(XML_XML_NAMESPACE);
4901 cur->prefix = xmlStrdup((const xmlChar *)"xml");
4902 cur->next = node->nsDef;
4903 node->nsDef = cur;
4904 return(cur);
4905 }
Owen Taylor3473f882001-02-23 17:55:21 +00004906 if (doc->oldNs == NULL) {
4907 /*
4908 * Allocate a new Namespace and fill the fields.
4909 */
4910 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4911 if (doc->oldNs == NULL) {
4912 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004913 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004914 return(NULL);
4915 }
4916 memset(doc->oldNs, 0, sizeof(xmlNs));
4917 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4918
4919 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4920 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4921 }
4922 return(doc->oldNs);
4923 }
4924 while (node != NULL) {
4925 if ((node->type == XML_ENTITY_REF_NODE) ||
4926 (node->type == XML_ENTITY_NODE) ||
4927 (node->type == XML_ENTITY_DECL))
4928 return(NULL);
4929 if (node->type == XML_ELEMENT_NODE) {
4930 cur = node->nsDef;
4931 while (cur != NULL) {
4932 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
4933 (cur->href != NULL))
4934 return(cur);
4935 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
4936 (cur->href != NULL) &&
4937 (xmlStrEqual(cur->prefix, nameSpace)))
4938 return(cur);
4939 cur = cur->next;
4940 }
4941 }
4942 node = node->parent;
4943 }
4944 return(NULL);
4945}
4946
4947/**
4948 * xmlSearchNsByHref:
4949 * @doc: the document
4950 * @node: the current node
4951 * @href: the namespace value
4952 *
4953 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
4954 * the defined namespace or return NULL otherwise.
4955 * Returns the namespace pointer or NULL.
4956 */
4957xmlNsPtr
4958xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
4959 xmlNsPtr cur;
4960 xmlNodePtr orig = node;
4961
4962 if ((node == NULL) || (href == NULL)) return(NULL);
4963 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004964 /*
4965 * Only the document can hold the XML spec namespace.
4966 */
Daniel Veillardc1a0da32002-08-14 08:32:18 +00004967 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4968 /*
4969 * The XML-1.0 namespace is normally held on the root
4970 * element. In this case exceptionally create it on the
4971 * node element.
4972 */
4973 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4974 if (cur == NULL) {
4975 xmlGenericError(xmlGenericErrorContext,
4976 "xmlSearchNs : malloc failed\n");
4977 return(NULL);
4978 }
4979 memset(cur, 0, sizeof(xmlNs));
4980 cur->type = XML_LOCAL_NAMESPACE;
4981 cur->href = xmlStrdup(XML_XML_NAMESPACE);
4982 cur->prefix = xmlStrdup((const xmlChar *)"xml");
4983 cur->next = node->nsDef;
4984 node->nsDef = cur;
4985 return(cur);
4986 }
Owen Taylor3473f882001-02-23 17:55:21 +00004987 if (doc->oldNs == NULL) {
4988 /*
4989 * Allocate a new Namespace and fill the fields.
4990 */
4991 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4992 if (doc->oldNs == NULL) {
4993 xmlGenericError(xmlGenericErrorContext,
4994 "xmlSearchNsByHref : malloc failed\n");
4995 return(NULL);
4996 }
4997 memset(doc->oldNs, 0, sizeof(xmlNs));
4998 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4999
5000 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5001 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5002 }
5003 return(doc->oldNs);
5004 }
5005 while (node != NULL) {
5006 cur = node->nsDef;
5007 while (cur != NULL) {
5008 if ((cur->href != NULL) && (href != NULL) &&
5009 (xmlStrEqual(cur->href, href))) {
5010 /*
5011 * Check that the prefix is not shadowed between orig and node
5012 */
5013 xmlNodePtr check = orig;
5014 xmlNsPtr tst;
5015
5016 while (check != node) {
5017 tst = check->nsDef;
5018 while (tst != NULL) {
5019 if ((tst->prefix == NULL) && (cur->prefix == NULL))
5020 goto shadowed;
5021 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
5022 (xmlStrEqual(tst->prefix, cur->prefix)))
5023 goto shadowed;
5024 tst = tst->next;
5025 }
5026 check = check->parent;
5027 }
5028 return(cur);
5029 }
5030shadowed:
5031 cur = cur->next;
5032 }
5033 node = node->parent;
5034 }
5035 return(NULL);
5036}
5037
5038/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005039 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005040 * @doc: the document
5041 * @tree: a node expected to hold the new namespace
5042 * @ns: the original namespace
5043 *
5044 * This function tries to locate a namespace definition in a tree
5045 * ancestors, or create a new namespace definition node similar to
5046 * @ns trying to reuse the same prefix. However if the given prefix is
5047 * null (default namespace) or reused within the subtree defined by
5048 * @tree or on one of its ancestors then a new prefix is generated.
5049 * Returns the (new) namespace definition or NULL in case of error
5050 */
5051xmlNsPtr
5052xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5053 xmlNsPtr def;
5054 xmlChar prefix[50];
5055 int counter = 1;
5056
5057 if (tree == NULL) {
5058#ifdef DEBUG_TREE
5059 xmlGenericError(xmlGenericErrorContext,
5060 "xmlNewReconciliedNs : tree == NULL\n");
5061#endif
5062 return(NULL);
5063 }
5064 if (ns == NULL) {
5065#ifdef DEBUG_TREE
5066 xmlGenericError(xmlGenericErrorContext,
5067 "xmlNewReconciliedNs : ns == NULL\n");
5068#endif
5069 return(NULL);
5070 }
5071 /*
5072 * Search an existing namespace definition inherited.
5073 */
5074 def = xmlSearchNsByHref(doc, tree, ns->href);
5075 if (def != NULL)
5076 return(def);
5077
5078 /*
5079 * Find a close prefix which is not already in use.
5080 * Let's strip namespace prefixes longer than 20 chars !
5081 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005082 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005083 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005084 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005085 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005086
Owen Taylor3473f882001-02-23 17:55:21 +00005087 def = xmlSearchNs(doc, tree, prefix);
5088 while (def != NULL) {
5089 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005090 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005091 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005092 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005093 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005094 def = xmlSearchNs(doc, tree, prefix);
5095 }
5096
5097 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005098 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005099 */
5100 def = xmlNewNs(tree, ns->href, prefix);
5101 return(def);
5102}
5103
5104/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005105 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005106 * @doc: the document
5107 * @tree: a node defining the subtree to reconciliate
5108 *
5109 * This function checks that all the namespaces declared within the given
5110 * tree are properly declared. This is needed for example after Copy or Cut
5111 * and then paste operations. The subtree may still hold pointers to
5112 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005113 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005114 * the new environment. If not possible the new namespaces are redeclared
5115 * on @tree at the top of the given subtree.
5116 * Returns the number of namespace declarations created or -1 in case of error.
5117 */
5118int
5119xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5120 xmlNsPtr *oldNs = NULL;
5121 xmlNsPtr *newNs = NULL;
5122 int sizeCache = 0;
5123 int nbCache = 0;
5124
5125 xmlNsPtr n;
5126 xmlNodePtr node = tree;
5127 xmlAttrPtr attr;
5128 int ret = 0, i;
5129
5130 while (node != NULL) {
5131 /*
5132 * Reconciliate the node namespace
5133 */
5134 if (node->ns != NULL) {
5135 /*
5136 * initialize the cache if needed
5137 */
5138 if (sizeCache == 0) {
5139 sizeCache = 10;
5140 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5141 sizeof(xmlNsPtr));
5142 if (oldNs == NULL) {
5143 xmlGenericError(xmlGenericErrorContext,
5144 "xmlReconciliateNs : memory pbm\n");
5145 return(-1);
5146 }
5147 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5148 sizeof(xmlNsPtr));
5149 if (newNs == NULL) {
5150 xmlGenericError(xmlGenericErrorContext,
5151 "xmlReconciliateNs : memory pbm\n");
5152 xmlFree(oldNs);
5153 return(-1);
5154 }
5155 }
5156 for (i = 0;i < nbCache;i++) {
5157 if (oldNs[i] == node->ns) {
5158 node->ns = newNs[i];
5159 break;
5160 }
5161 }
5162 if (i == nbCache) {
5163 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005164 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005165 */
5166 n = xmlNewReconciliedNs(doc, tree, node->ns);
5167 if (n != NULL) { /* :-( what if else ??? */
5168 /*
5169 * check if we need to grow the cache buffers.
5170 */
5171 if (sizeCache <= nbCache) {
5172 sizeCache *= 2;
5173 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5174 sizeof(xmlNsPtr));
5175 if (oldNs == NULL) {
5176 xmlGenericError(xmlGenericErrorContext,
5177 "xmlReconciliateNs : memory pbm\n");
5178 xmlFree(newNs);
5179 return(-1);
5180 }
5181 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5182 sizeof(xmlNsPtr));
5183 if (newNs == NULL) {
5184 xmlGenericError(xmlGenericErrorContext,
5185 "xmlReconciliateNs : memory pbm\n");
5186 xmlFree(oldNs);
5187 return(-1);
5188 }
5189 }
5190 newNs[nbCache] = n;
5191 oldNs[nbCache++] = node->ns;
5192 node->ns = n;
5193 }
5194 }
5195 }
5196 /*
5197 * now check for namespace hold by attributes on the node.
5198 */
5199 attr = node->properties;
5200 while (attr != NULL) {
5201 if (attr->ns != NULL) {
5202 /*
5203 * initialize the cache if needed
5204 */
5205 if (sizeCache == 0) {
5206 sizeCache = 10;
5207 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5208 sizeof(xmlNsPtr));
5209 if (oldNs == NULL) {
5210 xmlGenericError(xmlGenericErrorContext,
5211 "xmlReconciliateNs : memory pbm\n");
5212 return(-1);
5213 }
5214 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5215 sizeof(xmlNsPtr));
5216 if (newNs == NULL) {
5217 xmlGenericError(xmlGenericErrorContext,
5218 "xmlReconciliateNs : memory pbm\n");
5219 xmlFree(oldNs);
5220 return(-1);
5221 }
5222 }
5223 for (i = 0;i < nbCache;i++) {
5224 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005225 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005226 break;
5227 }
5228 }
5229 if (i == nbCache) {
5230 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005231 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005232 */
5233 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5234 if (n != NULL) { /* :-( what if else ??? */
5235 /*
5236 * check if we need to grow the cache buffers.
5237 */
5238 if (sizeCache <= nbCache) {
5239 sizeCache *= 2;
5240 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5241 sizeof(xmlNsPtr));
5242 if (oldNs == NULL) {
5243 xmlGenericError(xmlGenericErrorContext,
5244 "xmlReconciliateNs : memory pbm\n");
5245 xmlFree(newNs);
5246 return(-1);
5247 }
5248 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5249 sizeof(xmlNsPtr));
5250 if (newNs == NULL) {
5251 xmlGenericError(xmlGenericErrorContext,
5252 "xmlReconciliateNs : memory pbm\n");
5253 xmlFree(oldNs);
5254 return(-1);
5255 }
5256 }
5257 newNs[nbCache] = n;
5258 oldNs[nbCache++] = attr->ns;
5259 attr->ns = n;
5260 }
5261 }
5262 }
5263 attr = attr->next;
5264 }
5265
5266 /*
5267 * Browse the full subtree, deep first
5268 */
5269 if (node->children != NULL) {
5270 /* deep first */
5271 node = node->children;
5272 } else if ((node != tree) && (node->next != NULL)) {
5273 /* then siblings */
5274 node = node->next;
5275 } else if (node != tree) {
5276 /* go up to parents->next if needed */
5277 while (node != tree) {
5278 if (node->parent != NULL)
5279 node = node->parent;
5280 if ((node != tree) && (node->next != NULL)) {
5281 node = node->next;
5282 break;
5283 }
5284 if (node->parent == NULL) {
5285 node = NULL;
5286 break;
5287 }
5288 }
5289 /* exit condition */
5290 if (node == tree)
5291 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005292 } else
5293 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005294 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005295 if (oldNs != NULL)
5296 xmlFree(oldNs);
5297 if (newNs != NULL)
5298 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005299 return(ret);
5300}
5301
5302/**
5303 * xmlHasProp:
5304 * @node: the node
5305 * @name: the attribute name
5306 *
5307 * Search an attribute associated to a node
5308 * This function also looks in DTD attribute declaration for #FIXED or
5309 * default declaration values unless DTD use has been turned off.
5310 *
5311 * Returns the attribute or the attribute declaration or NULL if
5312 * neither was found.
5313 */
5314xmlAttrPtr
5315xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5316 xmlAttrPtr prop;
5317 xmlDocPtr doc;
5318
5319 if ((node == NULL) || (name == NULL)) return(NULL);
5320 /*
5321 * Check on the properties attached to the node
5322 */
5323 prop = node->properties;
5324 while (prop != NULL) {
5325 if (xmlStrEqual(prop->name, name)) {
5326 return(prop);
5327 }
5328 prop = prop->next;
5329 }
5330 if (!xmlCheckDTD) return(NULL);
5331
5332 /*
5333 * Check if there is a default declaration in the internal
5334 * or external subsets
5335 */
5336 doc = node->doc;
5337 if (doc != NULL) {
5338 xmlAttributePtr attrDecl;
5339 if (doc->intSubset != NULL) {
5340 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5341 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5342 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5343 if (attrDecl != NULL)
5344 return((xmlAttrPtr) attrDecl);
5345 }
5346 }
5347 return(NULL);
5348}
5349
5350/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005351 * xmlHasNsProp:
5352 * @node: the node
5353 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005354 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005355 *
5356 * Search for an attribute associated to a node
5357 * This attribute has to be anchored in the namespace specified.
5358 * This does the entity substitution.
5359 * This function looks in DTD attribute declaration for #FIXED or
5360 * default declaration values unless DTD use has been turned off.
5361 *
5362 * Returns the attribute or the attribute declaration or NULL
5363 * if neither was found.
5364 */
5365xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005366xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005367 xmlAttrPtr prop;
5368 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005369
5370 if (node == NULL)
5371 return(NULL);
5372
5373 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005374 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005375 return(xmlHasProp(node, name));
5376 while (prop != NULL) {
5377 /*
5378 * One need to have
5379 * - same attribute names
5380 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005381 */
5382 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005383 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5384 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005385 }
5386 prop = prop->next;
5387 }
5388 if (!xmlCheckDTD) return(NULL);
5389
5390 /*
5391 * Check if there is a default declaration in the internal
5392 * or external subsets
5393 */
5394 doc = node->doc;
5395 if (doc != NULL) {
5396 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005397 xmlAttributePtr attrDecl = NULL;
5398 xmlNsPtr *nsList, *cur;
5399 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005400
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005401 nsList = xmlGetNsList(node->doc, node);
5402 if (nsList == NULL)
5403 return(NULL);
5404 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5405 ename = xmlStrdup(node->ns->prefix);
5406 ename = xmlStrcat(ename, BAD_CAST ":");
5407 ename = xmlStrcat(ename, node->name);
5408 } else {
5409 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005410 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005411 if (ename == NULL) {
5412 xmlFree(nsList);
5413 return(NULL);
5414 }
5415
5416 cur = nsList;
5417 while (*cur != NULL) {
5418 if (xmlStrEqual((*cur)->href, nameSpace)) {
5419 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5420 name, (*cur)->prefix);
5421 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5422 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5423 name, (*cur)->prefix);
5424 }
5425 cur++;
5426 }
5427 xmlFree(nsList);
5428 xmlFree(ename);
5429 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005430 }
5431 }
5432 return(NULL);
5433}
5434
5435/**
Owen Taylor3473f882001-02-23 17:55:21 +00005436 * xmlGetProp:
5437 * @node: the node
5438 * @name: the attribute name
5439 *
5440 * Search and get the value of an attribute associated to a node
5441 * This does the entity substitution.
5442 * This function looks in DTD attribute declaration for #FIXED or
5443 * default declaration values unless DTD use has been turned off.
Daniel Veillard71531f32003-02-05 13:19:53 +00005444 * NOTE: this function acts independantly of namespaces associated
5445 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
5446 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00005447 *
5448 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005449 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005450 */
5451xmlChar *
5452xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5453 xmlAttrPtr prop;
5454 xmlDocPtr doc;
5455
5456 if ((node == NULL) || (name == NULL)) return(NULL);
5457 /*
5458 * Check on the properties attached to the node
5459 */
5460 prop = node->properties;
5461 while (prop != NULL) {
5462 if (xmlStrEqual(prop->name, name)) {
5463 xmlChar *ret;
5464
5465 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5466 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5467 return(ret);
5468 }
5469 prop = prop->next;
5470 }
5471 if (!xmlCheckDTD) return(NULL);
5472
5473 /*
5474 * Check if there is a default declaration in the internal
5475 * or external subsets
5476 */
5477 doc = node->doc;
5478 if (doc != NULL) {
5479 xmlAttributePtr attrDecl;
5480 if (doc->intSubset != NULL) {
5481 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5482 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5483 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5484 if (attrDecl != NULL)
5485 return(xmlStrdup(attrDecl->defaultValue));
5486 }
5487 }
5488 return(NULL);
5489}
5490
5491/**
Daniel Veillard71531f32003-02-05 13:19:53 +00005492 * xmlGetNoNsProp:
5493 * @node: the node
5494 * @name: the attribute name
5495 *
5496 * Search and get the value of an attribute associated to a node
5497 * This does the entity substitution.
5498 * This function looks in DTD attribute declaration for #FIXED or
5499 * default declaration values unless DTD use has been turned off.
5500 * This function is similar to xmlGetProp except it will accept only
5501 * an attribute in no namespace.
5502 *
5503 * Returns the attribute value or NULL if not found.
5504 * It's up to the caller to free the memory with xmlFree().
5505 */
5506xmlChar *
5507xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
5508 xmlAttrPtr prop;
5509 xmlDocPtr doc;
5510
5511 if ((node == NULL) || (name == NULL)) return(NULL);
5512 /*
5513 * Check on the properties attached to the node
5514 */
5515 prop = node->properties;
5516 while (prop != NULL) {
5517 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
5518 xmlChar *ret;
5519
5520 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5521 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5522 return(ret);
5523 }
5524 prop = prop->next;
5525 }
5526 if (!xmlCheckDTD) return(NULL);
5527
5528 /*
5529 * Check if there is a default declaration in the internal
5530 * or external subsets
5531 */
5532 doc = node->doc;
5533 if (doc != NULL) {
5534 xmlAttributePtr attrDecl;
5535 if (doc->intSubset != NULL) {
5536 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5537 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5538 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5539 if (attrDecl != NULL)
5540 return(xmlStrdup(attrDecl->defaultValue));
5541 }
5542 }
5543 return(NULL);
5544}
5545
5546/**
Owen Taylor3473f882001-02-23 17:55:21 +00005547 * xmlGetNsProp:
5548 * @node: the node
5549 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005550 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005551 *
5552 * Search and get the value of an attribute associated to a node
5553 * This attribute has to be anchored in the namespace specified.
5554 * This does the entity substitution.
5555 * This function looks in DTD attribute declaration for #FIXED or
5556 * default declaration values unless DTD use has been turned off.
5557 *
5558 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005559 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005560 */
5561xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00005562xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00005563 xmlAttrPtr prop;
5564 xmlDocPtr doc;
5565 xmlNsPtr ns;
5566
5567 if (node == NULL)
5568 return(NULL);
5569
5570 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005571 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00005572 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00005573 while (prop != NULL) {
5574 /*
5575 * One need to have
5576 * - same attribute names
5577 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005578 */
5579 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00005580 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00005581 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005582 xmlChar *ret;
5583
5584 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5585 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5586 return(ret);
5587 }
5588 prop = prop->next;
5589 }
5590 if (!xmlCheckDTD) return(NULL);
5591
5592 /*
5593 * Check if there is a default declaration in the internal
5594 * or external subsets
5595 */
5596 doc = node->doc;
5597 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005598 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00005599 xmlAttributePtr attrDecl;
5600
Owen Taylor3473f882001-02-23 17:55:21 +00005601 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5602 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5603 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5604
5605 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
5606 /*
5607 * The DTD declaration only allows a prefix search
5608 */
5609 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00005610 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00005611 return(xmlStrdup(attrDecl->defaultValue));
5612 }
5613 }
5614 }
5615 return(NULL);
5616}
5617
5618/**
5619 * xmlSetProp:
5620 * @node: the node
5621 * @name: the attribute name
5622 * @value: the attribute value
5623 *
5624 * Set (or reset) an attribute carried by a node.
5625 * Returns the attribute pointer.
5626 */
5627xmlAttrPtr
5628xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005629 xmlAttrPtr prop;
5630 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00005631
5632 if ((node == NULL) || (name == NULL))
5633 return(NULL);
5634 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005635 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00005636 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005637 if ((xmlStrEqual(prop->name, name)) &&
5638 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005639 xmlNodePtr oldprop = prop->children;
5640
Owen Taylor3473f882001-02-23 17:55:21 +00005641 prop->children = NULL;
5642 prop->last = NULL;
5643 if (value != NULL) {
5644 xmlChar *buffer;
5645 xmlNodePtr tmp;
5646
5647 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5648 prop->children = xmlStringGetNodeList(node->doc, buffer);
5649 prop->last = NULL;
5650 prop->doc = doc;
5651 tmp = prop->children;
5652 while (tmp != NULL) {
5653 tmp->parent = (xmlNodePtr) prop;
5654 tmp->doc = doc;
5655 if (tmp->next == NULL)
5656 prop->last = tmp;
5657 tmp = tmp->next;
5658 }
5659 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00005660 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005661 if (oldprop != NULL)
5662 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00005663 return(prop);
5664 }
5665 prop = prop->next;
5666 }
5667 prop = xmlNewProp(node, name, value);
5668 return(prop);
5669}
5670
5671/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005672 * xmlUnsetProp:
5673 * @node: the node
5674 * @name: the attribute name
5675 *
5676 * Remove an attribute carried by a node.
5677 * Returns 0 if successful, -1 if not found
5678 */
5679int
5680xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Daniel Veillard814a76d2003-01-23 18:24:20 +00005681 xmlAttrPtr prop, prev = NULL;;
Daniel Veillard75bea542001-05-11 17:41:21 +00005682
5683 if ((node == NULL) || (name == NULL))
5684 return(-1);
Daniel Veillard814a76d2003-01-23 18:24:20 +00005685 prop = node->properties;
Daniel Veillard75bea542001-05-11 17:41:21 +00005686 while (prop != NULL) {
5687 if ((xmlStrEqual(prop->name, name)) &&
5688 (prop->ns == NULL)) {
5689 if (prev == NULL)
5690 node->properties = prop->next;
5691 else
5692 prev->next = prop->next;
5693 xmlFreeProp(prop);
5694 return(0);
5695 }
5696 prev = prop;
5697 prop = prop->next;
5698 }
5699 return(-1);
5700}
5701
5702/**
Owen Taylor3473f882001-02-23 17:55:21 +00005703 * xmlSetNsProp:
5704 * @node: the node
5705 * @ns: the namespace definition
5706 * @name: the attribute name
5707 * @value: the attribute value
5708 *
5709 * Set (or reset) an attribute carried by a node.
5710 * The ns structure must be in scope, this is not checked.
5711 *
5712 * Returns the attribute pointer.
5713 */
5714xmlAttrPtr
5715xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
5716 const xmlChar *value) {
5717 xmlAttrPtr prop;
5718
5719 if ((node == NULL) || (name == NULL))
5720 return(NULL);
5721
5722 if (ns == NULL)
5723 return(xmlSetProp(node, name, value));
5724 if (ns->href == NULL)
5725 return(NULL);
5726 prop = node->properties;
5727
5728 while (prop != NULL) {
5729 /*
5730 * One need to have
5731 * - same attribute names
5732 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005733 */
5734 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00005735 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005736 if (prop->children != NULL)
5737 xmlFreeNodeList(prop->children);
5738 prop->children = NULL;
5739 prop->last = NULL;
5740 prop->ns = ns;
5741 if (value != NULL) {
5742 xmlChar *buffer;
5743 xmlNodePtr tmp;
5744
5745 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5746 prop->children = xmlStringGetNodeList(node->doc, buffer);
5747 prop->last = NULL;
5748 tmp = prop->children;
5749 while (tmp != NULL) {
5750 tmp->parent = (xmlNodePtr) prop;
5751 if (tmp->next == NULL)
5752 prop->last = tmp;
5753 tmp = tmp->next;
5754 }
5755 xmlFree(buffer);
5756 }
5757 return(prop);
5758 }
5759 prop = prop->next;
5760 }
5761 prop = xmlNewNsProp(node, ns, name, value);
5762 return(prop);
5763}
5764
5765/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005766 * xmlUnsetNsProp:
5767 * @node: the node
5768 * @ns: the namespace definition
5769 * @name: the attribute name
5770 *
5771 * Remove an attribute carried by a node.
5772 * Returns 0 if successful, -1 if not found
5773 */
5774int
5775xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
5776 xmlAttrPtr prop = node->properties, prev = NULL;;
5777
5778 if ((node == NULL) || (name == NULL))
5779 return(-1);
5780 if (ns == NULL)
5781 return(xmlUnsetProp(node, name));
5782 if (ns->href == NULL)
5783 return(-1);
5784 while (prop != NULL) {
5785 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00005786 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005787 if (prev == NULL)
5788 node->properties = prop->next;
5789 else
5790 prev->next = prop->next;
5791 xmlFreeProp(prop);
5792 return(0);
5793 }
5794 prev = prop;
5795 prop = prop->next;
5796 }
5797 return(-1);
5798}
5799
5800/**
Owen Taylor3473f882001-02-23 17:55:21 +00005801 * xmlNodeIsText:
5802 * @node: the node
5803 *
5804 * Is this node a Text node ?
5805 * Returns 1 yes, 0 no
5806 */
5807int
5808xmlNodeIsText(xmlNodePtr node) {
5809 if (node == NULL) return(0);
5810
5811 if (node->type == XML_TEXT_NODE) return(1);
5812 return(0);
5813}
5814
5815/**
5816 * xmlIsBlankNode:
5817 * @node: the node
5818 *
5819 * Checks whether this node is an empty or whitespace only
5820 * (and possibly ignorable) text-node.
5821 *
5822 * Returns 1 yes, 0 no
5823 */
5824int
5825xmlIsBlankNode(xmlNodePtr node) {
5826 const xmlChar *cur;
5827 if (node == NULL) return(0);
5828
Daniel Veillard7db37732001-07-12 01:20:08 +00005829 if ((node->type != XML_TEXT_NODE) &&
5830 (node->type != XML_CDATA_SECTION_NODE))
5831 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005832 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00005833 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00005834 while (*cur != 0) {
5835 if (!IS_BLANK(*cur)) return(0);
5836 cur++;
5837 }
5838
5839 return(1);
5840}
5841
5842/**
5843 * xmlTextConcat:
5844 * @node: the node
5845 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00005846 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00005847 *
5848 * Concat the given string at the end of the existing node content
5849 */
5850
5851void
5852xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
5853 if (node == NULL) return;
5854
5855 if ((node->type != XML_TEXT_NODE) &&
5856 (node->type != XML_CDATA_SECTION_NODE)) {
5857#ifdef DEBUG_TREE
5858 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005859 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005860#endif
5861 return;
5862 }
Owen Taylor3473f882001-02-23 17:55:21 +00005863 node->content = xmlStrncat(node->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005864}
5865
5866/************************************************************************
5867 * *
5868 * Output : to a FILE or in memory *
5869 * *
5870 ************************************************************************/
5871
Owen Taylor3473f882001-02-23 17:55:21 +00005872/**
5873 * xmlBufferCreate:
5874 *
5875 * routine to create an XML buffer.
5876 * returns the new structure.
5877 */
5878xmlBufferPtr
5879xmlBufferCreate(void) {
5880 xmlBufferPtr ret;
5881
5882 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5883 if (ret == NULL) {
5884 xmlGenericError(xmlGenericErrorContext,
5885 "xmlBufferCreate : out of memory!\n");
5886 return(NULL);
5887 }
5888 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00005889 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00005890 ret->alloc = xmlBufferAllocScheme;
5891 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5892 if (ret->content == NULL) {
5893 xmlGenericError(xmlGenericErrorContext,
5894 "xmlBufferCreate : out of memory!\n");
5895 xmlFree(ret);
5896 return(NULL);
5897 }
5898 ret->content[0] = 0;
5899 return(ret);
5900}
5901
5902/**
5903 * xmlBufferCreateSize:
5904 * @size: initial size of buffer
5905 *
5906 * routine to create an XML buffer.
5907 * returns the new structure.
5908 */
5909xmlBufferPtr
5910xmlBufferCreateSize(size_t size) {
5911 xmlBufferPtr ret;
5912
5913 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5914 if (ret == NULL) {
5915 xmlGenericError(xmlGenericErrorContext,
5916 "xmlBufferCreate : out of memory!\n");
5917 return(NULL);
5918 }
5919 ret->use = 0;
5920 ret->alloc = xmlBufferAllocScheme;
5921 ret->size = (size ? size+2 : 0); /* +1 for ending null */
5922 if (ret->size){
5923 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5924 if (ret->content == NULL) {
5925 xmlGenericError(xmlGenericErrorContext,
5926 "xmlBufferCreate : out of memory!\n");
5927 xmlFree(ret);
5928 return(NULL);
5929 }
5930 ret->content[0] = 0;
5931 } else
5932 ret->content = NULL;
5933 return(ret);
5934}
5935
5936/**
5937 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005938 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00005939 * @scheme: allocation scheme to use
5940 *
5941 * Sets the allocation scheme for this buffer
5942 */
5943void
5944xmlBufferSetAllocationScheme(xmlBufferPtr buf,
5945 xmlBufferAllocationScheme scheme) {
5946 if (buf == NULL) {
5947#ifdef DEBUG_BUFFER
5948 xmlGenericError(xmlGenericErrorContext,
5949 "xmlBufferSetAllocationScheme: buf == NULL\n");
5950#endif
5951 return;
5952 }
5953
5954 buf->alloc = scheme;
5955}
5956
5957/**
5958 * xmlBufferFree:
5959 * @buf: the buffer to free
5960 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00005961 * Frees an XML buffer. It frees both the content and the structure which
5962 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00005963 */
5964void
5965xmlBufferFree(xmlBufferPtr buf) {
5966 if (buf == NULL) {
5967#ifdef DEBUG_BUFFER
5968 xmlGenericError(xmlGenericErrorContext,
5969 "xmlBufferFree: buf == NULL\n");
5970#endif
5971 return;
5972 }
Daniel Veillard561b7f82002-03-20 21:55:57 +00005973 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005974 xmlFree(buf->content);
5975 }
Owen Taylor3473f882001-02-23 17:55:21 +00005976 xmlFree(buf);
5977}
5978
5979/**
5980 * xmlBufferEmpty:
5981 * @buf: the buffer
5982 *
5983 * empty a buffer.
5984 */
5985void
5986xmlBufferEmpty(xmlBufferPtr buf) {
5987 if (buf->content == NULL) return;
5988 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005989 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00005990}
5991
5992/**
5993 * xmlBufferShrink:
5994 * @buf: the buffer to dump
5995 * @len: the number of xmlChar to remove
5996 *
5997 * Remove the beginning of an XML buffer.
5998 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005999 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006000 */
6001int
6002xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
6003 if (len == 0) return(0);
6004 if (len > buf->use) return(-1);
6005
6006 buf->use -= len;
6007 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6008
6009 buf->content[buf->use] = 0;
6010 return(len);
6011}
6012
6013/**
6014 * xmlBufferGrow:
6015 * @buf: the buffer
6016 * @len: the minimum free size to allocate
6017 *
6018 * Grow the available space of an XML buffer.
6019 *
6020 * Returns the new available space or -1 in case of error
6021 */
6022int
6023xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6024 int size;
6025 xmlChar *newbuf;
6026
6027 if (len + buf->use < buf->size) return(0);
6028
6029 size = buf->use + len + 100;
6030
6031 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
6032 if (newbuf == NULL) return(-1);
6033 buf->content = newbuf;
6034 buf->size = size;
6035 return(buf->size - buf->use);
6036}
6037
6038/**
6039 * xmlBufferDump:
6040 * @file: the file output
6041 * @buf: the buffer to dump
6042 *
6043 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006044 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006045 */
6046int
6047xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6048 int ret;
6049
6050 if (buf == NULL) {
6051#ifdef DEBUG_BUFFER
6052 xmlGenericError(xmlGenericErrorContext,
6053 "xmlBufferDump: buf == NULL\n");
6054#endif
6055 return(0);
6056 }
6057 if (buf->content == NULL) {
6058#ifdef DEBUG_BUFFER
6059 xmlGenericError(xmlGenericErrorContext,
6060 "xmlBufferDump: buf->content == NULL\n");
6061#endif
6062 return(0);
6063 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006064 if (file == NULL)
6065 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006066 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6067 return(ret);
6068}
6069
6070/**
6071 * xmlBufferContent:
6072 * @buf: the buffer
6073 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006074 * Function to extract the content of a buffer
6075 *
Owen Taylor3473f882001-02-23 17:55:21 +00006076 * Returns the internal content
6077 */
6078
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006079const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006080xmlBufferContent(const xmlBufferPtr buf)
6081{
6082 if(!buf)
6083 return NULL;
6084
6085 return buf->content;
6086}
6087
6088/**
6089 * xmlBufferLength:
6090 * @buf: the buffer
6091 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006092 * Function to get the length of a buffer
6093 *
Owen Taylor3473f882001-02-23 17:55:21 +00006094 * Returns the length of data in the internal content
6095 */
6096
6097int
6098xmlBufferLength(const xmlBufferPtr buf)
6099{
6100 if(!buf)
6101 return 0;
6102
6103 return buf->use;
6104}
6105
6106/**
6107 * xmlBufferResize:
6108 * @buf: the buffer to resize
6109 * @size: the desired size
6110 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006111 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006112 *
6113 * Returns 0 in case of problems, 1 otherwise
6114 */
6115int
6116xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6117{
6118 unsigned int newSize;
6119 xmlChar* rebuf = NULL;
6120
6121 /*take care of empty case*/
6122 newSize = (buf->size ? buf->size*2 : size);
6123
6124 /* Don't resize if we don't have to */
6125 if (size < buf->size)
6126 return 1;
6127
6128 /* figure out new size */
6129 switch (buf->alloc){
6130 case XML_BUFFER_ALLOC_DOUBLEIT:
6131 while (size > newSize) newSize *= 2;
6132 break;
6133 case XML_BUFFER_ALLOC_EXACT:
6134 newSize = size+10;
6135 break;
6136 default:
6137 newSize = size+10;
6138 break;
6139 }
6140
6141 if (buf->content == NULL)
6142 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
6143 else
6144 rebuf = (xmlChar *) xmlRealloc(buf->content,
6145 newSize * sizeof(xmlChar));
6146 if (rebuf == NULL) {
6147 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006148 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006149 return 0;
6150 }
6151 buf->content = rebuf;
6152 buf->size = newSize;
6153
6154 return 1;
6155}
6156
6157/**
6158 * xmlBufferAdd:
6159 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006160 * @str: the #xmlChar string
6161 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006162 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006163 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006164 * str is recomputed.
6165 */
6166void
6167xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6168 unsigned int needSize;
6169
6170 if (str == NULL) {
6171#ifdef DEBUG_BUFFER
6172 xmlGenericError(xmlGenericErrorContext,
6173 "xmlBufferAdd: str == NULL\n");
6174#endif
6175 return;
6176 }
6177 if (len < -1) {
6178#ifdef DEBUG_BUFFER
6179 xmlGenericError(xmlGenericErrorContext,
6180 "xmlBufferAdd: len < 0\n");
6181#endif
6182 return;
6183 }
6184 if (len == 0) return;
6185
6186 if (len < 0)
6187 len = xmlStrlen(str);
6188
6189 if (len <= 0) return;
6190
6191 needSize = buf->use + len + 2;
6192 if (needSize > buf->size){
6193 if (!xmlBufferResize(buf, needSize)){
6194 xmlGenericError(xmlGenericErrorContext,
6195 "xmlBufferAdd : out of memory!\n");
6196 return;
6197 }
6198 }
6199
6200 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6201 buf->use += len;
6202 buf->content[buf->use] = 0;
6203}
6204
6205/**
6206 * xmlBufferAddHead:
6207 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006208 * @str: the #xmlChar string
6209 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006210 *
6211 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006212 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00006213 */
6214void
6215xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6216 unsigned int needSize;
6217
6218 if (str == NULL) {
6219#ifdef DEBUG_BUFFER
6220 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006221 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006222#endif
6223 return;
6224 }
6225 if (len < -1) {
6226#ifdef DEBUG_BUFFER
6227 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006228 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006229#endif
6230 return;
6231 }
6232 if (len == 0) return;
6233
6234 if (len < 0)
6235 len = xmlStrlen(str);
6236
6237 if (len <= 0) return;
6238
6239 needSize = buf->use + len + 2;
6240 if (needSize > buf->size){
6241 if (!xmlBufferResize(buf, needSize)){
6242 xmlGenericError(xmlGenericErrorContext,
6243 "xmlBufferAddHead : out of memory!\n");
6244 return;
6245 }
6246 }
6247
6248 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6249 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6250 buf->use += len;
6251 buf->content[buf->use] = 0;
6252}
6253
6254/**
6255 * xmlBufferCat:
6256 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006257 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006258 *
6259 * Append a zero terminated string to an XML buffer.
6260 */
6261void
6262xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
6263 if (str != NULL)
6264 xmlBufferAdd(buf, str, -1);
6265}
6266
6267/**
6268 * xmlBufferCCat:
6269 * @buf: the buffer to dump
6270 * @str: the C char string
6271 *
6272 * Append a zero terminated C string to an XML buffer.
6273 */
6274void
6275xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6276 const char *cur;
6277
6278 if (str == NULL) {
6279#ifdef DEBUG_BUFFER
6280 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006281 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006282#endif
6283 return;
6284 }
6285 for (cur = str;*cur != 0;cur++) {
6286 if (buf->use + 10 >= buf->size) {
6287 if (!xmlBufferResize(buf, buf->use+10)){
6288 xmlGenericError(xmlGenericErrorContext,
6289 "xmlBufferCCat : out of memory!\n");
6290 return;
6291 }
6292 }
6293 buf->content[buf->use++] = *cur;
6294 }
6295 buf->content[buf->use] = 0;
6296}
6297
6298/**
6299 * xmlBufferWriteCHAR:
6300 * @buf: the XML buffer
6301 * @string: the string to add
6302 *
6303 * routine which manages and grows an output buffer. This one adds
6304 * xmlChars at the end of the buffer.
6305 */
6306void
Owen Taylor3473f882001-02-23 17:55:21 +00006307xmlBufferWriteCHAR
Owen Taylor3473f882001-02-23 17:55:21 +00006308(xmlBufferPtr buf, const xmlChar *string) {
6309 xmlBufferCat(buf, string);
6310}
6311
6312/**
6313 * xmlBufferWriteChar:
6314 * @buf: the XML buffer output
6315 * @string: the string to add
6316 *
6317 * routine which manage and grows an output buffer. This one add
6318 * C chars at the end of the array.
6319 */
6320void
6321xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
6322 xmlBufferCCat(buf, string);
6323}
6324
6325
6326/**
6327 * xmlBufferWriteQuotedString:
6328 * @buf: the XML buffer output
6329 * @string: the string to add
6330 *
6331 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00006332 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00006333 * quote or double-quotes internally
6334 */
6335void
6336xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
6337 if (xmlStrchr(string, '"')) {
6338 if (xmlStrchr(string, '\'')) {
6339#ifdef DEBUG_BUFFER
6340 xmlGenericError(xmlGenericErrorContext,
6341 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
6342#endif
6343 }
6344 xmlBufferCCat(buf, "'");
6345 xmlBufferCat(buf, string);
6346 xmlBufferCCat(buf, "'");
6347 } else {
6348 xmlBufferCCat(buf, "\"");
6349 xmlBufferCat(buf, string);
6350 xmlBufferCCat(buf, "\"");
6351 }
6352}
6353
6354
6355/************************************************************************
6356 * *
6357 * Dumping XML tree content to a simple buffer *
6358 * *
6359 ************************************************************************/
6360
Owen Taylor3473f882001-02-23 17:55:21 +00006361/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00006362 * xmlAttrSerializeContent:
6363 * @buf: the XML buffer output
6364 * @doc: the document
6365 * @attr: the attribute pointer
6366 *
6367 * Serialize the attribute in the buffer
6368 */
6369static void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006370xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr)
6371{
Daniel Veillarda6d05382002-02-13 13:07:41 +00006372 const xmlChar *cur, *base;
6373 xmlNodePtr children;
6374
6375 children = attr->children;
6376 while (children != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006377 switch (children->type) {
6378 case XML_TEXT_NODE:
6379 base = cur = children->content;
6380 while (*cur != 0) {
6381 if (*cur == '\n') {
6382 if (base != cur)
6383 xmlBufferAdd(buf, base, cur - base);
6384 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
6385 cur++;
6386 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006387#if 0
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006388 } else if (*cur == '\'') {
6389 if (base != cur)
6390 xmlBufferAdd(buf, base, cur - base);
6391 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
6392 cur++;
6393 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006394#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006395 } else if (*cur == '"') {
6396 if (base != cur)
6397 xmlBufferAdd(buf, base, cur - base);
6398 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6399 cur++;
6400 base = cur;
6401 } else if (*cur == '<') {
6402 if (base != cur)
6403 xmlBufferAdd(buf, base, cur - base);
6404 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
6405 cur++;
6406 base = cur;
6407 } else if (*cur == '>') {
6408 if (base != cur)
6409 xmlBufferAdd(buf, base, cur - base);
6410 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
6411 cur++;
6412 base = cur;
6413 } else if (*cur == '&') {
6414 if (base != cur)
6415 xmlBufferAdd(buf, base, cur - base);
6416 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
6417 cur++;
6418 base = cur;
6419 } else if ((*cur >= 0x80) && ((doc == NULL) ||
6420 (doc->encoding ==
6421 NULL))) {
6422 /*
6423 * We assume we have UTF-8 content.
6424 */
6425 char tmp[10];
6426 int val = 0, l = 1;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006427
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006428 if (base != cur)
6429 xmlBufferAdd(buf, base, cur - base);
6430 if (*cur < 0xC0) {
6431 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6d05382002-02-13 13:07:41 +00006432 "xmlAttrSerializeContent : input not UTF-8\n");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006433 if (doc != NULL)
6434 doc->encoding =
6435 xmlStrdup(BAD_CAST "ISO-8859-1");
6436 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6437 tmp[sizeof(tmp) - 1] = 0;
6438 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6439 cur++;
6440 base = cur;
6441 continue;
6442 } else if (*cur < 0xE0) {
6443 val = (cur[0]) & 0x1F;
6444 val <<= 6;
6445 val |= (cur[1]) & 0x3F;
6446 l = 2;
6447 } else if (*cur < 0xF0) {
6448 val = (cur[0]) & 0x0F;
6449 val <<= 6;
6450 val |= (cur[1]) & 0x3F;
6451 val <<= 6;
6452 val |= (cur[2]) & 0x3F;
6453 l = 3;
6454 } else if (*cur < 0xF8) {
6455 val = (cur[0]) & 0x07;
6456 val <<= 6;
6457 val |= (cur[1]) & 0x3F;
6458 val <<= 6;
6459 val |= (cur[2]) & 0x3F;
6460 val <<= 6;
6461 val |= (cur[3]) & 0x3F;
6462 l = 4;
6463 }
6464 if ((l == 1) || (!IS_CHAR(val))) {
6465 xmlGenericError(xmlGenericErrorContext,
6466 "xmlAttrSerializeContent : char out of range\n");
6467 if (doc != NULL)
6468 doc->encoding =
6469 xmlStrdup(BAD_CAST "ISO-8859-1");
6470 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6471 tmp[sizeof(tmp) - 1] = 0;
6472 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6473 cur++;
6474 base = cur;
6475 continue;
6476 }
6477 /*
6478 * We could do multiple things here. Just save
6479 * as a char ref
6480 */
6481 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
6482 tmp[sizeof(tmp) - 1] = 0;
6483 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6484 cur += l;
6485 base = cur;
6486 } else {
6487 cur++;
6488 }
6489 }
6490 if (base != cur)
6491 xmlBufferAdd(buf, base, cur - base);
6492 break;
6493 case XML_ENTITY_REF_NODE:
6494 xmlBufferAdd(buf, BAD_CAST "&", 1);
6495 xmlBufferAdd(buf, children->name,
6496 xmlStrlen(children->name));
6497 xmlBufferAdd(buf, BAD_CAST ";", 1);
6498 break;
6499 default:
6500 /* should not happen unless we have a badly built tree */
6501 break;
6502 }
6503 children = children->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006504 }
6505}
6506
6507/**
6508 * xmlNodeDump:
6509 * @buf: the XML buffer output
6510 * @doc: the document
6511 * @cur: the current node
6512 * @level: the imbrication level for indenting
6513 * @format: is formatting allowed
6514 *
6515 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00006516 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006517 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006518 *
6519 * Returns the number of bytes written to the buffer or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00006520 */
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006521int
Owen Taylor3473f882001-02-23 17:55:21 +00006522xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006523 int format)
6524{
6525 unsigned int use;
6526 int ret;
6527 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006528
6529 if (cur == NULL) {
6530#ifdef DEBUG_TREE
6531 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006532 "xmlNodeDump : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006533#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006534 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006535 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006536 if (buf == NULL) {
6537#ifdef DEBUG_TREE
6538 xmlGenericError(xmlGenericErrorContext,
6539 "xmlNodeDump : buf == NULL\n");
6540#endif
6541 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006542 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006543 outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
6544 if (outbuf == NULL) {
6545 xmlGenericError(xmlGenericErrorContext,
6546 "xmlNodeDump: out of memory!\n");
6547 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006548 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006549 memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
6550 outbuf->buffer = buf;
6551 outbuf->encoder = NULL;
6552 outbuf->writecallback = NULL;
6553 outbuf->closecallback = NULL;
6554 outbuf->context = NULL;
6555 outbuf->written = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006556
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006557 use = buf->use;
6558 xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
6559 xmlFree(outbuf);
6560 ret = buf->use - use;
6561 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006562}
6563
6564/**
6565 * xmlElemDump:
6566 * @f: the FILE * for the output
6567 * @doc: the document
6568 * @cur: the current node
6569 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006570 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006571 */
6572void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006573xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur)
6574{
6575 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006576
6577 if (cur == NULL) {
6578#ifdef DEBUG_TREE
6579 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006580 "xmlElemDump : cur == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006581#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006582 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006583 }
Owen Taylor3473f882001-02-23 17:55:21 +00006584#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006585 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006586 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006587 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006588 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006589#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006590
6591 outbuf = xmlOutputBufferCreateFile(f, NULL);
6592 if (outbuf == NULL)
6593 return;
6594 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006595#ifdef LIBXML_HTML_ENABLED
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006596 htmlNodeDumpOutput(outbuf, doc, cur, NULL);
6597#else
6598 xmlGenericError(xmlGenericErrorContext,
6599 "HTML support not compiled in\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006600#endif /* LIBXML_HTML_ENABLED */
6601 } else
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006602 xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL);
6603 xmlOutputBufferClose(outbuf);
Owen Taylor3473f882001-02-23 17:55:21 +00006604}
6605
6606/************************************************************************
6607 * *
6608 * Dumping XML tree content to an I/O output buffer *
6609 * *
6610 ************************************************************************/
6611
Owen Taylor3473f882001-02-23 17:55:21 +00006612static void
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006613xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6614 int level, int format, const char *encoding);
6615static void
Owen Taylor3473f882001-02-23 17:55:21 +00006616xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6617 int level, int format, const char *encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006618static void
6619xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
6620 xmlNodePtr cur, int level, int format, const char *encoding);
6621
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00006622void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
6623
Owen Taylor3473f882001-02-23 17:55:21 +00006624/**
6625 * xmlNsDumpOutput:
6626 * @buf: the XML buffer output
6627 * @cur: a namespace
6628 *
6629 * Dump a local Namespace definition.
6630 * Should be called in the context of attributes dumps.
6631 */
6632static void
6633xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6634 if (cur == NULL) {
6635#ifdef DEBUG_TREE
6636 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006637 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006638#endif
6639 return;
6640 }
6641 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00006642 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
6643 return;
6644
Owen Taylor3473f882001-02-23 17:55:21 +00006645 /* Within the context of an element attributes */
6646 if (cur->prefix != NULL) {
6647 xmlOutputBufferWriteString(buf, " xmlns:");
6648 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6649 } else
6650 xmlOutputBufferWriteString(buf, " xmlns");
6651 xmlOutputBufferWriteString(buf, "=");
6652 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6653 }
6654}
6655
6656/**
6657 * xmlNsListDumpOutput:
6658 * @buf: the XML buffer output
6659 * @cur: the first namespace
6660 *
6661 * Dump a list of local Namespace definitions.
6662 * Should be called in the context of attributes dumps.
6663 */
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00006664void
Owen Taylor3473f882001-02-23 17:55:21 +00006665xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6666 while (cur != NULL) {
6667 xmlNsDumpOutput(buf, cur);
6668 cur = cur->next;
6669 }
6670}
6671
6672/**
6673 * xmlDtdDumpOutput:
6674 * @buf: the XML buffer output
6675 * @doc: the document
6676 * @encoding: an optional encoding string
6677 *
6678 * Dump the XML document DTD, if any.
6679 */
6680static void
6681xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6682 if (dtd == NULL) {
6683#ifdef DEBUG_TREE
6684 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006685 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006686#endif
6687 return;
6688 }
6689 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6690 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6691 if (dtd->ExternalID != NULL) {
6692 xmlOutputBufferWriteString(buf, " PUBLIC ");
6693 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6694 xmlOutputBufferWriteString(buf, " ");
6695 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6696 } else if (dtd->SystemID != NULL) {
6697 xmlOutputBufferWriteString(buf, " SYSTEM ");
6698 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6699 }
6700 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6701 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6702 xmlOutputBufferWriteString(buf, ">");
6703 return;
6704 }
6705 xmlOutputBufferWriteString(buf, " [\n");
6706 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6707 xmlOutputBufferWriteString(buf, "]>");
6708}
6709
6710/**
6711 * xmlAttrDumpOutput:
6712 * @buf: the XML buffer output
6713 * @doc: the document
6714 * @cur: the attribute pointer
6715 * @encoding: an optional encoding string
6716 *
6717 * Dump an XML attribute
6718 */
6719static void
6720xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006721 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006722 if (cur == NULL) {
6723#ifdef DEBUG_TREE
6724 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006725 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006726#endif
6727 return;
6728 }
6729 xmlOutputBufferWriteString(buf, " ");
6730 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6731 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6732 xmlOutputBufferWriteString(buf, ":");
6733 }
6734 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006735 xmlOutputBufferWriteString(buf, "=\"");
6736 xmlAttrSerializeContent(buf->buffer, doc, cur);
6737 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006738}
6739
6740/**
6741 * xmlAttrListDumpOutput:
6742 * @buf: the XML buffer output
6743 * @doc: the document
6744 * @cur: the first attribute pointer
6745 * @encoding: an optional encoding string
6746 *
6747 * Dump a list of XML attributes
6748 */
6749static void
6750xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6751 xmlAttrPtr cur, const char *encoding) {
6752 if (cur == NULL) {
6753#ifdef DEBUG_TREE
6754 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006755 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006756#endif
6757 return;
6758 }
6759 while (cur != NULL) {
6760 xmlAttrDumpOutput(buf, doc, cur, encoding);
6761 cur = cur->next;
6762 }
6763}
6764
6765
6766
6767/**
6768 * xmlNodeListDumpOutput:
6769 * @buf: the XML buffer output
6770 * @doc: the document
6771 * @cur: the first node
6772 * @level: the imbrication level for indenting
6773 * @format: is formatting allowed
6774 * @encoding: an optional encoding string
6775 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006776 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00006777 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006778 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006779 */
6780static void
6781xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6782 xmlNodePtr cur, int level, int format, const char *encoding) {
6783 int i;
6784
6785 if (cur == NULL) {
6786#ifdef DEBUG_TREE
6787 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006788 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006789#endif
6790 return;
6791 }
6792 while (cur != NULL) {
6793 if ((format) && (xmlIndentTreeOutput) &&
6794 (cur->type == XML_ELEMENT_NODE))
6795 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006796 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006797 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00006798 if (format) {
6799 xmlOutputBufferWriteString(buf, "\n");
6800 }
6801 cur = cur->next;
6802 }
6803}
6804
6805/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006806 * xmlNodeDumpOutputInternal:
Owen Taylor3473f882001-02-23 17:55:21 +00006807 * @buf: the XML buffer output
6808 * @doc: the document
6809 * @cur: the current node
6810 * @level: the imbrication level for indenting
6811 * @format: is formatting allowed
6812 * @encoding: an optional encoding string
6813 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006814 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00006815 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006816 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006817 */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006818static void
6819xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
6820 xmlNodePtr cur, int level, int format, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00006821 int i;
6822 xmlNodePtr tmp;
6823
6824 if (cur == NULL) {
6825#ifdef DEBUG_TREE
6826 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006827 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006828#endif
6829 return;
6830 }
6831 if (cur->type == XML_XINCLUDE_START)
6832 return;
6833 if (cur->type == XML_XINCLUDE_END)
6834 return;
6835 if (cur->type == XML_DTD_NODE) {
6836 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6837 return;
6838 }
6839 if (cur->type == XML_ELEMENT_DECL) {
6840 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6841 return;
6842 }
6843 if (cur->type == XML_ATTRIBUTE_DECL) {
6844 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6845 return;
6846 }
6847 if (cur->type == XML_ENTITY_DECL) {
6848 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6849 return;
6850 }
6851 if (cur->type == XML_TEXT_NODE) {
6852 if (cur->content != NULL) {
6853 if ((cur->name == xmlStringText) ||
6854 (cur->name != xmlStringTextNoenc)) {
6855 xmlChar *buffer;
6856
Owen Taylor3473f882001-02-23 17:55:21 +00006857 if (encoding == NULL)
6858 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6859 else
6860 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006861 if (buffer != NULL) {
6862 xmlOutputBufferWriteString(buf, (const char *)buffer);
6863 xmlFree(buffer);
6864 }
6865 } else {
6866 /*
6867 * Disable escaping, needed for XSLT
6868 */
Owen Taylor3473f882001-02-23 17:55:21 +00006869 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006870 }
6871 }
6872
6873 return;
6874 }
6875 if (cur->type == XML_PI_NODE) {
6876 if (cur->content != NULL) {
6877 xmlOutputBufferWriteString(buf, "<?");
6878 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6879 if (cur->content != NULL) {
6880 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00006881 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006882 }
6883 xmlOutputBufferWriteString(buf, "?>");
6884 } else {
6885 xmlOutputBufferWriteString(buf, "<?");
6886 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6887 xmlOutputBufferWriteString(buf, "?>");
6888 }
6889 return;
6890 }
6891 if (cur->type == XML_COMMENT_NODE) {
6892 if (cur->content != NULL) {
6893 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006894 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006895 xmlOutputBufferWriteString(buf, "-->");
6896 }
6897 return;
6898 }
6899 if (cur->type == XML_ENTITY_REF_NODE) {
6900 xmlOutputBufferWriteString(buf, "&");
6901 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6902 xmlOutputBufferWriteString(buf, ";");
6903 return;
6904 }
6905 if (cur->type == XML_CDATA_SECTION_NODE) {
6906 xmlOutputBufferWriteString(buf, "<![CDATA[");
6907 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006908 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006909 xmlOutputBufferWriteString(buf, "]]>");
6910 return;
6911 }
Daniel Veillard6aa2f602003-02-10 00:01:56 +00006912 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00006913 xmlNsDumpOutput(buf, (xmlNsPtr) cur);
Daniel Veillard6aa2f602003-02-10 00:01:56 +00006914 return;
6915 }
Owen Taylor3473f882001-02-23 17:55:21 +00006916
6917 if (format == 1) {
6918 tmp = cur->children;
6919 while (tmp != NULL) {
6920 if ((tmp->type == XML_TEXT_NODE) ||
6921 (tmp->type == XML_ENTITY_REF_NODE)) {
6922 format = 0;
6923 break;
6924 }
6925 tmp = tmp->next;
6926 }
6927 }
6928 xmlOutputBufferWriteString(buf, "<");
6929 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6930 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6931 xmlOutputBufferWriteString(buf, ":");
6932 }
6933
6934 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6935 if (cur->nsDef)
6936 xmlNsListDumpOutput(buf, cur->nsDef);
6937 if (cur->properties != NULL)
6938 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6939
Daniel Veillard7db37732001-07-12 01:20:08 +00006940 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6941 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006942 xmlOutputBufferWriteString(buf, "/>");
6943 return;
6944 }
6945 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006946 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006947 xmlChar *buffer;
6948
Owen Taylor3473f882001-02-23 17:55:21 +00006949 if (encoding == NULL)
6950 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6951 else
6952 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006953 if (buffer != NULL) {
6954 xmlOutputBufferWriteString(buf, (const char *)buffer);
6955 xmlFree(buffer);
6956 }
6957 }
6958 if (cur->children != NULL) {
6959 if (format) xmlOutputBufferWriteString(buf, "\n");
6960 xmlNodeListDumpOutput(buf, doc, cur->children,
6961 (level >= 0?level+1:-1), format, encoding);
6962 if ((xmlIndentTreeOutput) && (format))
6963 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006964 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006965 }
6966 xmlOutputBufferWriteString(buf, "</");
6967 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6968 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6969 xmlOutputBufferWriteString(buf, ":");
6970 }
6971
6972 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6973 xmlOutputBufferWriteString(buf, ">");
6974}
6975
6976/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006977 * xmlNodeDumpOutput:
6978 * @buf: the XML buffer output
6979 * @doc: the document
6980 * @cur: the current node
6981 * @level: the imbrication level for indenting
6982 * @format: is formatting allowed
6983 * @encoding: an optional encoding string
6984 *
6985 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00006986 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006987 * or xmlKeepBlanksDefault(0) was called
6988 */
6989void
6990xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006991 int level, int format, const char *encoding)
6992{
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006993#ifdef LIBXML_HTML_ENABLED
6994 xmlDtdPtr dtd;
6995 int is_xhtml = 0;
6996
6997 dtd = xmlGetIntSubset(doc);
6998 if (dtd != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006999 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7000 if (is_xhtml < 0)
7001 is_xhtml = 0;
7002 if ((is_xhtml) && (cur->parent == (xmlNodePtr) doc) &&
7003 (cur->type == XML_ELEMENT_NODE) &&
7004 (xmlStrEqual(cur->name, BAD_CAST "html"))) {
7005 if (encoding != NULL)
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007006 htmlSetMetaEncoding((htmlDocPtr) doc,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007007 (const xmlChar *) encoding);
7008 else
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007009 htmlSetMetaEncoding((htmlDocPtr) doc, BAD_CAST "UTF-8");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007010 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007011 }
7012
7013 if (is_xhtml)
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007014 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007015 else
7016#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007017 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007018}
7019
7020/**
Owen Taylor3473f882001-02-23 17:55:21 +00007021 * xmlDocContentDumpOutput:
7022 * @buf: the XML buffer output
7023 * @cur: the document
7024 * @encoding: an optional encoding string
7025 * @format: should formatting spaces been added
7026 *
7027 * Dump an XML document.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007028 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007029 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007030 */
7031static void
7032xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
7033 const char *encoding, int format) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007034#ifdef LIBXML_HTML_ENABLED
7035 xmlDtdPtr dtd;
7036 int is_xhtml = 0;
7037#endif
7038
Owen Taylor3473f882001-02-23 17:55:21 +00007039 xmlOutputBufferWriteString(buf, "<?xml version=");
7040 if (cur->version != NULL)
7041 xmlBufferWriteQuotedString(buf->buffer, cur->version);
7042 else
7043 xmlOutputBufferWriteString(buf, "\"1.0\"");
7044 if (encoding == NULL) {
7045 if (cur->encoding != NULL)
7046 encoding = (const char *) cur->encoding;
7047 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
7048 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
7049 }
7050 if (encoding != NULL) {
7051 xmlOutputBufferWriteString(buf, " encoding=");
7052 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
7053 }
7054 switch (cur->standalone) {
7055 case 0:
7056 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
7057 break;
7058 case 1:
7059 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
7060 break;
7061 }
7062 xmlOutputBufferWriteString(buf, "?>\n");
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007063
7064#ifdef LIBXML_HTML_ENABLED
7065 dtd = xmlGetIntSubset(cur);
7066 if (dtd != NULL) {
7067 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7068 if (is_xhtml < 0) is_xhtml = 0;
7069 }
7070 if (is_xhtml) {
7071 if (encoding != NULL)
7072 htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
7073 else
7074 htmlSetMetaEncoding(cur, BAD_CAST "UTF-8");
7075 }
7076#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007077 if (cur->children != NULL) {
7078 xmlNodePtr child = cur->children;
7079
7080 while (child != NULL) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007081#ifdef LIBXML_HTML_ENABLED
7082 if (is_xhtml)
7083 xhtmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
7084 else
7085#endif
7086 xmlNodeDumpOutputInternal(buf, cur, child, 0, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007087 xmlOutputBufferWriteString(buf, "\n");
7088 child = child->next;
7089 }
7090 }
7091}
7092
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007093#ifdef LIBXML_HTML_ENABLED
7094/************************************************************************
7095 * *
7096 * Functions specific to XHTML serialization *
7097 * *
7098 ************************************************************************/
7099
7100#define XHTML_STRICT_PUBLIC_ID BAD_CAST \
7101 "-//W3C//DTD XHTML 1.0 Strict//EN"
7102#define XHTML_STRICT_SYSTEM_ID BAD_CAST \
7103 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
7104#define XHTML_FRAME_PUBLIC_ID BAD_CAST \
7105 "-//W3C//DTD XHTML 1.0 Frameset//EN"
7106#define XHTML_FRAME_SYSTEM_ID BAD_CAST \
7107 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
7108#define XHTML_TRANS_PUBLIC_ID BAD_CAST \
7109 "-//W3C//DTD XHTML 1.0 Transitional//EN"
7110#define XHTML_TRANS_SYSTEM_ID BAD_CAST \
7111 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
7112
7113#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
7114/**
7115 * xmlIsXHTML:
7116 * @systemID: the system identifier
7117 * @publicID: the public identifier
7118 *
7119 * Try to find if the document correspond to an XHTML DTD
7120 *
7121 * Returns 1 if true, 0 if not and -1 in case of error
7122 */
7123int
7124xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) {
7125 if ((systemID == NULL) && (publicID == NULL))
7126 return(-1);
7127 if (publicID != NULL) {
7128 if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1);
7129 if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1);
7130 if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1);
7131 }
7132 if (systemID != NULL) {
7133 if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1);
7134 if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1);
7135 if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1);
7136 }
7137 return(0);
7138}
7139
7140/**
7141 * xhtmlIsEmpty:
7142 * @node: the node
7143 *
7144 * Check if a node is an empty xhtml node
7145 *
7146 * Returns 1 if the node is an empty node, 0 if not and -1 in case of error
7147 */
7148static int
7149xhtmlIsEmpty(xmlNodePtr node) {
7150 if (node == NULL)
7151 return(-1);
7152 if (node->type != XML_ELEMENT_NODE)
7153 return(0);
7154 if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME)))
7155 return(0);
7156 if (node->children != NULL)
7157 return(0);
7158 switch (node->name[0]) {
7159 case 'a':
7160 if (xmlStrEqual(node->name, BAD_CAST "area"))
7161 return(1);
7162 return(0);
7163 case 'b':
7164 if (xmlStrEqual(node->name, BAD_CAST "br"))
7165 return(1);
7166 if (xmlStrEqual(node->name, BAD_CAST "base"))
7167 return(1);
7168 if (xmlStrEqual(node->name, BAD_CAST "basefont"))
7169 return(1);
7170 return(0);
7171 case 'c':
7172 if (xmlStrEqual(node->name, BAD_CAST "col"))
7173 return(1);
7174 return(0);
7175 case 'f':
7176 if (xmlStrEqual(node->name, BAD_CAST "frame"))
7177 return(1);
7178 return(0);
7179 case 'h':
7180 if (xmlStrEqual(node->name, BAD_CAST "hr"))
7181 return(1);
7182 return(0);
7183 case 'i':
7184 if (xmlStrEqual(node->name, BAD_CAST "img"))
7185 return(1);
7186 if (xmlStrEqual(node->name, BAD_CAST "input"))
7187 return(1);
7188 if (xmlStrEqual(node->name, BAD_CAST "isindex"))
7189 return(1);
7190 return(0);
7191 case 'l':
7192 if (xmlStrEqual(node->name, BAD_CAST "link"))
7193 return(1);
7194 return(0);
7195 case 'm':
7196 if (xmlStrEqual(node->name, BAD_CAST "meta"))
7197 return(1);
7198 return(0);
7199 case 'p':
7200 if (xmlStrEqual(node->name, BAD_CAST "param"))
7201 return(1);
7202 return(0);
7203 }
7204 return(0);
7205}
7206
7207/**
7208 * xhtmlAttrListDumpOutput:
7209 * @buf: the XML buffer output
7210 * @doc: the document
7211 * @cur: the first attribute pointer
7212 * @encoding: an optional encoding string
7213 *
7214 * Dump a list of XML attributes
7215 */
7216static void
7217xhtmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7218 xmlAttrPtr cur, const char *encoding) {
7219 xmlAttrPtr xml_lang = NULL;
7220 xmlAttrPtr lang = NULL;
7221 xmlAttrPtr name = NULL;
7222 xmlAttrPtr id = NULL;
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007223 xmlNodePtr parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007224
7225 if (cur == NULL) {
7226#ifdef DEBUG_TREE
7227 xmlGenericError(xmlGenericErrorContext,
7228 "xmlAttrListDumpOutput : property == NULL\n");
7229#endif
7230 return;
7231 }
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007232 parent = cur->parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007233 while (cur != NULL) {
7234 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id")))
7235 id = cur;
7236 else
7237 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name")))
7238 name = cur;
7239 else
7240 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")))
7241 lang = cur;
7242 else
7243 if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) &&
7244 (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml")))
7245 xml_lang = cur;
7246 else if ((cur->ns == NULL) &&
7247 ((cur->children == NULL) ||
7248 (cur->children->content == NULL) ||
7249 (cur->children->content[0] == 0)) &&
7250 (htmlIsBooleanAttr(cur->name))) {
7251 if (cur->children != NULL)
7252 xmlFreeNode(cur->children);
7253 cur->children = xmlNewText(cur->name);
7254 if (cur->children != NULL)
7255 cur->children->parent = (xmlNodePtr) cur;
7256 }
7257 xmlAttrDumpOutput(buf, doc, cur, encoding);
7258 cur = cur->next;
7259 }
7260 /*
7261 * C.8
7262 */
7263 if ((name != NULL) && (id == NULL)) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007264 if ((parent != NULL) && (parent->name != NULL) &&
7265 ((xmlStrEqual(parent->name, BAD_CAST "a")) ||
7266 (xmlStrEqual(parent->name, BAD_CAST "p")) ||
7267 (xmlStrEqual(parent->name, BAD_CAST "div")) ||
7268 (xmlStrEqual(parent->name, BAD_CAST "img")) ||
7269 (xmlStrEqual(parent->name, BAD_CAST "map")) ||
7270 (xmlStrEqual(parent->name, BAD_CAST "applet")) ||
7271 (xmlStrEqual(parent->name, BAD_CAST "form")) ||
7272 (xmlStrEqual(parent->name, BAD_CAST "frame")) ||
7273 (xmlStrEqual(parent->name, BAD_CAST "iframe")))) {
7274 xmlOutputBufferWriteString(buf, " id=\"");
7275 xmlAttrSerializeContent(buf->buffer, doc, name);
7276 xmlOutputBufferWriteString(buf, "\"");
7277 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007278 }
7279 /*
7280 * C.7.
7281 */
7282 if ((lang != NULL) && (xml_lang == NULL)) {
7283 xmlOutputBufferWriteString(buf, " xml:lang=\"");
7284 xmlAttrSerializeContent(buf->buffer, doc, lang);
7285 xmlOutputBufferWriteString(buf, "\"");
7286 } else
7287 if ((xml_lang != NULL) && (lang == NULL)) {
7288 xmlOutputBufferWriteString(buf, " lang=\"");
7289 xmlAttrSerializeContent(buf->buffer, doc, xml_lang);
7290 xmlOutputBufferWriteString(buf, "\"");
7291 }
7292}
7293
7294/**
7295 * xhtmlNodeListDumpOutput:
7296 * @buf: the XML buffer output
7297 * @doc: the XHTML document
7298 * @cur: the first node
7299 * @level: the imbrication level for indenting
7300 * @format: is formatting allowed
7301 * @encoding: an optional encoding string
7302 *
7303 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007304 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007305 * or xmlKeepBlanksDefault(0) was called
7306 */
7307static void
7308xhtmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7309 xmlNodePtr cur, int level, int format, const char *encoding) {
7310 int i;
7311
7312 if (cur == NULL) {
7313#ifdef DEBUG_TREE
7314 xmlGenericError(xmlGenericErrorContext,
7315 "xhtmlNodeListDumpOutput : node == NULL\n");
7316#endif
7317 return;
7318 }
7319 while (cur != NULL) {
7320 if ((format) && (xmlIndentTreeOutput) &&
7321 (cur->type == XML_ELEMENT_NODE))
7322 for (i = 0;i < level;i++)
7323 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7324 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
7325 if (format) {
7326 xmlOutputBufferWriteString(buf, "\n");
7327 }
7328 cur = cur->next;
7329 }
7330}
7331
7332/**
7333 * xhtmlNodeDumpOutput:
7334 * @buf: the XML buffer output
7335 * @doc: the XHTML document
7336 * @cur: the current node
7337 * @level: the imbrication level for indenting
7338 * @format: is formatting allowed
7339 * @encoding: an optional encoding string
7340 *
7341 * Dump an XHTML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007342 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007343 * or xmlKeepBlanksDefault(0) was called
7344 */
7345static void
7346xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7347 int level, int format, const char *encoding) {
7348 int i;
7349 xmlNodePtr tmp;
7350
7351 if (cur == NULL) {
7352#ifdef DEBUG_TREE
7353 xmlGenericError(xmlGenericErrorContext,
7354 "xmlNodeDumpOutput : node == NULL\n");
7355#endif
7356 return;
7357 }
7358 if (cur->type == XML_XINCLUDE_START)
7359 return;
7360 if (cur->type == XML_XINCLUDE_END)
7361 return;
7362 if (cur->type == XML_DTD_NODE) {
7363 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7364 return;
7365 }
7366 if (cur->type == XML_ELEMENT_DECL) {
7367 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7368 return;
7369 }
7370 if (cur->type == XML_ATTRIBUTE_DECL) {
7371 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7372 return;
7373 }
7374 if (cur->type == XML_ENTITY_DECL) {
7375 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7376 return;
7377 }
7378 if (cur->type == XML_TEXT_NODE) {
7379 if (cur->content != NULL) {
7380 if ((cur->name == xmlStringText) ||
7381 (cur->name != xmlStringTextNoenc)) {
7382 xmlChar *buffer;
7383
7384 if (encoding == NULL)
7385 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7386 else
7387 buffer = xmlEncodeSpecialChars(doc, cur->content);
7388 if (buffer != NULL) {
7389 xmlOutputBufferWriteString(buf, (const char *)buffer);
7390 xmlFree(buffer);
7391 }
7392 } else {
7393 /*
7394 * Disable escaping, needed for XSLT
7395 */
7396 xmlOutputBufferWriteString(buf, (const char *) cur->content);
7397 }
7398 }
7399
7400 return;
7401 }
7402 if (cur->type == XML_PI_NODE) {
7403 if (cur->content != NULL) {
7404 xmlOutputBufferWriteString(buf, "<?");
7405 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7406 if (cur->content != NULL) {
7407 xmlOutputBufferWriteString(buf, " ");
7408 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7409 }
7410 xmlOutputBufferWriteString(buf, "?>");
7411 } else {
7412 xmlOutputBufferWriteString(buf, "<?");
7413 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7414 xmlOutputBufferWriteString(buf, "?>");
7415 }
7416 return;
7417 }
7418 if (cur->type == XML_COMMENT_NODE) {
7419 if (cur->content != NULL) {
7420 xmlOutputBufferWriteString(buf, "<!--");
7421 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7422 xmlOutputBufferWriteString(buf, "-->");
7423 }
7424 return;
7425 }
7426 if (cur->type == XML_ENTITY_REF_NODE) {
7427 xmlOutputBufferWriteString(buf, "&");
7428 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7429 xmlOutputBufferWriteString(buf, ";");
7430 return;
7431 }
7432 if (cur->type == XML_CDATA_SECTION_NODE) {
7433 xmlOutputBufferWriteString(buf, "<![CDATA[");
7434 if (cur->content != NULL)
7435 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7436 xmlOutputBufferWriteString(buf, "]]>");
7437 return;
7438 }
7439
7440 if (format == 1) {
7441 tmp = cur->children;
7442 while (tmp != NULL) {
7443 if ((tmp->type == XML_TEXT_NODE) ||
7444 (tmp->type == XML_ENTITY_REF_NODE)) {
7445 format = 0;
7446 break;
7447 }
7448 tmp = tmp->next;
7449 }
7450 }
7451 xmlOutputBufferWriteString(buf, "<");
7452 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7453 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7454 xmlOutputBufferWriteString(buf, ":");
7455 }
7456
7457 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7458 if (cur->nsDef)
7459 xmlNsListDumpOutput(buf, cur->nsDef);
7460 if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
7461 (cur->ns == NULL) && (cur->nsDef == NULL))) {
7462 /*
7463 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
7464 */
7465 xmlOutputBufferWriteString(buf,
7466 " xmlns=\"http://www.w3.org/1999/xhtml\"");
7467 }
7468 if (cur->properties != NULL)
7469 xhtmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7470
7471 if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) {
7472 if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
7473 (xhtmlIsEmpty(cur) == 1)) {
7474 /*
7475 * C.2. Empty Elements
7476 */
7477 xmlOutputBufferWriteString(buf, " />");
7478 } else {
7479 /*
7480 * C.3. Element Minimization and Empty Element Content
7481 */
7482 xmlOutputBufferWriteString(buf, "></");
7483 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7484 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7485 xmlOutputBufferWriteString(buf, ":");
7486 }
7487 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7488 xmlOutputBufferWriteString(buf, ">");
7489 }
7490 return;
7491 }
7492 xmlOutputBufferWriteString(buf, ">");
7493 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
7494 xmlChar *buffer;
7495
7496 if (encoding == NULL)
7497 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7498 else
7499 buffer = xmlEncodeSpecialChars(doc, cur->content);
7500 if (buffer != NULL) {
7501 xmlOutputBufferWriteString(buf, (const char *)buffer);
7502 xmlFree(buffer);
7503 }
7504 }
7505
7506 /*
7507 * 4.8. Script and Style elements
7508 */
7509 if ((cur->type == XML_ELEMENT_NODE) &&
7510 ((xmlStrEqual(cur->name, BAD_CAST "script")) ||
7511 (xmlStrEqual(cur->name, BAD_CAST "style"))) &&
7512 ((cur->ns == NULL) ||
7513 (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) {
7514 xmlNodePtr child = cur->children;
7515
7516 while (child != NULL) {
7517 if ((child->type == XML_TEXT_NODE) ||
7518 (child->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard64b35282002-12-04 15:10:40 +00007519 /*
7520 * Apparently CDATA escaping for style just break on IE,
7521 * mozilla and galeon, so ...
7522 */
7523 if (xmlStrEqual(cur->name, BAD_CAST "style") &&
7524 (xmlStrchr(child->content, '<') == NULL) &&
7525 (xmlStrchr(child->content, '>') == NULL) &&
7526 (xmlStrchr(child->content, '&') == NULL)) {
7527 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7528 } else {
7529 xmlOutputBufferWriteString(buf, "<![CDATA[");
7530 if (child->content != NULL)
7531 xmlOutputBufferWriteString(buf,
7532 (const char *)child->content);
7533 xmlOutputBufferWriteString(buf, "]]>");
7534 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007535 } else {
7536 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7537 }
7538 child = child->next;
7539 }
7540 } else if (cur->children != NULL) {
7541 if (format) xmlOutputBufferWriteString(buf, "\n");
7542 xhtmlNodeListDumpOutput(buf, doc, cur->children,
7543 (level >= 0?level+1:-1), format, encoding);
7544 if ((xmlIndentTreeOutput) && (format))
7545 for (i = 0;i < level;i++)
7546 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7547 }
7548 xmlOutputBufferWriteString(buf, "</");
7549 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7550 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7551 xmlOutputBufferWriteString(buf, ":");
7552 }
7553
7554 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7555 xmlOutputBufferWriteString(buf, ">");
7556}
7557#endif
7558
Owen Taylor3473f882001-02-23 17:55:21 +00007559/************************************************************************
7560 * *
7561 * Saving functions front-ends *
7562 * *
7563 ************************************************************************/
7564
7565/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00007566 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00007567 * @out_doc: Document to generate XML text from
7568 * @doc_txt_ptr: Memory pointer for allocated XML text
7569 * @doc_txt_len: Length of the generated XML text
7570 * @txt_encoding: Character encoding to use when generating XML text
7571 * @format: should formatting spaces been added
7572 *
7573 * Dump the current DOM tree into memory using the character encoding specified
7574 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007575 * allocated memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00007576 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007577 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007578 */
7579
7580void
7581xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007582 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007583 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007584 int dummy = 0;
7585
7586 xmlCharEncoding doc_charset;
7587 xmlOutputBufferPtr out_buff = NULL;
7588 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
7589
7590 if (doc_txt_len == NULL) {
7591 doc_txt_len = &dummy; /* Continue, caller just won't get length */
7592 }
7593
7594 if (doc_txt_ptr == NULL) {
7595 *doc_txt_len = 0;
7596 xmlGenericError(xmlGenericErrorContext,
7597 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
7598 return;
7599 }
7600
7601 *doc_txt_ptr = NULL;
7602 *doc_txt_len = 0;
7603
7604 if (out_doc == NULL) {
7605 /* No document, no output */
7606 xmlGenericError(xmlGenericErrorContext,
7607 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
7608 return;
7609 }
7610
7611 /*
7612 * Validate the encoding value, if provided.
7613 * This logic is copied from xmlSaveFileEnc.
7614 */
7615
7616 if (txt_encoding == NULL)
7617 txt_encoding = (const char *) out_doc->encoding;
7618 if (txt_encoding != NULL) {
7619 doc_charset = xmlParseCharEncoding(txt_encoding);
7620
7621 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
7622 xmlGenericError(xmlGenericErrorContext,
7623 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
7624 return;
7625
7626 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
7627 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
7628 if ( conv_hdlr == NULL ) {
7629 xmlGenericError(xmlGenericErrorContext,
7630 "%s: %s %s '%s'\n",
7631 "xmlDocDumpFormatMemoryEnc",
7632 "Failed to identify encoding handler for",
7633 "character set",
7634 txt_encoding);
7635 return;
7636 }
7637 }
7638 }
7639
7640 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
7641 xmlGenericError(xmlGenericErrorContext,
7642 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
7643 return;
7644 }
7645
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007646 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007647 xmlOutputBufferFlush(out_buff);
7648 if (out_buff->conv != NULL) {
7649 *doc_txt_len = out_buff->conv->use;
7650 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
7651 } else {
7652 *doc_txt_len = out_buff->buffer->use;
7653 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
7654 }
7655 (void)xmlOutputBufferClose(out_buff);
7656
7657 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
7658 *doc_txt_len = 0;
7659 xmlGenericError(xmlGenericErrorContext,
7660 "xmlDocDumpFormatMemoryEnc: %s\n",
7661 "Failed to allocate memory for document text representation.");
7662 }
7663
7664 return;
7665}
7666
7667/**
7668 * xmlDocDumpMemory:
7669 * @cur: the document
7670 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007671 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007672 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007673 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007674 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007675 */
7676void
7677xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
7678 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
7679}
7680
7681/**
7682 * xmlDocDumpFormatMemory:
7683 * @cur: the document
7684 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007685 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007686 * @format: should formatting spaces been added
7687 *
7688 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007689 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007690 * It's up to the caller to free the memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00007691 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007692 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007693 */
7694void
7695xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
7696 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
7697}
7698
7699/**
7700 * xmlDocDumpMemoryEnc:
7701 * @out_doc: Document to generate XML text from
7702 * @doc_txt_ptr: Memory pointer for allocated XML text
7703 * @doc_txt_len: Length of the generated XML text
7704 * @txt_encoding: Character encoding to use when generating XML text
7705 *
7706 * Dump the current DOM tree into memory using the character encoding specified
7707 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007708 * allocated memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007709 */
7710
7711void
7712xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
7713 int * doc_txt_len, const char * txt_encoding) {
7714 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007715 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007716}
7717
7718/**
7719 * xmlGetDocCompressMode:
7720 * @doc: the document
7721 *
7722 * get the compression ratio for a document, ZLIB based
7723 * Returns 0 (uncompressed) to 9 (max compression)
7724 */
7725int
7726xmlGetDocCompressMode (xmlDocPtr doc) {
7727 if (doc == NULL) return(-1);
7728 return(doc->compression);
7729}
7730
7731/**
7732 * xmlSetDocCompressMode:
7733 * @doc: the document
7734 * @mode: the compression ratio
7735 *
7736 * set the compression ratio for a document, ZLIB based
7737 * Correct values: 0 (uncompressed) to 9 (max compression)
7738 */
7739void
7740xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7741 if (doc == NULL) return;
7742 if (mode < 0) doc->compression = 0;
7743 else if (mode > 9) doc->compression = 9;
7744 else doc->compression = mode;
7745}
7746
7747/**
7748 * xmlGetCompressMode:
7749 *
7750 * get the default compression mode used, ZLIB based.
7751 * Returns 0 (uncompressed) to 9 (max compression)
7752 */
7753int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007754xmlGetCompressMode(void)
7755{
7756 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00007757}
7758
7759/**
7760 * xmlSetCompressMode:
7761 * @mode: the compression ratio
7762 *
7763 * set the default compression mode used, ZLIB based
7764 * Correct values: 0 (uncompressed) to 9 (max compression)
7765 */
7766void
7767xmlSetCompressMode(int mode) {
7768 if (mode < 0) xmlCompressMode = 0;
7769 else if (mode > 9) xmlCompressMode = 9;
7770 else xmlCompressMode = mode;
7771}
7772
7773/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007774 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00007775 * @f: the FILE*
7776 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00007777 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007778 *
7779 * Dump an XML document to an open FILE.
7780 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007781 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007782 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7783 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007784 */
7785int
Daniel Veillard9e412302002-06-10 15:59:44 +00007786xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007787 xmlOutputBufferPtr buf;
7788 const char * encoding;
7789 xmlCharEncodingHandlerPtr handler = NULL;
7790 int ret;
7791
7792 if (cur == NULL) {
7793#ifdef DEBUG_TREE
7794 xmlGenericError(xmlGenericErrorContext,
7795 "xmlDocDump : document == NULL\n");
7796#endif
7797 return(-1);
7798 }
7799 encoding = (const char *) cur->encoding;
7800
7801 if (encoding != NULL) {
7802 xmlCharEncoding enc;
7803
7804 enc = xmlParseCharEncoding(encoding);
7805
7806 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7807 xmlGenericError(xmlGenericErrorContext,
7808 "xmlDocDump: document not in UTF8\n");
7809 return(-1);
7810 }
7811 if (enc != XML_CHAR_ENCODING_UTF8) {
7812 handler = xmlFindCharEncodingHandler(encoding);
7813 if (handler == NULL) {
7814 xmlFree((char *) cur->encoding);
7815 cur->encoding = NULL;
7816 }
7817 }
7818 }
7819 buf = xmlOutputBufferCreateFile(f, handler);
7820 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00007821 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007822
7823 ret = xmlOutputBufferClose(buf);
7824 return(ret);
7825}
7826
7827/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007828 * xmlDocDump:
7829 * @f: the FILE*
7830 * @cur: the document
7831 *
7832 * Dump an XML document to an open FILE.
7833 *
7834 * returns: the number of bytes written or -1 in case of failure.
7835 */
7836int
7837xmlDocDump(FILE *f, xmlDocPtr cur) {
7838 return(xmlDocFormatDump (f, cur, 0));
7839}
7840
7841/**
Owen Taylor3473f882001-02-23 17:55:21 +00007842 * xmlSaveFileTo:
7843 * @buf: an output I/O buffer
7844 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007845 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00007846 *
7847 * Dump an XML document to an I/O buffer.
7848 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007849 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007850 */
7851int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007852xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007853 int ret;
7854
7855 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007856 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007857 ret = xmlOutputBufferClose(buf);
7858 return(ret);
7859}
7860
7861/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00007862 * xmlSaveFormatFileTo:
7863 * @buf: an output I/O buffer
7864 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007865 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00007866 * @format: should formatting spaces been added
7867 *
7868 * Dump an XML document to an I/O buffer.
7869 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007870 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007871 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7872 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardeefd4492001-04-28 16:55:50 +00007873 */
7874int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007875xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00007876 int ret;
7877
7878 if (buf == NULL) return(0);
7879 xmlDocContentDumpOutput(buf, cur, encoding, format);
7880 ret = xmlOutputBufferClose(buf);
7881 return(ret);
7882}
7883
7884/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00007885 * xmlSaveFormatFileEnc:
Daniel Veillardf012a642001-07-23 19:10:52 +00007886 * @filename: the filename or URL to output
7887 * @cur: the document being saved
7888 * @encoding: the name of the encoding to use or NULL.
7889 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00007890 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00007891 * Dump an XML document to a file or an URL.
7892 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007893 * Returns the number of bytes written or -1 in case of error.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007894 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7895 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007896 */
7897int
Daniel Veillardf012a642001-07-23 19:10:52 +00007898xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
7899 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00007900 xmlOutputBufferPtr buf;
7901 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00007902 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00007903 int ret;
7904
Daniel Veillard4dbe77a2003-01-14 00:17:42 +00007905 if (cur == NULL)
7906 return(-1);
7907
Daniel Veillardfb25a512002-01-13 20:32:08 +00007908 if (encoding == NULL)
7909 encoding = (const char *) cur->encoding;
7910
Owen Taylor3473f882001-02-23 17:55:21 +00007911 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00007912
7913 enc = xmlParseCharEncoding(encoding);
7914 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7915 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007916 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007917 return(-1);
7918 }
7919 if (enc != XML_CHAR_ENCODING_UTF8) {
7920 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00007921 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007922 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007923 }
7924 }
7925
Daniel Veillardf012a642001-07-23 19:10:52 +00007926#ifdef HAVE_ZLIB_H
7927 if (cur->compression < 0) cur->compression = xmlCompressMode;
7928#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007929 /*
7930 * save the content to a temp buffer.
7931 */
Daniel Veillardf012a642001-07-23 19:10:52 +00007932 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00007933 if (buf == NULL) return(-1);
7934
Daniel Veillardf012a642001-07-23 19:10:52 +00007935 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007936
7937 ret = xmlOutputBufferClose(buf);
7938 return(ret);
7939}
7940
Daniel Veillardf012a642001-07-23 19:10:52 +00007941
7942/**
7943 * xmlSaveFileEnc:
7944 * @filename: the filename (or URL)
7945 * @cur: the document
7946 * @encoding: the name of an encoding (or NULL)
7947 *
7948 * Dump an XML document, converting it to the given encoding
7949 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007950 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00007951 */
7952int
7953xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
7954 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
7955}
7956
Owen Taylor3473f882001-02-23 17:55:21 +00007957/**
Daniel Veillard67fee942001-04-26 18:59:03 +00007958 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00007959 * @filename: the filename (or URL)
7960 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00007961 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007962 *
7963 * Dump an XML document to a file. Will use compression if
7964 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00007965 * used. If @format is set then the document will be indented on output.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007966 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7967 * or xmlKeepBlanksDefault(0) was called
Daniel Veillard67fee942001-04-26 18:59:03 +00007968 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007969 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007970 */
7971int
Daniel Veillard67fee942001-04-26 18:59:03 +00007972xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007973 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00007974}
7975
Daniel Veillard67fee942001-04-26 18:59:03 +00007976/**
7977 * xmlSaveFile:
7978 * @filename: the filename (or URL)
7979 * @cur: the document
7980 *
7981 * Dump an XML document to a file. Will use compression if
7982 * compiled in and enabled. If @filename is "-" the stdout file is
7983 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00007984 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00007985 */
7986int
7987xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007988 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00007989}
7990