blob: 7fc306c29f895c1133b5b1879b92efef2e5a15a3 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002 * tree.c : implementation of access function for an XML tree.
Owen Taylor3473f882001-02-23 17:55:21 +00003 *
Daniel Veillardd5c2f922002-11-21 14:10:52 +00004 * References:
5 * XHTML 1.0 W3C REC: http://www.w3.org/TR/2002/REC-xhtml1-20020801/
6 *
Owen Taylor3473f882001-02-23 17:55:21 +00007 * See Copyright for the status of this software.
8 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00009 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000010 *
Owen Taylor3473f882001-02-23 17:55:21 +000011 */
12
Daniel Veillard34ce8be2002-03-18 19:37:11 +000013#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000014#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000015
Owen Taylor3473f882001-02-23 17:55:21 +000016#include <string.h> /* for memset() only ! */
17
18#ifdef HAVE_CTYPE_H
19#include <ctype.h>
20#endif
21#ifdef HAVE_STDLIB_H
22#include <stdlib.h>
23#endif
24#ifdef HAVE_ZLIB_H
25#include <zlib.h>
26#endif
27
28#include <libxml/xmlmemory.h>
29#include <libxml/tree.h>
30#include <libxml/parser.h>
Daniel Veillardb8c9be92001-07-09 16:01:19 +000031#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000032#include <libxml/entities.h>
33#include <libxml/valid.h>
34#include <libxml/xmlerror.h>
Daniel Veillardbdb9ba72001-04-11 11:28:06 +000035#include <libxml/parserInternals.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000036#include <libxml/globals.h>
Daniel Veillardd5c2f922002-11-21 14:10:52 +000037#ifdef LIBXML_HTML_ENABLED
38#include <libxml/HTMLtree.h>
39#endif
Owen Taylor3473f882001-02-23 17:55:21 +000040
Daniel Veillard56a4cb82001-03-24 17:00:36 +000041xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
42
43/************************************************************************
44 * *
45 * A few static variables and macros *
46 * *
47 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +000048/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +000049const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000050/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +000051const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +000052 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000053/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +000054const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
55
Owen Taylor3473f882001-02-23 17:55:21 +000056static int xmlCompressMode = 0;
57static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000058
Owen Taylor3473f882001-02-23 17:55:21 +000059#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
60 xmlNodePtr ulccur = (n)->children; \
61 if (ulccur == NULL) { \
62 (n)->last = NULL; \
63 } else { \
64 while (ulccur->next != NULL) { \
65 ulccur->parent = (n); \
66 ulccur = ulccur->next; \
67 } \
68 ulccur->parent = (n); \
69 (n)->last = ulccur; \
70}}
71
72/* #define DEBUG_BUFFER */
73/* #define DEBUG_TREE */
74
75/************************************************************************
76 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +000077 * Functions to move to entities.c once the *
78 * API freeze is smoothen and they can be made public. *
79 * *
80 ************************************************************************/
81#include <libxml/hash.h>
82
83/**
84 * xmlGetEntityFromDtd:
85 * @dtd: A pointer to the DTD to search
86 * @name: The entity name
87 *
88 * Do an entity lookup in the DTD entity hash table and
89 * return the corresponding entity, if found.
90 *
91 * Returns A pointer to the entity structure or NULL if not found.
92 */
93static xmlEntityPtr
94xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
95 xmlEntitiesTablePtr table;
96
97 if((dtd != NULL) && (dtd->entities != NULL)) {
98 table = (xmlEntitiesTablePtr) dtd->entities;
99 return((xmlEntityPtr) xmlHashLookup(table, name));
100 /* return(xmlGetEntityFromTable(table, name)); */
101 }
102 return(NULL);
103}
104/**
105 * xmlGetParameterEntityFromDtd:
106 * @dtd: A pointer to the DTD to search
107 * @name: The entity name
108 *
109 * Do an entity lookup in the DTD pararmeter entity hash table and
110 * return the corresponding entity, if found.
111 *
112 * Returns A pointer to the entity structure or NULL if not found.
113 */
114static xmlEntityPtr
115xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
116 xmlEntitiesTablePtr table;
117
118 if ((dtd != NULL) && (dtd->pentities != NULL)) {
119 table = (xmlEntitiesTablePtr) dtd->pentities;
120 return((xmlEntityPtr) xmlHashLookup(table, name));
121 /* return(xmlGetEntityFromTable(table, name)); */
122 }
123 return(NULL);
124}
125
126/************************************************************************
127 * *
Daniel Veillardd2298792003-02-14 16:54:11 +0000128 * Check Name, NCName and QName strings *
129 * *
130 ************************************************************************/
131
132#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
133
134/**
135 * xmlValidateNCName:
136 * @value: the value to check
137 * @space: allow spaces in front and end of the string
138 *
139 * Check that a value conforms to the lexical space of NCName
140 *
141 * Returns 0 if this validates, a positive error code number otherwise
142 * and -1 in case of internal or API error.
143 */
144int
145xmlValidateNCName(const xmlChar *value, int space) {
146 const xmlChar *cur = value;
147 int c,l;
148
149 /*
150 * First quick algorithm for ASCII range
151 */
152 if (space)
153 while (IS_BLANK(*cur)) cur++;
154 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
155 (*cur == '_'))
156 cur++;
157 else
158 goto try_complex;
159 while (((*cur >= 'a') && (*cur <= 'z')) ||
160 ((*cur >= 'A') && (*cur <= 'Z')) ||
161 ((*cur >= '0') && (*cur <= '9')) ||
162 (*cur == '_') || (*cur == '-') || (*cur == '.'))
163 cur++;
164 if (space)
165 while (IS_BLANK(*cur)) cur++;
166 if (*cur == 0)
167 return(0);
168
169try_complex:
170 /*
171 * Second check for chars outside the ASCII range
172 */
173 cur = value;
174 c = CUR_SCHAR(cur, l);
175 if (space) {
176 while (IS_BLANK(c)) {
177 cur += l;
178 c = CUR_SCHAR(cur, l);
179 }
180 }
181 if ((!xmlIsLetter(c)) && (c != '_'))
182 return(1);
183 cur += l;
184 c = CUR_SCHAR(cur, l);
185 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') ||
186 (c == '-') || (c == '_') || xmlIsCombining(c) ||
187 xmlIsExtender(c)) {
188 cur += l;
189 c = CUR_SCHAR(cur, l);
190 }
191 if (space) {
192 while (IS_BLANK(c)) {
193 cur += l;
194 c = CUR_SCHAR(cur, l);
195 }
196 }
197 if (c != 0)
198 return(1);
199
200 return(0);
201}
202
203/**
204 * xmlValidateQName:
205 * @value: the value to check
206 * @space: allow spaces in front and end of the string
207 *
208 * Check that a value conforms to the lexical space of QName
209 *
210 * Returns 0 if this validates, a positive error code number otherwise
211 * and -1 in case of internal or API error.
212 */
213int
214xmlValidateQName(const xmlChar *value, int space) {
215 const xmlChar *cur = value;
216 int c,l;
217
218 /*
219 * First quick algorithm for ASCII range
220 */
221 if (space)
222 while (IS_BLANK(*cur)) cur++;
223 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
224 (*cur == '_'))
225 cur++;
226 else
227 goto try_complex;
228 while (((*cur >= 'a') && (*cur <= 'z')) ||
229 ((*cur >= 'A') && (*cur <= 'Z')) ||
230 ((*cur >= '0') && (*cur <= '9')) ||
231 (*cur == '_') || (*cur == '-') || (*cur == '.'))
232 cur++;
233 if (*cur == ':') {
234 cur++;
235 if (((*cur >= 'a') && (*cur <= 'z')) ||
236 ((*cur >= 'A') && (*cur <= 'Z')) ||
237 (*cur == '_'))
238 cur++;
239 else
240 goto try_complex;
241 while (((*cur >= 'a') && (*cur <= 'z')) ||
242 ((*cur >= 'A') && (*cur <= 'Z')) ||
243 ((*cur >= '0') && (*cur <= '9')) ||
244 (*cur == '_') || (*cur == '-') || (*cur == '.'))
245 cur++;
246 }
247 if (space)
248 while (IS_BLANK(*cur)) cur++;
249 if (*cur == 0)
250 return(0);
251
252try_complex:
253 /*
254 * Second check for chars outside the ASCII range
255 */
256 cur = value;
257 c = CUR_SCHAR(cur, l);
258 if (space) {
259 while (IS_BLANK(c)) {
260 cur += l;
261 c = CUR_SCHAR(cur, l);
262 }
263 }
264 if ((!xmlIsLetter(c)) && (c != '_'))
265 return(1);
266 cur += l;
267 c = CUR_SCHAR(cur, l);
268 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') ||
269 (c == '-') || (c == '_') || xmlIsCombining(c) ||
270 xmlIsExtender(c)) {
271 cur += l;
272 c = CUR_SCHAR(cur, l);
273 }
274 if (c == ':') {
275 cur += l;
276 c = CUR_SCHAR(cur, l);
277 if ((!xmlIsLetter(c)) && (c != '_'))
278 return(1);
279 cur += l;
280 c = CUR_SCHAR(cur, l);
281 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') ||
282 (c == '-') || (c == '_') || xmlIsCombining(c) ||
283 xmlIsExtender(c)) {
284 cur += l;
285 c = CUR_SCHAR(cur, l);
286 }
287 }
288 if (space) {
289 while (IS_BLANK(c)) {
290 cur += l;
291 c = CUR_SCHAR(cur, l);
292 }
293 }
294 if (c != 0)
295 return(1);
296 return(0);
297}
298
299/**
300 * xmlValidateName:
301 * @value: the value to check
302 * @space: allow spaces in front and end of the string
303 *
304 * Check that a value conforms to the lexical space of Name
305 *
306 * Returns 0 if this validates, a positive error code number otherwise
307 * and -1 in case of internal or API error.
308 */
309int
310xmlValidateName(const xmlChar *value, int space) {
311 const xmlChar *cur = value;
312 int c,l;
313
314 /*
315 * First quick algorithm for ASCII range
316 */
317 if (space)
318 while (IS_BLANK(*cur)) cur++;
319 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
320 (*cur == '_') || (*cur == ':'))
321 cur++;
322 else
323 goto try_complex;
324 while (((*cur >= 'a') && (*cur <= 'z')) ||
325 ((*cur >= 'A') && (*cur <= 'Z')) ||
326 ((*cur >= '0') && (*cur <= '9')) ||
327 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
328 cur++;
329 if (space)
330 while (IS_BLANK(*cur)) cur++;
331 if (*cur == 0)
332 return(0);
333
334try_complex:
335 /*
336 * Second check for chars outside the ASCII range
337 */
338 cur = value;
339 c = CUR_SCHAR(cur, l);
340 if (space) {
341 while (IS_BLANK(c)) {
342 cur += l;
343 c = CUR_SCHAR(cur, l);
344 }
345 }
346 if ((!xmlIsLetter(c)) && (c != '_') && (c != ':'))
347 return(1);
348 cur += l;
349 c = CUR_SCHAR(cur, l);
350 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') || (c == ':') ||
351 (c == '-') || (c == '_') || xmlIsCombining(c) || xmlIsExtender(c)) {
352 cur += l;
353 c = CUR_SCHAR(cur, l);
354 }
355 if (space) {
356 while (IS_BLANK(c)) {
357 cur += l;
358 c = CUR_SCHAR(cur, l);
359 }
360 }
361 if (c != 0)
362 return(1);
363 return(0);
364}
365
Daniel Veillardd4310742003-02-18 21:12:46 +0000366/**
367 * xmlValidateNMToken:
368 * @value: the value to check
369 * @space: allow spaces in front and end of the string
370 *
371 * Check that a value conforms to the lexical space of NMToken
372 *
373 * Returns 0 if this validates, a positive error code number otherwise
374 * and -1 in case of internal or API error.
375 */
376int
377xmlValidateNMToken(const xmlChar *value, int space) {
378 const xmlChar *cur = value;
379 int c,l;
380
381 /*
382 * First quick algorithm for ASCII range
383 */
384 if (space)
385 while (IS_BLANK(*cur)) cur++;
386 if (((*cur >= 'a') && (*cur <= 'z')) ||
387 ((*cur >= 'A') && (*cur <= 'Z')) ||
388 ((*cur >= '0') && (*cur <= '9')) ||
389 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
390 cur++;
391 else
392 goto try_complex;
393 while (((*cur >= 'a') && (*cur <= 'z')) ||
394 ((*cur >= 'A') && (*cur <= 'Z')) ||
395 ((*cur >= '0') && (*cur <= '9')) ||
396 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
397 cur++;
398 if (space)
399 while (IS_BLANK(*cur)) cur++;
400 if (*cur == 0)
401 return(0);
402
403try_complex:
404 /*
405 * Second check for chars outside the ASCII range
406 */
407 cur = value;
408 c = CUR_SCHAR(cur, l);
409 if (space) {
410 while (IS_BLANK(c)) {
411 cur += l;
412 c = CUR_SCHAR(cur, l);
413 }
414 }
415 if (!(xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') || (c == ':') ||
416 (c == '-') || (c == '_') || xmlIsCombining(c) || xmlIsExtender(c)))
417 return(1);
418 cur += l;
419 c = CUR_SCHAR(cur, l);
420 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') || (c == ':') ||
421 (c == '-') || (c == '_') || xmlIsCombining(c) || xmlIsExtender(c)) {
422 cur += l;
423 c = CUR_SCHAR(cur, l);
424 }
425 if (space) {
426 while (IS_BLANK(c)) {
427 cur += l;
428 c = CUR_SCHAR(cur, l);
429 }
430 }
431 if (c != 0)
432 return(1);
433 return(0);
434}
435
Daniel Veillardd2298792003-02-14 16:54:11 +0000436/************************************************************************
437 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000438 * Allocation and deallocation of basic structures *
439 * *
440 ************************************************************************/
441
442/**
443 * xmlSetBufferAllocationScheme:
444 * @scheme: allocation method to use
445 *
446 * Set the buffer allocation method. Types are
447 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
448 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
449 * improves performance
450 */
451void
452xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
453 xmlBufferAllocScheme = scheme;
454}
455
456/**
457 * xmlGetBufferAllocationScheme:
458 *
459 * Types are
460 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
461 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
462 * improves performance
463 *
464 * Returns the current allocation scheme
465 */
466xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000467xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000468 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000469}
470
471/**
472 * xmlNewNs:
473 * @node: the element carrying the namespace
474 * @href: the URI associated
475 * @prefix: the prefix for the namespace
476 *
477 * Creation of a new Namespace. This function will refuse to create
478 * a namespace with a similar prefix than an existing one present on this
479 * node.
480 * We use href==NULL in the case of an element creation where the namespace
481 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000482 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000483 */
484xmlNsPtr
485xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
486 xmlNsPtr cur;
487
488 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
489 return(NULL);
490
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000491 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
492 return(NULL);
493
Owen Taylor3473f882001-02-23 17:55:21 +0000494 /*
495 * Allocate a new Namespace and fill the fields.
496 */
497 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
498 if (cur == NULL) {
499 xmlGenericError(xmlGenericErrorContext,
500 "xmlNewNs : malloc failed\n");
501 return(NULL);
502 }
503 memset(cur, 0, sizeof(xmlNs));
504 cur->type = XML_LOCAL_NAMESPACE;
505
506 if (href != NULL)
507 cur->href = xmlStrdup(href);
508 if (prefix != NULL)
509 cur->prefix = xmlStrdup(prefix);
510
511 /*
512 * Add it at the end to preserve parsing order ...
513 * and checks for existing use of the prefix
514 */
515 if (node != NULL) {
516 if (node->nsDef == NULL) {
517 node->nsDef = cur;
518 } else {
519 xmlNsPtr prev = node->nsDef;
520
521 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
522 (xmlStrEqual(prev->prefix, cur->prefix))) {
523 xmlFreeNs(cur);
524 return(NULL);
525 }
526 while (prev->next != NULL) {
527 prev = prev->next;
528 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
529 (xmlStrEqual(prev->prefix, cur->prefix))) {
530 xmlFreeNs(cur);
531 return(NULL);
532 }
533 }
534 prev->next = cur;
535 }
536 }
537 return(cur);
538}
539
540/**
541 * xmlSetNs:
542 * @node: a node in the document
543 * @ns: a namespace pointer
544 *
545 * Associate a namespace to a node, a posteriori.
546 */
547void
548xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
549 if (node == NULL) {
550#ifdef DEBUG_TREE
551 xmlGenericError(xmlGenericErrorContext,
552 "xmlSetNs: node == NULL\n");
553#endif
554 return;
555 }
556 node->ns = ns;
557}
558
559/**
560 * xmlFreeNs:
561 * @cur: the namespace pointer
562 *
563 * Free up the structures associated to a namespace
564 */
565void
566xmlFreeNs(xmlNsPtr cur) {
567 if (cur == NULL) {
568#ifdef DEBUG_TREE
569 xmlGenericError(xmlGenericErrorContext,
570 "xmlFreeNs : ns == NULL\n");
571#endif
572 return;
573 }
574 if (cur->href != NULL) xmlFree((char *) cur->href);
575 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000576 xmlFree(cur);
577}
578
579/**
580 * xmlFreeNsList:
581 * @cur: the first namespace pointer
582 *
583 * Free up all the structures associated to the chained namespaces.
584 */
585void
586xmlFreeNsList(xmlNsPtr cur) {
587 xmlNsPtr next;
588 if (cur == NULL) {
589#ifdef DEBUG_TREE
590 xmlGenericError(xmlGenericErrorContext,
591 "xmlFreeNsList : ns == NULL\n");
592#endif
593 return;
594 }
595 while (cur != NULL) {
596 next = cur->next;
597 xmlFreeNs(cur);
598 cur = next;
599 }
600}
601
602/**
603 * xmlNewDtd:
604 * @doc: the document pointer
605 * @name: the DTD name
606 * @ExternalID: the external ID
607 * @SystemID: the system ID
608 *
609 * Creation of a new DTD for the external subset. To create an
610 * internal subset, use xmlCreateIntSubset().
611 *
612 * Returns a pointer to the new DTD structure
613 */
614xmlDtdPtr
615xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
616 const xmlChar *ExternalID, const xmlChar *SystemID) {
617 xmlDtdPtr cur;
618
619 if ((doc != NULL) && (doc->extSubset != NULL)) {
620#ifdef DEBUG_TREE
621 xmlGenericError(xmlGenericErrorContext,
622 "xmlNewDtd(%s): document %s already have a DTD %s\n",
623 /* !!! */ (char *) name, doc->name,
624 /* !!! */ (char *)doc->extSubset->name);
625#endif
626 return(NULL);
627 }
628
629 /*
630 * Allocate a new DTD and fill the fields.
631 */
632 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
633 if (cur == NULL) {
634 xmlGenericError(xmlGenericErrorContext,
635 "xmlNewDtd : malloc failed\n");
636 return(NULL);
637 }
638 memset(cur, 0 , sizeof(xmlDtd));
639 cur->type = XML_DTD_NODE;
640
641 if (name != NULL)
642 cur->name = xmlStrdup(name);
643 if (ExternalID != NULL)
644 cur->ExternalID = xmlStrdup(ExternalID);
645 if (SystemID != NULL)
646 cur->SystemID = xmlStrdup(SystemID);
647 if (doc != NULL)
648 doc->extSubset = cur;
649 cur->doc = doc;
650
Daniel Veillard5335dc52003-01-01 20:59:38 +0000651 if (xmlRegisterNodeDefaultValue)
652 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000653 return(cur);
654}
655
656/**
657 * xmlGetIntSubset:
658 * @doc: the document pointer
659 *
660 * Get the internal subset of a document
661 * Returns a pointer to the DTD structure or NULL if not found
662 */
663
664xmlDtdPtr
665xmlGetIntSubset(xmlDocPtr doc) {
666 xmlNodePtr cur;
667
668 if (doc == NULL)
669 return(NULL);
670 cur = doc->children;
671 while (cur != NULL) {
672 if (cur->type == XML_DTD_NODE)
673 return((xmlDtdPtr) cur);
674 cur = cur->next;
675 }
676 return((xmlDtdPtr) doc->intSubset);
677}
678
679/**
680 * xmlCreateIntSubset:
681 * @doc: the document pointer
682 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000683 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000684 * @SystemID: the system ID
685 *
686 * Create the internal subset of a document
687 * Returns a pointer to the new DTD structure
688 */
689xmlDtdPtr
690xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
691 const xmlChar *ExternalID, const xmlChar *SystemID) {
692 xmlDtdPtr cur;
693
694 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
695#ifdef DEBUG_TREE
696 xmlGenericError(xmlGenericErrorContext,
697
698 "xmlCreateIntSubset(): document %s already have an internal subset\n",
699 doc->name);
700#endif
701 return(NULL);
702 }
703
704 /*
705 * Allocate a new DTD and fill the fields.
706 */
707 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
708 if (cur == NULL) {
709 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000710 "xmlCreateIntSubset : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000711 return(NULL);
712 }
713 memset(cur, 0, sizeof(xmlDtd));
714 cur->type = XML_DTD_NODE;
715
716 if (name != NULL)
717 cur->name = xmlStrdup(name);
718 if (ExternalID != NULL)
719 cur->ExternalID = xmlStrdup(ExternalID);
720 if (SystemID != NULL)
721 cur->SystemID = xmlStrdup(SystemID);
722 if (doc != NULL) {
723 doc->intSubset = cur;
724 cur->parent = doc;
725 cur->doc = doc;
726 if (doc->children == NULL) {
727 doc->children = (xmlNodePtr) cur;
728 doc->last = (xmlNodePtr) cur;
729 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000730 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000731 xmlNodePtr prev;
732
Owen Taylor3473f882001-02-23 17:55:21 +0000733 prev = doc->children;
734 prev->prev = (xmlNodePtr) cur;
735 cur->next = prev;
736 doc->children = (xmlNodePtr) cur;
737 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000738 xmlNodePtr next;
739
740 next = doc->children;
741 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
742 next = next->next;
743 if (next == NULL) {
744 cur->prev = doc->last;
745 cur->prev->next = (xmlNodePtr) cur;
746 cur->next = NULL;
747 doc->last = (xmlNodePtr) cur;
748 } else {
749 cur->next = next;
750 cur->prev = next->prev;
751 if (cur->prev == NULL)
752 doc->children = (xmlNodePtr) cur;
753 else
754 cur->prev->next = (xmlNodePtr) cur;
755 next->prev = (xmlNodePtr) cur;
756 }
Owen Taylor3473f882001-02-23 17:55:21 +0000757 }
758 }
759 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000760
761 if (xmlRegisterNodeDefaultValue)
762 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000763 return(cur);
764}
765
766/**
767 * xmlFreeDtd:
768 * @cur: the DTD structure to free up
769 *
770 * Free a DTD structure.
771 */
772void
773xmlFreeDtd(xmlDtdPtr cur) {
774 if (cur == NULL) {
775#ifdef DEBUG_TREE
776 xmlGenericError(xmlGenericErrorContext,
777 "xmlFreeDtd : DTD == NULL\n");
778#endif
779 return;
780 }
Daniel Veillard5335dc52003-01-01 20:59:38 +0000781
782 if (xmlDeregisterNodeDefaultValue)
783 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
784
Owen Taylor3473f882001-02-23 17:55:21 +0000785 if (cur->children != NULL) {
786 xmlNodePtr next, c = cur->children;
787
788 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000789 * Cleanup all the DTD comments they are not in the DTD
Owen Taylor3473f882001-02-23 17:55:21 +0000790 * indexes.
791 */
792 while (c != NULL) {
793 next = c->next;
794 if (c->type == XML_COMMENT_NODE) {
795 xmlUnlinkNode(c);
796 xmlFreeNode(c);
797 }
798 c = next;
799 }
800 }
801 if (cur->name != NULL) xmlFree((char *) cur->name);
802 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
803 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
804 /* TODO !!! */
805 if (cur->notations != NULL)
806 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
807
808 if (cur->elements != NULL)
809 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
810 if (cur->attributes != NULL)
811 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
812 if (cur->entities != NULL)
813 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
814 if (cur->pentities != NULL)
815 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
816
Owen Taylor3473f882001-02-23 17:55:21 +0000817 xmlFree(cur);
818}
819
820/**
821 * xmlNewDoc:
822 * @version: xmlChar string giving the version of XML "1.0"
823 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000824 * Creates a new XML document
825 *
Owen Taylor3473f882001-02-23 17:55:21 +0000826 * Returns a new document
827 */
828xmlDocPtr
829xmlNewDoc(const xmlChar *version) {
830 xmlDocPtr cur;
831
832 if (version == NULL)
833 version = (const xmlChar *) "1.0";
834
835 /*
836 * Allocate a new document and fill the fields.
837 */
838 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
839 if (cur == NULL) {
840 xmlGenericError(xmlGenericErrorContext,
841 "xmlNewDoc : malloc failed\n");
842 return(NULL);
843 }
844 memset(cur, 0, sizeof(xmlDoc));
845 cur->type = XML_DOCUMENT_NODE;
846
847 cur->version = xmlStrdup(version);
848 cur->standalone = -1;
849 cur->compression = -1; /* not initialized */
850 cur->doc = cur;
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000851 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +0000852
853 if (xmlRegisterNodeDefaultValue)
854 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000855 return(cur);
856}
857
858/**
859 * xmlFreeDoc:
860 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +0000861 *
862 * Free up all the structures used by a document, tree included.
863 */
864void
865xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +0000866 xmlDtdPtr extSubset, intSubset;
867
Owen Taylor3473f882001-02-23 17:55:21 +0000868 if (cur == NULL) {
869#ifdef DEBUG_TREE
870 xmlGenericError(xmlGenericErrorContext,
871 "xmlFreeDoc : document == NULL\n");
872#endif
873 return;
874 }
Daniel Veillard5335dc52003-01-01 20:59:38 +0000875
876 if (xmlDeregisterNodeDefaultValue)
877 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
878
Daniel Veillard76d66f42001-05-16 21:05:17 +0000879 /*
880 * Do this before freeing the children list to avoid ID lookups
881 */
882 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
883 cur->ids = NULL;
884 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
885 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000886 extSubset = cur->extSubset;
887 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +0000888 if (intSubset == extSubset)
889 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000890 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000891 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000892 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000893 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000894 }
Daniel Veillarda9142e72001-06-19 11:07:54 +0000895 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000896 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000897 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000898 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000899 }
900
901 if (cur->children != NULL) xmlFreeNodeList(cur->children);
902
Owen Taylor3473f882001-02-23 17:55:21 +0000903 if (cur->version != NULL) xmlFree((char *) cur->version);
904 if (cur->name != NULL) xmlFree((char *) cur->name);
905 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Owen Taylor3473f882001-02-23 17:55:21 +0000906 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +0000907 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Owen Taylor3473f882001-02-23 17:55:21 +0000908 xmlFree(cur);
909}
910
911/**
912 * xmlStringLenGetNodeList:
913 * @doc: the document
914 * @value: the value of the text
915 * @len: the length of the string value
916 *
917 * Parse the value string and build the node list associated. Should
918 * produce a flat tree with only TEXTs and ENTITY_REFs.
919 * Returns a pointer to the first child
920 */
921xmlNodePtr
922xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
923 xmlNodePtr ret = NULL, last = NULL;
924 xmlNodePtr node;
925 xmlChar *val;
926 const xmlChar *cur = value;
927 const xmlChar *q;
928 xmlEntityPtr ent;
929
930 if (value == NULL) return(NULL);
931
932 q = cur;
933 while ((*cur != 0) && (cur - value < len)) {
934 if (*cur == '&') {
935 /*
936 * Save the current text.
937 */
938 if (cur != q) {
939 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
940 xmlNodeAddContentLen(last, q, cur - q);
941 } else {
942 node = xmlNewDocTextLen(doc, q, cur - q);
943 if (node == NULL) return(ret);
944 if (last == NULL)
945 last = ret = node;
946 else {
947 last->next = node;
948 node->prev = last;
949 last = node;
950 }
951 }
952 }
953 /*
954 * Read the entity string
955 */
956 cur++;
957 q = cur;
958 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
959 if ((*cur == 0) || (cur - value >= len)) {
960#ifdef DEBUG_TREE
961 xmlGenericError(xmlGenericErrorContext,
962 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
963#endif
964 return(ret);
965 }
966 if (cur != q) {
967 /*
968 * Predefined entities don't generate nodes
969 */
970 val = xmlStrndup(q, cur - q);
971 ent = xmlGetDocEntity(doc, val);
972 if ((ent != NULL) &&
973 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
974 if (last == NULL) {
975 node = xmlNewDocText(doc, ent->content);
976 last = ret = node;
977 } else
978 xmlNodeAddContent(last, ent->content);
979
980 } else {
981 /*
982 * Create a new REFERENCE_REF node
983 */
984 node = xmlNewReference(doc, val);
985 if (node == NULL) {
986 if (val != NULL) xmlFree(val);
987 return(ret);
988 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +0000989 else if ((ent != NULL) && (ent->children == NULL)) {
990 xmlNodePtr tmp;
991
992 ent->children =
993 xmlStringGetNodeList(doc, (const xmlChar*)node->content);
994 tmp = ent->children;
995 while (tmp) {
996 tmp->parent = (xmlNodePtr)ent;
997 tmp = tmp->next;
998 }
999 }
Owen Taylor3473f882001-02-23 17:55:21 +00001000 if (last == NULL)
1001 last = ret = node;
1002 else {
1003 last->next = node;
1004 node->prev = last;
1005 last = node;
1006 }
1007 }
1008 xmlFree(val);
1009 }
1010 cur++;
1011 q = cur;
1012 } else
1013 cur++;
1014 }
1015 if (cur != q) {
1016 /*
1017 * Handle the last piece of text.
1018 */
1019 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1020 xmlNodeAddContentLen(last, q, cur - q);
1021 } else {
1022 node = xmlNewDocTextLen(doc, q, cur - q);
1023 if (node == NULL) return(ret);
1024 if (last == NULL)
1025 last = ret = node;
1026 else {
1027 last->next = node;
1028 node->prev = last;
1029 last = node;
1030 }
1031 }
1032 }
1033 return(ret);
1034}
1035
1036/**
1037 * xmlStringGetNodeList:
1038 * @doc: the document
1039 * @value: the value of the attribute
1040 *
1041 * Parse the value string and build the node list associated. Should
1042 * produce a flat tree with only TEXTs and ENTITY_REFs.
1043 * Returns a pointer to the first child
1044 */
1045xmlNodePtr
1046xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1047 xmlNodePtr ret = NULL, last = NULL;
1048 xmlNodePtr node;
1049 xmlChar *val;
1050 const xmlChar *cur = value;
1051 const xmlChar *q;
1052 xmlEntityPtr ent;
1053
1054 if (value == NULL) return(NULL);
1055
1056 q = cur;
1057 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001058 if (cur[0] == '&') {
1059 int charval = 0;
1060 xmlChar tmp;
1061
Owen Taylor3473f882001-02-23 17:55:21 +00001062 /*
1063 * Save the current text.
1064 */
1065 if (cur != q) {
1066 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1067 xmlNodeAddContentLen(last, q, cur - q);
1068 } else {
1069 node = xmlNewDocTextLen(doc, q, cur - q);
1070 if (node == NULL) return(ret);
1071 if (last == NULL)
1072 last = ret = node;
1073 else {
1074 last->next = node;
1075 node->prev = last;
1076 last = node;
1077 }
1078 }
1079 }
Owen Taylor3473f882001-02-23 17:55:21 +00001080 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001081 if ((cur[1] == '#') && (cur[2] == 'x')) {
1082 cur += 3;
1083 tmp = *cur;
1084 while (tmp != ';') { /* Non input consuming loop */
1085 if ((tmp >= '0') && (tmp <= '9'))
1086 charval = charval * 16 + (tmp - '0');
1087 else if ((tmp >= 'a') && (tmp <= 'f'))
1088 charval = charval * 16 + (tmp - 'a') + 10;
1089 else if ((tmp >= 'A') && (tmp <= 'F'))
1090 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001091 else {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001092 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001093 "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001094 charval = 0;
1095 break;
1096 }
1097 cur++;
1098 tmp = *cur;
1099 }
1100 if (tmp == ';')
1101 cur++;
1102 q = cur;
1103 } else if (cur[1] == '#') {
1104 cur += 2;
1105 tmp = *cur;
1106 while (tmp != ';') { /* Non input consuming loops */
1107 if ((tmp >= '0') && (tmp <= '9'))
1108 charval = charval * 10 + (tmp - '0');
1109 else {
1110 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001111 "xmlStringGetNodeList: invalid decimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001112 charval = 0;
1113 break;
1114 }
1115 cur++;
1116 tmp = *cur;
1117 }
1118 if (tmp == ';')
1119 cur++;
1120 q = cur;
1121 } else {
1122 /*
1123 * Read the entity string
1124 */
1125 cur++;
1126 q = cur;
1127 while ((*cur != 0) && (*cur != ';')) cur++;
1128 if (*cur == 0) {
1129#ifdef DEBUG_TREE
1130 xmlGenericError(xmlGenericErrorContext,
1131 "xmlStringGetNodeList: unterminated entity %30s\n", q);
1132#endif
1133 return(ret);
1134 }
1135 if (cur != q) {
1136 /*
1137 * Predefined entities don't generate nodes
1138 */
1139 val = xmlStrndup(q, cur - q);
1140 ent = xmlGetDocEntity(doc, val);
1141 if ((ent != NULL) &&
1142 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1143 if (last == NULL) {
1144 node = xmlNewDocText(doc, ent->content);
1145 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001146 } else if (last->type != XML_TEXT_NODE) {
1147 node = xmlNewDocText(doc, ent->content);
1148 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001149 } else
1150 xmlNodeAddContent(last, ent->content);
1151
1152 } else {
1153 /*
1154 * Create a new REFERENCE_REF node
1155 */
1156 node = xmlNewReference(doc, val);
1157 if (node == NULL) {
1158 if (val != NULL) xmlFree(val);
1159 return(ret);
1160 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001161 else if ((ent != NULL) && (ent->children == NULL)) {
1162 xmlNodePtr temp;
1163
1164 ent->children = xmlStringGetNodeList(doc,
1165 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001166 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001167 temp = ent->children;
1168 while (temp) {
1169 temp->parent = (xmlNodePtr)ent;
1170 temp = temp->next;
1171 }
1172 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001173 if (last == NULL) {
1174 last = ret = node;
1175 } else {
1176 last = xmlAddNextSibling(last, node);
1177 }
1178 }
1179 xmlFree(val);
1180 }
1181 cur++;
1182 q = cur;
1183 }
1184 if (charval != 0) {
1185 xmlChar buf[10];
1186 int len;
1187
1188 len = xmlCopyCharMultiByte(buf, charval);
1189 buf[len] = 0;
1190 node = xmlNewDocText(doc, buf);
1191 if (node != NULL) {
1192 if (last == NULL) {
1193 last = ret = node;
1194 } else {
1195 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001196 }
1197 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001198
1199 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001200 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001201 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001202 cur++;
1203 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001204 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001205 /*
1206 * Handle the last piece of text.
1207 */
1208 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1209 xmlNodeAddContentLen(last, q, cur - q);
1210 } else {
1211 node = xmlNewDocTextLen(doc, q, cur - q);
1212 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001213 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001214 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001215 } else {
1216 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001217 }
1218 }
1219 }
1220 return(ret);
1221}
1222
1223/**
1224 * xmlNodeListGetString:
1225 * @doc: the document
1226 * @list: a Node list
1227 * @inLine: should we replace entity contents or show their external form
1228 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001229 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001230 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001231 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001232 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001233 */
1234xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001235xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1236{
Owen Taylor3473f882001-02-23 17:55:21 +00001237 xmlNodePtr node = list;
1238 xmlChar *ret = NULL;
1239 xmlEntityPtr ent;
1240
Daniel Veillard7646b182002-04-20 06:41:40 +00001241 if (list == NULL)
1242 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001243
1244 while (node != NULL) {
1245 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001246 (node->type == XML_CDATA_SECTION_NODE)) {
1247 if (inLine) {
1248 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001249 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001250 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001251
Daniel Veillard7646b182002-04-20 06:41:40 +00001252 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1253 if (buffer != NULL) {
1254 ret = xmlStrcat(ret, buffer);
1255 xmlFree(buffer);
1256 }
1257 }
1258 } else if (node->type == XML_ENTITY_REF_NODE) {
1259 if (inLine) {
1260 ent = xmlGetDocEntity(doc, node->name);
1261 if (ent != NULL) {
1262 xmlChar *buffer;
1263
1264 /* an entity content can be any "well balanced chunk",
1265 * i.e. the result of the content [43] production:
1266 * http://www.w3.org/TR/REC-xml#NT-content.
1267 * So it can contain text, CDATA section or nested
1268 * entity reference nodes (among others).
1269 * -> we recursive call xmlNodeListGetString()
1270 * which handles these types */
1271 buffer = xmlNodeListGetString(doc, ent->children, 1);
1272 if (buffer != NULL) {
1273 ret = xmlStrcat(ret, buffer);
1274 xmlFree(buffer);
1275 }
1276 } else {
1277 ret = xmlStrcat(ret, node->content);
1278 }
1279 } else {
1280 xmlChar buf[2];
1281
1282 buf[0] = '&';
1283 buf[1] = 0;
1284 ret = xmlStrncat(ret, buf, 1);
1285 ret = xmlStrcat(ret, node->name);
1286 buf[0] = ';';
1287 buf[1] = 0;
1288 ret = xmlStrncat(ret, buf, 1);
1289 }
1290 }
1291#if 0
1292 else {
1293 xmlGenericError(xmlGenericErrorContext,
1294 "xmlGetNodeListString : invalid node type %d\n",
1295 node->type);
1296 }
1297#endif
1298 node = node->next;
1299 }
1300 return (ret);
1301}
Owen Taylor3473f882001-02-23 17:55:21 +00001302/**
1303 * xmlNodeListGetRawString:
1304 * @doc: the document
1305 * @list: a Node list
1306 * @inLine: should we replace entity contents or show their external form
1307 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001308 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001309 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1310 * this function doesn't do any character encoding handling.
1311 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001312 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001313 */
1314xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001315xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1316{
Owen Taylor3473f882001-02-23 17:55:21 +00001317 xmlNodePtr node = list;
1318 xmlChar *ret = NULL;
1319 xmlEntityPtr ent;
1320
Daniel Veillard7646b182002-04-20 06:41:40 +00001321 if (list == NULL)
1322 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001323
1324 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001325 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001326 (node->type == XML_CDATA_SECTION_NODE)) {
1327 if (inLine) {
1328 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001329 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001330 xmlChar *buffer;
1331
1332 buffer = xmlEncodeSpecialChars(doc, node->content);
1333 if (buffer != NULL) {
1334 ret = xmlStrcat(ret, buffer);
1335 xmlFree(buffer);
1336 }
1337 }
1338 } else if (node->type == XML_ENTITY_REF_NODE) {
1339 if (inLine) {
1340 ent = xmlGetDocEntity(doc, node->name);
1341 if (ent != NULL) {
1342 xmlChar *buffer;
1343
1344 /* an entity content can be any "well balanced chunk",
1345 * i.e. the result of the content [43] production:
1346 * http://www.w3.org/TR/REC-xml#NT-content.
1347 * So it can contain text, CDATA section or nested
1348 * entity reference nodes (among others).
1349 * -> we recursive call xmlNodeListGetRawString()
1350 * which handles these types */
1351 buffer =
1352 xmlNodeListGetRawString(doc, ent->children, 1);
1353 if (buffer != NULL) {
1354 ret = xmlStrcat(ret, buffer);
1355 xmlFree(buffer);
1356 }
1357 } else {
1358 ret = xmlStrcat(ret, node->content);
1359 }
1360 } else {
1361 xmlChar buf[2];
1362
1363 buf[0] = '&';
1364 buf[1] = 0;
1365 ret = xmlStrncat(ret, buf, 1);
1366 ret = xmlStrcat(ret, node->name);
1367 buf[0] = ';';
1368 buf[1] = 0;
1369 ret = xmlStrncat(ret, buf, 1);
1370 }
1371 }
Owen Taylor3473f882001-02-23 17:55:21 +00001372#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001373 else {
1374 xmlGenericError(xmlGenericErrorContext,
1375 "xmlGetNodeListString : invalid node type %d\n",
1376 node->type);
1377 }
Owen Taylor3473f882001-02-23 17:55:21 +00001378#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001379 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001380 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001381 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001382}
1383
1384/**
1385 * xmlNewProp:
1386 * @node: the holding node
1387 * @name: the name of the attribute
1388 * @value: the value of the attribute
1389 *
1390 * Create a new property carried by a node.
1391 * Returns a pointer to the attribute
1392 */
1393xmlAttrPtr
1394xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1395 xmlAttrPtr cur;
1396 xmlDocPtr doc = NULL;
1397
1398 if (name == NULL) {
1399#ifdef DEBUG_TREE
1400 xmlGenericError(xmlGenericErrorContext,
1401 "xmlNewProp : name == NULL\n");
1402#endif
1403 return(NULL);
1404 }
1405
1406 /*
1407 * Allocate a new property and fill the fields.
1408 */
1409 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1410 if (cur == NULL) {
1411 xmlGenericError(xmlGenericErrorContext,
1412 "xmlNewProp : malloc failed\n");
1413 return(NULL);
1414 }
1415 memset(cur, 0, sizeof(xmlAttr));
1416 cur->type = XML_ATTRIBUTE_NODE;
1417
1418 cur->parent = node;
1419 if (node != NULL) {
1420 doc = node->doc;
1421 cur->doc = doc;
1422 }
1423 cur->name = xmlStrdup(name);
1424 if (value != NULL) {
1425 xmlChar *buffer;
1426 xmlNodePtr tmp;
1427
1428 buffer = xmlEncodeEntitiesReentrant(doc, value);
1429 cur->children = xmlStringGetNodeList(doc, buffer);
1430 cur->last = NULL;
1431 tmp = cur->children;
1432 while (tmp != NULL) {
1433 tmp->parent = (xmlNodePtr) cur;
1434 tmp->doc = doc;
1435 if (tmp->next == NULL)
1436 cur->last = tmp;
1437 tmp = tmp->next;
1438 }
1439 xmlFree(buffer);
1440 }
1441
1442 /*
1443 * Add it at the end to preserve parsing order ...
1444 */
1445 if (node != NULL) {
1446 if (node->properties == NULL) {
1447 node->properties = cur;
1448 } else {
1449 xmlAttrPtr prev = node->properties;
1450
1451 while (prev->next != NULL) prev = prev->next;
1452 prev->next = cur;
1453 cur->prev = prev;
1454 }
1455 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001456
1457 if (xmlRegisterNodeDefaultValue)
1458 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001459 return(cur);
1460}
1461
1462/**
1463 * xmlNewNsProp:
1464 * @node: the holding node
1465 * @ns: the namespace
1466 * @name: the name of the attribute
1467 * @value: the value of the attribute
1468 *
1469 * Create a new property tagged with a namespace and carried by a node.
1470 * Returns a pointer to the attribute
1471 */
1472xmlAttrPtr
1473xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1474 const xmlChar *value) {
1475 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001476 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001477
1478 if (name == NULL) {
1479#ifdef DEBUG_TREE
1480 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001481 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001482#endif
1483 return(NULL);
1484 }
1485
1486 /*
1487 * Allocate a new property and fill the fields.
1488 */
1489 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1490 if (cur == NULL) {
1491 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001492 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001493 return(NULL);
1494 }
1495 memset(cur, 0, sizeof(xmlAttr));
1496 cur->type = XML_ATTRIBUTE_NODE;
1497
1498 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001499 if (node != NULL) {
1500 doc = node->doc;
1501 cur->doc = doc;
1502 }
Owen Taylor3473f882001-02-23 17:55:21 +00001503 cur->ns = ns;
1504 cur->name = xmlStrdup(name);
1505 if (value != NULL) {
1506 xmlChar *buffer;
1507 xmlNodePtr tmp;
1508
Daniel Veillarda682b212001-06-07 19:59:42 +00001509 buffer = xmlEncodeEntitiesReentrant(doc, value);
1510 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001511 cur->last = NULL;
1512 tmp = cur->children;
1513 while (tmp != NULL) {
1514 tmp->parent = (xmlNodePtr) cur;
1515 if (tmp->next == NULL)
1516 cur->last = tmp;
1517 tmp = tmp->next;
1518 }
1519 xmlFree(buffer);
1520 }
1521
1522 /*
1523 * Add it at the end to preserve parsing order ...
1524 */
1525 if (node != NULL) {
1526 if (node->properties == NULL) {
1527 node->properties = cur;
1528 } else {
1529 xmlAttrPtr prev = node->properties;
1530
1531 while (prev->next != NULL) prev = prev->next;
1532 prev->next = cur;
1533 cur->prev = prev;
1534 }
1535 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001536
1537 if (xmlRegisterNodeDefaultValue)
1538 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001539 return(cur);
1540}
1541
1542/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001543 * xmlNewNsPropEatName:
1544 * @node: the holding node
1545 * @ns: the namespace
1546 * @name: the name of the attribute
1547 * @value: the value of the attribute
1548 *
1549 * Create a new property tagged with a namespace and carried by a node.
1550 * Returns a pointer to the attribute
1551 */
1552xmlAttrPtr
1553xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1554 const xmlChar *value) {
1555 xmlAttrPtr cur;
1556 xmlDocPtr doc = NULL;
1557
1558 if (name == NULL) {
1559#ifdef DEBUG_TREE
1560 xmlGenericError(xmlGenericErrorContext,
1561 "xmlNewNsPropEatName : name == NULL\n");
1562#endif
1563 return(NULL);
1564 }
1565
1566 /*
1567 * Allocate a new property and fill the fields.
1568 */
1569 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1570 if (cur == NULL) {
1571 xmlGenericError(xmlGenericErrorContext,
1572 "xmlNewNsPropEatName : malloc failed\n");
1573 return(NULL);
1574 }
1575 memset(cur, 0, sizeof(xmlAttr));
1576 cur->type = XML_ATTRIBUTE_NODE;
1577
1578 cur->parent = node;
1579 if (node != NULL) {
1580 doc = node->doc;
1581 cur->doc = doc;
1582 }
1583 cur->ns = ns;
1584 cur->name = name;
1585 if (value != NULL) {
1586 xmlChar *buffer;
1587 xmlNodePtr tmp;
1588
1589 buffer = xmlEncodeEntitiesReentrant(doc, value);
1590 cur->children = xmlStringGetNodeList(doc, buffer);
1591 cur->last = NULL;
1592 tmp = cur->children;
1593 while (tmp != NULL) {
1594 tmp->parent = (xmlNodePtr) cur;
1595 if (tmp->next == NULL)
1596 cur->last = tmp;
1597 tmp = tmp->next;
1598 }
1599 xmlFree(buffer);
1600 }
1601
1602 /*
1603 * Add it at the end to preserve parsing order ...
1604 */
1605 if (node != NULL) {
1606 if (node->properties == NULL) {
1607 node->properties = cur;
1608 } else {
1609 xmlAttrPtr prev = node->properties;
1610
1611 while (prev->next != NULL) prev = prev->next;
1612 prev->next = cur;
1613 cur->prev = prev;
1614 }
1615 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001616
1617 if (xmlRegisterNodeDefaultValue)
1618 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001619 return(cur);
1620}
1621
1622/**
Owen Taylor3473f882001-02-23 17:55:21 +00001623 * xmlNewDocProp:
1624 * @doc: the document
1625 * @name: the name of the attribute
1626 * @value: the value of the attribute
1627 *
1628 * Create a new property carried by a document.
1629 * Returns a pointer to the attribute
1630 */
1631xmlAttrPtr
1632xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1633 xmlAttrPtr cur;
1634
1635 if (name == NULL) {
1636#ifdef DEBUG_TREE
1637 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001638 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001639#endif
1640 return(NULL);
1641 }
1642
1643 /*
1644 * Allocate a new property and fill the fields.
1645 */
1646 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1647 if (cur == NULL) {
1648 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001649 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001650 return(NULL);
1651 }
1652 memset(cur, 0, sizeof(xmlAttr));
1653 cur->type = XML_ATTRIBUTE_NODE;
1654
1655 cur->name = xmlStrdup(name);
1656 cur->doc = doc;
1657 if (value != NULL) {
1658 xmlNodePtr tmp;
1659
1660 cur->children = xmlStringGetNodeList(doc, value);
1661 cur->last = NULL;
1662
1663 tmp = cur->children;
1664 while (tmp != NULL) {
1665 tmp->parent = (xmlNodePtr) cur;
1666 if (tmp->next == NULL)
1667 cur->last = tmp;
1668 tmp = tmp->next;
1669 }
1670 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001671
1672 if (xmlRegisterNodeDefaultValue)
1673 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001674 return(cur);
1675}
1676
1677/**
1678 * xmlFreePropList:
1679 * @cur: the first property in the list
1680 *
1681 * Free a property and all its siblings, all the children are freed too.
1682 */
1683void
1684xmlFreePropList(xmlAttrPtr cur) {
1685 xmlAttrPtr next;
1686 if (cur == NULL) {
1687#ifdef DEBUG_TREE
1688 xmlGenericError(xmlGenericErrorContext,
1689 "xmlFreePropList : property == NULL\n");
1690#endif
1691 return;
1692 }
1693 while (cur != NULL) {
1694 next = cur->next;
1695 xmlFreeProp(cur);
1696 cur = next;
1697 }
1698}
1699
1700/**
1701 * xmlFreeProp:
1702 * @cur: an attribute
1703 *
1704 * Free one attribute, all the content is freed too
1705 */
1706void
1707xmlFreeProp(xmlAttrPtr cur) {
1708 if (cur == NULL) {
1709#ifdef DEBUG_TREE
1710 xmlGenericError(xmlGenericErrorContext,
1711 "xmlFreeProp : property == NULL\n");
1712#endif
1713 return;
1714 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001715
1716 if (xmlDeregisterNodeDefaultValue)
1717 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1718
Owen Taylor3473f882001-02-23 17:55:21 +00001719 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001720 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1721 ((cur->parent->doc->intSubset != NULL) ||
1722 (cur->parent->doc->extSubset != NULL))) {
1723 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1724 xmlRemoveID(cur->parent->doc, cur);
1725 }
Owen Taylor3473f882001-02-23 17:55:21 +00001726 if (cur->name != NULL) xmlFree((char *) cur->name);
1727 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001728 xmlFree(cur);
1729}
1730
1731/**
1732 * xmlRemoveProp:
1733 * @cur: an attribute
1734 *
1735 * Unlink and free one attribute, all the content is freed too
1736 * Note this doesn't work for namespace definition attributes
1737 *
1738 * Returns 0 if success and -1 in case of error.
1739 */
1740int
1741xmlRemoveProp(xmlAttrPtr cur) {
1742 xmlAttrPtr tmp;
1743 if (cur == NULL) {
1744#ifdef DEBUG_TREE
1745 xmlGenericError(xmlGenericErrorContext,
1746 "xmlRemoveProp : cur == NULL\n");
1747#endif
1748 return(-1);
1749 }
1750 if (cur->parent == NULL) {
1751#ifdef DEBUG_TREE
1752 xmlGenericError(xmlGenericErrorContext,
1753 "xmlRemoveProp : cur->parent == NULL\n");
1754#endif
1755 return(-1);
1756 }
1757 tmp = cur->parent->properties;
1758 if (tmp == cur) {
1759 cur->parent->properties = cur->next;
1760 xmlFreeProp(cur);
1761 return(0);
1762 }
1763 while (tmp != NULL) {
1764 if (tmp->next == cur) {
1765 tmp->next = cur->next;
1766 if (tmp->next != NULL)
1767 tmp->next->prev = tmp;
1768 xmlFreeProp(cur);
1769 return(0);
1770 }
1771 tmp = tmp->next;
1772 }
1773#ifdef DEBUG_TREE
1774 xmlGenericError(xmlGenericErrorContext,
1775 "xmlRemoveProp : attribute not owned by its node\n");
1776#endif
1777 return(-1);
1778}
1779
1780/**
1781 * xmlNewPI:
1782 * @name: the processing instruction name
1783 * @content: the PI content
1784 *
1785 * Creation of a processing instruction element.
1786 * Returns a pointer to the new node object.
1787 */
1788xmlNodePtr
1789xmlNewPI(const xmlChar *name, const xmlChar *content) {
1790 xmlNodePtr cur;
1791
1792 if (name == NULL) {
1793#ifdef DEBUG_TREE
1794 xmlGenericError(xmlGenericErrorContext,
1795 "xmlNewPI : name == NULL\n");
1796#endif
1797 return(NULL);
1798 }
1799
1800 /*
1801 * Allocate a new node and fill the fields.
1802 */
1803 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1804 if (cur == NULL) {
1805 xmlGenericError(xmlGenericErrorContext,
1806 "xmlNewPI : malloc failed\n");
1807 return(NULL);
1808 }
1809 memset(cur, 0, sizeof(xmlNode));
1810 cur->type = XML_PI_NODE;
1811
1812 cur->name = xmlStrdup(name);
1813 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001814 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001815 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001816
1817 if (xmlRegisterNodeDefaultValue)
1818 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001819 return(cur);
1820}
1821
1822/**
1823 * xmlNewNode:
1824 * @ns: namespace if any
1825 * @name: the node name
1826 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001827 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001828 *
1829 * Returns a pointer to the new node object.
1830 */
1831xmlNodePtr
1832xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1833 xmlNodePtr cur;
1834
1835 if (name == NULL) {
1836#ifdef DEBUG_TREE
1837 xmlGenericError(xmlGenericErrorContext,
1838 "xmlNewNode : name == NULL\n");
1839#endif
1840 return(NULL);
1841 }
1842
1843 /*
1844 * Allocate a new node and fill the fields.
1845 */
1846 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1847 if (cur == NULL) {
1848 xmlGenericError(xmlGenericErrorContext,
1849 "xmlNewNode : malloc failed\n");
1850 return(NULL);
1851 }
1852 memset(cur, 0, sizeof(xmlNode));
1853 cur->type = XML_ELEMENT_NODE;
1854
1855 cur->name = xmlStrdup(name);
1856 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001857
1858 if (xmlRegisterNodeDefaultValue)
1859 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001860 return(cur);
1861}
1862
1863/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001864 * xmlNewNodeEatName:
1865 * @ns: namespace if any
1866 * @name: the node name
1867 *
1868 * Creation of a new node element. @ns is optional (NULL).
1869 *
1870 * Returns a pointer to the new node object.
1871 */
1872xmlNodePtr
1873xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
1874 xmlNodePtr cur;
1875
1876 if (name == NULL) {
1877#ifdef DEBUG_TREE
1878 xmlGenericError(xmlGenericErrorContext,
1879 "xmlNewNode : name == NULL\n");
1880#endif
1881 return(NULL);
1882 }
1883
1884 /*
1885 * Allocate a new node and fill the fields.
1886 */
1887 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1888 if (cur == NULL) {
1889 xmlGenericError(xmlGenericErrorContext,
1890 "xmlNewNode : malloc failed\n");
1891 return(NULL);
1892 }
1893 memset(cur, 0, sizeof(xmlNode));
1894 cur->type = XML_ELEMENT_NODE;
1895
1896 cur->name = name;
1897 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001898
1899 if (xmlRegisterNodeDefaultValue)
1900 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001901 return(cur);
1902}
1903
1904/**
Owen Taylor3473f882001-02-23 17:55:21 +00001905 * xmlNewDocNode:
1906 * @doc: the document
1907 * @ns: namespace if any
1908 * @name: the node name
1909 * @content: the XML text content if any
1910 *
1911 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001912 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001913 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1914 * references, but XML special chars need to be escaped first by using
1915 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1916 * need entities support.
1917 *
1918 * Returns a pointer to the new node object.
1919 */
1920xmlNodePtr
1921xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1922 const xmlChar *name, const xmlChar *content) {
1923 xmlNodePtr cur;
1924
1925 cur = xmlNewNode(ns, name);
1926 if (cur != NULL) {
1927 cur->doc = doc;
1928 if (content != NULL) {
1929 cur->children = xmlStringGetNodeList(doc, content);
1930 UPDATE_LAST_CHILD_AND_PARENT(cur)
1931 }
1932 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001933
Owen Taylor3473f882001-02-23 17:55:21 +00001934 return(cur);
1935}
1936
Daniel Veillard46de64e2002-05-29 08:21:33 +00001937/**
1938 * xmlNewDocNodeEatName:
1939 * @doc: the document
1940 * @ns: namespace if any
1941 * @name: the node name
1942 * @content: the XML text content if any
1943 *
1944 * Creation of a new node element within a document. @ns and @content
1945 * are optional (NULL).
1946 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1947 * references, but XML special chars need to be escaped first by using
1948 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1949 * need entities support.
1950 *
1951 * Returns a pointer to the new node object.
1952 */
1953xmlNodePtr
1954xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
1955 xmlChar *name, const xmlChar *content) {
1956 xmlNodePtr cur;
1957
1958 cur = xmlNewNodeEatName(ns, name);
1959 if (cur != NULL) {
1960 cur->doc = doc;
1961 if (content != NULL) {
1962 cur->children = xmlStringGetNodeList(doc, content);
1963 UPDATE_LAST_CHILD_AND_PARENT(cur)
1964 }
1965 }
1966 return(cur);
1967}
1968
Owen Taylor3473f882001-02-23 17:55:21 +00001969
1970/**
1971 * xmlNewDocRawNode:
1972 * @doc: the document
1973 * @ns: namespace if any
1974 * @name: the node name
1975 * @content: the text content if any
1976 *
1977 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001978 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001979 *
1980 * Returns a pointer to the new node object.
1981 */
1982xmlNodePtr
1983xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1984 const xmlChar *name, const xmlChar *content) {
1985 xmlNodePtr cur;
1986
1987 cur = xmlNewNode(ns, name);
1988 if (cur != NULL) {
1989 cur->doc = doc;
1990 if (content != NULL) {
1991 cur->children = xmlNewDocText(doc, content);
1992 UPDATE_LAST_CHILD_AND_PARENT(cur)
1993 }
1994 }
1995 return(cur);
1996}
1997
1998/**
1999 * xmlNewDocFragment:
2000 * @doc: the document owning the fragment
2001 *
2002 * Creation of a new Fragment node.
2003 * Returns a pointer to the new node object.
2004 */
2005xmlNodePtr
2006xmlNewDocFragment(xmlDocPtr doc) {
2007 xmlNodePtr cur;
2008
2009 /*
2010 * Allocate a new DocumentFragment node and fill the fields.
2011 */
2012 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2013 if (cur == NULL) {
2014 xmlGenericError(xmlGenericErrorContext,
2015 "xmlNewDocFragment : malloc failed\n");
2016 return(NULL);
2017 }
2018 memset(cur, 0, sizeof(xmlNode));
2019 cur->type = XML_DOCUMENT_FRAG_NODE;
2020
2021 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002022
2023 if (xmlRegisterNodeDefaultValue)
2024 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002025 return(cur);
2026}
2027
2028/**
2029 * xmlNewText:
2030 * @content: the text content
2031 *
2032 * Creation of a new text node.
2033 * Returns a pointer to the new node object.
2034 */
2035xmlNodePtr
2036xmlNewText(const xmlChar *content) {
2037 xmlNodePtr cur;
2038
2039 /*
2040 * Allocate a new node and fill the fields.
2041 */
2042 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2043 if (cur == NULL) {
2044 xmlGenericError(xmlGenericErrorContext,
2045 "xmlNewText : malloc failed\n");
2046 return(NULL);
2047 }
2048 memset(cur, 0, sizeof(xmlNode));
2049 cur->type = XML_TEXT_NODE;
2050
2051 cur->name = xmlStringText;
2052 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002053 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002054 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002055
2056 if (xmlRegisterNodeDefaultValue)
2057 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002058 return(cur);
2059}
2060
2061/**
2062 * xmlNewTextChild:
2063 * @parent: the parent node
2064 * @ns: a namespace if any
2065 * @name: the name of the child
2066 * @content: the text content of the child if any.
2067 *
2068 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002069 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002070 * a child TEXT node will be created containing the string content.
2071 *
2072 * Returns a pointer to the new node object.
2073 */
2074xmlNodePtr
2075xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2076 const xmlChar *name, const xmlChar *content) {
2077 xmlNodePtr cur, prev;
2078
2079 if (parent == NULL) {
2080#ifdef DEBUG_TREE
2081 xmlGenericError(xmlGenericErrorContext,
2082 "xmlNewTextChild : parent == NULL\n");
2083#endif
2084 return(NULL);
2085 }
2086
2087 if (name == NULL) {
2088#ifdef DEBUG_TREE
2089 xmlGenericError(xmlGenericErrorContext,
2090 "xmlNewTextChild : name == NULL\n");
2091#endif
2092 return(NULL);
2093 }
2094
2095 /*
2096 * Allocate a new node
2097 */
2098 if (ns == NULL)
2099 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2100 else
2101 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2102 if (cur == NULL) return(NULL);
2103
2104 /*
2105 * add the new element at the end of the children list.
2106 */
2107 cur->type = XML_ELEMENT_NODE;
2108 cur->parent = parent;
2109 cur->doc = parent->doc;
2110 if (parent->children == NULL) {
2111 parent->children = cur;
2112 parent->last = cur;
2113 } else {
2114 prev = parent->last;
2115 prev->next = cur;
2116 cur->prev = prev;
2117 parent->last = cur;
2118 }
2119
2120 return(cur);
2121}
2122
2123/**
2124 * xmlNewCharRef:
2125 * @doc: the document
2126 * @name: the char ref string, starting with # or "&# ... ;"
2127 *
2128 * Creation of a new character reference node.
2129 * Returns a pointer to the new node object.
2130 */
2131xmlNodePtr
2132xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2133 xmlNodePtr cur;
2134
2135 /*
2136 * Allocate a new node and fill the fields.
2137 */
2138 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2139 if (cur == NULL) {
2140 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002141 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002142 return(NULL);
2143 }
2144 memset(cur, 0, sizeof(xmlNode));
2145 cur->type = XML_ENTITY_REF_NODE;
2146
2147 cur->doc = doc;
2148 if (name[0] == '&') {
2149 int len;
2150 name++;
2151 len = xmlStrlen(name);
2152 if (name[len - 1] == ';')
2153 cur->name = xmlStrndup(name, len - 1);
2154 else
2155 cur->name = xmlStrndup(name, len);
2156 } else
2157 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002158
2159 if (xmlRegisterNodeDefaultValue)
2160 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002161 return(cur);
2162}
2163
2164/**
2165 * xmlNewReference:
2166 * @doc: the document
2167 * @name: the reference name, or the reference string with & and ;
2168 *
2169 * Creation of a new reference node.
2170 * Returns a pointer to the new node object.
2171 */
2172xmlNodePtr
2173xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2174 xmlNodePtr cur;
2175 xmlEntityPtr ent;
2176
2177 /*
2178 * Allocate a new node and fill the fields.
2179 */
2180 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2181 if (cur == NULL) {
2182 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002183 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002184 return(NULL);
2185 }
2186 memset(cur, 0, sizeof(xmlNode));
2187 cur->type = XML_ENTITY_REF_NODE;
2188
2189 cur->doc = doc;
2190 if (name[0] == '&') {
2191 int len;
2192 name++;
2193 len = xmlStrlen(name);
2194 if (name[len - 1] == ';')
2195 cur->name = xmlStrndup(name, len - 1);
2196 else
2197 cur->name = xmlStrndup(name, len);
2198 } else
2199 cur->name = xmlStrdup(name);
2200
2201 ent = xmlGetDocEntity(doc, cur->name);
2202 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002203 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002204 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002205 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002206 * updated. Not sure if this is 100% correct.
2207 * -George
2208 */
2209 cur->children = (xmlNodePtr) ent;
2210 cur->last = (xmlNodePtr) ent;
2211 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002212
2213 if (xmlRegisterNodeDefaultValue)
2214 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002215 return(cur);
2216}
2217
2218/**
2219 * xmlNewDocText:
2220 * @doc: the document
2221 * @content: the text content
2222 *
2223 * Creation of a new text node within a document.
2224 * Returns a pointer to the new node object.
2225 */
2226xmlNodePtr
2227xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2228 xmlNodePtr cur;
2229
2230 cur = xmlNewText(content);
2231 if (cur != NULL) cur->doc = doc;
2232 return(cur);
2233}
2234
2235/**
2236 * xmlNewTextLen:
2237 * @content: the text content
2238 * @len: the text len.
2239 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002240 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002241 * Returns a pointer to the new node object.
2242 */
2243xmlNodePtr
2244xmlNewTextLen(const xmlChar *content, int len) {
2245 xmlNodePtr cur;
2246
2247 /*
2248 * Allocate a new node and fill the fields.
2249 */
2250 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2251 if (cur == NULL) {
2252 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002253 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002254 return(NULL);
2255 }
2256 memset(cur, 0, sizeof(xmlNode));
2257 cur->type = XML_TEXT_NODE;
2258
2259 cur->name = xmlStringText;
2260 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002261 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002262 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002263
2264 if (xmlRegisterNodeDefaultValue)
2265 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002266 return(cur);
2267}
2268
2269/**
2270 * xmlNewDocTextLen:
2271 * @doc: the document
2272 * @content: the text content
2273 * @len: the text len.
2274 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002275 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002276 * text node pertain to a given document.
2277 * Returns a pointer to the new node object.
2278 */
2279xmlNodePtr
2280xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2281 xmlNodePtr cur;
2282
2283 cur = xmlNewTextLen(content, len);
2284 if (cur != NULL) cur->doc = doc;
2285 return(cur);
2286}
2287
2288/**
2289 * xmlNewComment:
2290 * @content: the comment content
2291 *
2292 * Creation of a new node containing a comment.
2293 * Returns a pointer to the new node object.
2294 */
2295xmlNodePtr
2296xmlNewComment(const xmlChar *content) {
2297 xmlNodePtr cur;
2298
2299 /*
2300 * Allocate a new node and fill the fields.
2301 */
2302 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2303 if (cur == NULL) {
2304 xmlGenericError(xmlGenericErrorContext,
2305 "xmlNewComment : malloc failed\n");
2306 return(NULL);
2307 }
2308 memset(cur, 0, sizeof(xmlNode));
2309 cur->type = XML_COMMENT_NODE;
2310
2311 cur->name = xmlStringComment;
2312 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002313 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002314 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002315
2316 if (xmlRegisterNodeDefaultValue)
2317 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002318 return(cur);
2319}
2320
2321/**
2322 * xmlNewCDataBlock:
2323 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002324 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002325 * @len: the length of the block
2326 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002327 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002328 * Returns a pointer to the new node object.
2329 */
2330xmlNodePtr
2331xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2332 xmlNodePtr cur;
2333
2334 /*
2335 * Allocate a new node and fill the fields.
2336 */
2337 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2338 if (cur == NULL) {
2339 xmlGenericError(xmlGenericErrorContext,
2340 "xmlNewCDataBlock : malloc failed\n");
2341 return(NULL);
2342 }
2343 memset(cur, 0, sizeof(xmlNode));
2344 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002345 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002346
2347 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002348 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002349 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002350
2351 if (xmlRegisterNodeDefaultValue)
2352 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002353 return(cur);
2354}
2355
2356/**
2357 * xmlNewDocComment:
2358 * @doc: the document
2359 * @content: the comment content
2360 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002361 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002362 * Returns a pointer to the new node object.
2363 */
2364xmlNodePtr
2365xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2366 xmlNodePtr cur;
2367
2368 cur = xmlNewComment(content);
2369 if (cur != NULL) cur->doc = doc;
2370 return(cur);
2371}
2372
2373/**
2374 * xmlSetTreeDoc:
2375 * @tree: the top element
2376 * @doc: the document
2377 *
2378 * update all nodes under the tree to point to the right document
2379 */
2380void
2381xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002382 xmlAttrPtr prop;
2383
Owen Taylor3473f882001-02-23 17:55:21 +00002384 if (tree == NULL)
2385 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002386 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002387 if(tree->type == XML_ELEMENT_NODE) {
2388 prop = tree->properties;
2389 while (prop != NULL) {
2390 prop->doc = doc;
2391 xmlSetListDoc(prop->children, doc);
2392 prop = prop->next;
2393 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002394 }
Owen Taylor3473f882001-02-23 17:55:21 +00002395 if (tree->children != NULL)
2396 xmlSetListDoc(tree->children, doc);
2397 tree->doc = doc;
2398 }
2399}
2400
2401/**
2402 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002403 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002404 * @doc: the document
2405 *
2406 * update all nodes in the list to point to the right document
2407 */
2408void
2409xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2410 xmlNodePtr cur;
2411
2412 if (list == NULL)
2413 return;
2414 cur = list;
2415 while (cur != NULL) {
2416 if (cur->doc != doc)
2417 xmlSetTreeDoc(cur, doc);
2418 cur = cur->next;
2419 }
2420}
2421
2422
2423/**
2424 * xmlNewChild:
2425 * @parent: the parent node
2426 * @ns: a namespace if any
2427 * @name: the name of the child
2428 * @content: the XML content of the child if any.
2429 *
2430 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002431 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002432 * a child list containing the TEXTs and ENTITY_REFs node will be created.
2433 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2434 * references, but XML special chars need to be escaped first by using
2435 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
2436 * support is not needed.
2437 *
2438 * Returns a pointer to the new node object.
2439 */
2440xmlNodePtr
2441xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2442 const xmlChar *name, const xmlChar *content) {
2443 xmlNodePtr cur, prev;
2444
2445 if (parent == NULL) {
2446#ifdef DEBUG_TREE
2447 xmlGenericError(xmlGenericErrorContext,
2448 "xmlNewChild : parent == NULL\n");
2449#endif
2450 return(NULL);
2451 }
2452
2453 if (name == NULL) {
2454#ifdef DEBUG_TREE
2455 xmlGenericError(xmlGenericErrorContext,
2456 "xmlNewChild : name == NULL\n");
2457#endif
2458 return(NULL);
2459 }
2460
2461 /*
2462 * Allocate a new node
2463 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002464 if (parent->type == XML_ELEMENT_NODE) {
2465 if (ns == NULL)
2466 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2467 else
2468 cur = xmlNewDocNode(parent->doc, ns, name, content);
2469 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2470 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2471 if (ns == NULL)
2472 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2473 else
2474 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002475 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2476 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002477 } else {
2478 return(NULL);
2479 }
Owen Taylor3473f882001-02-23 17:55:21 +00002480 if (cur == NULL) return(NULL);
2481
2482 /*
2483 * add the new element at the end of the children list.
2484 */
2485 cur->type = XML_ELEMENT_NODE;
2486 cur->parent = parent;
2487 cur->doc = parent->doc;
2488 if (parent->children == NULL) {
2489 parent->children = cur;
2490 parent->last = cur;
2491 } else {
2492 prev = parent->last;
2493 prev->next = cur;
2494 cur->prev = prev;
2495 parent->last = cur;
2496 }
2497
2498 return(cur);
2499}
2500
2501/**
2502 * xmlAddNextSibling:
2503 * @cur: the child node
2504 * @elem: the new node
2505 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002506 * Add a new node @elem as the next sibling of @cur
2507 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002508 * first unlinked from its existing context.
2509 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002510 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2511 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002512 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002513 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002514 */
2515xmlNodePtr
2516xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2517 if (cur == NULL) {
2518#ifdef DEBUG_TREE
2519 xmlGenericError(xmlGenericErrorContext,
2520 "xmlAddNextSibling : cur == NULL\n");
2521#endif
2522 return(NULL);
2523 }
2524 if (elem == NULL) {
2525#ifdef DEBUG_TREE
2526 xmlGenericError(xmlGenericErrorContext,
2527 "xmlAddNextSibling : elem == NULL\n");
2528#endif
2529 return(NULL);
2530 }
2531
2532 xmlUnlinkNode(elem);
2533
2534 if (elem->type == XML_TEXT_NODE) {
2535 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002536 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002537 xmlFreeNode(elem);
2538 return(cur);
2539 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002540 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2541 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002542 xmlChar *tmp;
2543
2544 tmp = xmlStrdup(elem->content);
2545 tmp = xmlStrcat(tmp, cur->next->content);
2546 xmlNodeSetContent(cur->next, tmp);
2547 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002548 xmlFreeNode(elem);
2549 return(cur->next);
2550 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002551 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2552 /* check if an attribute with the same name exists */
2553 xmlAttrPtr attr;
2554
2555 if (elem->ns == NULL)
2556 attr = xmlHasProp(cur->parent, elem->name);
2557 else
2558 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2559 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2560 /* different instance, destroy it (attributes must be unique) */
2561 xmlFreeProp(attr);
2562 }
Owen Taylor3473f882001-02-23 17:55:21 +00002563 }
2564
2565 if (elem->doc != cur->doc) {
2566 xmlSetTreeDoc(elem, cur->doc);
2567 }
2568 elem->parent = cur->parent;
2569 elem->prev = cur;
2570 elem->next = cur->next;
2571 cur->next = elem;
2572 if (elem->next != NULL)
2573 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002574 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002575 elem->parent->last = elem;
2576 return(elem);
2577}
2578
2579/**
2580 * xmlAddPrevSibling:
2581 * @cur: the child node
2582 * @elem: the new node
2583 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002584 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002585 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002586 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002587 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002588 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2589 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002590 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002591 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002592 */
2593xmlNodePtr
2594xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2595 if (cur == NULL) {
2596#ifdef DEBUG_TREE
2597 xmlGenericError(xmlGenericErrorContext,
2598 "xmlAddPrevSibling : cur == NULL\n");
2599#endif
2600 return(NULL);
2601 }
2602 if (elem == NULL) {
2603#ifdef DEBUG_TREE
2604 xmlGenericError(xmlGenericErrorContext,
2605 "xmlAddPrevSibling : elem == NULL\n");
2606#endif
2607 return(NULL);
2608 }
2609
2610 xmlUnlinkNode(elem);
2611
2612 if (elem->type == XML_TEXT_NODE) {
2613 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002614 xmlChar *tmp;
2615
2616 tmp = xmlStrdup(elem->content);
2617 tmp = xmlStrcat(tmp, cur->content);
2618 xmlNodeSetContent(cur, tmp);
2619 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002620 xmlFreeNode(elem);
2621 return(cur);
2622 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002623 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2624 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002625 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002626 xmlFreeNode(elem);
2627 return(cur->prev);
2628 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002629 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2630 /* check if an attribute with the same name exists */
2631 xmlAttrPtr attr;
2632
2633 if (elem->ns == NULL)
2634 attr = xmlHasProp(cur->parent, elem->name);
2635 else
2636 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2637 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2638 /* different instance, destroy it (attributes must be unique) */
2639 xmlFreeProp(attr);
2640 }
Owen Taylor3473f882001-02-23 17:55:21 +00002641 }
2642
2643 if (elem->doc != cur->doc) {
2644 xmlSetTreeDoc(elem, cur->doc);
2645 }
2646 elem->parent = cur->parent;
2647 elem->next = cur;
2648 elem->prev = cur->prev;
2649 cur->prev = elem;
2650 if (elem->prev != NULL)
2651 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002652 if (elem->parent != NULL) {
2653 if (elem->type == XML_ATTRIBUTE_NODE) {
2654 if (elem->parent->properties == (xmlAttrPtr) cur) {
2655 elem->parent->properties = (xmlAttrPtr) elem;
2656 }
2657 } else {
2658 if (elem->parent->children == cur) {
2659 elem->parent->children = elem;
2660 }
2661 }
2662 }
Owen Taylor3473f882001-02-23 17:55:21 +00002663 return(elem);
2664}
2665
2666/**
2667 * xmlAddSibling:
2668 * @cur: the child node
2669 * @elem: the new node
2670 *
2671 * Add a new element @elem to the list of siblings of @cur
2672 * merging adjacent TEXT nodes (@elem may be freed)
2673 * If the new element was already inserted in a document it is
2674 * first unlinked from its existing context.
2675 *
2676 * Returns the new element or NULL in case of error.
2677 */
2678xmlNodePtr
2679xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2680 xmlNodePtr parent;
2681
2682 if (cur == NULL) {
2683#ifdef DEBUG_TREE
2684 xmlGenericError(xmlGenericErrorContext,
2685 "xmlAddSibling : cur == NULL\n");
2686#endif
2687 return(NULL);
2688 }
2689
2690 if (elem == NULL) {
2691#ifdef DEBUG_TREE
2692 xmlGenericError(xmlGenericErrorContext,
2693 "xmlAddSibling : elem == NULL\n");
2694#endif
2695 return(NULL);
2696 }
2697
2698 /*
2699 * Constant time is we can rely on the ->parent->last to find
2700 * the last sibling.
2701 */
2702 if ((cur->parent != NULL) &&
2703 (cur->parent->children != NULL) &&
2704 (cur->parent->last != NULL) &&
2705 (cur->parent->last->next == NULL)) {
2706 cur = cur->parent->last;
2707 } else {
2708 while (cur->next != NULL) cur = cur->next;
2709 }
2710
2711 xmlUnlinkNode(elem);
2712
2713 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002714 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002715 xmlFreeNode(elem);
2716 return(cur);
2717 }
2718
2719 if (elem->doc != cur->doc) {
2720 xmlSetTreeDoc(elem, cur->doc);
2721 }
2722 parent = cur->parent;
2723 elem->prev = cur;
2724 elem->next = NULL;
2725 elem->parent = parent;
2726 cur->next = elem;
2727 if (parent != NULL)
2728 parent->last = elem;
2729
2730 return(elem);
2731}
2732
2733/**
2734 * xmlAddChildList:
2735 * @parent: the parent node
2736 * @cur: the first node in the list
2737 *
2738 * Add a list of node at the end of the child list of the parent
2739 * merging adjacent TEXT nodes (@cur may be freed)
2740 *
2741 * Returns the last child or NULL in case of error.
2742 */
2743xmlNodePtr
2744xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2745 xmlNodePtr prev;
2746
2747 if (parent == NULL) {
2748#ifdef DEBUG_TREE
2749 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002750 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002751#endif
2752 return(NULL);
2753 }
2754
2755 if (cur == NULL) {
2756#ifdef DEBUG_TREE
2757 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002758 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002759#endif
2760 return(NULL);
2761 }
2762
2763 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2764 (cur->doc != parent->doc)) {
2765#ifdef DEBUG_TREE
2766 xmlGenericError(xmlGenericErrorContext,
2767 "Elements moved to a different document\n");
2768#endif
2769 }
2770
2771 /*
2772 * add the first element at the end of the children list.
2773 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00002774
Owen Taylor3473f882001-02-23 17:55:21 +00002775 if (parent->children == NULL) {
2776 parent->children = cur;
2777 } else {
2778 /*
2779 * If cur and parent->last both are TEXT nodes, then merge them.
2780 */
2781 if ((cur->type == XML_TEXT_NODE) &&
2782 (parent->last->type == XML_TEXT_NODE) &&
2783 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00002784 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002785 /*
2786 * if it's the only child, nothing more to be done.
2787 */
2788 if (cur->next == NULL) {
2789 xmlFreeNode(cur);
2790 return(parent->last);
2791 }
2792 prev = cur;
2793 cur = cur->next;
2794 xmlFreeNode(prev);
2795 }
2796 prev = parent->last;
2797 prev->next = cur;
2798 cur->prev = prev;
2799 }
2800 while (cur->next != NULL) {
2801 cur->parent = parent;
2802 if (cur->doc != parent->doc) {
2803 xmlSetTreeDoc(cur, parent->doc);
2804 }
2805 cur = cur->next;
2806 }
2807 cur->parent = parent;
2808 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2809 parent->last = cur;
2810
2811 return(cur);
2812}
2813
2814/**
2815 * xmlAddChild:
2816 * @parent: the parent node
2817 * @cur: the child node
2818 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002819 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00002820 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002821 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2822 * If there is an attribute with equal name, it is first destroyed.
2823 *
Owen Taylor3473f882001-02-23 17:55:21 +00002824 * Returns the child or NULL in case of error.
2825 */
2826xmlNodePtr
2827xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2828 xmlNodePtr prev;
2829
2830 if (parent == NULL) {
2831#ifdef DEBUG_TREE
2832 xmlGenericError(xmlGenericErrorContext,
2833 "xmlAddChild : parent == NULL\n");
2834#endif
2835 return(NULL);
2836 }
2837
2838 if (cur == NULL) {
2839#ifdef DEBUG_TREE
2840 xmlGenericError(xmlGenericErrorContext,
2841 "xmlAddChild : child == NULL\n");
2842#endif
2843 return(NULL);
2844 }
2845
Owen Taylor3473f882001-02-23 17:55:21 +00002846 /*
2847 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002848 * cur is then freed.
2849 */
2850 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002851 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002852 (parent->content != NULL) &&
2853 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002854 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002855 xmlFreeNode(cur);
2856 return(parent);
2857 }
2858 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002859 (parent->last->name == cur->name) &&
2860 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002861 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002862 xmlFreeNode(cur);
2863 return(parent->last);
2864 }
2865 }
2866
2867 /*
2868 * add the new element at the end of the children list.
2869 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00002870 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00002871 cur->parent = parent;
2872 if (cur->doc != parent->doc) {
2873 xmlSetTreeDoc(cur, parent->doc);
2874 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002875 /* this check prevents a loop on tree-traversions if a developer
2876 * tries to add a node to its parent multiple times
2877 */
2878 if (prev == parent)
2879 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002880
2881 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002882 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002883 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002884 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00002885 (parent->content != NULL) &&
2886 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002887 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002888 xmlFreeNode(cur);
2889 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002890 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002891 if (cur->type == XML_ATTRIBUTE_NODE) {
2892 if (parent->properties == NULL) {
2893 parent->properties = (xmlAttrPtr) cur;
2894 } else {
2895 /* check if an attribute with the same name exists */
2896 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00002897
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002898 if (cur->ns == NULL)
2899 lastattr = xmlHasProp(parent, cur->name);
2900 else
2901 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
2902 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
2903 /* different instance, destroy it (attributes must be unique) */
2904 xmlFreeProp(lastattr);
2905 }
2906 /* find the end */
2907 lastattr = parent->properties;
2908 while (lastattr->next != NULL) {
2909 lastattr = lastattr->next;
2910 }
2911 lastattr->next = (xmlAttrPtr) cur;
2912 ((xmlAttrPtr) cur)->prev = lastattr;
2913 }
2914 } else {
2915 if (parent->children == NULL) {
2916 parent->children = cur;
2917 parent->last = cur;
2918 } else {
2919 prev = parent->last;
2920 prev->next = cur;
2921 cur->prev = prev;
2922 parent->last = cur;
2923 }
2924 }
Owen Taylor3473f882001-02-23 17:55:21 +00002925 return(cur);
2926}
2927
2928/**
2929 * xmlGetLastChild:
2930 * @parent: the parent node
2931 *
2932 * Search the last child of a node.
2933 * Returns the last child or NULL if none.
2934 */
2935xmlNodePtr
2936xmlGetLastChild(xmlNodePtr parent) {
2937 if (parent == NULL) {
2938#ifdef DEBUG_TREE
2939 xmlGenericError(xmlGenericErrorContext,
2940 "xmlGetLastChild : parent == NULL\n");
2941#endif
2942 return(NULL);
2943 }
2944 return(parent->last);
2945}
2946
2947/**
2948 * xmlFreeNodeList:
2949 * @cur: the first node in the list
2950 *
2951 * Free a node and all its siblings, this is a recursive behaviour, all
2952 * the children are freed too.
2953 */
2954void
2955xmlFreeNodeList(xmlNodePtr cur) {
2956 xmlNodePtr next;
2957 if (cur == NULL) {
2958#ifdef DEBUG_TREE
2959 xmlGenericError(xmlGenericErrorContext,
2960 "xmlFreeNodeList : node == NULL\n");
2961#endif
2962 return;
2963 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00002964 if (cur->type == XML_NAMESPACE_DECL) {
2965 xmlFreeNsList((xmlNsPtr) cur);
2966 return;
2967 }
Owen Taylor3473f882001-02-23 17:55:21 +00002968 while (cur != NULL) {
2969 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002970 /* unroll to speed up freeing the document */
2971 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00002972
2973 if (xmlDeregisterNodeDefaultValue)
2974 xmlDeregisterNodeDefaultValue(cur);
2975
Daniel Veillard02141ea2001-04-30 11:46:40 +00002976 if ((cur->children != NULL) &&
2977 (cur->type != XML_ENTITY_REF_NODE))
2978 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00002979 if (((cur->type == XML_ELEMENT_NODE) ||
2980 (cur->type == XML_XINCLUDE_START) ||
2981 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002982 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00002983 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002984 if ((cur->type != XML_ELEMENT_NODE) &&
2985 (cur->type != XML_XINCLUDE_START) &&
2986 (cur->type != XML_XINCLUDE_END) &&
2987 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002988 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002989 }
2990 if (((cur->type == XML_ELEMENT_NODE) ||
2991 (cur->type == XML_XINCLUDE_START) ||
2992 (cur->type == XML_XINCLUDE_END)) &&
2993 (cur->nsDef != NULL))
2994 xmlFreeNsList(cur->nsDef);
2995
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002996 /*
2997 * When a node is a text node or a comment, it uses a global static
2998 * variable for the name of the node.
2999 *
3000 * The xmlStrEqual comparisons need to be done when (happened with
3001 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003002 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00003003 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003004 * the string addresses compare are not sufficient.
3005 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003006 if ((cur->name != NULL) &&
3007 (cur->name != xmlStringText) &&
3008 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003009 (cur->name != xmlStringComment)) {
3010 if (cur->type == XML_TEXT_NODE) {
3011 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
3012 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
3013 xmlFree((char *) cur->name);
3014 } else if (cur->type == XML_COMMENT_NODE) {
3015 if (!xmlStrEqual(cur->name, xmlStringComment))
3016 xmlFree((char *) cur->name);
3017 } else
3018 xmlFree((char *) cur->name);
3019 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00003020 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003021 xmlFree(cur);
3022 }
Owen Taylor3473f882001-02-23 17:55:21 +00003023 cur = next;
3024 }
3025}
3026
3027/**
3028 * xmlFreeNode:
3029 * @cur: the node
3030 *
3031 * Free a node, this is a recursive behaviour, all the children are freed too.
3032 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3033 */
3034void
3035xmlFreeNode(xmlNodePtr cur) {
3036 if (cur == NULL) {
3037#ifdef DEBUG_TREE
3038 xmlGenericError(xmlGenericErrorContext,
3039 "xmlFreeNode : node == NULL\n");
3040#endif
3041 return;
3042 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003043
Daniel Veillard02141ea2001-04-30 11:46:40 +00003044 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003045 if (cur->type == XML_DTD_NODE) {
3046 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003047 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003048 }
3049 if (cur->type == XML_NAMESPACE_DECL) {
3050 xmlFreeNs((xmlNsPtr) cur);
3051 return;
3052 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003053 if (cur->type == XML_ATTRIBUTE_NODE) {
3054 xmlFreeProp((xmlAttrPtr) cur);
3055 return;
3056 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003057
3058 if (xmlDeregisterNodeDefaultValue)
3059 xmlDeregisterNodeDefaultValue(cur);
3060
Owen Taylor3473f882001-02-23 17:55:21 +00003061 if ((cur->children != NULL) &&
3062 (cur->type != XML_ENTITY_REF_NODE))
3063 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003064 if (((cur->type == XML_ELEMENT_NODE) ||
3065 (cur->type == XML_XINCLUDE_START) ||
3066 (cur->type == XML_XINCLUDE_END)) &&
3067 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003068 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003069 if ((cur->type != XML_ELEMENT_NODE) &&
3070 (cur->content != NULL) &&
3071 (cur->type != XML_ENTITY_REF_NODE) &&
3072 (cur->type != XML_XINCLUDE_END) &&
3073 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003074 xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003075 }
3076
Daniel Veillardacd370f2001-06-09 17:17:51 +00003077 /*
3078 * When a node is a text node or a comment, it uses a global static
3079 * variable for the name of the node.
3080 *
3081 * The xmlStrEqual comparisons need to be done when (happened with
3082 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003083 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00003084 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00003085 * are not sufficient.
3086 */
Owen Taylor3473f882001-02-23 17:55:21 +00003087 if ((cur->name != NULL) &&
3088 (cur->name != xmlStringText) &&
3089 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00003090 (cur->name != xmlStringComment)) {
3091 if (cur->type == XML_TEXT_NODE) {
3092 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
3093 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
3094 xmlFree((char *) cur->name);
3095 } else if (cur->type == XML_COMMENT_NODE) {
3096 if (!xmlStrEqual(cur->name, xmlStringComment))
3097 xmlFree((char *) cur->name);
3098 } else
3099 xmlFree((char *) cur->name);
3100 }
3101
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003102 if (((cur->type == XML_ELEMENT_NODE) ||
3103 (cur->type == XML_XINCLUDE_START) ||
3104 (cur->type == XML_XINCLUDE_END)) &&
3105 (cur->nsDef != NULL))
3106 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003107 xmlFree(cur);
3108}
3109
3110/**
3111 * xmlUnlinkNode:
3112 * @cur: the node
3113 *
3114 * Unlink a node from it's current context, the node is not freed
3115 */
3116void
3117xmlUnlinkNode(xmlNodePtr cur) {
3118 if (cur == NULL) {
3119#ifdef DEBUG_TREE
3120 xmlGenericError(xmlGenericErrorContext,
3121 "xmlUnlinkNode : node == NULL\n");
3122#endif
3123 return;
3124 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003125 if (cur->type == XML_DTD_NODE) {
3126 xmlDocPtr doc;
3127 doc = cur->doc;
3128 if (doc->intSubset == (xmlDtdPtr) cur)
3129 doc->intSubset = NULL;
3130 if (doc->extSubset == (xmlDtdPtr) cur)
3131 doc->extSubset = NULL;
3132 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003133 if (cur->parent != NULL) {
3134 xmlNodePtr parent;
3135 parent = cur->parent;
3136 if (cur->type == XML_ATTRIBUTE_NODE) {
3137 if (parent->properties == (xmlAttrPtr) cur)
3138 parent->properties = ((xmlAttrPtr) cur)->next;
3139 } else {
3140 if (parent->children == cur)
3141 parent->children = cur->next;
3142 if (parent->last == cur)
3143 parent->last = cur->prev;
3144 }
3145 cur->parent = NULL;
3146 }
Owen Taylor3473f882001-02-23 17:55:21 +00003147 if (cur->next != NULL)
3148 cur->next->prev = cur->prev;
3149 if (cur->prev != NULL)
3150 cur->prev->next = cur->next;
3151 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003152}
3153
3154/**
3155 * xmlReplaceNode:
3156 * @old: the old node
3157 * @cur: the node
3158 *
3159 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003160 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003161 * first unlinked from its existing context.
3162 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003163 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003164 */
3165xmlNodePtr
3166xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3167 if (old == NULL) {
3168#ifdef DEBUG_TREE
3169 xmlGenericError(xmlGenericErrorContext,
3170 "xmlReplaceNode : old == NULL\n");
3171#endif
3172 return(NULL);
3173 }
3174 if (cur == NULL) {
3175 xmlUnlinkNode(old);
3176 return(old);
3177 }
3178 if (cur == old) {
3179 return(old);
3180 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003181 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3182#ifdef DEBUG_TREE
3183 xmlGenericError(xmlGenericErrorContext,
3184 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3185#endif
3186 return(old);
3187 }
3188 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3189#ifdef DEBUG_TREE
3190 xmlGenericError(xmlGenericErrorContext,
3191 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3192#endif
3193 return(old);
3194 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003195 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3196#ifdef DEBUG_TREE
3197 xmlGenericError(xmlGenericErrorContext,
3198 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3199#endif
3200 return(old);
3201 }
3202 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3203#ifdef DEBUG_TREE
3204 xmlGenericError(xmlGenericErrorContext,
3205 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3206#endif
3207 return(old);
3208 }
Owen Taylor3473f882001-02-23 17:55:21 +00003209 xmlUnlinkNode(cur);
3210 cur->doc = old->doc;
3211 cur->parent = old->parent;
3212 cur->next = old->next;
3213 if (cur->next != NULL)
3214 cur->next->prev = cur;
3215 cur->prev = old->prev;
3216 if (cur->prev != NULL)
3217 cur->prev->next = cur;
3218 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003219 if (cur->type == XML_ATTRIBUTE_NODE) {
3220 if (cur->parent->properties == (xmlAttrPtr)old)
3221 cur->parent->properties = ((xmlAttrPtr) cur);
3222 } else {
3223 if (cur->parent->children == old)
3224 cur->parent->children = cur;
3225 if (cur->parent->last == old)
3226 cur->parent->last = cur;
3227 }
Owen Taylor3473f882001-02-23 17:55:21 +00003228 }
3229 old->next = old->prev = NULL;
3230 old->parent = NULL;
3231 return(old);
3232}
3233
3234/************************************************************************
3235 * *
3236 * Copy operations *
3237 * *
3238 ************************************************************************/
3239
3240/**
3241 * xmlCopyNamespace:
3242 * @cur: the namespace
3243 *
3244 * Do a copy of the namespace.
3245 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003246 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003247 */
3248xmlNsPtr
3249xmlCopyNamespace(xmlNsPtr cur) {
3250 xmlNsPtr ret;
3251
3252 if (cur == NULL) return(NULL);
3253 switch (cur->type) {
3254 case XML_LOCAL_NAMESPACE:
3255 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3256 break;
3257 default:
3258#ifdef DEBUG_TREE
3259 xmlGenericError(xmlGenericErrorContext,
3260 "xmlCopyNamespace: invalid type %d\n", cur->type);
3261#endif
3262 return(NULL);
3263 }
3264 return(ret);
3265}
3266
3267/**
3268 * xmlCopyNamespaceList:
3269 * @cur: the first namespace
3270 *
3271 * Do a copy of an namespace list.
3272 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003273 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003274 */
3275xmlNsPtr
3276xmlCopyNamespaceList(xmlNsPtr cur) {
3277 xmlNsPtr ret = NULL;
3278 xmlNsPtr p = NULL,q;
3279
3280 while (cur != NULL) {
3281 q = xmlCopyNamespace(cur);
3282 if (p == NULL) {
3283 ret = p = q;
3284 } else {
3285 p->next = q;
3286 p = q;
3287 }
3288 cur = cur->next;
3289 }
3290 return(ret);
3291}
3292
3293static xmlNodePtr
3294xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3295/**
3296 * xmlCopyProp:
3297 * @target: the element where the attribute will be grafted
3298 * @cur: the attribute
3299 *
3300 * Do a copy of the attribute.
3301 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003302 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003303 */
3304xmlAttrPtr
3305xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3306 xmlAttrPtr ret;
3307
3308 if (cur == NULL) return(NULL);
3309 if (target != NULL)
3310 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3311 else if (cur->parent != NULL)
3312 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3313 else if (cur->children != NULL)
3314 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3315 else
3316 ret = xmlNewDocProp(NULL, cur->name, NULL);
3317 if (ret == NULL) return(NULL);
3318 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003319
Owen Taylor3473f882001-02-23 17:55:21 +00003320 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003321 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003322/*
3323 * if (target->doc)
3324 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3325 * else if (cur->doc) / * target may not yet have a doc : KPI * /
3326 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
3327 * else
3328 * ns = NULL;
3329 * ret->ns = ns;
3330 */
3331 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3332 if (ns == NULL) {
3333 /*
3334 * Humm, we are copying an element whose namespace is defined
3335 * out of the new tree scope. Search it in the original tree
3336 * and add it at the top of the new tree
3337 */
3338 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3339 if (ns != NULL) {
3340 xmlNodePtr root = target;
3341 xmlNodePtr pred = NULL;
3342
3343 while (root->parent != NULL) {
3344 pred = root;
3345 root = root->parent;
3346 }
3347 if (root == (xmlNodePtr) target->doc) {
3348 /* correct possibly cycling above the document elt */
3349 root = pred;
3350 }
3351 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3352 }
3353 } else {
3354 /*
3355 * we have to find something appropriate here since
3356 * we cant be sure, that the namespce we found is identified
3357 * by the prefix
3358 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003359 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003360 /* this is the nice case */
3361 ret->ns = ns;
3362 } else {
3363 /*
3364 * we are in trouble: we need a new reconcilied namespace.
3365 * This is expensive
3366 */
3367 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3368 }
3369 }
3370
Owen Taylor3473f882001-02-23 17:55:21 +00003371 } else
3372 ret->ns = NULL;
3373
3374 if (cur->children != NULL) {
3375 xmlNodePtr tmp;
3376
3377 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3378 ret->last = NULL;
3379 tmp = ret->children;
3380 while (tmp != NULL) {
3381 /* tmp->parent = (xmlNodePtr)ret; */
3382 if (tmp->next == NULL)
3383 ret->last = tmp;
3384 tmp = tmp->next;
3385 }
3386 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003387 /*
3388 * Try to handle IDs
3389 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003390 if ((target!= NULL) && (cur!= NULL) &&
3391 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003392 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3393 if (xmlIsID(cur->doc, cur->parent, cur)) {
3394 xmlChar *id;
3395
3396 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3397 if (id != NULL) {
3398 xmlAddID(NULL, target->doc, id, ret);
3399 xmlFree(id);
3400 }
3401 }
3402 }
Owen Taylor3473f882001-02-23 17:55:21 +00003403 return(ret);
3404}
3405
3406/**
3407 * xmlCopyPropList:
3408 * @target: the element where the attributes will be grafted
3409 * @cur: the first attribute
3410 *
3411 * Do a copy of an attribute list.
3412 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003413 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003414 */
3415xmlAttrPtr
3416xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3417 xmlAttrPtr ret = NULL;
3418 xmlAttrPtr p = NULL,q;
3419
3420 while (cur != NULL) {
3421 q = xmlCopyProp(target, cur);
3422 if (p == NULL) {
3423 ret = p = q;
3424 } else {
3425 p->next = q;
3426 q->prev = p;
3427 p = q;
3428 }
3429 cur = cur->next;
3430 }
3431 return(ret);
3432}
3433
3434/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003435 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003436 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003437 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003438 * tricky reason: namespaces. Doing a direct copy of a node
3439 * say RPM:Copyright without changing the namespace pointer to
3440 * something else can produce stale links. One way to do it is
3441 * to keep a reference counter but this doesn't work as soon
3442 * as one move the element or the subtree out of the scope of
3443 * the existing namespace. The actual solution seems to add
3444 * a copy of the namespace at the top of the copied tree if
3445 * not available in the subtree.
3446 * Hence two functions, the public front-end call the inner ones
3447 */
3448
3449static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003450xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003451 int recursive) {
3452 xmlNodePtr ret;
3453
3454 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003455 switch (node->type) {
3456 case XML_TEXT_NODE:
3457 case XML_CDATA_SECTION_NODE:
3458 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003459 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003460 case XML_ENTITY_REF_NODE:
3461 case XML_ENTITY_NODE:
3462 case XML_PI_NODE:
3463 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003464 case XML_XINCLUDE_START:
3465 case XML_XINCLUDE_END:
3466 break;
3467 case XML_ATTRIBUTE_NODE:
3468 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3469 case XML_NAMESPACE_DECL:
3470 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3471
Daniel Veillard39196eb2001-06-19 18:09:42 +00003472 case XML_DOCUMENT_NODE:
3473 case XML_HTML_DOCUMENT_NODE:
3474#ifdef LIBXML_DOCB_ENABLED
3475 case XML_DOCB_DOCUMENT_NODE:
3476#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003477 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00003478 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003479 case XML_NOTATION_NODE:
3480 case XML_DTD_NODE:
3481 case XML_ELEMENT_DECL:
3482 case XML_ATTRIBUTE_DECL:
3483 case XML_ENTITY_DECL:
3484 return(NULL);
3485 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003486
Owen Taylor3473f882001-02-23 17:55:21 +00003487 /*
3488 * Allocate a new node and fill the fields.
3489 */
3490 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3491 if (ret == NULL) {
3492 xmlGenericError(xmlGenericErrorContext,
3493 "xmlStaticCopyNode : malloc failed\n");
3494 return(NULL);
3495 }
3496 memset(ret, 0, sizeof(xmlNode));
3497 ret->type = node->type;
3498
3499 ret->doc = doc;
3500 ret->parent = parent;
3501 if (node->name == xmlStringText)
3502 ret->name = xmlStringText;
3503 else if (node->name == xmlStringTextNoenc)
3504 ret->name = xmlStringTextNoenc;
3505 else if (node->name == xmlStringComment)
3506 ret->name = xmlStringComment;
3507 else if (node->name != NULL)
3508 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003509 if ((node->type != XML_ELEMENT_NODE) &&
3510 (node->content != NULL) &&
3511 (node->type != XML_ENTITY_REF_NODE) &&
3512 (node->type != XML_XINCLUDE_END) &&
3513 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003514 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003515 }else{
3516 if (node->type == XML_ELEMENT_NODE)
3517 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00003518 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003519 if (parent != NULL) {
3520 xmlNodePtr tmp;
3521
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003522 /*
3523 * this is a tricky part for the node register thing:
3524 * in case ret does get coalesced in xmlAddChild
3525 * the deregister-node callback is called; so we register ret now already
3526 */
3527 if (xmlRegisterNodeDefaultValue)
3528 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3529
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003530 tmp = xmlAddChild(parent, ret);
3531 /* node could have coalesced */
3532 if (tmp != ret)
3533 return(tmp);
3534 }
Owen Taylor3473f882001-02-23 17:55:21 +00003535
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003536 if (!recursive)
3537 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003538 if (node->nsDef != NULL)
3539 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3540
3541 if (node->ns != NULL) {
3542 xmlNsPtr ns;
3543
3544 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3545 if (ns == NULL) {
3546 /*
3547 * Humm, we are copying an element whose namespace is defined
3548 * out of the new tree scope. Search it in the original tree
3549 * and add it at the top of the new tree
3550 */
3551 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3552 if (ns != NULL) {
3553 xmlNodePtr root = ret;
3554
3555 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003556 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003557 }
3558 } else {
3559 /*
3560 * reference the existing namespace definition in our own tree.
3561 */
3562 ret->ns = ns;
3563 }
3564 }
3565 if (node->properties != NULL)
3566 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003567 if (node->type == XML_ENTITY_REF_NODE) {
3568 if ((doc == NULL) || (node->doc != doc)) {
3569 /*
3570 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003571 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003572 * we cannot keep the reference. Try to find it in the
3573 * target document.
3574 */
3575 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3576 } else {
3577 ret->children = node->children;
3578 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003579 ret->last = ret->children;
3580 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003581 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003582 UPDATE_LAST_CHILD_AND_PARENT(ret)
3583 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003584
3585out:
3586 /* if parent != NULL we already registered the node above */
3587 if (parent == NULL && xmlRegisterNodeDefaultValue)
3588 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003589 return(ret);
3590}
3591
3592static xmlNodePtr
3593xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3594 xmlNodePtr ret = NULL;
3595 xmlNodePtr p = NULL,q;
3596
3597 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003598 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003599 if (doc == NULL) {
3600 node = node->next;
3601 continue;
3602 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003603 if (doc->intSubset == NULL) {
3604 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3605 q->doc = doc;
3606 q->parent = parent;
3607 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003608 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003609 } else {
3610 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003611 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003612 }
3613 } else
3614 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003615 if (ret == NULL) {
3616 q->prev = NULL;
3617 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003618 } else if (p != q) {
3619 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003620 p->next = q;
3621 q->prev = p;
3622 p = q;
3623 }
3624 node = node->next;
3625 }
3626 return(ret);
3627}
3628
3629/**
3630 * xmlCopyNode:
3631 * @node: the node
3632 * @recursive: if 1 do a recursive copy.
3633 *
3634 * Do a copy of the node.
3635 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003636 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003637 */
3638xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003639xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003640 xmlNodePtr ret;
3641
3642 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3643 return(ret);
3644}
3645
3646/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003647 * xmlDocCopyNode:
3648 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003649 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003650 * @recursive: if 1 do a recursive copy.
3651 *
3652 * Do a copy of the node to a given document.
3653 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003654 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003655 */
3656xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003657xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003658 xmlNodePtr ret;
3659
3660 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3661 return(ret);
3662}
3663
3664/**
Owen Taylor3473f882001-02-23 17:55:21 +00003665 * xmlCopyNodeList:
3666 * @node: the first node in the list.
3667 *
3668 * Do a recursive copy of the node list.
3669 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003670 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003671 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003672xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003673 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3674 return(ret);
3675}
3676
3677/**
Owen Taylor3473f882001-02-23 17:55:21 +00003678 * xmlCopyDtd:
3679 * @dtd: the dtd
3680 *
3681 * Do a copy of the dtd.
3682 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003683 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003684 */
3685xmlDtdPtr
3686xmlCopyDtd(xmlDtdPtr dtd) {
3687 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003688 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003689
3690 if (dtd == NULL) return(NULL);
3691 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3692 if (ret == NULL) return(NULL);
3693 if (dtd->entities != NULL)
3694 ret->entities = (void *) xmlCopyEntitiesTable(
3695 (xmlEntitiesTablePtr) dtd->entities);
3696 if (dtd->notations != NULL)
3697 ret->notations = (void *) xmlCopyNotationTable(
3698 (xmlNotationTablePtr) dtd->notations);
3699 if (dtd->elements != NULL)
3700 ret->elements = (void *) xmlCopyElementTable(
3701 (xmlElementTablePtr) dtd->elements);
3702 if (dtd->attributes != NULL)
3703 ret->attributes = (void *) xmlCopyAttributeTable(
3704 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003705 if (dtd->pentities != NULL)
3706 ret->pentities = (void *) xmlCopyEntitiesTable(
3707 (xmlEntitiesTablePtr) dtd->pentities);
3708
3709 cur = dtd->children;
3710 while (cur != NULL) {
3711 q = NULL;
3712
3713 if (cur->type == XML_ENTITY_DECL) {
3714 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3715 switch (tmp->etype) {
3716 case XML_INTERNAL_GENERAL_ENTITY:
3717 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3718 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3719 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3720 break;
3721 case XML_INTERNAL_PARAMETER_ENTITY:
3722 case XML_EXTERNAL_PARAMETER_ENTITY:
3723 q = (xmlNodePtr)
3724 xmlGetParameterEntityFromDtd(ret, tmp->name);
3725 break;
3726 case XML_INTERNAL_PREDEFINED_ENTITY:
3727 break;
3728 }
3729 } else if (cur->type == XML_ELEMENT_DECL) {
3730 xmlElementPtr tmp = (xmlElementPtr) cur;
3731 q = (xmlNodePtr)
3732 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3733 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3734 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3735 q = (xmlNodePtr)
3736 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3737 } else if (cur->type == XML_COMMENT_NODE) {
3738 q = xmlCopyNode(cur, 0);
3739 }
3740
3741 if (q == NULL) {
3742 cur = cur->next;
3743 continue;
3744 }
3745
3746 if (p == NULL)
3747 ret->children = q;
3748 else
3749 p->next = q;
3750
3751 q->prev = p;
3752 q->parent = (xmlNodePtr) ret;
3753 q->next = NULL;
3754 ret->last = q;
3755 p = q;
3756 cur = cur->next;
3757 }
3758
Owen Taylor3473f882001-02-23 17:55:21 +00003759 return(ret);
3760}
3761
3762/**
3763 * xmlCopyDoc:
3764 * @doc: the document
3765 * @recursive: if 1 do a recursive copy.
3766 *
3767 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003768 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003769 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003770 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003771 */
3772xmlDocPtr
3773xmlCopyDoc(xmlDocPtr doc, int recursive) {
3774 xmlDocPtr ret;
3775
3776 if (doc == NULL) return(NULL);
3777 ret = xmlNewDoc(doc->version);
3778 if (ret == NULL) return(NULL);
3779 if (doc->name != NULL)
3780 ret->name = xmlMemStrdup(doc->name);
3781 if (doc->encoding != NULL)
3782 ret->encoding = xmlStrdup(doc->encoding);
3783 ret->charset = doc->charset;
3784 ret->compression = doc->compression;
3785 ret->standalone = doc->standalone;
3786 if (!recursive) return(ret);
3787
Daniel Veillardb33c2012001-04-25 12:59:04 +00003788 ret->last = NULL;
3789 ret->children = NULL;
3790 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003791 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003792 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003793 ret->intSubset->parent = ret;
3794 }
Owen Taylor3473f882001-02-23 17:55:21 +00003795 if (doc->oldNs != NULL)
3796 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3797 if (doc->children != NULL) {
3798 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003799
3800 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3801 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003802 ret->last = NULL;
3803 tmp = ret->children;
3804 while (tmp != NULL) {
3805 if (tmp->next == NULL)
3806 ret->last = tmp;
3807 tmp = tmp->next;
3808 }
3809 }
3810 return(ret);
3811}
3812
3813/************************************************************************
3814 * *
3815 * Content access functions *
3816 * *
3817 ************************************************************************/
3818
3819/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003820 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003821 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00003822 *
3823 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003824 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003825 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003826 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003827 */
3828long
3829xmlGetLineNo(xmlNodePtr node)
3830{
3831 long result = -1;
3832
3833 if (!node)
3834 return result;
3835 if (node->type == XML_ELEMENT_NODE)
3836 result = (long) node->content;
3837 else if ((node->prev != NULL) &&
3838 ((node->prev->type == XML_ELEMENT_NODE) ||
3839 (node->prev->type == XML_TEXT_NODE)))
3840 result = xmlGetLineNo(node->prev);
3841 else if ((node->parent != NULL) &&
3842 ((node->parent->type == XML_ELEMENT_NODE) ||
3843 (node->parent->type == XML_TEXT_NODE)))
3844 result = xmlGetLineNo(node->parent);
3845
3846 return result;
3847}
3848
3849/**
3850 * xmlGetNodePath:
3851 * @node: a node
3852 *
3853 * Build a structure based Path for the given node
3854 *
3855 * Returns the new path or NULL in case of error. The caller must free
3856 * the returned string
3857 */
3858xmlChar *
3859xmlGetNodePath(xmlNodePtr node)
3860{
3861 xmlNodePtr cur, tmp, next;
3862 xmlChar *buffer = NULL, *temp;
3863 size_t buf_len;
3864 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00003865 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00003866 const char *name;
3867 char nametemp[100];
3868 int occur = 0;
3869
3870 if (node == NULL)
3871 return (NULL);
3872
3873 buf_len = 500;
3874 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3875 if (buffer == NULL)
3876 return (NULL);
3877 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3878 if (buf == NULL) {
3879 xmlFree(buffer);
3880 return (NULL);
3881 }
3882
3883 buffer[0] = 0;
3884 cur = node;
3885 do {
3886 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003887 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003888 occur = 0;
3889 if ((cur->type == XML_DOCUMENT_NODE) ||
3890 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3891 if (buffer[0] == '/')
3892 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003893 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003894 next = NULL;
3895 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003896 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003897 name = (const char *) cur->name;
3898 if (cur->ns) {
3899 snprintf(nametemp, sizeof(nametemp) - 1,
3900 "%s:%s", cur->ns->prefix, cur->name);
3901 nametemp[sizeof(nametemp) - 1] = 0;
3902 name = nametemp;
3903 }
3904 next = cur->parent;
3905
3906 /*
3907 * Thumbler index computation
3908 */
3909 tmp = cur->prev;
3910 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00003911 if ((tmp->type == XML_ELEMENT_NODE) &&
3912 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00003913 occur++;
3914 tmp = tmp->prev;
3915 }
3916 if (occur == 0) {
3917 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00003918 while (tmp != NULL && occur == 0) {
3919 if ((tmp->type == XML_ELEMENT_NODE) &&
3920 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00003921 occur++;
3922 tmp = tmp->next;
3923 }
3924 if (occur != 0)
3925 occur = 1;
3926 } else
3927 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00003928 } else if (cur->type == XML_COMMENT_NODE) {
3929 sep = "/";
3930 name = "comment()";
3931 next = cur->parent;
3932
3933 /*
3934 * Thumbler index computation
3935 */
3936 tmp = cur->prev;
3937 while (tmp != NULL) {
3938 if (tmp->type == XML_COMMENT_NODE)
3939 occur++;
3940 tmp = tmp->prev;
3941 }
3942 if (occur == 0) {
3943 tmp = cur->next;
3944 while (tmp != NULL && occur == 0) {
3945 if (tmp->type == XML_COMMENT_NODE)
3946 occur++;
3947 tmp = tmp->next;
3948 }
3949 if (occur != 0)
3950 occur = 1;
3951 } else
3952 occur++;
3953 } else if ((cur->type == XML_TEXT_NODE) ||
3954 (cur->type == XML_CDATA_SECTION_NODE)) {
3955 sep = "/";
3956 name = "text()";
3957 next = cur->parent;
3958
3959 /*
3960 * Thumbler index computation
3961 */
3962 tmp = cur->prev;
3963 while (tmp != NULL) {
3964 if ((cur->type == XML_TEXT_NODE) ||
3965 (cur->type == XML_CDATA_SECTION_NODE))
3966 occur++;
3967 tmp = tmp->prev;
3968 }
3969 if (occur == 0) {
3970 tmp = cur->next;
3971 while (tmp != NULL && occur == 0) {
3972 if ((cur->type == XML_TEXT_NODE) ||
3973 (cur->type == XML_CDATA_SECTION_NODE))
3974 occur++;
3975 tmp = tmp->next;
3976 }
3977 if (occur != 0)
3978 occur = 1;
3979 } else
3980 occur++;
3981 } else if (cur->type == XML_PI_NODE) {
3982 sep = "/";
3983 snprintf(nametemp, sizeof(nametemp) - 1,
3984 "processing-instruction('%s')", cur->name);
3985 nametemp[sizeof(nametemp) - 1] = 0;
3986 name = nametemp;
3987
3988 next = cur->parent;
3989
3990 /*
3991 * Thumbler index computation
3992 */
3993 tmp = cur->prev;
3994 while (tmp != NULL) {
3995 if ((tmp->type == XML_PI_NODE) &&
3996 (xmlStrEqual(cur->name, tmp->name)))
3997 occur++;
3998 tmp = tmp->prev;
3999 }
4000 if (occur == 0) {
4001 tmp = cur->next;
4002 while (tmp != NULL && occur == 0) {
4003 if ((tmp->type == XML_PI_NODE) &&
4004 (xmlStrEqual(cur->name, tmp->name)))
4005 occur++;
4006 tmp = tmp->next;
4007 }
4008 if (occur != 0)
4009 occur = 1;
4010 } else
4011 occur++;
4012
Daniel Veillard8faa7832001-11-26 15:58:08 +00004013 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004014 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004015 name = (const char *) (((xmlAttrPtr) cur)->name);
4016 next = ((xmlAttrPtr) cur)->parent;
4017 } else {
4018 next = cur->parent;
4019 }
4020
4021 /*
4022 * Make sure there is enough room
4023 */
4024 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4025 buf_len =
4026 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4027 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4028 if (temp == NULL) {
4029 xmlFree(buf);
4030 xmlFree(buffer);
4031 return (NULL);
4032 }
4033 buffer = temp;
4034 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4035 if (temp == NULL) {
4036 xmlFree(buf);
4037 xmlFree(buffer);
4038 return (NULL);
4039 }
4040 buf = temp;
4041 }
4042 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004043 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004044 sep, name, (char *) buffer);
4045 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004046 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004047 sep, name, occur, (char *) buffer);
4048 snprintf((char *) buffer, buf_len, "%s", buf);
4049 cur = next;
4050 } while (cur != NULL);
4051 xmlFree(buf);
4052 return (buffer);
4053}
4054
4055/**
Owen Taylor3473f882001-02-23 17:55:21 +00004056 * xmlDocGetRootElement:
4057 * @doc: the document
4058 *
4059 * Get the root element of the document (doc->children is a list
4060 * containing possibly comments, PIs, etc ...).
4061 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004062 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004063 */
4064xmlNodePtr
4065xmlDocGetRootElement(xmlDocPtr doc) {
4066 xmlNodePtr ret;
4067
4068 if (doc == NULL) return(NULL);
4069 ret = doc->children;
4070 while (ret != NULL) {
4071 if (ret->type == XML_ELEMENT_NODE)
4072 return(ret);
4073 ret = ret->next;
4074 }
4075 return(ret);
4076}
4077
4078/**
4079 * xmlDocSetRootElement:
4080 * @doc: the document
4081 * @root: the new document root element
4082 *
4083 * Set the root element of the document (doc->children is a list
4084 * containing possibly comments, PIs, etc ...).
4085 *
4086 * Returns the old root element if any was found
4087 */
4088xmlNodePtr
4089xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4090 xmlNodePtr old = NULL;
4091
4092 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004093 if (root == NULL)
4094 return(NULL);
4095 xmlUnlinkNode(root);
4096 root->doc = doc;
4097 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004098 old = doc->children;
4099 while (old != NULL) {
4100 if (old->type == XML_ELEMENT_NODE)
4101 break;
4102 old = old->next;
4103 }
4104 if (old == NULL) {
4105 if (doc->children == NULL) {
4106 doc->children = root;
4107 doc->last = root;
4108 } else {
4109 xmlAddSibling(doc->children, root);
4110 }
4111 } else {
4112 xmlReplaceNode(old, root);
4113 }
4114 return(old);
4115}
4116
4117/**
4118 * xmlNodeSetLang:
4119 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004120 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004121 *
4122 * Set the language of a node, i.e. the values of the xml:lang
4123 * attribute.
4124 */
4125void
4126xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004127 xmlNsPtr ns;
4128
Owen Taylor3473f882001-02-23 17:55:21 +00004129 if (cur == NULL) return;
4130 switch(cur->type) {
4131 case XML_TEXT_NODE:
4132 case XML_CDATA_SECTION_NODE:
4133 case XML_COMMENT_NODE:
4134 case XML_DOCUMENT_NODE:
4135 case XML_DOCUMENT_TYPE_NODE:
4136 case XML_DOCUMENT_FRAG_NODE:
4137 case XML_NOTATION_NODE:
4138 case XML_HTML_DOCUMENT_NODE:
4139 case XML_DTD_NODE:
4140 case XML_ELEMENT_DECL:
4141 case XML_ATTRIBUTE_DECL:
4142 case XML_ENTITY_DECL:
4143 case XML_PI_NODE:
4144 case XML_ENTITY_REF_NODE:
4145 case XML_ENTITY_NODE:
4146 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004147#ifdef LIBXML_DOCB_ENABLED
4148 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004149#endif
4150 case XML_XINCLUDE_START:
4151 case XML_XINCLUDE_END:
4152 return;
4153 case XML_ELEMENT_NODE:
4154 case XML_ATTRIBUTE_NODE:
4155 break;
4156 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004157 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4158 if (ns == NULL)
4159 return;
4160 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004161}
4162
4163/**
4164 * xmlNodeGetLang:
4165 * @cur: the node being checked
4166 *
4167 * Searches the language of a node, i.e. the values of the xml:lang
4168 * attribute or the one carried by the nearest ancestor.
4169 *
4170 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004171 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004172 */
4173xmlChar *
4174xmlNodeGetLang(xmlNodePtr cur) {
4175 xmlChar *lang;
4176
4177 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004178 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004179 if (lang != NULL)
4180 return(lang);
4181 cur = cur->parent;
4182 }
4183 return(NULL);
4184}
4185
4186
4187/**
4188 * xmlNodeSetSpacePreserve:
4189 * @cur: the node being changed
4190 * @val: the xml:space value ("0": default, 1: "preserve")
4191 *
4192 * Set (or reset) the space preserving behaviour of a node, i.e. the
4193 * value of the xml:space attribute.
4194 */
4195void
4196xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004197 xmlNsPtr ns;
4198
Owen Taylor3473f882001-02-23 17:55:21 +00004199 if (cur == NULL) return;
4200 switch(cur->type) {
4201 case XML_TEXT_NODE:
4202 case XML_CDATA_SECTION_NODE:
4203 case XML_COMMENT_NODE:
4204 case XML_DOCUMENT_NODE:
4205 case XML_DOCUMENT_TYPE_NODE:
4206 case XML_DOCUMENT_FRAG_NODE:
4207 case XML_NOTATION_NODE:
4208 case XML_HTML_DOCUMENT_NODE:
4209 case XML_DTD_NODE:
4210 case XML_ELEMENT_DECL:
4211 case XML_ATTRIBUTE_DECL:
4212 case XML_ENTITY_DECL:
4213 case XML_PI_NODE:
4214 case XML_ENTITY_REF_NODE:
4215 case XML_ENTITY_NODE:
4216 case XML_NAMESPACE_DECL:
4217 case XML_XINCLUDE_START:
4218 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004219#ifdef LIBXML_DOCB_ENABLED
4220 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004221#endif
4222 return;
4223 case XML_ELEMENT_NODE:
4224 case XML_ATTRIBUTE_NODE:
4225 break;
4226 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004227 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4228 if (ns == NULL)
4229 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004230 switch (val) {
4231 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004232 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004233 break;
4234 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004235 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004236 break;
4237 }
4238}
4239
4240/**
4241 * xmlNodeGetSpacePreserve:
4242 * @cur: the node being checked
4243 *
4244 * Searches the space preserving behaviour of a node, i.e. the values
4245 * of the xml:space attribute or the one carried by the nearest
4246 * ancestor.
4247 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004248 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004249 */
4250int
4251xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4252 xmlChar *space;
4253
4254 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004255 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004256 if (space != NULL) {
4257 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4258 xmlFree(space);
4259 return(1);
4260 }
4261 if (xmlStrEqual(space, BAD_CAST "default")) {
4262 xmlFree(space);
4263 return(0);
4264 }
4265 xmlFree(space);
4266 }
4267 cur = cur->parent;
4268 }
4269 return(-1);
4270}
4271
4272/**
4273 * xmlNodeSetName:
4274 * @cur: the node being changed
4275 * @name: the new tag name
4276 *
4277 * Set (or reset) the name of a node.
4278 */
4279void
4280xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
4281 if (cur == NULL) return;
4282 if (name == NULL) return;
4283 switch(cur->type) {
4284 case XML_TEXT_NODE:
4285 case XML_CDATA_SECTION_NODE:
4286 case XML_COMMENT_NODE:
4287 case XML_DOCUMENT_TYPE_NODE:
4288 case XML_DOCUMENT_FRAG_NODE:
4289 case XML_NOTATION_NODE:
4290 case XML_HTML_DOCUMENT_NODE:
4291 case XML_NAMESPACE_DECL:
4292 case XML_XINCLUDE_START:
4293 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004294#ifdef LIBXML_DOCB_ENABLED
4295 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004296#endif
4297 return;
4298 case XML_ELEMENT_NODE:
4299 case XML_ATTRIBUTE_NODE:
4300 case XML_PI_NODE:
4301 case XML_ENTITY_REF_NODE:
4302 case XML_ENTITY_NODE:
4303 case XML_DTD_NODE:
4304 case XML_DOCUMENT_NODE:
4305 case XML_ELEMENT_DECL:
4306 case XML_ATTRIBUTE_DECL:
4307 case XML_ENTITY_DECL:
4308 break;
4309 }
4310 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4311 cur->name = xmlStrdup(name);
4312}
4313
4314/**
4315 * xmlNodeSetBase:
4316 * @cur: the node being changed
4317 * @uri: the new base URI
4318 *
4319 * Set (or reset) the base URI of a node, i.e. the value of the
4320 * xml:base attribute.
4321 */
4322void
4323xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004324 xmlNsPtr ns;
4325
Owen Taylor3473f882001-02-23 17:55:21 +00004326 if (cur == NULL) return;
4327 switch(cur->type) {
4328 case XML_TEXT_NODE:
4329 case XML_CDATA_SECTION_NODE:
4330 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004331 case XML_DOCUMENT_TYPE_NODE:
4332 case XML_DOCUMENT_FRAG_NODE:
4333 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004334 case XML_DTD_NODE:
4335 case XML_ELEMENT_DECL:
4336 case XML_ATTRIBUTE_DECL:
4337 case XML_ENTITY_DECL:
4338 case XML_PI_NODE:
4339 case XML_ENTITY_REF_NODE:
4340 case XML_ENTITY_NODE:
4341 case XML_NAMESPACE_DECL:
4342 case XML_XINCLUDE_START:
4343 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004344 return;
4345 case XML_ELEMENT_NODE:
4346 case XML_ATTRIBUTE_NODE:
4347 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004348 case XML_DOCUMENT_NODE:
4349#ifdef LIBXML_DOCB_ENABLED
4350 case XML_DOCB_DOCUMENT_NODE:
4351#endif
4352 case XML_HTML_DOCUMENT_NODE: {
4353 xmlDocPtr doc = (xmlDocPtr) cur;
4354
4355 if (doc->URL != NULL)
4356 xmlFree((xmlChar *) doc->URL);
4357 if (uri == NULL)
4358 doc->URL = NULL;
4359 else
4360 doc->URL = xmlStrdup(uri);
4361 return;
4362 }
Owen Taylor3473f882001-02-23 17:55:21 +00004363 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004364
4365 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4366 if (ns == NULL)
4367 return;
4368 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004369}
4370
4371/**
Owen Taylor3473f882001-02-23 17:55:21 +00004372 * xmlNodeGetBase:
4373 * @doc: the document the node pertains to
4374 * @cur: the node being checked
4375 *
4376 * Searches for the BASE URL. The code should work on both XML
4377 * and HTML document even if base mechanisms are completely different.
4378 * It returns the base as defined in RFC 2396 sections
4379 * 5.1.1. Base URI within Document Content
4380 * and
4381 * 5.1.2. Base URI from the Encapsulating Entity
4382 * However it does not return the document base (5.1.3), use
4383 * xmlDocumentGetBase() for this
4384 *
4385 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004386 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004387 */
4388xmlChar *
4389xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004390 xmlChar *oldbase = NULL;
4391 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004392
4393 if ((cur == NULL) && (doc == NULL))
4394 return(NULL);
4395 if (doc == NULL) doc = cur->doc;
4396 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4397 cur = doc->children;
4398 while ((cur != NULL) && (cur->name != NULL)) {
4399 if (cur->type != XML_ELEMENT_NODE) {
4400 cur = cur->next;
4401 continue;
4402 }
4403 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4404 cur = cur->children;
4405 continue;
4406 }
4407 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4408 cur = cur->children;
4409 continue;
4410 }
4411 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4412 return(xmlGetProp(cur, BAD_CAST "href"));
4413 }
4414 cur = cur->next;
4415 }
4416 return(NULL);
4417 }
4418 while (cur != NULL) {
4419 if (cur->type == XML_ENTITY_DECL) {
4420 xmlEntityPtr ent = (xmlEntityPtr) cur;
4421 return(xmlStrdup(ent->URI));
4422 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004423 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004424 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004425 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004426 if (oldbase != NULL) {
4427 newbase = xmlBuildURI(oldbase, base);
4428 if (newbase != NULL) {
4429 xmlFree(oldbase);
4430 xmlFree(base);
4431 oldbase = newbase;
4432 } else {
4433 xmlFree(oldbase);
4434 xmlFree(base);
4435 return(NULL);
4436 }
4437 } else {
4438 oldbase = base;
4439 }
4440 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4441 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4442 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4443 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004444 }
4445 }
Owen Taylor3473f882001-02-23 17:55:21 +00004446 cur = cur->parent;
4447 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004448 if ((doc != NULL) && (doc->URL != NULL)) {
4449 if (oldbase == NULL)
4450 return(xmlStrdup(doc->URL));
4451 newbase = xmlBuildURI(oldbase, doc->URL);
4452 xmlFree(oldbase);
4453 return(newbase);
4454 }
4455 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004456}
4457
4458/**
4459 * xmlNodeGetContent:
4460 * @cur: the node being read
4461 *
4462 * Read the value of a node, this can be either the text carried
4463 * directly by this node if it's a TEXT node or the aggregate string
4464 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004465 * Entity references are substituted.
4466 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004467 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004468 */
4469xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004470xmlNodeGetContent(xmlNodePtr cur)
4471{
4472 if (cur == NULL)
4473 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004474 switch (cur->type) {
4475 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004476 case XML_ELEMENT_NODE:{
4477 xmlNodePtr tmp = cur;
4478 xmlBufferPtr buffer;
4479 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004480
Daniel Veillard814a76d2003-01-23 18:24:20 +00004481 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004482 if (buffer == NULL)
4483 return (NULL);
4484 while (tmp != NULL) {
4485 switch (tmp->type) {
4486 case XML_CDATA_SECTION_NODE:
4487 case XML_TEXT_NODE:
4488 if (tmp->content != NULL)
4489 xmlBufferCat(buffer, tmp->content);
4490 break;
4491 case XML_ENTITY_REF_NODE:{
4492 /* recursive substitution of entity references */
4493 xmlChar *cont = xmlNodeGetContent(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00004494
Daniel Veillard7646b182002-04-20 06:41:40 +00004495 if (cont) {
4496 xmlBufferCat(buffer,
4497 (const xmlChar *) cont);
4498 xmlFree(cont);
4499 }
4500 break;
4501 }
4502 default:
4503 break;
4504 }
4505 /*
4506 * Skip to next node
4507 */
4508 if (tmp->children != NULL) {
4509 if (tmp->children->type != XML_ENTITY_DECL) {
4510 tmp = tmp->children;
4511 continue;
4512 }
4513 }
4514 if (tmp == cur)
4515 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00004516
Daniel Veillard7646b182002-04-20 06:41:40 +00004517 if (tmp->next != NULL) {
4518 tmp = tmp->next;
4519 continue;
4520 }
4521
4522 do {
4523 tmp = tmp->parent;
4524 if (tmp == NULL)
4525 break;
4526 if (tmp == cur) {
4527 tmp = NULL;
4528 break;
4529 }
4530 if (tmp->next != NULL) {
4531 tmp = tmp->next;
4532 break;
4533 }
4534 } while (tmp != NULL);
4535 }
4536 ret = buffer->content;
4537 buffer->content = NULL;
4538 xmlBufferFree(buffer);
4539 return (ret);
4540 }
4541 case XML_ATTRIBUTE_NODE:{
4542 xmlAttrPtr attr = (xmlAttrPtr) cur;
4543
4544 if (attr->parent != NULL)
4545 return (xmlNodeListGetString
4546 (attr->parent->doc, attr->children, 1));
4547 else
4548 return (xmlNodeListGetString(NULL, attr->children, 1));
4549 break;
4550 }
Owen Taylor3473f882001-02-23 17:55:21 +00004551 case XML_COMMENT_NODE:
4552 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004553 if (cur->content != NULL)
4554 return (xmlStrdup(cur->content));
4555 return (NULL);
4556 case XML_ENTITY_REF_NODE:{
4557 xmlEntityPtr ent;
4558 xmlNodePtr tmp;
4559 xmlBufferPtr buffer;
4560 xmlChar *ret;
4561
4562 /* lookup entity declaration */
4563 ent = xmlGetDocEntity(cur->doc, cur->name);
4564 if (ent == NULL)
4565 return (NULL);
4566
4567 buffer = xmlBufferCreate();
4568 if (buffer == NULL)
4569 return (NULL);
4570
4571 /* an entity content can be any "well balanced chunk",
4572 * i.e. the result of the content [43] production:
4573 * http://www.w3.org/TR/REC-xml#NT-content
4574 * -> we iterate through child nodes and recursive call
4575 * xmlNodeGetContent() which handles all possible node types */
4576 tmp = ent->children;
4577 while (tmp) {
4578 xmlChar *cont = xmlNodeGetContent(tmp);
4579
4580 if (cont) {
4581 xmlBufferCat(buffer, (const xmlChar *) cont);
4582 xmlFree(cont);
4583 }
4584 tmp = tmp->next;
4585 }
4586
4587 ret = buffer->content;
4588 buffer->content = NULL;
4589 xmlBufferFree(buffer);
4590 return (ret);
4591 }
Owen Taylor3473f882001-02-23 17:55:21 +00004592 case XML_ENTITY_NODE:
4593 case XML_DOCUMENT_NODE:
4594 case XML_HTML_DOCUMENT_NODE:
4595 case XML_DOCUMENT_TYPE_NODE:
4596 case XML_NOTATION_NODE:
4597 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004598 case XML_XINCLUDE_START:
4599 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004600#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004601 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004602#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00004603 return (NULL);
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004604 case XML_NAMESPACE_DECL: {
4605 xmlChar *tmp;
4606
4607 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4608 return (tmp);
4609 }
Owen Taylor3473f882001-02-23 17:55:21 +00004610 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004611 /* TODO !!! */
4612 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004613 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004614 /* TODO !!! */
4615 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004616 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004617 /* TODO !!! */
4618 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004619 case XML_CDATA_SECTION_NODE:
4620 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004621 if (cur->content != NULL)
4622 return (xmlStrdup(cur->content));
4623 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004624 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004625 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004626}
Owen Taylor3473f882001-02-23 17:55:21 +00004627/**
4628 * xmlNodeSetContent:
4629 * @cur: the node being modified
4630 * @content: the new value of the content
4631 *
4632 * Replace the content of a node.
4633 */
4634void
4635xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4636 if (cur == NULL) {
4637#ifdef DEBUG_TREE
4638 xmlGenericError(xmlGenericErrorContext,
4639 "xmlNodeSetContent : node == NULL\n");
4640#endif
4641 return;
4642 }
4643 switch (cur->type) {
4644 case XML_DOCUMENT_FRAG_NODE:
4645 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004646 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004647 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4648 cur->children = xmlStringGetNodeList(cur->doc, content);
4649 UPDATE_LAST_CHILD_AND_PARENT(cur)
4650 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004651 case XML_TEXT_NODE:
4652 case XML_CDATA_SECTION_NODE:
4653 case XML_ENTITY_REF_NODE:
4654 case XML_ENTITY_NODE:
4655 case XML_PI_NODE:
4656 case XML_COMMENT_NODE:
4657 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004658 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004659 }
4660 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4661 cur->last = cur->children = NULL;
4662 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004663 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00004664 } else
4665 cur->content = NULL;
4666 break;
4667 case XML_DOCUMENT_NODE:
4668 case XML_HTML_DOCUMENT_NODE:
4669 case XML_DOCUMENT_TYPE_NODE:
4670 case XML_XINCLUDE_START:
4671 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004672#ifdef LIBXML_DOCB_ENABLED
4673 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004674#endif
4675 break;
4676 case XML_NOTATION_NODE:
4677 break;
4678 case XML_DTD_NODE:
4679 break;
4680 case XML_NAMESPACE_DECL:
4681 break;
4682 case XML_ELEMENT_DECL:
4683 /* TODO !!! */
4684 break;
4685 case XML_ATTRIBUTE_DECL:
4686 /* TODO !!! */
4687 break;
4688 case XML_ENTITY_DECL:
4689 /* TODO !!! */
4690 break;
4691 }
4692}
4693
4694/**
4695 * xmlNodeSetContentLen:
4696 * @cur: the node being modified
4697 * @content: the new value of the content
4698 * @len: the size of @content
4699 *
4700 * Replace the content of a node.
4701 */
4702void
4703xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4704 if (cur == NULL) {
4705#ifdef DEBUG_TREE
4706 xmlGenericError(xmlGenericErrorContext,
4707 "xmlNodeSetContentLen : node == NULL\n");
4708#endif
4709 return;
4710 }
4711 switch (cur->type) {
4712 case XML_DOCUMENT_FRAG_NODE:
4713 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004714 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004715 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4716 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
4717 UPDATE_LAST_CHILD_AND_PARENT(cur)
4718 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004719 case XML_TEXT_NODE:
4720 case XML_CDATA_SECTION_NODE:
4721 case XML_ENTITY_REF_NODE:
4722 case XML_ENTITY_NODE:
4723 case XML_PI_NODE:
4724 case XML_COMMENT_NODE:
4725 case XML_NOTATION_NODE:
4726 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004727 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004728 }
4729 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4730 cur->children = cur->last = NULL;
4731 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004732 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004733 } else
4734 cur->content = NULL;
4735 break;
4736 case XML_DOCUMENT_NODE:
4737 case XML_DTD_NODE:
4738 case XML_HTML_DOCUMENT_NODE:
4739 case XML_DOCUMENT_TYPE_NODE:
4740 case XML_NAMESPACE_DECL:
4741 case XML_XINCLUDE_START:
4742 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004743#ifdef LIBXML_DOCB_ENABLED
4744 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004745#endif
4746 break;
4747 case XML_ELEMENT_DECL:
4748 /* TODO !!! */
4749 break;
4750 case XML_ATTRIBUTE_DECL:
4751 /* TODO !!! */
4752 break;
4753 case XML_ENTITY_DECL:
4754 /* TODO !!! */
4755 break;
4756 }
4757}
4758
4759/**
4760 * xmlNodeAddContentLen:
4761 * @cur: the node being modified
4762 * @content: extra content
4763 * @len: the size of @content
4764 *
4765 * Append the extra substring to the node content.
4766 */
4767void
4768xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4769 if (cur == NULL) {
4770#ifdef DEBUG_TREE
4771 xmlGenericError(xmlGenericErrorContext,
4772 "xmlNodeAddContentLen : node == NULL\n");
4773#endif
4774 return;
4775 }
4776 if (len <= 0) return;
4777 switch (cur->type) {
4778 case XML_DOCUMENT_FRAG_NODE:
4779 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004780 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004781
Daniel Veillard7db37732001-07-12 01:20:08 +00004782 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004783 newNode = xmlNewTextLen(content, len);
4784 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004785 tmp = xmlAddChild(cur, newNode);
4786 if (tmp != newNode)
4787 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004788 if ((last != NULL) && (last->next == newNode)) {
4789 xmlTextMerge(last, newNode);
4790 }
4791 }
4792 break;
4793 }
4794 case XML_ATTRIBUTE_NODE:
4795 break;
4796 case XML_TEXT_NODE:
4797 case XML_CDATA_SECTION_NODE:
4798 case XML_ENTITY_REF_NODE:
4799 case XML_ENTITY_NODE:
4800 case XML_PI_NODE:
4801 case XML_COMMENT_NODE:
4802 case XML_NOTATION_NODE:
4803 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004804 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004805 }
4806 case XML_DOCUMENT_NODE:
4807 case XML_DTD_NODE:
4808 case XML_HTML_DOCUMENT_NODE:
4809 case XML_DOCUMENT_TYPE_NODE:
4810 case XML_NAMESPACE_DECL:
4811 case XML_XINCLUDE_START:
4812 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004813#ifdef LIBXML_DOCB_ENABLED
4814 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004815#endif
4816 break;
4817 case XML_ELEMENT_DECL:
4818 case XML_ATTRIBUTE_DECL:
4819 case XML_ENTITY_DECL:
4820 break;
4821 }
4822}
4823
4824/**
4825 * xmlNodeAddContent:
4826 * @cur: the node being modified
4827 * @content: extra content
4828 *
4829 * Append the extra substring to the node content.
4830 */
4831void
4832xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
4833 int len;
4834
4835 if (cur == NULL) {
4836#ifdef DEBUG_TREE
4837 xmlGenericError(xmlGenericErrorContext,
4838 "xmlNodeAddContent : node == NULL\n");
4839#endif
4840 return;
4841 }
4842 if (content == NULL) return;
4843 len = xmlStrlen(content);
4844 xmlNodeAddContentLen(cur, content, len);
4845}
4846
4847/**
4848 * xmlTextMerge:
4849 * @first: the first text node
4850 * @second: the second text node being merged
4851 *
4852 * Merge two text nodes into one
4853 * Returns the first text node augmented
4854 */
4855xmlNodePtr
4856xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
4857 if (first == NULL) return(second);
4858 if (second == NULL) return(first);
4859 if (first->type != XML_TEXT_NODE) return(first);
4860 if (second->type != XML_TEXT_NODE) return(first);
4861 if (second->name != first->name)
4862 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00004863 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004864 xmlUnlinkNode(second);
4865 xmlFreeNode(second);
4866 return(first);
4867}
4868
4869/**
4870 * xmlGetNsList:
4871 * @doc: the document
4872 * @node: the current node
4873 *
4874 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00004875 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00004876 * that need to be freed by the caller or NULL if no
4877 * namespace if defined
4878 */
4879xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00004880xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
4881{
Owen Taylor3473f882001-02-23 17:55:21 +00004882 xmlNsPtr cur;
4883 xmlNsPtr *ret = NULL;
4884 int nbns = 0;
4885 int maxns = 10;
4886 int i;
4887
4888 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00004889 if (node->type == XML_ELEMENT_NODE) {
4890 cur = node->nsDef;
4891 while (cur != NULL) {
4892 if (ret == NULL) {
4893 ret =
4894 (xmlNsPtr *) xmlMalloc((maxns + 1) *
4895 sizeof(xmlNsPtr));
4896 if (ret == NULL) {
4897 xmlGenericError(xmlGenericErrorContext,
4898 "xmlGetNsList : out of memory!\n");
4899 return (NULL);
4900 }
4901 ret[nbns] = NULL;
4902 }
4903 for (i = 0; i < nbns; i++) {
4904 if ((cur->prefix == ret[i]->prefix) ||
4905 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
4906 break;
4907 }
4908 if (i >= nbns) {
4909 if (nbns >= maxns) {
4910 maxns *= 2;
4911 ret = (xmlNsPtr *) xmlRealloc(ret,
4912 (maxns +
4913 1) *
4914 sizeof(xmlNsPtr));
4915 if (ret == NULL) {
4916 xmlGenericError(xmlGenericErrorContext,
4917 "xmlGetNsList : realloc failed!\n");
4918 return (NULL);
4919 }
4920 }
4921 ret[nbns++] = cur;
4922 ret[nbns] = NULL;
4923 }
Owen Taylor3473f882001-02-23 17:55:21 +00004924
Daniel Veillard77044732001-06-29 21:31:07 +00004925 cur = cur->next;
4926 }
4927 }
4928 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004929 }
Daniel Veillard77044732001-06-29 21:31:07 +00004930 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004931}
4932
4933/**
4934 * xmlSearchNs:
4935 * @doc: the document
4936 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004937 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004938 *
4939 * Search a Ns registered under a given name space for a document.
4940 * recurse on the parents until it finds the defined namespace
4941 * or return NULL otherwise.
4942 * @nameSpace can be NULL, this is a search for the default namespace.
4943 * We don't allow to cross entities boundaries. If you don't declare
4944 * the namespace within those you will be in troubles !!! A warning
4945 * is generated to cover this case.
4946 *
4947 * Returns the namespace pointer or NULL.
4948 */
4949xmlNsPtr
4950xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4951 xmlNsPtr cur;
4952
4953 if (node == NULL) return(NULL);
4954 if ((nameSpace != NULL) &&
4955 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00004956 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4957 /*
4958 * The XML-1.0 namespace is normally held on the root
4959 * element. In this case exceptionally create it on the
4960 * node element.
4961 */
4962 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4963 if (cur == NULL) {
4964 xmlGenericError(xmlGenericErrorContext,
4965 "xmlSearchNs : malloc failed\n");
4966 return(NULL);
4967 }
4968 memset(cur, 0, sizeof(xmlNs));
4969 cur->type = XML_LOCAL_NAMESPACE;
4970 cur->href = xmlStrdup(XML_XML_NAMESPACE);
4971 cur->prefix = xmlStrdup((const xmlChar *)"xml");
4972 cur->next = node->nsDef;
4973 node->nsDef = cur;
4974 return(cur);
4975 }
Owen Taylor3473f882001-02-23 17:55:21 +00004976 if (doc->oldNs == NULL) {
4977 /*
4978 * Allocate a new Namespace and fill the fields.
4979 */
4980 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4981 if (doc->oldNs == NULL) {
4982 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004983 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004984 return(NULL);
4985 }
4986 memset(doc->oldNs, 0, sizeof(xmlNs));
4987 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4988
4989 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4990 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4991 }
4992 return(doc->oldNs);
4993 }
4994 while (node != NULL) {
4995 if ((node->type == XML_ENTITY_REF_NODE) ||
4996 (node->type == XML_ENTITY_NODE) ||
4997 (node->type == XML_ENTITY_DECL))
4998 return(NULL);
4999 if (node->type == XML_ELEMENT_NODE) {
5000 cur = node->nsDef;
5001 while (cur != NULL) {
5002 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5003 (cur->href != NULL))
5004 return(cur);
5005 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5006 (cur->href != NULL) &&
5007 (xmlStrEqual(cur->prefix, nameSpace)))
5008 return(cur);
5009 cur = cur->next;
5010 }
5011 }
5012 node = node->parent;
5013 }
5014 return(NULL);
5015}
5016
5017/**
5018 * xmlSearchNsByHref:
5019 * @doc: the document
5020 * @node: the current node
5021 * @href: the namespace value
5022 *
5023 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5024 * the defined namespace or return NULL otherwise.
5025 * Returns the namespace pointer or NULL.
5026 */
5027xmlNsPtr
5028xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
5029 xmlNsPtr cur;
5030 xmlNodePtr orig = node;
5031
5032 if ((node == NULL) || (href == NULL)) return(NULL);
5033 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00005034 /*
5035 * Only the document can hold the XML spec namespace.
5036 */
Daniel Veillardc1a0da32002-08-14 08:32:18 +00005037 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5038 /*
5039 * The XML-1.0 namespace is normally held on the root
5040 * element. In this case exceptionally create it on the
5041 * node element.
5042 */
5043 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5044 if (cur == NULL) {
5045 xmlGenericError(xmlGenericErrorContext,
5046 "xmlSearchNs : malloc failed\n");
5047 return(NULL);
5048 }
5049 memset(cur, 0, sizeof(xmlNs));
5050 cur->type = XML_LOCAL_NAMESPACE;
5051 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5052 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5053 cur->next = node->nsDef;
5054 node->nsDef = cur;
5055 return(cur);
5056 }
Owen Taylor3473f882001-02-23 17:55:21 +00005057 if (doc->oldNs == NULL) {
5058 /*
5059 * Allocate a new Namespace and fill the fields.
5060 */
5061 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5062 if (doc->oldNs == NULL) {
5063 xmlGenericError(xmlGenericErrorContext,
5064 "xmlSearchNsByHref : malloc failed\n");
5065 return(NULL);
5066 }
5067 memset(doc->oldNs, 0, sizeof(xmlNs));
5068 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5069
5070 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5071 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5072 }
5073 return(doc->oldNs);
5074 }
5075 while (node != NULL) {
5076 cur = node->nsDef;
5077 while (cur != NULL) {
5078 if ((cur->href != NULL) && (href != NULL) &&
5079 (xmlStrEqual(cur->href, href))) {
5080 /*
5081 * Check that the prefix is not shadowed between orig and node
5082 */
5083 xmlNodePtr check = orig;
5084 xmlNsPtr tst;
5085
5086 while (check != node) {
5087 tst = check->nsDef;
5088 while (tst != NULL) {
5089 if ((tst->prefix == NULL) && (cur->prefix == NULL))
5090 goto shadowed;
5091 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
5092 (xmlStrEqual(tst->prefix, cur->prefix)))
5093 goto shadowed;
5094 tst = tst->next;
5095 }
5096 check = check->parent;
5097 }
5098 return(cur);
5099 }
5100shadowed:
5101 cur = cur->next;
5102 }
5103 node = node->parent;
5104 }
5105 return(NULL);
5106}
5107
5108/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005109 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005110 * @doc: the document
5111 * @tree: a node expected to hold the new namespace
5112 * @ns: the original namespace
5113 *
5114 * This function tries to locate a namespace definition in a tree
5115 * ancestors, or create a new namespace definition node similar to
5116 * @ns trying to reuse the same prefix. However if the given prefix is
5117 * null (default namespace) or reused within the subtree defined by
5118 * @tree or on one of its ancestors then a new prefix is generated.
5119 * Returns the (new) namespace definition or NULL in case of error
5120 */
5121xmlNsPtr
5122xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5123 xmlNsPtr def;
5124 xmlChar prefix[50];
5125 int counter = 1;
5126
5127 if (tree == NULL) {
5128#ifdef DEBUG_TREE
5129 xmlGenericError(xmlGenericErrorContext,
5130 "xmlNewReconciliedNs : tree == NULL\n");
5131#endif
5132 return(NULL);
5133 }
5134 if (ns == NULL) {
5135#ifdef DEBUG_TREE
5136 xmlGenericError(xmlGenericErrorContext,
5137 "xmlNewReconciliedNs : ns == NULL\n");
5138#endif
5139 return(NULL);
5140 }
5141 /*
5142 * Search an existing namespace definition inherited.
5143 */
5144 def = xmlSearchNsByHref(doc, tree, ns->href);
5145 if (def != NULL)
5146 return(def);
5147
5148 /*
5149 * Find a close prefix which is not already in use.
5150 * Let's strip namespace prefixes longer than 20 chars !
5151 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005152 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005153 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005154 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005155 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005156
Owen Taylor3473f882001-02-23 17:55:21 +00005157 def = xmlSearchNs(doc, tree, prefix);
5158 while (def != NULL) {
5159 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005160 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005161 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005162 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005163 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005164 def = xmlSearchNs(doc, tree, prefix);
5165 }
5166
5167 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005168 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005169 */
5170 def = xmlNewNs(tree, ns->href, prefix);
5171 return(def);
5172}
5173
5174/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005175 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005176 * @doc: the document
5177 * @tree: a node defining the subtree to reconciliate
5178 *
5179 * This function checks that all the namespaces declared within the given
5180 * tree are properly declared. This is needed for example after Copy or Cut
5181 * and then paste operations. The subtree may still hold pointers to
5182 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005183 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005184 * the new environment. If not possible the new namespaces are redeclared
5185 * on @tree at the top of the given subtree.
5186 * Returns the number of namespace declarations created or -1 in case of error.
5187 */
5188int
5189xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5190 xmlNsPtr *oldNs = NULL;
5191 xmlNsPtr *newNs = NULL;
5192 int sizeCache = 0;
5193 int nbCache = 0;
5194
5195 xmlNsPtr n;
5196 xmlNodePtr node = tree;
5197 xmlAttrPtr attr;
5198 int ret = 0, i;
5199
5200 while (node != NULL) {
5201 /*
5202 * Reconciliate the node namespace
5203 */
5204 if (node->ns != NULL) {
5205 /*
5206 * initialize the cache if needed
5207 */
5208 if (sizeCache == 0) {
5209 sizeCache = 10;
5210 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5211 sizeof(xmlNsPtr));
5212 if (oldNs == NULL) {
5213 xmlGenericError(xmlGenericErrorContext,
5214 "xmlReconciliateNs : memory pbm\n");
5215 return(-1);
5216 }
5217 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5218 sizeof(xmlNsPtr));
5219 if (newNs == NULL) {
5220 xmlGenericError(xmlGenericErrorContext,
5221 "xmlReconciliateNs : memory pbm\n");
5222 xmlFree(oldNs);
5223 return(-1);
5224 }
5225 }
5226 for (i = 0;i < nbCache;i++) {
5227 if (oldNs[i] == node->ns) {
5228 node->ns = newNs[i];
5229 break;
5230 }
5231 }
5232 if (i == nbCache) {
5233 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005234 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005235 */
5236 n = xmlNewReconciliedNs(doc, tree, node->ns);
5237 if (n != NULL) { /* :-( what if else ??? */
5238 /*
5239 * check if we need to grow the cache buffers.
5240 */
5241 if (sizeCache <= nbCache) {
5242 sizeCache *= 2;
5243 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5244 sizeof(xmlNsPtr));
5245 if (oldNs == NULL) {
5246 xmlGenericError(xmlGenericErrorContext,
5247 "xmlReconciliateNs : memory pbm\n");
5248 xmlFree(newNs);
5249 return(-1);
5250 }
5251 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5252 sizeof(xmlNsPtr));
5253 if (newNs == NULL) {
5254 xmlGenericError(xmlGenericErrorContext,
5255 "xmlReconciliateNs : memory pbm\n");
5256 xmlFree(oldNs);
5257 return(-1);
5258 }
5259 }
5260 newNs[nbCache] = n;
5261 oldNs[nbCache++] = node->ns;
5262 node->ns = n;
5263 }
5264 }
5265 }
5266 /*
5267 * now check for namespace hold by attributes on the node.
5268 */
5269 attr = node->properties;
5270 while (attr != NULL) {
5271 if (attr->ns != NULL) {
5272 /*
5273 * initialize the cache if needed
5274 */
5275 if (sizeCache == 0) {
5276 sizeCache = 10;
5277 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5278 sizeof(xmlNsPtr));
5279 if (oldNs == NULL) {
5280 xmlGenericError(xmlGenericErrorContext,
5281 "xmlReconciliateNs : memory pbm\n");
5282 return(-1);
5283 }
5284 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5285 sizeof(xmlNsPtr));
5286 if (newNs == NULL) {
5287 xmlGenericError(xmlGenericErrorContext,
5288 "xmlReconciliateNs : memory pbm\n");
5289 xmlFree(oldNs);
5290 return(-1);
5291 }
5292 }
5293 for (i = 0;i < nbCache;i++) {
5294 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005295 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005296 break;
5297 }
5298 }
5299 if (i == nbCache) {
5300 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005301 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005302 */
5303 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5304 if (n != NULL) { /* :-( what if else ??? */
5305 /*
5306 * check if we need to grow the cache buffers.
5307 */
5308 if (sizeCache <= nbCache) {
5309 sizeCache *= 2;
5310 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5311 sizeof(xmlNsPtr));
5312 if (oldNs == NULL) {
5313 xmlGenericError(xmlGenericErrorContext,
5314 "xmlReconciliateNs : memory pbm\n");
5315 xmlFree(newNs);
5316 return(-1);
5317 }
5318 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5319 sizeof(xmlNsPtr));
5320 if (newNs == NULL) {
5321 xmlGenericError(xmlGenericErrorContext,
5322 "xmlReconciliateNs : memory pbm\n");
5323 xmlFree(oldNs);
5324 return(-1);
5325 }
5326 }
5327 newNs[nbCache] = n;
5328 oldNs[nbCache++] = attr->ns;
5329 attr->ns = n;
5330 }
5331 }
5332 }
5333 attr = attr->next;
5334 }
5335
5336 /*
5337 * Browse the full subtree, deep first
5338 */
5339 if (node->children != NULL) {
5340 /* deep first */
5341 node = node->children;
5342 } else if ((node != tree) && (node->next != NULL)) {
5343 /* then siblings */
5344 node = node->next;
5345 } else if (node != tree) {
5346 /* go up to parents->next if needed */
5347 while (node != tree) {
5348 if (node->parent != NULL)
5349 node = node->parent;
5350 if ((node != tree) && (node->next != NULL)) {
5351 node = node->next;
5352 break;
5353 }
5354 if (node->parent == NULL) {
5355 node = NULL;
5356 break;
5357 }
5358 }
5359 /* exit condition */
5360 if (node == tree)
5361 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005362 } else
5363 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005364 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005365 if (oldNs != NULL)
5366 xmlFree(oldNs);
5367 if (newNs != NULL)
5368 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005369 return(ret);
5370}
5371
5372/**
5373 * xmlHasProp:
5374 * @node: the node
5375 * @name: the attribute name
5376 *
5377 * Search an attribute associated to a node
5378 * This function also looks in DTD attribute declaration for #FIXED or
5379 * default declaration values unless DTD use has been turned off.
5380 *
5381 * Returns the attribute or the attribute declaration or NULL if
5382 * neither was found.
5383 */
5384xmlAttrPtr
5385xmlHasProp(xmlNodePtr node, const xmlChar *name) {
5386 xmlAttrPtr prop;
5387 xmlDocPtr doc;
5388
5389 if ((node == NULL) || (name == NULL)) return(NULL);
5390 /*
5391 * Check on the properties attached to the node
5392 */
5393 prop = node->properties;
5394 while (prop != NULL) {
5395 if (xmlStrEqual(prop->name, name)) {
5396 return(prop);
5397 }
5398 prop = prop->next;
5399 }
5400 if (!xmlCheckDTD) return(NULL);
5401
5402 /*
5403 * Check if there is a default declaration in the internal
5404 * or external subsets
5405 */
5406 doc = node->doc;
5407 if (doc != NULL) {
5408 xmlAttributePtr attrDecl;
5409 if (doc->intSubset != NULL) {
5410 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5411 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5412 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5413 if (attrDecl != NULL)
5414 return((xmlAttrPtr) attrDecl);
5415 }
5416 }
5417 return(NULL);
5418}
5419
5420/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005421 * xmlHasNsProp:
5422 * @node: the node
5423 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005424 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005425 *
5426 * Search for an attribute associated to a node
5427 * This attribute has to be anchored in the namespace specified.
5428 * This does the entity substitution.
5429 * This function looks in DTD attribute declaration for #FIXED or
5430 * default declaration values unless DTD use has been turned off.
5431 *
5432 * Returns the attribute or the attribute declaration or NULL
5433 * if neither was found.
5434 */
5435xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005436xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005437 xmlAttrPtr prop;
5438 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005439
5440 if (node == NULL)
5441 return(NULL);
5442
5443 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005444 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005445 return(xmlHasProp(node, name));
5446 while (prop != NULL) {
5447 /*
5448 * One need to have
5449 * - same attribute names
5450 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005451 */
5452 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005453 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5454 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005455 }
5456 prop = prop->next;
5457 }
5458 if (!xmlCheckDTD) return(NULL);
5459
5460 /*
5461 * Check if there is a default declaration in the internal
5462 * or external subsets
5463 */
5464 doc = node->doc;
5465 if (doc != NULL) {
5466 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005467 xmlAttributePtr attrDecl = NULL;
5468 xmlNsPtr *nsList, *cur;
5469 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005470
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005471 nsList = xmlGetNsList(node->doc, node);
5472 if (nsList == NULL)
5473 return(NULL);
5474 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5475 ename = xmlStrdup(node->ns->prefix);
5476 ename = xmlStrcat(ename, BAD_CAST ":");
5477 ename = xmlStrcat(ename, node->name);
5478 } else {
5479 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005480 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005481 if (ename == NULL) {
5482 xmlFree(nsList);
5483 return(NULL);
5484 }
5485
5486 cur = nsList;
5487 while (*cur != NULL) {
5488 if (xmlStrEqual((*cur)->href, nameSpace)) {
5489 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5490 name, (*cur)->prefix);
5491 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5492 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5493 name, (*cur)->prefix);
5494 }
5495 cur++;
5496 }
5497 xmlFree(nsList);
5498 xmlFree(ename);
5499 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005500 }
5501 }
5502 return(NULL);
5503}
5504
5505/**
Owen Taylor3473f882001-02-23 17:55:21 +00005506 * xmlGetProp:
5507 * @node: the node
5508 * @name: the attribute name
5509 *
5510 * Search and get the value of an attribute associated to a node
5511 * This does the entity substitution.
5512 * This function looks in DTD attribute declaration for #FIXED or
5513 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00005514 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00005515 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
5516 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00005517 *
5518 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005519 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005520 */
5521xmlChar *
5522xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5523 xmlAttrPtr prop;
5524 xmlDocPtr doc;
5525
5526 if ((node == NULL) || (name == NULL)) return(NULL);
5527 /*
5528 * Check on the properties attached to the node
5529 */
5530 prop = node->properties;
5531 while (prop != NULL) {
5532 if (xmlStrEqual(prop->name, name)) {
5533 xmlChar *ret;
5534
5535 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5536 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5537 return(ret);
5538 }
5539 prop = prop->next;
5540 }
5541 if (!xmlCheckDTD) return(NULL);
5542
5543 /*
5544 * Check if there is a default declaration in the internal
5545 * or external subsets
5546 */
5547 doc = node->doc;
5548 if (doc != NULL) {
5549 xmlAttributePtr attrDecl;
5550 if (doc->intSubset != NULL) {
5551 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5552 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5553 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5554 if (attrDecl != NULL)
5555 return(xmlStrdup(attrDecl->defaultValue));
5556 }
5557 }
5558 return(NULL);
5559}
5560
5561/**
Daniel Veillard71531f32003-02-05 13:19:53 +00005562 * xmlGetNoNsProp:
5563 * @node: the node
5564 * @name: the attribute name
5565 *
5566 * Search and get the value of an attribute associated to a node
5567 * This does the entity substitution.
5568 * This function looks in DTD attribute declaration for #FIXED or
5569 * default declaration values unless DTD use has been turned off.
5570 * This function is similar to xmlGetProp except it will accept only
5571 * an attribute in no namespace.
5572 *
5573 * Returns the attribute value or NULL if not found.
5574 * It's up to the caller to free the memory with xmlFree().
5575 */
5576xmlChar *
5577xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
5578 xmlAttrPtr prop;
5579 xmlDocPtr doc;
5580
5581 if ((node == NULL) || (name == NULL)) return(NULL);
5582 /*
5583 * Check on the properties attached to the node
5584 */
5585 prop = node->properties;
5586 while (prop != NULL) {
5587 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
5588 xmlChar *ret;
5589
5590 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5591 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5592 return(ret);
5593 }
5594 prop = prop->next;
5595 }
5596 if (!xmlCheckDTD) return(NULL);
5597
5598 /*
5599 * Check if there is a default declaration in the internal
5600 * or external subsets
5601 */
5602 doc = node->doc;
5603 if (doc != NULL) {
5604 xmlAttributePtr attrDecl;
5605 if (doc->intSubset != NULL) {
5606 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5607 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5608 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5609 if (attrDecl != NULL)
5610 return(xmlStrdup(attrDecl->defaultValue));
5611 }
5612 }
5613 return(NULL);
5614}
5615
5616/**
Owen Taylor3473f882001-02-23 17:55:21 +00005617 * xmlGetNsProp:
5618 * @node: the node
5619 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005620 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005621 *
5622 * Search and get the value of an attribute associated to a node
5623 * This attribute has to be anchored in the namespace specified.
5624 * This does the entity substitution.
5625 * This function looks in DTD attribute declaration for #FIXED or
5626 * default declaration values unless DTD use has been turned off.
5627 *
5628 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005629 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005630 */
5631xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00005632xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00005633 xmlAttrPtr prop;
5634 xmlDocPtr doc;
5635 xmlNsPtr ns;
5636
5637 if (node == NULL)
5638 return(NULL);
5639
5640 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005641 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00005642 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00005643 while (prop != NULL) {
5644 /*
5645 * One need to have
5646 * - same attribute names
5647 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005648 */
5649 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00005650 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00005651 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005652 xmlChar *ret;
5653
5654 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5655 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5656 return(ret);
5657 }
5658 prop = prop->next;
5659 }
5660 if (!xmlCheckDTD) return(NULL);
5661
5662 /*
5663 * Check if there is a default declaration in the internal
5664 * or external subsets
5665 */
5666 doc = node->doc;
5667 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005668 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00005669 xmlAttributePtr attrDecl;
5670
Owen Taylor3473f882001-02-23 17:55:21 +00005671 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5672 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5673 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5674
5675 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
5676 /*
5677 * The DTD declaration only allows a prefix search
5678 */
5679 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00005680 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00005681 return(xmlStrdup(attrDecl->defaultValue));
5682 }
5683 }
5684 }
5685 return(NULL);
5686}
5687
5688/**
5689 * xmlSetProp:
5690 * @node: the node
5691 * @name: the attribute name
5692 * @value: the attribute value
5693 *
5694 * Set (or reset) an attribute carried by a node.
5695 * Returns the attribute pointer.
5696 */
5697xmlAttrPtr
5698xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005699 xmlAttrPtr prop;
5700 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00005701
5702 if ((node == NULL) || (name == NULL))
5703 return(NULL);
5704 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005705 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00005706 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005707 if ((xmlStrEqual(prop->name, name)) &&
5708 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005709 xmlNodePtr oldprop = prop->children;
5710
Owen Taylor3473f882001-02-23 17:55:21 +00005711 prop->children = NULL;
5712 prop->last = NULL;
5713 if (value != NULL) {
5714 xmlChar *buffer;
5715 xmlNodePtr tmp;
5716
5717 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5718 prop->children = xmlStringGetNodeList(node->doc, buffer);
5719 prop->last = NULL;
5720 prop->doc = doc;
5721 tmp = prop->children;
5722 while (tmp != NULL) {
5723 tmp->parent = (xmlNodePtr) prop;
5724 tmp->doc = doc;
5725 if (tmp->next == NULL)
5726 prop->last = tmp;
5727 tmp = tmp->next;
5728 }
5729 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00005730 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005731 if (oldprop != NULL)
5732 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00005733 return(prop);
5734 }
5735 prop = prop->next;
5736 }
5737 prop = xmlNewProp(node, name, value);
5738 return(prop);
5739}
5740
5741/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005742 * xmlUnsetProp:
5743 * @node: the node
5744 * @name: the attribute name
5745 *
5746 * Remove an attribute carried by a node.
5747 * Returns 0 if successful, -1 if not found
5748 */
5749int
5750xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Daniel Veillard814a76d2003-01-23 18:24:20 +00005751 xmlAttrPtr prop, prev = NULL;;
Daniel Veillard75bea542001-05-11 17:41:21 +00005752
5753 if ((node == NULL) || (name == NULL))
5754 return(-1);
Daniel Veillard814a76d2003-01-23 18:24:20 +00005755 prop = node->properties;
Daniel Veillard75bea542001-05-11 17:41:21 +00005756 while (prop != NULL) {
5757 if ((xmlStrEqual(prop->name, name)) &&
5758 (prop->ns == NULL)) {
5759 if (prev == NULL)
5760 node->properties = prop->next;
5761 else
5762 prev->next = prop->next;
5763 xmlFreeProp(prop);
5764 return(0);
5765 }
5766 prev = prop;
5767 prop = prop->next;
5768 }
5769 return(-1);
5770}
5771
5772/**
Owen Taylor3473f882001-02-23 17:55:21 +00005773 * xmlSetNsProp:
5774 * @node: the node
5775 * @ns: the namespace definition
5776 * @name: the attribute name
5777 * @value: the attribute value
5778 *
5779 * Set (or reset) an attribute carried by a node.
5780 * The ns structure must be in scope, this is not checked.
5781 *
5782 * Returns the attribute pointer.
5783 */
5784xmlAttrPtr
5785xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
5786 const xmlChar *value) {
5787 xmlAttrPtr prop;
5788
5789 if ((node == NULL) || (name == NULL))
5790 return(NULL);
5791
5792 if (ns == NULL)
5793 return(xmlSetProp(node, name, value));
5794 if (ns->href == NULL)
5795 return(NULL);
5796 prop = node->properties;
5797
5798 while (prop != NULL) {
5799 /*
5800 * One need to have
5801 * - same attribute names
5802 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005803 */
5804 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00005805 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005806 if (prop->children != NULL)
5807 xmlFreeNodeList(prop->children);
5808 prop->children = NULL;
5809 prop->last = NULL;
5810 prop->ns = ns;
5811 if (value != NULL) {
5812 xmlChar *buffer;
5813 xmlNodePtr tmp;
5814
5815 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5816 prop->children = xmlStringGetNodeList(node->doc, buffer);
5817 prop->last = NULL;
5818 tmp = prop->children;
5819 while (tmp != NULL) {
5820 tmp->parent = (xmlNodePtr) prop;
5821 if (tmp->next == NULL)
5822 prop->last = tmp;
5823 tmp = tmp->next;
5824 }
5825 xmlFree(buffer);
5826 }
5827 return(prop);
5828 }
5829 prop = prop->next;
5830 }
5831 prop = xmlNewNsProp(node, ns, name, value);
5832 return(prop);
5833}
5834
5835/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005836 * xmlUnsetNsProp:
5837 * @node: the node
5838 * @ns: the namespace definition
5839 * @name: the attribute name
5840 *
5841 * Remove an attribute carried by a node.
5842 * Returns 0 if successful, -1 if not found
5843 */
5844int
5845xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
5846 xmlAttrPtr prop = node->properties, prev = NULL;;
5847
5848 if ((node == NULL) || (name == NULL))
5849 return(-1);
5850 if (ns == NULL)
5851 return(xmlUnsetProp(node, name));
5852 if (ns->href == NULL)
5853 return(-1);
5854 while (prop != NULL) {
5855 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00005856 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005857 if (prev == NULL)
5858 node->properties = prop->next;
5859 else
5860 prev->next = prop->next;
5861 xmlFreeProp(prop);
5862 return(0);
5863 }
5864 prev = prop;
5865 prop = prop->next;
5866 }
5867 return(-1);
5868}
5869
5870/**
Owen Taylor3473f882001-02-23 17:55:21 +00005871 * xmlNodeIsText:
5872 * @node: the node
5873 *
5874 * Is this node a Text node ?
5875 * Returns 1 yes, 0 no
5876 */
5877int
5878xmlNodeIsText(xmlNodePtr node) {
5879 if (node == NULL) return(0);
5880
5881 if (node->type == XML_TEXT_NODE) return(1);
5882 return(0);
5883}
5884
5885/**
5886 * xmlIsBlankNode:
5887 * @node: the node
5888 *
5889 * Checks whether this node is an empty or whitespace only
5890 * (and possibly ignorable) text-node.
5891 *
5892 * Returns 1 yes, 0 no
5893 */
5894int
5895xmlIsBlankNode(xmlNodePtr node) {
5896 const xmlChar *cur;
5897 if (node == NULL) return(0);
5898
Daniel Veillard7db37732001-07-12 01:20:08 +00005899 if ((node->type != XML_TEXT_NODE) &&
5900 (node->type != XML_CDATA_SECTION_NODE))
5901 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005902 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00005903 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00005904 while (*cur != 0) {
5905 if (!IS_BLANK(*cur)) return(0);
5906 cur++;
5907 }
5908
5909 return(1);
5910}
5911
5912/**
5913 * xmlTextConcat:
5914 * @node: the node
5915 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00005916 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00005917 *
5918 * Concat the given string at the end of the existing node content
5919 */
5920
5921void
5922xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
5923 if (node == NULL) return;
5924
5925 if ((node->type != XML_TEXT_NODE) &&
5926 (node->type != XML_CDATA_SECTION_NODE)) {
5927#ifdef DEBUG_TREE
5928 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005929 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005930#endif
5931 return;
5932 }
Owen Taylor3473f882001-02-23 17:55:21 +00005933 node->content = xmlStrncat(node->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005934}
5935
5936/************************************************************************
5937 * *
5938 * Output : to a FILE or in memory *
5939 * *
5940 ************************************************************************/
5941
Owen Taylor3473f882001-02-23 17:55:21 +00005942/**
5943 * xmlBufferCreate:
5944 *
5945 * routine to create an XML buffer.
5946 * returns the new structure.
5947 */
5948xmlBufferPtr
5949xmlBufferCreate(void) {
5950 xmlBufferPtr ret;
5951
5952 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5953 if (ret == NULL) {
5954 xmlGenericError(xmlGenericErrorContext,
5955 "xmlBufferCreate : out of memory!\n");
5956 return(NULL);
5957 }
5958 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00005959 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00005960 ret->alloc = xmlBufferAllocScheme;
5961 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5962 if (ret->content == NULL) {
5963 xmlGenericError(xmlGenericErrorContext,
5964 "xmlBufferCreate : out of memory!\n");
5965 xmlFree(ret);
5966 return(NULL);
5967 }
5968 ret->content[0] = 0;
5969 return(ret);
5970}
5971
5972/**
5973 * xmlBufferCreateSize:
5974 * @size: initial size of buffer
5975 *
5976 * routine to create an XML buffer.
5977 * returns the new structure.
5978 */
5979xmlBufferPtr
5980xmlBufferCreateSize(size_t size) {
5981 xmlBufferPtr ret;
5982
5983 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5984 if (ret == NULL) {
5985 xmlGenericError(xmlGenericErrorContext,
5986 "xmlBufferCreate : out of memory!\n");
5987 return(NULL);
5988 }
5989 ret->use = 0;
5990 ret->alloc = xmlBufferAllocScheme;
5991 ret->size = (size ? size+2 : 0); /* +1 for ending null */
5992 if (ret->size){
5993 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5994 if (ret->content == NULL) {
5995 xmlGenericError(xmlGenericErrorContext,
5996 "xmlBufferCreate : out of memory!\n");
5997 xmlFree(ret);
5998 return(NULL);
5999 }
6000 ret->content[0] = 0;
6001 } else
6002 ret->content = NULL;
6003 return(ret);
6004}
6005
6006/**
6007 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006008 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006009 * @scheme: allocation scheme to use
6010 *
6011 * Sets the allocation scheme for this buffer
6012 */
6013void
6014xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6015 xmlBufferAllocationScheme scheme) {
6016 if (buf == NULL) {
6017#ifdef DEBUG_BUFFER
6018 xmlGenericError(xmlGenericErrorContext,
6019 "xmlBufferSetAllocationScheme: buf == NULL\n");
6020#endif
6021 return;
6022 }
6023
6024 buf->alloc = scheme;
6025}
6026
6027/**
6028 * xmlBufferFree:
6029 * @buf: the buffer to free
6030 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006031 * Frees an XML buffer. It frees both the content and the structure which
6032 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006033 */
6034void
6035xmlBufferFree(xmlBufferPtr buf) {
6036 if (buf == NULL) {
6037#ifdef DEBUG_BUFFER
6038 xmlGenericError(xmlGenericErrorContext,
6039 "xmlBufferFree: buf == NULL\n");
6040#endif
6041 return;
6042 }
Daniel Veillard561b7f82002-03-20 21:55:57 +00006043 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006044 xmlFree(buf->content);
6045 }
Owen Taylor3473f882001-02-23 17:55:21 +00006046 xmlFree(buf);
6047}
6048
6049/**
6050 * xmlBufferEmpty:
6051 * @buf: the buffer
6052 *
6053 * empty a buffer.
6054 */
6055void
6056xmlBufferEmpty(xmlBufferPtr buf) {
6057 if (buf->content == NULL) return;
6058 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006059 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00006060}
6061
6062/**
6063 * xmlBufferShrink:
6064 * @buf: the buffer to dump
6065 * @len: the number of xmlChar to remove
6066 *
6067 * Remove the beginning of an XML buffer.
6068 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006069 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006070 */
6071int
6072xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
6073 if (len == 0) return(0);
6074 if (len > buf->use) return(-1);
6075
6076 buf->use -= len;
6077 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6078
6079 buf->content[buf->use] = 0;
6080 return(len);
6081}
6082
6083/**
6084 * xmlBufferGrow:
6085 * @buf: the buffer
6086 * @len: the minimum free size to allocate
6087 *
6088 * Grow the available space of an XML buffer.
6089 *
6090 * Returns the new available space or -1 in case of error
6091 */
6092int
6093xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6094 int size;
6095 xmlChar *newbuf;
6096
6097 if (len + buf->use < buf->size) return(0);
6098
6099 size = buf->use + len + 100;
6100
6101 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
6102 if (newbuf == NULL) return(-1);
6103 buf->content = newbuf;
6104 buf->size = size;
6105 return(buf->size - buf->use);
6106}
6107
6108/**
6109 * xmlBufferDump:
6110 * @file: the file output
6111 * @buf: the buffer to dump
6112 *
6113 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006114 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006115 */
6116int
6117xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6118 int ret;
6119
6120 if (buf == NULL) {
6121#ifdef DEBUG_BUFFER
6122 xmlGenericError(xmlGenericErrorContext,
6123 "xmlBufferDump: buf == NULL\n");
6124#endif
6125 return(0);
6126 }
6127 if (buf->content == NULL) {
6128#ifdef DEBUG_BUFFER
6129 xmlGenericError(xmlGenericErrorContext,
6130 "xmlBufferDump: buf->content == NULL\n");
6131#endif
6132 return(0);
6133 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006134 if (file == NULL)
6135 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006136 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6137 return(ret);
6138}
6139
6140/**
6141 * xmlBufferContent:
6142 * @buf: the buffer
6143 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006144 * Function to extract the content of a buffer
6145 *
Owen Taylor3473f882001-02-23 17:55:21 +00006146 * Returns the internal content
6147 */
6148
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006149const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006150xmlBufferContent(const xmlBufferPtr buf)
6151{
6152 if(!buf)
6153 return NULL;
6154
6155 return buf->content;
6156}
6157
6158/**
6159 * xmlBufferLength:
6160 * @buf: the buffer
6161 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006162 * Function to get the length of a buffer
6163 *
Owen Taylor3473f882001-02-23 17:55:21 +00006164 * Returns the length of data in the internal content
6165 */
6166
6167int
6168xmlBufferLength(const xmlBufferPtr buf)
6169{
6170 if(!buf)
6171 return 0;
6172
6173 return buf->use;
6174}
6175
6176/**
6177 * xmlBufferResize:
6178 * @buf: the buffer to resize
6179 * @size: the desired size
6180 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006181 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006182 *
6183 * Returns 0 in case of problems, 1 otherwise
6184 */
6185int
6186xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6187{
6188 unsigned int newSize;
6189 xmlChar* rebuf = NULL;
6190
6191 /*take care of empty case*/
6192 newSize = (buf->size ? buf->size*2 : size);
6193
6194 /* Don't resize if we don't have to */
6195 if (size < buf->size)
6196 return 1;
6197
6198 /* figure out new size */
6199 switch (buf->alloc){
6200 case XML_BUFFER_ALLOC_DOUBLEIT:
6201 while (size > newSize) newSize *= 2;
6202 break;
6203 case XML_BUFFER_ALLOC_EXACT:
6204 newSize = size+10;
6205 break;
6206 default:
6207 newSize = size+10;
6208 break;
6209 }
6210
6211 if (buf->content == NULL)
6212 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
6213 else
6214 rebuf = (xmlChar *) xmlRealloc(buf->content,
6215 newSize * sizeof(xmlChar));
6216 if (rebuf == NULL) {
6217 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006218 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006219 return 0;
6220 }
6221 buf->content = rebuf;
6222 buf->size = newSize;
6223
6224 return 1;
6225}
6226
6227/**
6228 * xmlBufferAdd:
6229 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006230 * @str: the #xmlChar string
6231 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006232 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006233 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006234 * str is recomputed.
6235 */
6236void
6237xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6238 unsigned int needSize;
6239
6240 if (str == NULL) {
6241#ifdef DEBUG_BUFFER
6242 xmlGenericError(xmlGenericErrorContext,
6243 "xmlBufferAdd: str == NULL\n");
6244#endif
6245 return;
6246 }
6247 if (len < -1) {
6248#ifdef DEBUG_BUFFER
6249 xmlGenericError(xmlGenericErrorContext,
6250 "xmlBufferAdd: len < 0\n");
6251#endif
6252 return;
6253 }
6254 if (len == 0) return;
6255
6256 if (len < 0)
6257 len = xmlStrlen(str);
6258
6259 if (len <= 0) return;
6260
6261 needSize = buf->use + len + 2;
6262 if (needSize > buf->size){
6263 if (!xmlBufferResize(buf, needSize)){
6264 xmlGenericError(xmlGenericErrorContext,
6265 "xmlBufferAdd : out of memory!\n");
6266 return;
6267 }
6268 }
6269
6270 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6271 buf->use += len;
6272 buf->content[buf->use] = 0;
6273}
6274
6275/**
6276 * xmlBufferAddHead:
6277 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006278 * @str: the #xmlChar string
6279 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006280 *
6281 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006282 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00006283 */
6284void
6285xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6286 unsigned int needSize;
6287
6288 if (str == NULL) {
6289#ifdef DEBUG_BUFFER
6290 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006291 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006292#endif
6293 return;
6294 }
6295 if (len < -1) {
6296#ifdef DEBUG_BUFFER
6297 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006298 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006299#endif
6300 return;
6301 }
6302 if (len == 0) return;
6303
6304 if (len < 0)
6305 len = xmlStrlen(str);
6306
6307 if (len <= 0) return;
6308
6309 needSize = buf->use + len + 2;
6310 if (needSize > buf->size){
6311 if (!xmlBufferResize(buf, needSize)){
6312 xmlGenericError(xmlGenericErrorContext,
6313 "xmlBufferAddHead : out of memory!\n");
6314 return;
6315 }
6316 }
6317
6318 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6319 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6320 buf->use += len;
6321 buf->content[buf->use] = 0;
6322}
6323
6324/**
6325 * xmlBufferCat:
6326 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006327 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006328 *
6329 * Append a zero terminated string to an XML buffer.
6330 */
6331void
6332xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
6333 if (str != NULL)
6334 xmlBufferAdd(buf, str, -1);
6335}
6336
6337/**
6338 * xmlBufferCCat:
6339 * @buf: the buffer to dump
6340 * @str: the C char string
6341 *
6342 * Append a zero terminated C string to an XML buffer.
6343 */
6344void
6345xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6346 const char *cur;
6347
6348 if (str == NULL) {
6349#ifdef DEBUG_BUFFER
6350 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006351 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006352#endif
6353 return;
6354 }
6355 for (cur = str;*cur != 0;cur++) {
6356 if (buf->use + 10 >= buf->size) {
6357 if (!xmlBufferResize(buf, buf->use+10)){
6358 xmlGenericError(xmlGenericErrorContext,
6359 "xmlBufferCCat : out of memory!\n");
6360 return;
6361 }
6362 }
6363 buf->content[buf->use++] = *cur;
6364 }
6365 buf->content[buf->use] = 0;
6366}
6367
6368/**
6369 * xmlBufferWriteCHAR:
6370 * @buf: the XML buffer
6371 * @string: the string to add
6372 *
6373 * routine which manages and grows an output buffer. This one adds
6374 * xmlChars at the end of the buffer.
6375 */
6376void
Owen Taylor3473f882001-02-23 17:55:21 +00006377xmlBufferWriteCHAR
Owen Taylor3473f882001-02-23 17:55:21 +00006378(xmlBufferPtr buf, const xmlChar *string) {
6379 xmlBufferCat(buf, string);
6380}
6381
6382/**
6383 * xmlBufferWriteChar:
6384 * @buf: the XML buffer output
6385 * @string: the string to add
6386 *
6387 * routine which manage and grows an output buffer. This one add
6388 * C chars at the end of the array.
6389 */
6390void
6391xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
6392 xmlBufferCCat(buf, string);
6393}
6394
6395
6396/**
6397 * xmlBufferWriteQuotedString:
6398 * @buf: the XML buffer output
6399 * @string: the string to add
6400 *
6401 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00006402 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00006403 * quote or double-quotes internally
6404 */
6405void
6406xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
6407 if (xmlStrchr(string, '"')) {
6408 if (xmlStrchr(string, '\'')) {
6409#ifdef DEBUG_BUFFER
6410 xmlGenericError(xmlGenericErrorContext,
6411 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
6412#endif
6413 }
6414 xmlBufferCCat(buf, "'");
6415 xmlBufferCat(buf, string);
6416 xmlBufferCCat(buf, "'");
6417 } else {
6418 xmlBufferCCat(buf, "\"");
6419 xmlBufferCat(buf, string);
6420 xmlBufferCCat(buf, "\"");
6421 }
6422}
6423
6424
6425/************************************************************************
6426 * *
6427 * Dumping XML tree content to a simple buffer *
6428 * *
6429 ************************************************************************/
6430
Owen Taylor3473f882001-02-23 17:55:21 +00006431/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00006432 * xmlAttrSerializeContent:
6433 * @buf: the XML buffer output
6434 * @doc: the document
6435 * @attr: the attribute pointer
6436 *
6437 * Serialize the attribute in the buffer
6438 */
6439static void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006440xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr)
6441{
Daniel Veillarda6d05382002-02-13 13:07:41 +00006442 const xmlChar *cur, *base;
6443 xmlNodePtr children;
6444
6445 children = attr->children;
6446 while (children != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006447 switch (children->type) {
6448 case XML_TEXT_NODE:
6449 base = cur = children->content;
6450 while (*cur != 0) {
6451 if (*cur == '\n') {
6452 if (base != cur)
6453 xmlBufferAdd(buf, base, cur - base);
6454 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
6455 cur++;
6456 base = cur;
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006457 } else if (*cur == '\r') {
6458 if (base != cur)
6459 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006460 xmlBufferAdd(buf, BAD_CAST "&#13;", 5);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006461 cur++;
6462 base = cur;
6463 } else if (*cur == '\t') {
6464 if (base != cur)
6465 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006466 xmlBufferAdd(buf, BAD_CAST "&#9;", 4);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006467 cur++;
6468 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006469#if 0
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006470 } else if (*cur == '\'') {
6471 if (base != cur)
6472 xmlBufferAdd(buf, base, cur - base);
6473 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
6474 cur++;
6475 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006476#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006477 } else if (*cur == '"') {
6478 if (base != cur)
6479 xmlBufferAdd(buf, base, cur - base);
6480 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6481 cur++;
6482 base = cur;
6483 } else if (*cur == '<') {
6484 if (base != cur)
6485 xmlBufferAdd(buf, base, cur - base);
6486 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
6487 cur++;
6488 base = cur;
6489 } else if (*cur == '>') {
6490 if (base != cur)
6491 xmlBufferAdd(buf, base, cur - base);
6492 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
6493 cur++;
6494 base = cur;
6495 } else if (*cur == '&') {
6496 if (base != cur)
6497 xmlBufferAdd(buf, base, cur - base);
6498 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
6499 cur++;
6500 base = cur;
6501 } else if ((*cur >= 0x80) && ((doc == NULL) ||
6502 (doc->encoding ==
6503 NULL))) {
6504 /*
6505 * We assume we have UTF-8 content.
6506 */
6507 char tmp[10];
6508 int val = 0, l = 1;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006509
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006510 if (base != cur)
6511 xmlBufferAdd(buf, base, cur - base);
6512 if (*cur < 0xC0) {
6513 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6d05382002-02-13 13:07:41 +00006514 "xmlAttrSerializeContent : input not UTF-8\n");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006515 if (doc != NULL)
6516 doc->encoding =
6517 xmlStrdup(BAD_CAST "ISO-8859-1");
6518 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6519 tmp[sizeof(tmp) - 1] = 0;
6520 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6521 cur++;
6522 base = cur;
6523 continue;
6524 } else if (*cur < 0xE0) {
6525 val = (cur[0]) & 0x1F;
6526 val <<= 6;
6527 val |= (cur[1]) & 0x3F;
6528 l = 2;
6529 } else if (*cur < 0xF0) {
6530 val = (cur[0]) & 0x0F;
6531 val <<= 6;
6532 val |= (cur[1]) & 0x3F;
6533 val <<= 6;
6534 val |= (cur[2]) & 0x3F;
6535 l = 3;
6536 } else if (*cur < 0xF8) {
6537 val = (cur[0]) & 0x07;
6538 val <<= 6;
6539 val |= (cur[1]) & 0x3F;
6540 val <<= 6;
6541 val |= (cur[2]) & 0x3F;
6542 val <<= 6;
6543 val |= (cur[3]) & 0x3F;
6544 l = 4;
6545 }
6546 if ((l == 1) || (!IS_CHAR(val))) {
6547 xmlGenericError(xmlGenericErrorContext,
6548 "xmlAttrSerializeContent : char out of range\n");
6549 if (doc != NULL)
6550 doc->encoding =
6551 xmlStrdup(BAD_CAST "ISO-8859-1");
6552 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6553 tmp[sizeof(tmp) - 1] = 0;
6554 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6555 cur++;
6556 base = cur;
6557 continue;
6558 }
6559 /*
6560 * We could do multiple things here. Just save
6561 * as a char ref
6562 */
6563 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
6564 tmp[sizeof(tmp) - 1] = 0;
6565 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6566 cur += l;
6567 base = cur;
6568 } else {
6569 cur++;
6570 }
6571 }
6572 if (base != cur)
6573 xmlBufferAdd(buf, base, cur - base);
6574 break;
6575 case XML_ENTITY_REF_NODE:
6576 xmlBufferAdd(buf, BAD_CAST "&", 1);
6577 xmlBufferAdd(buf, children->name,
6578 xmlStrlen(children->name));
6579 xmlBufferAdd(buf, BAD_CAST ";", 1);
6580 break;
6581 default:
6582 /* should not happen unless we have a badly built tree */
6583 break;
6584 }
6585 children = children->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006586 }
6587}
6588
6589/**
6590 * xmlNodeDump:
6591 * @buf: the XML buffer output
6592 * @doc: the document
6593 * @cur: the current node
6594 * @level: the imbrication level for indenting
6595 * @format: is formatting allowed
6596 *
6597 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00006598 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006599 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006600 *
6601 * Returns the number of bytes written to the buffer or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00006602 */
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006603int
Owen Taylor3473f882001-02-23 17:55:21 +00006604xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006605 int format)
6606{
6607 unsigned int use;
6608 int ret;
6609 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006610
6611 if (cur == NULL) {
6612#ifdef DEBUG_TREE
6613 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006614 "xmlNodeDump : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006615#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006616 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006617 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006618 if (buf == NULL) {
6619#ifdef DEBUG_TREE
6620 xmlGenericError(xmlGenericErrorContext,
6621 "xmlNodeDump : buf == NULL\n");
6622#endif
6623 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006624 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006625 outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
6626 if (outbuf == NULL) {
6627 xmlGenericError(xmlGenericErrorContext,
6628 "xmlNodeDump: out of memory!\n");
6629 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006630 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006631 memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
6632 outbuf->buffer = buf;
6633 outbuf->encoder = NULL;
6634 outbuf->writecallback = NULL;
6635 outbuf->closecallback = NULL;
6636 outbuf->context = NULL;
6637 outbuf->written = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006638
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006639 use = buf->use;
6640 xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
6641 xmlFree(outbuf);
6642 ret = buf->use - use;
6643 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006644}
6645
6646/**
6647 * xmlElemDump:
6648 * @f: the FILE * for the output
6649 * @doc: the document
6650 * @cur: the current node
6651 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006652 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006653 */
6654void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006655xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur)
6656{
6657 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006658
6659 if (cur == NULL) {
6660#ifdef DEBUG_TREE
6661 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006662 "xmlElemDump : cur == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006663#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006664 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006665 }
Owen Taylor3473f882001-02-23 17:55:21 +00006666#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006667 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006668 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006669 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006670 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006671#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006672
6673 outbuf = xmlOutputBufferCreateFile(f, NULL);
6674 if (outbuf == NULL)
6675 return;
6676 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006677#ifdef LIBXML_HTML_ENABLED
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006678 htmlNodeDumpOutput(outbuf, doc, cur, NULL);
6679#else
6680 xmlGenericError(xmlGenericErrorContext,
6681 "HTML support not compiled in\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006682#endif /* LIBXML_HTML_ENABLED */
6683 } else
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006684 xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL);
6685 xmlOutputBufferClose(outbuf);
Owen Taylor3473f882001-02-23 17:55:21 +00006686}
6687
6688/************************************************************************
6689 * *
6690 * Dumping XML tree content to an I/O output buffer *
6691 * *
6692 ************************************************************************/
6693
Owen Taylor3473f882001-02-23 17:55:21 +00006694static void
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006695xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6696 int level, int format, const char *encoding);
6697static void
Owen Taylor3473f882001-02-23 17:55:21 +00006698xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6699 int level, int format, const char *encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006700static void
6701xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
6702 xmlNodePtr cur, int level, int format, const char *encoding);
6703
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00006704void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
6705
Owen Taylor3473f882001-02-23 17:55:21 +00006706/**
6707 * xmlNsDumpOutput:
6708 * @buf: the XML buffer output
6709 * @cur: a namespace
6710 *
6711 * Dump a local Namespace definition.
6712 * Should be called in the context of attributes dumps.
6713 */
6714static void
6715xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6716 if (cur == NULL) {
6717#ifdef DEBUG_TREE
6718 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006719 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006720#endif
6721 return;
6722 }
6723 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00006724 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
6725 return;
6726
Owen Taylor3473f882001-02-23 17:55:21 +00006727 /* Within the context of an element attributes */
6728 if (cur->prefix != NULL) {
6729 xmlOutputBufferWriteString(buf, " xmlns:");
6730 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6731 } else
6732 xmlOutputBufferWriteString(buf, " xmlns");
6733 xmlOutputBufferWriteString(buf, "=");
6734 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6735 }
6736}
6737
6738/**
6739 * xmlNsListDumpOutput:
6740 * @buf: the XML buffer output
6741 * @cur: the first namespace
6742 *
6743 * Dump a list of local Namespace definitions.
6744 * Should be called in the context of attributes dumps.
6745 */
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00006746void
Owen Taylor3473f882001-02-23 17:55:21 +00006747xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6748 while (cur != NULL) {
6749 xmlNsDumpOutput(buf, cur);
6750 cur = cur->next;
6751 }
6752}
6753
6754/**
6755 * xmlDtdDumpOutput:
6756 * @buf: the XML buffer output
6757 * @doc: the document
6758 * @encoding: an optional encoding string
6759 *
6760 * Dump the XML document DTD, if any.
6761 */
6762static void
6763xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6764 if (dtd == NULL) {
6765#ifdef DEBUG_TREE
6766 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006767 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006768#endif
6769 return;
6770 }
6771 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6772 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6773 if (dtd->ExternalID != NULL) {
6774 xmlOutputBufferWriteString(buf, " PUBLIC ");
6775 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6776 xmlOutputBufferWriteString(buf, " ");
6777 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6778 } else if (dtd->SystemID != NULL) {
6779 xmlOutputBufferWriteString(buf, " SYSTEM ");
6780 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6781 }
6782 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6783 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6784 xmlOutputBufferWriteString(buf, ">");
6785 return;
6786 }
6787 xmlOutputBufferWriteString(buf, " [\n");
6788 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6789 xmlOutputBufferWriteString(buf, "]>");
6790}
6791
6792/**
6793 * xmlAttrDumpOutput:
6794 * @buf: the XML buffer output
6795 * @doc: the document
6796 * @cur: the attribute pointer
6797 * @encoding: an optional encoding string
6798 *
6799 * Dump an XML attribute
6800 */
6801static void
6802xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006803 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006804 if (cur == NULL) {
6805#ifdef DEBUG_TREE
6806 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006807 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006808#endif
6809 return;
6810 }
6811 xmlOutputBufferWriteString(buf, " ");
6812 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6813 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6814 xmlOutputBufferWriteString(buf, ":");
6815 }
6816 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006817 xmlOutputBufferWriteString(buf, "=\"");
6818 xmlAttrSerializeContent(buf->buffer, doc, cur);
6819 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006820}
6821
6822/**
6823 * xmlAttrListDumpOutput:
6824 * @buf: the XML buffer output
6825 * @doc: the document
6826 * @cur: the first attribute pointer
6827 * @encoding: an optional encoding string
6828 *
6829 * Dump a list of XML attributes
6830 */
6831static void
6832xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6833 xmlAttrPtr cur, const char *encoding) {
6834 if (cur == NULL) {
6835#ifdef DEBUG_TREE
6836 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006837 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006838#endif
6839 return;
6840 }
6841 while (cur != NULL) {
6842 xmlAttrDumpOutput(buf, doc, cur, encoding);
6843 cur = cur->next;
6844 }
6845}
6846
6847
6848
6849/**
6850 * xmlNodeListDumpOutput:
6851 * @buf: the XML buffer output
6852 * @doc: the document
6853 * @cur: the first node
6854 * @level: the imbrication level for indenting
6855 * @format: is formatting allowed
6856 * @encoding: an optional encoding string
6857 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006858 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00006859 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006860 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006861 */
6862static void
6863xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6864 xmlNodePtr cur, int level, int format, const char *encoding) {
6865 int i;
6866
6867 if (cur == NULL) {
6868#ifdef DEBUG_TREE
6869 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006870 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006871#endif
6872 return;
6873 }
6874 while (cur != NULL) {
6875 if ((format) && (xmlIndentTreeOutput) &&
6876 (cur->type == XML_ELEMENT_NODE))
6877 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006878 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006879 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00006880 if (format) {
6881 xmlOutputBufferWriteString(buf, "\n");
6882 }
6883 cur = cur->next;
6884 }
6885}
6886
6887/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006888 * xmlNodeDumpOutputInternal:
Owen Taylor3473f882001-02-23 17:55:21 +00006889 * @buf: the XML buffer output
6890 * @doc: the document
6891 * @cur: the current node
6892 * @level: the imbrication level for indenting
6893 * @format: is formatting allowed
6894 * @encoding: an optional encoding string
6895 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006896 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00006897 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006898 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006899 */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006900static void
6901xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
6902 xmlNodePtr cur, int level, int format, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00006903 int i;
6904 xmlNodePtr tmp;
6905
6906 if (cur == NULL) {
6907#ifdef DEBUG_TREE
6908 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006909 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006910#endif
6911 return;
6912 }
6913 if (cur->type == XML_XINCLUDE_START)
6914 return;
6915 if (cur->type == XML_XINCLUDE_END)
6916 return;
6917 if (cur->type == XML_DTD_NODE) {
6918 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6919 return;
6920 }
6921 if (cur->type == XML_ELEMENT_DECL) {
6922 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6923 return;
6924 }
6925 if (cur->type == XML_ATTRIBUTE_DECL) {
6926 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6927 return;
6928 }
6929 if (cur->type == XML_ENTITY_DECL) {
6930 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6931 return;
6932 }
6933 if (cur->type == XML_TEXT_NODE) {
6934 if (cur->content != NULL) {
6935 if ((cur->name == xmlStringText) ||
6936 (cur->name != xmlStringTextNoenc)) {
6937 xmlChar *buffer;
6938
Owen Taylor3473f882001-02-23 17:55:21 +00006939 if (encoding == NULL)
6940 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6941 else
6942 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006943 if (buffer != NULL) {
6944 xmlOutputBufferWriteString(buf, (const char *)buffer);
6945 xmlFree(buffer);
6946 }
6947 } else {
6948 /*
6949 * Disable escaping, needed for XSLT
6950 */
Owen Taylor3473f882001-02-23 17:55:21 +00006951 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006952 }
6953 }
6954
6955 return;
6956 }
6957 if (cur->type == XML_PI_NODE) {
6958 if (cur->content != NULL) {
6959 xmlOutputBufferWriteString(buf, "<?");
6960 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6961 if (cur->content != NULL) {
6962 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00006963 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006964 }
6965 xmlOutputBufferWriteString(buf, "?>");
6966 } else {
6967 xmlOutputBufferWriteString(buf, "<?");
6968 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6969 xmlOutputBufferWriteString(buf, "?>");
6970 }
6971 return;
6972 }
6973 if (cur->type == XML_COMMENT_NODE) {
6974 if (cur->content != NULL) {
6975 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006976 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006977 xmlOutputBufferWriteString(buf, "-->");
6978 }
6979 return;
6980 }
6981 if (cur->type == XML_ENTITY_REF_NODE) {
6982 xmlOutputBufferWriteString(buf, "&");
6983 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6984 xmlOutputBufferWriteString(buf, ";");
6985 return;
6986 }
6987 if (cur->type == XML_CDATA_SECTION_NODE) {
6988 xmlOutputBufferWriteString(buf, "<![CDATA[");
6989 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006990 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006991 xmlOutputBufferWriteString(buf, "]]>");
6992 return;
6993 }
Daniel Veillard6aa2f602003-02-10 00:01:56 +00006994 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00006995 xmlNsDumpOutput(buf, (xmlNsPtr) cur);
Daniel Veillard6aa2f602003-02-10 00:01:56 +00006996 return;
6997 }
Owen Taylor3473f882001-02-23 17:55:21 +00006998
6999 if (format == 1) {
7000 tmp = cur->children;
7001 while (tmp != NULL) {
7002 if ((tmp->type == XML_TEXT_NODE) ||
7003 (tmp->type == XML_ENTITY_REF_NODE)) {
7004 format = 0;
7005 break;
7006 }
7007 tmp = tmp->next;
7008 }
7009 }
7010 xmlOutputBufferWriteString(buf, "<");
7011 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7012 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7013 xmlOutputBufferWriteString(buf, ":");
7014 }
7015
7016 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7017 if (cur->nsDef)
7018 xmlNsListDumpOutput(buf, cur->nsDef);
7019 if (cur->properties != NULL)
7020 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7021
Daniel Veillard7db37732001-07-12 01:20:08 +00007022 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
7023 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007024 xmlOutputBufferWriteString(buf, "/>");
7025 return;
7026 }
7027 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00007028 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007029 xmlChar *buffer;
7030
Owen Taylor3473f882001-02-23 17:55:21 +00007031 if (encoding == NULL)
7032 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7033 else
7034 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007035 if (buffer != NULL) {
7036 xmlOutputBufferWriteString(buf, (const char *)buffer);
7037 xmlFree(buffer);
7038 }
7039 }
7040 if (cur->children != NULL) {
7041 if (format) xmlOutputBufferWriteString(buf, "\n");
7042 xmlNodeListDumpOutput(buf, doc, cur->children,
7043 (level >= 0?level+1:-1), format, encoding);
7044 if ((xmlIndentTreeOutput) && (format))
7045 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007046 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00007047 }
7048 xmlOutputBufferWriteString(buf, "</");
7049 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7050 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7051 xmlOutputBufferWriteString(buf, ":");
7052 }
7053
7054 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7055 xmlOutputBufferWriteString(buf, ">");
7056}
7057
7058/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007059 * xmlNodeDumpOutput:
7060 * @buf: the XML buffer output
7061 * @doc: the document
7062 * @cur: the current node
7063 * @level: the imbrication level for indenting
7064 * @format: is formatting allowed
7065 * @encoding: an optional encoding string
7066 *
7067 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007068 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007069 * or xmlKeepBlanksDefault(0) was called
7070 */
7071void
7072xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007073 int level, int format, const char *encoding)
7074{
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007075#ifdef LIBXML_HTML_ENABLED
7076 xmlDtdPtr dtd;
7077 int is_xhtml = 0;
7078
7079 dtd = xmlGetIntSubset(doc);
7080 if (dtd != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007081 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7082 if (is_xhtml < 0)
7083 is_xhtml = 0;
7084 if ((is_xhtml) && (cur->parent == (xmlNodePtr) doc) &&
7085 (cur->type == XML_ELEMENT_NODE) &&
7086 (xmlStrEqual(cur->name, BAD_CAST "html"))) {
7087 if (encoding != NULL)
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007088 htmlSetMetaEncoding((htmlDocPtr) doc,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007089 (const xmlChar *) encoding);
7090 else
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007091 htmlSetMetaEncoding((htmlDocPtr) doc, BAD_CAST "UTF-8");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007092 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007093 }
7094
7095 if (is_xhtml)
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007096 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007097 else
7098#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007099 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007100}
7101
7102/**
Owen Taylor3473f882001-02-23 17:55:21 +00007103 * xmlDocContentDumpOutput:
7104 * @buf: the XML buffer output
7105 * @cur: the document
7106 * @encoding: an optional encoding string
7107 * @format: should formatting spaces been added
7108 *
7109 * Dump an XML document.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007110 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007111 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007112 */
7113static void
7114xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
7115 const char *encoding, int format) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007116#ifdef LIBXML_HTML_ENABLED
7117 xmlDtdPtr dtd;
7118 int is_xhtml = 0;
7119#endif
7120
Owen Taylor3473f882001-02-23 17:55:21 +00007121 xmlOutputBufferWriteString(buf, "<?xml version=");
7122 if (cur->version != NULL)
7123 xmlBufferWriteQuotedString(buf->buffer, cur->version);
7124 else
7125 xmlOutputBufferWriteString(buf, "\"1.0\"");
7126 if (encoding == NULL) {
7127 if (cur->encoding != NULL)
7128 encoding = (const char *) cur->encoding;
7129 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
7130 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
7131 }
7132 if (encoding != NULL) {
7133 xmlOutputBufferWriteString(buf, " encoding=");
7134 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
7135 }
7136 switch (cur->standalone) {
7137 case 0:
7138 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
7139 break;
7140 case 1:
7141 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
7142 break;
7143 }
7144 xmlOutputBufferWriteString(buf, "?>\n");
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007145
7146#ifdef LIBXML_HTML_ENABLED
7147 dtd = xmlGetIntSubset(cur);
7148 if (dtd != NULL) {
7149 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7150 if (is_xhtml < 0) is_xhtml = 0;
7151 }
7152 if (is_xhtml) {
7153 if (encoding != NULL)
7154 htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
7155 else
7156 htmlSetMetaEncoding(cur, BAD_CAST "UTF-8");
7157 }
7158#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007159 if (cur->children != NULL) {
7160 xmlNodePtr child = cur->children;
7161
7162 while (child != NULL) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007163#ifdef LIBXML_HTML_ENABLED
7164 if (is_xhtml)
7165 xhtmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
7166 else
7167#endif
7168 xmlNodeDumpOutputInternal(buf, cur, child, 0, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007169 xmlOutputBufferWriteString(buf, "\n");
7170 child = child->next;
7171 }
7172 }
7173}
7174
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007175#ifdef LIBXML_HTML_ENABLED
7176/************************************************************************
7177 * *
7178 * Functions specific to XHTML serialization *
7179 * *
7180 ************************************************************************/
7181
7182#define XHTML_STRICT_PUBLIC_ID BAD_CAST \
7183 "-//W3C//DTD XHTML 1.0 Strict//EN"
7184#define XHTML_STRICT_SYSTEM_ID BAD_CAST \
7185 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
7186#define XHTML_FRAME_PUBLIC_ID BAD_CAST \
7187 "-//W3C//DTD XHTML 1.0 Frameset//EN"
7188#define XHTML_FRAME_SYSTEM_ID BAD_CAST \
7189 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
7190#define XHTML_TRANS_PUBLIC_ID BAD_CAST \
7191 "-//W3C//DTD XHTML 1.0 Transitional//EN"
7192#define XHTML_TRANS_SYSTEM_ID BAD_CAST \
7193 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
7194
7195#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
7196/**
7197 * xmlIsXHTML:
7198 * @systemID: the system identifier
7199 * @publicID: the public identifier
7200 *
7201 * Try to find if the document correspond to an XHTML DTD
7202 *
7203 * Returns 1 if true, 0 if not and -1 in case of error
7204 */
7205int
7206xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) {
7207 if ((systemID == NULL) && (publicID == NULL))
7208 return(-1);
7209 if (publicID != NULL) {
7210 if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1);
7211 if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1);
7212 if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1);
7213 }
7214 if (systemID != NULL) {
7215 if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1);
7216 if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1);
7217 if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1);
7218 }
7219 return(0);
7220}
7221
7222/**
7223 * xhtmlIsEmpty:
7224 * @node: the node
7225 *
7226 * Check if a node is an empty xhtml node
7227 *
7228 * Returns 1 if the node is an empty node, 0 if not and -1 in case of error
7229 */
7230static int
7231xhtmlIsEmpty(xmlNodePtr node) {
7232 if (node == NULL)
7233 return(-1);
7234 if (node->type != XML_ELEMENT_NODE)
7235 return(0);
7236 if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME)))
7237 return(0);
7238 if (node->children != NULL)
7239 return(0);
7240 switch (node->name[0]) {
7241 case 'a':
7242 if (xmlStrEqual(node->name, BAD_CAST "area"))
7243 return(1);
7244 return(0);
7245 case 'b':
7246 if (xmlStrEqual(node->name, BAD_CAST "br"))
7247 return(1);
7248 if (xmlStrEqual(node->name, BAD_CAST "base"))
7249 return(1);
7250 if (xmlStrEqual(node->name, BAD_CAST "basefont"))
7251 return(1);
7252 return(0);
7253 case 'c':
7254 if (xmlStrEqual(node->name, BAD_CAST "col"))
7255 return(1);
7256 return(0);
7257 case 'f':
7258 if (xmlStrEqual(node->name, BAD_CAST "frame"))
7259 return(1);
7260 return(0);
7261 case 'h':
7262 if (xmlStrEqual(node->name, BAD_CAST "hr"))
7263 return(1);
7264 return(0);
7265 case 'i':
7266 if (xmlStrEqual(node->name, BAD_CAST "img"))
7267 return(1);
7268 if (xmlStrEqual(node->name, BAD_CAST "input"))
7269 return(1);
7270 if (xmlStrEqual(node->name, BAD_CAST "isindex"))
7271 return(1);
7272 return(0);
7273 case 'l':
7274 if (xmlStrEqual(node->name, BAD_CAST "link"))
7275 return(1);
7276 return(0);
7277 case 'm':
7278 if (xmlStrEqual(node->name, BAD_CAST "meta"))
7279 return(1);
7280 return(0);
7281 case 'p':
7282 if (xmlStrEqual(node->name, BAD_CAST "param"))
7283 return(1);
7284 return(0);
7285 }
7286 return(0);
7287}
7288
7289/**
7290 * xhtmlAttrListDumpOutput:
7291 * @buf: the XML buffer output
7292 * @doc: the document
7293 * @cur: the first attribute pointer
7294 * @encoding: an optional encoding string
7295 *
7296 * Dump a list of XML attributes
7297 */
7298static void
7299xhtmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7300 xmlAttrPtr cur, const char *encoding) {
7301 xmlAttrPtr xml_lang = NULL;
7302 xmlAttrPtr lang = NULL;
7303 xmlAttrPtr name = NULL;
7304 xmlAttrPtr id = NULL;
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007305 xmlNodePtr parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007306
7307 if (cur == NULL) {
7308#ifdef DEBUG_TREE
7309 xmlGenericError(xmlGenericErrorContext,
7310 "xmlAttrListDumpOutput : property == NULL\n");
7311#endif
7312 return;
7313 }
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007314 parent = cur->parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007315 while (cur != NULL) {
7316 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id")))
7317 id = cur;
7318 else
7319 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name")))
7320 name = cur;
7321 else
7322 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")))
7323 lang = cur;
7324 else
7325 if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) &&
7326 (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml")))
7327 xml_lang = cur;
7328 else if ((cur->ns == NULL) &&
7329 ((cur->children == NULL) ||
7330 (cur->children->content == NULL) ||
7331 (cur->children->content[0] == 0)) &&
7332 (htmlIsBooleanAttr(cur->name))) {
7333 if (cur->children != NULL)
7334 xmlFreeNode(cur->children);
7335 cur->children = xmlNewText(cur->name);
7336 if (cur->children != NULL)
7337 cur->children->parent = (xmlNodePtr) cur;
7338 }
7339 xmlAttrDumpOutput(buf, doc, cur, encoding);
7340 cur = cur->next;
7341 }
7342 /*
7343 * C.8
7344 */
7345 if ((name != NULL) && (id == NULL)) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007346 if ((parent != NULL) && (parent->name != NULL) &&
7347 ((xmlStrEqual(parent->name, BAD_CAST "a")) ||
7348 (xmlStrEqual(parent->name, BAD_CAST "p")) ||
7349 (xmlStrEqual(parent->name, BAD_CAST "div")) ||
7350 (xmlStrEqual(parent->name, BAD_CAST "img")) ||
7351 (xmlStrEqual(parent->name, BAD_CAST "map")) ||
7352 (xmlStrEqual(parent->name, BAD_CAST "applet")) ||
7353 (xmlStrEqual(parent->name, BAD_CAST "form")) ||
7354 (xmlStrEqual(parent->name, BAD_CAST "frame")) ||
7355 (xmlStrEqual(parent->name, BAD_CAST "iframe")))) {
7356 xmlOutputBufferWriteString(buf, " id=\"");
7357 xmlAttrSerializeContent(buf->buffer, doc, name);
7358 xmlOutputBufferWriteString(buf, "\"");
7359 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007360 }
7361 /*
7362 * C.7.
7363 */
7364 if ((lang != NULL) && (xml_lang == NULL)) {
7365 xmlOutputBufferWriteString(buf, " xml:lang=\"");
7366 xmlAttrSerializeContent(buf->buffer, doc, lang);
7367 xmlOutputBufferWriteString(buf, "\"");
7368 } else
7369 if ((xml_lang != NULL) && (lang == NULL)) {
7370 xmlOutputBufferWriteString(buf, " lang=\"");
7371 xmlAttrSerializeContent(buf->buffer, doc, xml_lang);
7372 xmlOutputBufferWriteString(buf, "\"");
7373 }
7374}
7375
7376/**
7377 * xhtmlNodeListDumpOutput:
7378 * @buf: the XML buffer output
7379 * @doc: the XHTML document
7380 * @cur: the first node
7381 * @level: the imbrication level for indenting
7382 * @format: is formatting allowed
7383 * @encoding: an optional encoding string
7384 *
7385 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007386 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007387 * or xmlKeepBlanksDefault(0) was called
7388 */
7389static void
7390xhtmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7391 xmlNodePtr cur, int level, int format, const char *encoding) {
7392 int i;
7393
7394 if (cur == NULL) {
7395#ifdef DEBUG_TREE
7396 xmlGenericError(xmlGenericErrorContext,
7397 "xhtmlNodeListDumpOutput : node == NULL\n");
7398#endif
7399 return;
7400 }
7401 while (cur != NULL) {
7402 if ((format) && (xmlIndentTreeOutput) &&
7403 (cur->type == XML_ELEMENT_NODE))
7404 for (i = 0;i < level;i++)
7405 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7406 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
7407 if (format) {
7408 xmlOutputBufferWriteString(buf, "\n");
7409 }
7410 cur = cur->next;
7411 }
7412}
7413
7414/**
7415 * xhtmlNodeDumpOutput:
7416 * @buf: the XML buffer output
7417 * @doc: the XHTML document
7418 * @cur: the current node
7419 * @level: the imbrication level for indenting
7420 * @format: is formatting allowed
7421 * @encoding: an optional encoding string
7422 *
7423 * Dump an XHTML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007424 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007425 * or xmlKeepBlanksDefault(0) was called
7426 */
7427static void
7428xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7429 int level, int format, const char *encoding) {
7430 int i;
7431 xmlNodePtr tmp;
7432
7433 if (cur == NULL) {
7434#ifdef DEBUG_TREE
7435 xmlGenericError(xmlGenericErrorContext,
7436 "xmlNodeDumpOutput : node == NULL\n");
7437#endif
7438 return;
7439 }
7440 if (cur->type == XML_XINCLUDE_START)
7441 return;
7442 if (cur->type == XML_XINCLUDE_END)
7443 return;
7444 if (cur->type == XML_DTD_NODE) {
7445 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7446 return;
7447 }
7448 if (cur->type == XML_ELEMENT_DECL) {
7449 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7450 return;
7451 }
7452 if (cur->type == XML_ATTRIBUTE_DECL) {
7453 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7454 return;
7455 }
7456 if (cur->type == XML_ENTITY_DECL) {
7457 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7458 return;
7459 }
7460 if (cur->type == XML_TEXT_NODE) {
7461 if (cur->content != NULL) {
7462 if ((cur->name == xmlStringText) ||
7463 (cur->name != xmlStringTextNoenc)) {
7464 xmlChar *buffer;
7465
7466 if (encoding == NULL)
7467 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7468 else
7469 buffer = xmlEncodeSpecialChars(doc, cur->content);
7470 if (buffer != NULL) {
7471 xmlOutputBufferWriteString(buf, (const char *)buffer);
7472 xmlFree(buffer);
7473 }
7474 } else {
7475 /*
7476 * Disable escaping, needed for XSLT
7477 */
7478 xmlOutputBufferWriteString(buf, (const char *) cur->content);
7479 }
7480 }
7481
7482 return;
7483 }
7484 if (cur->type == XML_PI_NODE) {
7485 if (cur->content != NULL) {
7486 xmlOutputBufferWriteString(buf, "<?");
7487 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7488 if (cur->content != NULL) {
7489 xmlOutputBufferWriteString(buf, " ");
7490 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7491 }
7492 xmlOutputBufferWriteString(buf, "?>");
7493 } else {
7494 xmlOutputBufferWriteString(buf, "<?");
7495 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7496 xmlOutputBufferWriteString(buf, "?>");
7497 }
7498 return;
7499 }
7500 if (cur->type == XML_COMMENT_NODE) {
7501 if (cur->content != NULL) {
7502 xmlOutputBufferWriteString(buf, "<!--");
7503 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7504 xmlOutputBufferWriteString(buf, "-->");
7505 }
7506 return;
7507 }
7508 if (cur->type == XML_ENTITY_REF_NODE) {
7509 xmlOutputBufferWriteString(buf, "&");
7510 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7511 xmlOutputBufferWriteString(buf, ";");
7512 return;
7513 }
7514 if (cur->type == XML_CDATA_SECTION_NODE) {
7515 xmlOutputBufferWriteString(buf, "<![CDATA[");
7516 if (cur->content != NULL)
7517 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7518 xmlOutputBufferWriteString(buf, "]]>");
7519 return;
7520 }
7521
7522 if (format == 1) {
7523 tmp = cur->children;
7524 while (tmp != NULL) {
7525 if ((tmp->type == XML_TEXT_NODE) ||
7526 (tmp->type == XML_ENTITY_REF_NODE)) {
7527 format = 0;
7528 break;
7529 }
7530 tmp = tmp->next;
7531 }
7532 }
7533 xmlOutputBufferWriteString(buf, "<");
7534 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7535 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7536 xmlOutputBufferWriteString(buf, ":");
7537 }
7538
7539 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7540 if (cur->nsDef)
7541 xmlNsListDumpOutput(buf, cur->nsDef);
7542 if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
7543 (cur->ns == NULL) && (cur->nsDef == NULL))) {
7544 /*
7545 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
7546 */
7547 xmlOutputBufferWriteString(buf,
7548 " xmlns=\"http://www.w3.org/1999/xhtml\"");
7549 }
7550 if (cur->properties != NULL)
7551 xhtmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7552
7553 if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) {
7554 if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
7555 (xhtmlIsEmpty(cur) == 1)) {
7556 /*
7557 * C.2. Empty Elements
7558 */
7559 xmlOutputBufferWriteString(buf, " />");
7560 } else {
7561 /*
7562 * C.3. Element Minimization and Empty Element Content
7563 */
7564 xmlOutputBufferWriteString(buf, "></");
7565 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7566 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7567 xmlOutputBufferWriteString(buf, ":");
7568 }
7569 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7570 xmlOutputBufferWriteString(buf, ">");
7571 }
7572 return;
7573 }
7574 xmlOutputBufferWriteString(buf, ">");
7575 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
7576 xmlChar *buffer;
7577
7578 if (encoding == NULL)
7579 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7580 else
7581 buffer = xmlEncodeSpecialChars(doc, cur->content);
7582 if (buffer != NULL) {
7583 xmlOutputBufferWriteString(buf, (const char *)buffer);
7584 xmlFree(buffer);
7585 }
7586 }
7587
7588 /*
7589 * 4.8. Script and Style elements
7590 */
7591 if ((cur->type == XML_ELEMENT_NODE) &&
7592 ((xmlStrEqual(cur->name, BAD_CAST "script")) ||
7593 (xmlStrEqual(cur->name, BAD_CAST "style"))) &&
7594 ((cur->ns == NULL) ||
7595 (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) {
7596 xmlNodePtr child = cur->children;
7597
7598 while (child != NULL) {
7599 if ((child->type == XML_TEXT_NODE) ||
7600 (child->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard64b35282002-12-04 15:10:40 +00007601 /*
7602 * Apparently CDATA escaping for style just break on IE,
7603 * mozilla and galeon, so ...
7604 */
7605 if (xmlStrEqual(cur->name, BAD_CAST "style") &&
7606 (xmlStrchr(child->content, '<') == NULL) &&
7607 (xmlStrchr(child->content, '>') == NULL) &&
7608 (xmlStrchr(child->content, '&') == NULL)) {
7609 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7610 } else {
7611 xmlOutputBufferWriteString(buf, "<![CDATA[");
7612 if (child->content != NULL)
7613 xmlOutputBufferWriteString(buf,
7614 (const char *)child->content);
7615 xmlOutputBufferWriteString(buf, "]]>");
7616 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007617 } else {
7618 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7619 }
7620 child = child->next;
7621 }
7622 } else if (cur->children != NULL) {
7623 if (format) xmlOutputBufferWriteString(buf, "\n");
7624 xhtmlNodeListDumpOutput(buf, doc, cur->children,
7625 (level >= 0?level+1:-1), format, encoding);
7626 if ((xmlIndentTreeOutput) && (format))
7627 for (i = 0;i < level;i++)
7628 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7629 }
7630 xmlOutputBufferWriteString(buf, "</");
7631 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7632 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7633 xmlOutputBufferWriteString(buf, ":");
7634 }
7635
7636 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7637 xmlOutputBufferWriteString(buf, ">");
7638}
7639#endif
7640
Owen Taylor3473f882001-02-23 17:55:21 +00007641/************************************************************************
7642 * *
7643 * Saving functions front-ends *
7644 * *
7645 ************************************************************************/
7646
7647/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00007648 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00007649 * @out_doc: Document to generate XML text from
7650 * @doc_txt_ptr: Memory pointer for allocated XML text
7651 * @doc_txt_len: Length of the generated XML text
7652 * @txt_encoding: Character encoding to use when generating XML text
7653 * @format: should formatting spaces been added
7654 *
7655 * Dump the current DOM tree into memory using the character encoding specified
7656 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007657 * allocated memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00007658 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007659 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007660 */
7661
7662void
7663xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007664 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007665 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007666 int dummy = 0;
7667
7668 xmlCharEncoding doc_charset;
7669 xmlOutputBufferPtr out_buff = NULL;
7670 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
7671
7672 if (doc_txt_len == NULL) {
7673 doc_txt_len = &dummy; /* Continue, caller just won't get length */
7674 }
7675
7676 if (doc_txt_ptr == NULL) {
7677 *doc_txt_len = 0;
7678 xmlGenericError(xmlGenericErrorContext,
7679 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
7680 return;
7681 }
7682
7683 *doc_txt_ptr = NULL;
7684 *doc_txt_len = 0;
7685
7686 if (out_doc == NULL) {
7687 /* No document, no output */
7688 xmlGenericError(xmlGenericErrorContext,
7689 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
7690 return;
7691 }
7692
7693 /*
7694 * Validate the encoding value, if provided.
7695 * This logic is copied from xmlSaveFileEnc.
7696 */
7697
7698 if (txt_encoding == NULL)
7699 txt_encoding = (const char *) out_doc->encoding;
7700 if (txt_encoding != NULL) {
7701 doc_charset = xmlParseCharEncoding(txt_encoding);
7702
7703 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
7704 xmlGenericError(xmlGenericErrorContext,
7705 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
7706 return;
7707
7708 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
7709 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
7710 if ( conv_hdlr == NULL ) {
7711 xmlGenericError(xmlGenericErrorContext,
7712 "%s: %s %s '%s'\n",
7713 "xmlDocDumpFormatMemoryEnc",
7714 "Failed to identify encoding handler for",
7715 "character set",
7716 txt_encoding);
7717 return;
7718 }
7719 }
7720 }
7721
7722 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
7723 xmlGenericError(xmlGenericErrorContext,
7724 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
7725 return;
7726 }
7727
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007728 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007729 xmlOutputBufferFlush(out_buff);
7730 if (out_buff->conv != NULL) {
7731 *doc_txt_len = out_buff->conv->use;
7732 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
7733 } else {
7734 *doc_txt_len = out_buff->buffer->use;
7735 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
7736 }
7737 (void)xmlOutputBufferClose(out_buff);
7738
7739 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
7740 *doc_txt_len = 0;
7741 xmlGenericError(xmlGenericErrorContext,
7742 "xmlDocDumpFormatMemoryEnc: %s\n",
7743 "Failed to allocate memory for document text representation.");
7744 }
7745
7746 return;
7747}
7748
7749/**
7750 * xmlDocDumpMemory:
7751 * @cur: the document
7752 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007753 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007754 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007755 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007756 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007757 */
7758void
7759xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
7760 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
7761}
7762
7763/**
7764 * xmlDocDumpFormatMemory:
7765 * @cur: the document
7766 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007767 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007768 * @format: should formatting spaces been added
7769 *
7770 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007771 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007772 * It's up to the caller to free the memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00007773 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007774 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007775 */
7776void
7777xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
7778 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
7779}
7780
7781/**
7782 * xmlDocDumpMemoryEnc:
7783 * @out_doc: Document to generate XML text from
7784 * @doc_txt_ptr: Memory pointer for allocated XML text
7785 * @doc_txt_len: Length of the generated XML text
7786 * @txt_encoding: Character encoding to use when generating XML text
7787 *
7788 * Dump the current DOM tree into memory using the character encoding specified
7789 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007790 * allocated memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007791 */
7792
7793void
7794xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
7795 int * doc_txt_len, const char * txt_encoding) {
7796 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007797 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007798}
7799
7800/**
7801 * xmlGetDocCompressMode:
7802 * @doc: the document
7803 *
7804 * get the compression ratio for a document, ZLIB based
7805 * Returns 0 (uncompressed) to 9 (max compression)
7806 */
7807int
7808xmlGetDocCompressMode (xmlDocPtr doc) {
7809 if (doc == NULL) return(-1);
7810 return(doc->compression);
7811}
7812
7813/**
7814 * xmlSetDocCompressMode:
7815 * @doc: the document
7816 * @mode: the compression ratio
7817 *
7818 * set the compression ratio for a document, ZLIB based
7819 * Correct values: 0 (uncompressed) to 9 (max compression)
7820 */
7821void
7822xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7823 if (doc == NULL) return;
7824 if (mode < 0) doc->compression = 0;
7825 else if (mode > 9) doc->compression = 9;
7826 else doc->compression = mode;
7827}
7828
7829/**
7830 * xmlGetCompressMode:
7831 *
7832 * get the default compression mode used, ZLIB based.
7833 * Returns 0 (uncompressed) to 9 (max compression)
7834 */
7835int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007836xmlGetCompressMode(void)
7837{
7838 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00007839}
7840
7841/**
7842 * xmlSetCompressMode:
7843 * @mode: the compression ratio
7844 *
7845 * set the default compression mode used, ZLIB based
7846 * Correct values: 0 (uncompressed) to 9 (max compression)
7847 */
7848void
7849xmlSetCompressMode(int mode) {
7850 if (mode < 0) xmlCompressMode = 0;
7851 else if (mode > 9) xmlCompressMode = 9;
7852 else xmlCompressMode = mode;
7853}
7854
7855/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007856 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00007857 * @f: the FILE*
7858 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00007859 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007860 *
7861 * Dump an XML document to an open FILE.
7862 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007863 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007864 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7865 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007866 */
7867int
Daniel Veillard9e412302002-06-10 15:59:44 +00007868xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007869 xmlOutputBufferPtr buf;
7870 const char * encoding;
7871 xmlCharEncodingHandlerPtr handler = NULL;
7872 int ret;
7873
7874 if (cur == NULL) {
7875#ifdef DEBUG_TREE
7876 xmlGenericError(xmlGenericErrorContext,
7877 "xmlDocDump : document == NULL\n");
7878#endif
7879 return(-1);
7880 }
7881 encoding = (const char *) cur->encoding;
7882
7883 if (encoding != NULL) {
7884 xmlCharEncoding enc;
7885
7886 enc = xmlParseCharEncoding(encoding);
7887
7888 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7889 xmlGenericError(xmlGenericErrorContext,
7890 "xmlDocDump: document not in UTF8\n");
7891 return(-1);
7892 }
7893 if (enc != XML_CHAR_ENCODING_UTF8) {
7894 handler = xmlFindCharEncodingHandler(encoding);
7895 if (handler == NULL) {
7896 xmlFree((char *) cur->encoding);
7897 cur->encoding = NULL;
7898 }
7899 }
7900 }
7901 buf = xmlOutputBufferCreateFile(f, handler);
7902 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00007903 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007904
7905 ret = xmlOutputBufferClose(buf);
7906 return(ret);
7907}
7908
7909/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007910 * xmlDocDump:
7911 * @f: the FILE*
7912 * @cur: the document
7913 *
7914 * Dump an XML document to an open FILE.
7915 *
7916 * returns: the number of bytes written or -1 in case of failure.
7917 */
7918int
7919xmlDocDump(FILE *f, xmlDocPtr cur) {
7920 return(xmlDocFormatDump (f, cur, 0));
7921}
7922
7923/**
Owen Taylor3473f882001-02-23 17:55:21 +00007924 * xmlSaveFileTo:
7925 * @buf: an output I/O buffer
7926 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007927 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00007928 *
7929 * Dump an XML document to an I/O buffer.
7930 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007931 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007932 */
7933int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007934xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007935 int ret;
7936
7937 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007938 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007939 ret = xmlOutputBufferClose(buf);
7940 return(ret);
7941}
7942
7943/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00007944 * xmlSaveFormatFileTo:
7945 * @buf: an output I/O buffer
7946 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007947 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00007948 * @format: should formatting spaces been added
7949 *
7950 * Dump an XML document to an I/O buffer.
7951 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007952 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007953 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7954 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardeefd4492001-04-28 16:55:50 +00007955 */
7956int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007957xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00007958 int ret;
7959
7960 if (buf == NULL) return(0);
7961 xmlDocContentDumpOutput(buf, cur, encoding, format);
7962 ret = xmlOutputBufferClose(buf);
7963 return(ret);
7964}
7965
7966/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00007967 * xmlSaveFormatFileEnc:
Daniel Veillardf012a642001-07-23 19:10:52 +00007968 * @filename: the filename or URL to output
7969 * @cur: the document being saved
7970 * @encoding: the name of the encoding to use or NULL.
7971 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00007972 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00007973 * Dump an XML document to a file or an URL.
7974 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007975 * Returns the number of bytes written or -1 in case of error.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007976 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7977 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007978 */
7979int
Daniel Veillardf012a642001-07-23 19:10:52 +00007980xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
7981 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00007982 xmlOutputBufferPtr buf;
7983 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00007984 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00007985 int ret;
7986
Daniel Veillard4dbe77a2003-01-14 00:17:42 +00007987 if (cur == NULL)
7988 return(-1);
7989
Daniel Veillardfb25a512002-01-13 20:32:08 +00007990 if (encoding == NULL)
7991 encoding = (const char *) cur->encoding;
7992
Owen Taylor3473f882001-02-23 17:55:21 +00007993 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00007994
7995 enc = xmlParseCharEncoding(encoding);
7996 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7997 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007998 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007999 return(-1);
8000 }
8001 if (enc != XML_CHAR_ENCODING_UTF8) {
8002 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00008003 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00008004 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00008005 }
8006 }
8007
Daniel Veillardf012a642001-07-23 19:10:52 +00008008#ifdef HAVE_ZLIB_H
8009 if (cur->compression < 0) cur->compression = xmlCompressMode;
8010#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008011 /*
8012 * save the content to a temp buffer.
8013 */
Daniel Veillardf012a642001-07-23 19:10:52 +00008014 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00008015 if (buf == NULL) return(-1);
8016
Daniel Veillardf012a642001-07-23 19:10:52 +00008017 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008018
8019 ret = xmlOutputBufferClose(buf);
8020 return(ret);
8021}
8022
Daniel Veillardf012a642001-07-23 19:10:52 +00008023
8024/**
8025 * xmlSaveFileEnc:
8026 * @filename: the filename (or URL)
8027 * @cur: the document
8028 * @encoding: the name of an encoding (or NULL)
8029 *
8030 * Dump an XML document, converting it to the given encoding
8031 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008032 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00008033 */
8034int
8035xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
8036 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
8037}
8038
Owen Taylor3473f882001-02-23 17:55:21 +00008039/**
Daniel Veillard67fee942001-04-26 18:59:03 +00008040 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00008041 * @filename: the filename (or URL)
8042 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00008043 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00008044 *
8045 * Dump an XML document to a file. Will use compression if
8046 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00008047 * used. If @format is set then the document will be indented on output.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008048 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8049 * or xmlKeepBlanksDefault(0) was called
Daniel Veillard67fee942001-04-26 18:59:03 +00008050 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008051 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008052 */
8053int
Daniel Veillard67fee942001-04-26 18:59:03 +00008054xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008055 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00008056}
8057
Daniel Veillard67fee942001-04-26 18:59:03 +00008058/**
8059 * xmlSaveFile:
8060 * @filename: the filename (or URL)
8061 * @cur: the document
8062 *
8063 * Dump an XML document to a file. Will use compression if
8064 * compiled in and enabled. If @filename is "-" the stdout file is
8065 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00008066 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00008067 */
8068int
8069xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008070 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00008071}
8072