blob: ca1a7bb8b2fbe1e5dc201eedd9e81ae22fbfae38 [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 Veillarda880b122003-04-21 21:36:41 +000041int __xmlRegisterCallbacks = 0;
42
Daniel Veillard56a4cb82001-03-24 17:00:36 +000043xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
44
45/************************************************************************
46 * *
47 * A few static variables and macros *
48 * *
49 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +000050/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +000051const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000052/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +000053const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +000054 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000055/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +000056const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
57
Owen Taylor3473f882001-02-23 17:55:21 +000058static int xmlCompressMode = 0;
59static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000060
Owen Taylor3473f882001-02-23 17:55:21 +000061#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
62 xmlNodePtr ulccur = (n)->children; \
63 if (ulccur == NULL) { \
64 (n)->last = NULL; \
65 } else { \
66 while (ulccur->next != NULL) { \
67 ulccur->parent = (n); \
68 ulccur = ulccur->next; \
69 } \
70 ulccur->parent = (n); \
71 (n)->last = ulccur; \
72}}
73
74/* #define DEBUG_BUFFER */
75/* #define DEBUG_TREE */
76
77/************************************************************************
78 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +000079 * Functions to move to entities.c once the *
80 * API freeze is smoothen and they can be made public. *
81 * *
82 ************************************************************************/
83#include <libxml/hash.h>
84
85/**
86 * xmlGetEntityFromDtd:
87 * @dtd: A pointer to the DTD to search
88 * @name: The entity name
89 *
90 * Do an entity lookup in the DTD entity hash table and
91 * return the corresponding entity, if found.
92 *
93 * Returns A pointer to the entity structure or NULL if not found.
94 */
95static xmlEntityPtr
96xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
97 xmlEntitiesTablePtr table;
98
99 if((dtd != NULL) && (dtd->entities != NULL)) {
100 table = (xmlEntitiesTablePtr) dtd->entities;
101 return((xmlEntityPtr) xmlHashLookup(table, name));
102 /* return(xmlGetEntityFromTable(table, name)); */
103 }
104 return(NULL);
105}
106/**
107 * xmlGetParameterEntityFromDtd:
108 * @dtd: A pointer to the DTD to search
109 * @name: The entity name
110 *
111 * Do an entity lookup in the DTD pararmeter entity hash table and
112 * return the corresponding entity, if found.
113 *
114 * Returns A pointer to the entity structure or NULL if not found.
115 */
116static xmlEntityPtr
117xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
118 xmlEntitiesTablePtr table;
119
120 if ((dtd != NULL) && (dtd->pentities != NULL)) {
121 table = (xmlEntitiesTablePtr) dtd->pentities;
122 return((xmlEntityPtr) xmlHashLookup(table, name));
123 /* return(xmlGetEntityFromTable(table, name)); */
124 }
125 return(NULL);
126}
127
128/************************************************************************
129 * *
Daniel Veillardc00cda82003-04-07 10:22:39 +0000130 * QName handling helper *
131 * *
132 ************************************************************************/
133
134/**
135 * xmlBuildQName:
136 * @ncname: the Name
137 * @prefix: the prefix
138 * @memory: preallocated memory
139 * @len: preallocated memory length
140 *
141 * Builds the QName @prefix:@ncname in @memory if there is enough space
142 * and prefix is not NULL nor empty, otherwise allocate a new string.
143 * If prefix is NULL or empty it returns ncname.
144 *
145 * Returns the new string which must be freed by the caller if different from
146 * @memory and @ncname or NULL in case of error
147 */
148xmlChar *
149xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix,
150 xmlChar *memory, int len) {
151 int lenn, lenp;
152 xmlChar *ret;
153
154 if ((ncname == NULL) || (*ncname == 0)) return(NULL);
155 if ((prefix == NULL) || (*prefix == 0)) return((xmlChar *) ncname);
156
157 lenn = strlen((char *) ncname);
158 lenp = strlen((char *) prefix);
159
160 if ((memory == NULL) || (len < lenn + lenp + 2)) {
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000161 ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000162 if (ret == NULL) return(NULL);
163 } else {
164 ret = memory;
165 }
166 memcpy(&ret[0], prefix, lenp);
167 ret[lenp] = ':';
168 memcpy(&ret[lenp + 1], ncname, lenn);
169 ret[lenn + lenp + 1] = 0;
170 return(ret);
171}
172
173/**
174 * xmlSplitQName2:
175 * @name: the full QName
176 * @prefix: a xmlChar **
177 *
178 * parse an XML qualified name string
179 *
180 * [NS 5] QName ::= (Prefix ':')? LocalPart
181 *
182 * [NS 6] Prefix ::= NCName
183 *
184 * [NS 7] LocalPart ::= NCName
185 *
186 * Returns NULL if not a QName, otherwise the local part, and prefix
187 * is updated to get the Prefix if any.
188 */
189
190xmlChar *
191xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
192 int len = 0;
193 xmlChar *ret = NULL;
194
195 *prefix = NULL;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000196 if (name == NULL) return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +0000197
198#ifndef XML_XML_NAMESPACE
199 /* xml: prefix is not really a namespace */
200 if ((name[0] == 'x') && (name[1] == 'm') &&
201 (name[2] == 'l') && (name[3] == ':'))
202 return(NULL);
203#endif
204
205 /* nasty but valid */
206 if (name[0] == ':')
207 return(NULL);
208
209 /*
210 * we are not trying to validate but just to cut, and yes it will
211 * work even if this is as set of UTF-8 encoded chars
212 */
213 while ((name[len] != 0) && (name[len] != ':'))
214 len++;
215
216 if (name[len] == 0)
217 return(NULL);
218
219 *prefix = xmlStrndup(name, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000220 if (*prefix == NULL) {
221 xmlGenericError(xmlGenericErrorContext,
222 "xmlSplitQName2 : out of memory!\n");
223 return(NULL);
224 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000225 ret = xmlStrdup(&name[len + 1]);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000226 if (ret == NULL) {
227 xmlGenericError(xmlGenericErrorContext,
228 "xmlSplitQName2 : out of memory!\n");
229 if (*prefix != NULL) {
230 xmlFree(*prefix);
231 *prefix = NULL;
232 }
233 return(NULL);
234 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000235
236 return(ret);
237}
238
Daniel Veillard8d73bcb2003-08-04 01:06:15 +0000239/**
240 * xmlSplitQName3:
241 * @name: the full QName
242 * @len: an int *
243 *
244 * parse an XML qualified name string,i
245 *
246 * returns NULL if it is not a Qualified Name, otherwise, update len
247 * with the lenght in byte of the prefix and return a pointer
248 */
249
250const xmlChar *
251xmlSplitQName3(const xmlChar *name, int *len) {
252 int l = 0;
253
254 if (name == NULL) return(NULL);
255 if (len == NULL) return(NULL);
256
257 /* nasty but valid */
258 if (name[0] == ':')
259 return(NULL);
260
261 /*
262 * we are not trying to validate but just to cut, and yes it will
263 * work even if this is as set of UTF-8 encoded chars
264 */
265 while ((name[l] != 0) && (name[l] != ':'))
266 l++;
267
268 if (name[l] == 0)
269 return(NULL);
270
271 *len = l;
272
273 return(&name[l+1]);
274}
275
Daniel Veillardc00cda82003-04-07 10:22:39 +0000276/************************************************************************
277 * *
Daniel Veillardd2298792003-02-14 16:54:11 +0000278 * Check Name, NCName and QName strings *
279 * *
280 ************************************************************************/
281
282#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
283
284/**
285 * xmlValidateNCName:
286 * @value: the value to check
287 * @space: allow spaces in front and end of the string
288 *
289 * Check that a value conforms to the lexical space of NCName
290 *
291 * Returns 0 if this validates, a positive error code number otherwise
292 * and -1 in case of internal or API error.
293 */
294int
295xmlValidateNCName(const xmlChar *value, int space) {
296 const xmlChar *cur = value;
297 int c,l;
298
299 /*
300 * First quick algorithm for ASCII range
301 */
302 if (space)
303 while (IS_BLANK(*cur)) cur++;
304 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
305 (*cur == '_'))
306 cur++;
307 else
308 goto try_complex;
309 while (((*cur >= 'a') && (*cur <= 'z')) ||
310 ((*cur >= 'A') && (*cur <= 'Z')) ||
311 ((*cur >= '0') && (*cur <= '9')) ||
312 (*cur == '_') || (*cur == '-') || (*cur == '.'))
313 cur++;
314 if (space)
315 while (IS_BLANK(*cur)) cur++;
316 if (*cur == 0)
317 return(0);
318
319try_complex:
320 /*
321 * Second check for chars outside the ASCII range
322 */
323 cur = value;
324 c = CUR_SCHAR(cur, l);
325 if (space) {
326 while (IS_BLANK(c)) {
327 cur += l;
328 c = CUR_SCHAR(cur, l);
329 }
330 }
331 if ((!xmlIsLetter(c)) && (c != '_'))
332 return(1);
333 cur += l;
334 c = CUR_SCHAR(cur, l);
335 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') ||
336 (c == '-') || (c == '_') || xmlIsCombining(c) ||
337 xmlIsExtender(c)) {
338 cur += l;
339 c = CUR_SCHAR(cur, l);
340 }
341 if (space) {
342 while (IS_BLANK(c)) {
343 cur += l;
344 c = CUR_SCHAR(cur, l);
345 }
346 }
347 if (c != 0)
348 return(1);
349
350 return(0);
351}
352
353/**
354 * xmlValidateQName:
355 * @value: the value to check
356 * @space: allow spaces in front and end of the string
357 *
358 * Check that a value conforms to the lexical space of QName
359 *
360 * Returns 0 if this validates, a positive error code number otherwise
361 * and -1 in case of internal or API error.
362 */
363int
364xmlValidateQName(const xmlChar *value, int space) {
365 const xmlChar *cur = value;
366 int c,l;
367
368 /*
369 * First quick algorithm for ASCII range
370 */
371 if (space)
372 while (IS_BLANK(*cur)) cur++;
373 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
374 (*cur == '_'))
375 cur++;
376 else
377 goto try_complex;
378 while (((*cur >= 'a') && (*cur <= 'z')) ||
379 ((*cur >= 'A') && (*cur <= 'Z')) ||
380 ((*cur >= '0') && (*cur <= '9')) ||
381 (*cur == '_') || (*cur == '-') || (*cur == '.'))
382 cur++;
383 if (*cur == ':') {
384 cur++;
385 if (((*cur >= 'a') && (*cur <= 'z')) ||
386 ((*cur >= 'A') && (*cur <= 'Z')) ||
387 (*cur == '_'))
388 cur++;
389 else
390 goto try_complex;
391 while (((*cur >= 'a') && (*cur <= 'z')) ||
392 ((*cur >= 'A') && (*cur <= 'Z')) ||
393 ((*cur >= '0') && (*cur <= '9')) ||
394 (*cur == '_') || (*cur == '-') || (*cur == '.'))
395 cur++;
396 }
397 if (space)
398 while (IS_BLANK(*cur)) cur++;
399 if (*cur == 0)
400 return(0);
401
402try_complex:
403 /*
404 * Second check for chars outside the ASCII range
405 */
406 cur = value;
407 c = CUR_SCHAR(cur, l);
408 if (space) {
409 while (IS_BLANK(c)) {
410 cur += l;
411 c = CUR_SCHAR(cur, l);
412 }
413 }
414 if ((!xmlIsLetter(c)) && (c != '_'))
415 return(1);
416 cur += l;
417 c = CUR_SCHAR(cur, l);
418 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') ||
419 (c == '-') || (c == '_') || xmlIsCombining(c) ||
420 xmlIsExtender(c)) {
421 cur += l;
422 c = CUR_SCHAR(cur, l);
423 }
424 if (c == ':') {
425 cur += l;
426 c = CUR_SCHAR(cur, l);
427 if ((!xmlIsLetter(c)) && (c != '_'))
428 return(1);
429 cur += l;
430 c = CUR_SCHAR(cur, l);
431 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') ||
432 (c == '-') || (c == '_') || xmlIsCombining(c) ||
433 xmlIsExtender(c)) {
434 cur += l;
435 c = CUR_SCHAR(cur, l);
436 }
437 }
438 if (space) {
439 while (IS_BLANK(c)) {
440 cur += l;
441 c = CUR_SCHAR(cur, l);
442 }
443 }
444 if (c != 0)
445 return(1);
446 return(0);
447}
448
449/**
450 * xmlValidateName:
451 * @value: the value to check
452 * @space: allow spaces in front and end of the string
453 *
454 * Check that a value conforms to the lexical space of Name
455 *
456 * Returns 0 if this validates, a positive error code number otherwise
457 * and -1 in case of internal or API error.
458 */
459int
460xmlValidateName(const xmlChar *value, int space) {
461 const xmlChar *cur = value;
462 int c,l;
463
464 /*
465 * First quick algorithm for ASCII range
466 */
467 if (space)
468 while (IS_BLANK(*cur)) cur++;
469 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
470 (*cur == '_') || (*cur == ':'))
471 cur++;
472 else
473 goto try_complex;
474 while (((*cur >= 'a') && (*cur <= 'z')) ||
475 ((*cur >= 'A') && (*cur <= 'Z')) ||
476 ((*cur >= '0') && (*cur <= '9')) ||
477 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
478 cur++;
479 if (space)
480 while (IS_BLANK(*cur)) cur++;
481 if (*cur == 0)
482 return(0);
483
484try_complex:
485 /*
486 * Second check for chars outside the ASCII range
487 */
488 cur = value;
489 c = CUR_SCHAR(cur, l);
490 if (space) {
491 while (IS_BLANK(c)) {
492 cur += l;
493 c = CUR_SCHAR(cur, l);
494 }
495 }
496 if ((!xmlIsLetter(c)) && (c != '_') && (c != ':'))
497 return(1);
498 cur += l;
499 c = CUR_SCHAR(cur, l);
500 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') || (c == ':') ||
501 (c == '-') || (c == '_') || xmlIsCombining(c) || xmlIsExtender(c)) {
502 cur += l;
503 c = CUR_SCHAR(cur, l);
504 }
505 if (space) {
506 while (IS_BLANK(c)) {
507 cur += l;
508 c = CUR_SCHAR(cur, l);
509 }
510 }
511 if (c != 0)
512 return(1);
513 return(0);
514}
515
Daniel Veillardd4310742003-02-18 21:12:46 +0000516/**
517 * xmlValidateNMToken:
518 * @value: the value to check
519 * @space: allow spaces in front and end of the string
520 *
521 * Check that a value conforms to the lexical space of NMToken
522 *
523 * Returns 0 if this validates, a positive error code number otherwise
524 * and -1 in case of internal or API error.
525 */
526int
527xmlValidateNMToken(const xmlChar *value, int space) {
528 const xmlChar *cur = value;
529 int c,l;
530
531 /*
532 * First quick algorithm for ASCII range
533 */
534 if (space)
535 while (IS_BLANK(*cur)) cur++;
536 if (((*cur >= 'a') && (*cur <= 'z')) ||
537 ((*cur >= 'A') && (*cur <= 'Z')) ||
538 ((*cur >= '0') && (*cur <= '9')) ||
539 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
540 cur++;
541 else
542 goto try_complex;
543 while (((*cur >= 'a') && (*cur <= 'z')) ||
544 ((*cur >= 'A') && (*cur <= 'Z')) ||
545 ((*cur >= '0') && (*cur <= '9')) ||
546 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
547 cur++;
548 if (space)
549 while (IS_BLANK(*cur)) cur++;
550 if (*cur == 0)
551 return(0);
552
553try_complex:
554 /*
555 * Second check for chars outside the ASCII range
556 */
557 cur = value;
558 c = CUR_SCHAR(cur, l);
559 if (space) {
560 while (IS_BLANK(c)) {
561 cur += l;
562 c = CUR_SCHAR(cur, l);
563 }
564 }
565 if (!(xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') || (c == ':') ||
566 (c == '-') || (c == '_') || xmlIsCombining(c) || xmlIsExtender(c)))
567 return(1);
568 cur += l;
569 c = CUR_SCHAR(cur, l);
570 while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') || (c == ':') ||
571 (c == '-') || (c == '_') || xmlIsCombining(c) || xmlIsExtender(c)) {
572 cur += l;
573 c = CUR_SCHAR(cur, l);
574 }
575 if (space) {
576 while (IS_BLANK(c)) {
577 cur += l;
578 c = CUR_SCHAR(cur, l);
579 }
580 }
581 if (c != 0)
582 return(1);
583 return(0);
584}
585
Daniel Veillardd2298792003-02-14 16:54:11 +0000586/************************************************************************
587 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000588 * Allocation and deallocation of basic structures *
589 * *
590 ************************************************************************/
591
592/**
593 * xmlSetBufferAllocationScheme:
594 * @scheme: allocation method to use
595 *
596 * Set the buffer allocation method. Types are
597 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
598 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
599 * improves performance
600 */
601void
602xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
603 xmlBufferAllocScheme = scheme;
604}
605
606/**
607 * xmlGetBufferAllocationScheme:
608 *
609 * Types are
610 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
611 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
612 * improves performance
613 *
614 * Returns the current allocation scheme
615 */
616xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000617xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000618 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000619}
620
621/**
622 * xmlNewNs:
623 * @node: the element carrying the namespace
624 * @href: the URI associated
625 * @prefix: the prefix for the namespace
626 *
627 * Creation of a new Namespace. This function will refuse to create
628 * a namespace with a similar prefix than an existing one present on this
629 * node.
630 * We use href==NULL in the case of an element creation where the namespace
631 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000632 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000633 */
634xmlNsPtr
635xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
636 xmlNsPtr cur;
637
638 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
639 return(NULL);
640
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000641 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
642 return(NULL);
643
Owen Taylor3473f882001-02-23 17:55:21 +0000644 /*
645 * Allocate a new Namespace and fill the fields.
646 */
647 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
648 if (cur == NULL) {
649 xmlGenericError(xmlGenericErrorContext,
650 "xmlNewNs : malloc failed\n");
651 return(NULL);
652 }
653 memset(cur, 0, sizeof(xmlNs));
654 cur->type = XML_LOCAL_NAMESPACE;
655
656 if (href != NULL)
657 cur->href = xmlStrdup(href);
658 if (prefix != NULL)
659 cur->prefix = xmlStrdup(prefix);
660
661 /*
662 * Add it at the end to preserve parsing order ...
663 * and checks for existing use of the prefix
664 */
665 if (node != NULL) {
666 if (node->nsDef == NULL) {
667 node->nsDef = cur;
668 } else {
669 xmlNsPtr prev = node->nsDef;
670
671 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
672 (xmlStrEqual(prev->prefix, cur->prefix))) {
673 xmlFreeNs(cur);
674 return(NULL);
675 }
676 while (prev->next != NULL) {
677 prev = prev->next;
678 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
679 (xmlStrEqual(prev->prefix, cur->prefix))) {
680 xmlFreeNs(cur);
681 return(NULL);
682 }
683 }
684 prev->next = cur;
685 }
686 }
687 return(cur);
688}
689
690/**
691 * xmlSetNs:
692 * @node: a node in the document
693 * @ns: a namespace pointer
694 *
695 * Associate a namespace to a node, a posteriori.
696 */
697void
698xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
699 if (node == NULL) {
700#ifdef DEBUG_TREE
701 xmlGenericError(xmlGenericErrorContext,
702 "xmlSetNs: node == NULL\n");
703#endif
704 return;
705 }
706 node->ns = ns;
707}
708
709/**
710 * xmlFreeNs:
711 * @cur: the namespace pointer
712 *
713 * Free up the structures associated to a namespace
714 */
715void
716xmlFreeNs(xmlNsPtr cur) {
717 if (cur == NULL) {
718#ifdef DEBUG_TREE
719 xmlGenericError(xmlGenericErrorContext,
720 "xmlFreeNs : ns == NULL\n");
721#endif
722 return;
723 }
724 if (cur->href != NULL) xmlFree((char *) cur->href);
725 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000726 xmlFree(cur);
727}
728
729/**
730 * xmlFreeNsList:
731 * @cur: the first namespace pointer
732 *
733 * Free up all the structures associated to the chained namespaces.
734 */
735void
736xmlFreeNsList(xmlNsPtr cur) {
737 xmlNsPtr next;
738 if (cur == NULL) {
739#ifdef DEBUG_TREE
740 xmlGenericError(xmlGenericErrorContext,
741 "xmlFreeNsList : ns == NULL\n");
742#endif
743 return;
744 }
745 while (cur != NULL) {
746 next = cur->next;
747 xmlFreeNs(cur);
748 cur = next;
749 }
750}
751
752/**
753 * xmlNewDtd:
754 * @doc: the document pointer
755 * @name: the DTD name
756 * @ExternalID: the external ID
757 * @SystemID: the system ID
758 *
759 * Creation of a new DTD for the external subset. To create an
760 * internal subset, use xmlCreateIntSubset().
761 *
762 * Returns a pointer to the new DTD structure
763 */
764xmlDtdPtr
765xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
766 const xmlChar *ExternalID, const xmlChar *SystemID) {
767 xmlDtdPtr cur;
768
769 if ((doc != NULL) && (doc->extSubset != NULL)) {
770#ifdef DEBUG_TREE
771 xmlGenericError(xmlGenericErrorContext,
772 "xmlNewDtd(%s): document %s already have a DTD %s\n",
773 /* !!! */ (char *) name, doc->name,
774 /* !!! */ (char *)doc->extSubset->name);
775#endif
776 return(NULL);
777 }
778
779 /*
780 * Allocate a new DTD and fill the fields.
781 */
782 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
783 if (cur == NULL) {
784 xmlGenericError(xmlGenericErrorContext,
785 "xmlNewDtd : malloc failed\n");
786 return(NULL);
787 }
788 memset(cur, 0 , sizeof(xmlDtd));
789 cur->type = XML_DTD_NODE;
790
791 if (name != NULL)
792 cur->name = xmlStrdup(name);
793 if (ExternalID != NULL)
794 cur->ExternalID = xmlStrdup(ExternalID);
795 if (SystemID != NULL)
796 cur->SystemID = xmlStrdup(SystemID);
797 if (doc != NULL)
798 doc->extSubset = cur;
799 cur->doc = doc;
800
Daniel Veillarda880b122003-04-21 21:36:41 +0000801 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000802 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000803 return(cur);
804}
805
806/**
807 * xmlGetIntSubset:
808 * @doc: the document pointer
809 *
810 * Get the internal subset of a document
811 * Returns a pointer to the DTD structure or NULL if not found
812 */
813
814xmlDtdPtr
815xmlGetIntSubset(xmlDocPtr doc) {
816 xmlNodePtr cur;
817
818 if (doc == NULL)
819 return(NULL);
820 cur = doc->children;
821 while (cur != NULL) {
822 if (cur->type == XML_DTD_NODE)
823 return((xmlDtdPtr) cur);
824 cur = cur->next;
825 }
826 return((xmlDtdPtr) doc->intSubset);
827}
828
829/**
830 * xmlCreateIntSubset:
831 * @doc: the document pointer
832 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000833 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000834 * @SystemID: the system ID
835 *
836 * Create the internal subset of a document
837 * Returns a pointer to the new DTD structure
838 */
839xmlDtdPtr
840xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
841 const xmlChar *ExternalID, const xmlChar *SystemID) {
842 xmlDtdPtr cur;
843
844 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
845#ifdef DEBUG_TREE
846 xmlGenericError(xmlGenericErrorContext,
847
848 "xmlCreateIntSubset(): document %s already have an internal subset\n",
849 doc->name);
850#endif
851 return(NULL);
852 }
853
854 /*
855 * Allocate a new DTD and fill the fields.
856 */
857 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
858 if (cur == NULL) {
859 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000860 "xmlCreateIntSubset : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000861 return(NULL);
862 }
863 memset(cur, 0, sizeof(xmlDtd));
864 cur->type = XML_DTD_NODE;
865
866 if (name != NULL)
867 cur->name = xmlStrdup(name);
868 if (ExternalID != NULL)
869 cur->ExternalID = xmlStrdup(ExternalID);
870 if (SystemID != NULL)
871 cur->SystemID = xmlStrdup(SystemID);
872 if (doc != NULL) {
873 doc->intSubset = cur;
874 cur->parent = doc;
875 cur->doc = doc;
876 if (doc->children == NULL) {
877 doc->children = (xmlNodePtr) cur;
878 doc->last = (xmlNodePtr) cur;
879 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000880 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000881 xmlNodePtr prev;
882
Owen Taylor3473f882001-02-23 17:55:21 +0000883 prev = doc->children;
884 prev->prev = (xmlNodePtr) cur;
885 cur->next = prev;
886 doc->children = (xmlNodePtr) cur;
887 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000888 xmlNodePtr next;
889
890 next = doc->children;
891 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
892 next = next->next;
893 if (next == NULL) {
894 cur->prev = doc->last;
895 cur->prev->next = (xmlNodePtr) cur;
896 cur->next = NULL;
897 doc->last = (xmlNodePtr) cur;
898 } else {
899 cur->next = next;
900 cur->prev = next->prev;
901 if (cur->prev == NULL)
902 doc->children = (xmlNodePtr) cur;
903 else
904 cur->prev->next = (xmlNodePtr) cur;
905 next->prev = (xmlNodePtr) cur;
906 }
Owen Taylor3473f882001-02-23 17:55:21 +0000907 }
908 }
909 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000910
Daniel Veillarda880b122003-04-21 21:36:41 +0000911 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +0000912 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000913 return(cur);
914}
915
916/**
917 * xmlFreeDtd:
918 * @cur: the DTD structure to free up
919 *
920 * Free a DTD structure.
921 */
922void
923xmlFreeDtd(xmlDtdPtr cur) {
924 if (cur == NULL) {
925#ifdef DEBUG_TREE
926 xmlGenericError(xmlGenericErrorContext,
927 "xmlFreeDtd : DTD == NULL\n");
928#endif
929 return;
930 }
Daniel Veillard5335dc52003-01-01 20:59:38 +0000931
Daniel Veillarda880b122003-04-21 21:36:41 +0000932 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +0000933 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
934
Owen Taylor3473f882001-02-23 17:55:21 +0000935 if (cur->children != NULL) {
936 xmlNodePtr next, c = cur->children;
937
938 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000939 * Cleanup all the DTD comments they are not in the DTD
Owen Taylor3473f882001-02-23 17:55:21 +0000940 * indexes.
941 */
942 while (c != NULL) {
943 next = c->next;
Daniel Veillardd72c7e32003-05-12 21:55:03 +0000944 if ((c->type == XML_COMMENT_NODE) || (c->type == XML_PI_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000945 xmlUnlinkNode(c);
946 xmlFreeNode(c);
947 }
948 c = next;
949 }
950 }
951 if (cur->name != NULL) xmlFree((char *) cur->name);
952 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
953 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
954 /* TODO !!! */
955 if (cur->notations != NULL)
956 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
957
958 if (cur->elements != NULL)
959 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
960 if (cur->attributes != NULL)
961 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
962 if (cur->entities != NULL)
963 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
964 if (cur->pentities != NULL)
965 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
966
Owen Taylor3473f882001-02-23 17:55:21 +0000967 xmlFree(cur);
968}
969
970/**
971 * xmlNewDoc:
972 * @version: xmlChar string giving the version of XML "1.0"
973 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000974 * Creates a new XML document
975 *
Owen Taylor3473f882001-02-23 17:55:21 +0000976 * Returns a new document
977 */
978xmlDocPtr
979xmlNewDoc(const xmlChar *version) {
980 xmlDocPtr cur;
981
982 if (version == NULL)
983 version = (const xmlChar *) "1.0";
984
985 /*
986 * Allocate a new document and fill the fields.
987 */
988 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
989 if (cur == NULL) {
990 xmlGenericError(xmlGenericErrorContext,
991 "xmlNewDoc : malloc failed\n");
992 return(NULL);
993 }
994 memset(cur, 0, sizeof(xmlDoc));
995 cur->type = XML_DOCUMENT_NODE;
996
997 cur->version = xmlStrdup(version);
998 cur->standalone = -1;
999 cur->compression = -1; /* not initialized */
1000 cur->doc = cur;
Daniel Veillarda6874ca2003-07-29 16:47:24 +00001001 /*
1002 * The in memory encoding is always UTF8
1003 * This field will never change and would
1004 * be obsolete if not for binary compatibility.
1005 */
Daniel Veillardd2f3ec72001-04-11 07:50:02 +00001006 cur->charset = XML_CHAR_ENCODING_UTF8;
Daniel Veillard5335dc52003-01-01 20:59:38 +00001007
Daniel Veillarda880b122003-04-21 21:36:41 +00001008 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001009 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001010 return(cur);
1011}
1012
1013/**
1014 * xmlFreeDoc:
1015 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +00001016 *
1017 * Free up all the structures used by a document, tree included.
1018 */
1019void
1020xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +00001021 xmlDtdPtr extSubset, intSubset;
1022
Owen Taylor3473f882001-02-23 17:55:21 +00001023 if (cur == NULL) {
1024#ifdef DEBUG_TREE
1025 xmlGenericError(xmlGenericErrorContext,
1026 "xmlFreeDoc : document == NULL\n");
1027#endif
1028 return;
1029 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001030
Daniel Veillarda880b122003-04-21 21:36:41 +00001031 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001032 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1033
Daniel Veillard76d66f42001-05-16 21:05:17 +00001034 /*
1035 * Do this before freeing the children list to avoid ID lookups
1036 */
1037 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1038 cur->ids = NULL;
1039 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1040 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001041 extSubset = cur->extSubset;
1042 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +00001043 if (intSubset == extSubset)
1044 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001045 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001046 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001047 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001048 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001049 }
Daniel Veillarda9142e72001-06-19 11:07:54 +00001050 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +00001051 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001052 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +00001053 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +00001054 }
1055
1056 if (cur->children != NULL) xmlFreeNodeList(cur->children);
1057
Owen Taylor3473f882001-02-23 17:55:21 +00001058 if (cur->version != NULL) xmlFree((char *) cur->version);
1059 if (cur->name != NULL) xmlFree((char *) cur->name);
1060 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00001061 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +00001062 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Owen Taylor3473f882001-02-23 17:55:21 +00001063 xmlFree(cur);
1064}
1065
1066/**
1067 * xmlStringLenGetNodeList:
1068 * @doc: the document
1069 * @value: the value of the text
1070 * @len: the length of the string value
1071 *
1072 * Parse the value string and build the node list associated. Should
1073 * produce a flat tree with only TEXTs and ENTITY_REFs.
1074 * Returns a pointer to the first child
1075 */
1076xmlNodePtr
1077xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1078 xmlNodePtr ret = NULL, last = NULL;
1079 xmlNodePtr node;
1080 xmlChar *val;
1081 const xmlChar *cur = value;
1082 const xmlChar *q;
1083 xmlEntityPtr ent;
1084
1085 if (value == NULL) return(NULL);
1086
1087 q = cur;
1088 while ((*cur != 0) && (cur - value < len)) {
1089 if (*cur == '&') {
1090 /*
1091 * Save the current text.
1092 */
1093 if (cur != q) {
1094 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1095 xmlNodeAddContentLen(last, q, cur - q);
1096 } else {
1097 node = xmlNewDocTextLen(doc, q, cur - q);
1098 if (node == NULL) return(ret);
1099 if (last == NULL)
1100 last = ret = node;
1101 else {
1102 last->next = node;
1103 node->prev = last;
1104 last = node;
1105 }
1106 }
1107 }
1108 /*
1109 * Read the entity string
1110 */
1111 cur++;
1112 q = cur;
1113 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
1114 if ((*cur == 0) || (cur - value >= len)) {
1115#ifdef DEBUG_TREE
1116 xmlGenericError(xmlGenericErrorContext,
1117 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
1118#endif
1119 return(ret);
1120 }
1121 if (cur != q) {
1122 /*
1123 * Predefined entities don't generate nodes
1124 */
1125 val = xmlStrndup(q, cur - q);
1126 ent = xmlGetDocEntity(doc, val);
1127 if ((ent != NULL) &&
1128 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1129 if (last == NULL) {
1130 node = xmlNewDocText(doc, ent->content);
1131 last = ret = node;
1132 } else
1133 xmlNodeAddContent(last, ent->content);
1134
1135 } else {
1136 /*
1137 * Create a new REFERENCE_REF node
1138 */
1139 node = xmlNewReference(doc, val);
1140 if (node == NULL) {
1141 if (val != NULL) xmlFree(val);
1142 return(ret);
1143 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001144 else if ((ent != NULL) && (ent->children == NULL)) {
1145 xmlNodePtr tmp;
1146
1147 ent->children =
1148 xmlStringGetNodeList(doc, (const xmlChar*)node->content);
1149 tmp = ent->children;
1150 while (tmp) {
1151 tmp->parent = (xmlNodePtr)ent;
1152 tmp = tmp->next;
1153 }
1154 }
Owen Taylor3473f882001-02-23 17:55:21 +00001155 if (last == NULL)
1156 last = ret = node;
1157 else {
1158 last->next = node;
1159 node->prev = last;
1160 last = node;
1161 }
1162 }
1163 xmlFree(val);
1164 }
1165 cur++;
1166 q = cur;
1167 } else
1168 cur++;
1169 }
1170 if (cur != q) {
1171 /*
1172 * Handle the last piece of text.
1173 */
1174 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1175 xmlNodeAddContentLen(last, q, cur - q);
1176 } else {
1177 node = xmlNewDocTextLen(doc, q, cur - q);
1178 if (node == NULL) return(ret);
1179 if (last == NULL)
1180 last = ret = node;
1181 else {
1182 last->next = node;
1183 node->prev = last;
1184 last = node;
1185 }
1186 }
1187 }
1188 return(ret);
1189}
1190
1191/**
1192 * xmlStringGetNodeList:
1193 * @doc: the document
1194 * @value: the value of the attribute
1195 *
1196 * Parse the value string and build the node list associated. Should
1197 * produce a flat tree with only TEXTs and ENTITY_REFs.
1198 * Returns a pointer to the first child
1199 */
1200xmlNodePtr
1201xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1202 xmlNodePtr ret = NULL, last = NULL;
1203 xmlNodePtr node;
1204 xmlChar *val;
1205 const xmlChar *cur = value;
1206 const xmlChar *q;
1207 xmlEntityPtr ent;
1208
1209 if (value == NULL) return(NULL);
1210
1211 q = cur;
1212 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001213 if (cur[0] == '&') {
1214 int charval = 0;
1215 xmlChar tmp;
1216
Owen Taylor3473f882001-02-23 17:55:21 +00001217 /*
1218 * Save the current text.
1219 */
1220 if (cur != q) {
1221 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1222 xmlNodeAddContentLen(last, q, cur - q);
1223 } else {
1224 node = xmlNewDocTextLen(doc, q, cur - q);
1225 if (node == NULL) return(ret);
1226 if (last == NULL)
1227 last = ret = node;
1228 else {
1229 last->next = node;
1230 node->prev = last;
1231 last = node;
1232 }
1233 }
1234 }
Owen Taylor3473f882001-02-23 17:55:21 +00001235 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001236 if ((cur[1] == '#') && (cur[2] == 'x')) {
1237 cur += 3;
1238 tmp = *cur;
1239 while (tmp != ';') { /* Non input consuming loop */
1240 if ((tmp >= '0') && (tmp <= '9'))
1241 charval = charval * 16 + (tmp - '0');
1242 else if ((tmp >= 'a') && (tmp <= 'f'))
1243 charval = charval * 16 + (tmp - 'a') + 10;
1244 else if ((tmp >= 'A') && (tmp <= 'F'))
1245 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +00001246 else {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001247 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001248 "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001249 charval = 0;
1250 break;
1251 }
1252 cur++;
1253 tmp = *cur;
1254 }
1255 if (tmp == ';')
1256 cur++;
1257 q = cur;
1258 } else if (cur[1] == '#') {
1259 cur += 2;
1260 tmp = *cur;
1261 while (tmp != ';') { /* Non input consuming loops */
1262 if ((tmp >= '0') && (tmp <= '9'))
1263 charval = charval * 10 + (tmp - '0');
1264 else {
1265 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001266 "xmlStringGetNodeList: invalid decimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001267 charval = 0;
1268 break;
1269 }
1270 cur++;
1271 tmp = *cur;
1272 }
1273 if (tmp == ';')
1274 cur++;
1275 q = cur;
1276 } else {
1277 /*
1278 * Read the entity string
1279 */
1280 cur++;
1281 q = cur;
1282 while ((*cur != 0) && (*cur != ';')) cur++;
1283 if (*cur == 0) {
1284#ifdef DEBUG_TREE
1285 xmlGenericError(xmlGenericErrorContext,
1286 "xmlStringGetNodeList: unterminated entity %30s\n", q);
1287#endif
1288 return(ret);
1289 }
1290 if (cur != q) {
1291 /*
1292 * Predefined entities don't generate nodes
1293 */
1294 val = xmlStrndup(q, cur - q);
1295 ent = xmlGetDocEntity(doc, val);
1296 if ((ent != NULL) &&
1297 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1298 if (last == NULL) {
1299 node = xmlNewDocText(doc, ent->content);
1300 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +00001301 } else if (last->type != XML_TEXT_NODE) {
1302 node = xmlNewDocText(doc, ent->content);
1303 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001304 } else
1305 xmlNodeAddContent(last, ent->content);
1306
1307 } else {
1308 /*
1309 * Create a new REFERENCE_REF node
1310 */
1311 node = xmlNewReference(doc, val);
1312 if (node == NULL) {
1313 if (val != NULL) xmlFree(val);
1314 return(ret);
1315 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001316 else if ((ent != NULL) && (ent->children == NULL)) {
1317 xmlNodePtr temp;
1318
1319 ent->children = xmlStringGetNodeList(doc,
1320 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +00001321 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +00001322 temp = ent->children;
1323 while (temp) {
1324 temp->parent = (xmlNodePtr)ent;
1325 temp = temp->next;
1326 }
1327 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001328 if (last == NULL) {
1329 last = ret = node;
1330 } else {
1331 last = xmlAddNextSibling(last, node);
1332 }
1333 }
1334 xmlFree(val);
1335 }
1336 cur++;
1337 q = cur;
1338 }
1339 if (charval != 0) {
1340 xmlChar buf[10];
1341 int len;
1342
1343 len = xmlCopyCharMultiByte(buf, charval);
1344 buf[len] = 0;
1345 node = xmlNewDocText(doc, buf);
1346 if (node != NULL) {
1347 if (last == NULL) {
1348 last = ret = node;
1349 } else {
1350 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001351 }
1352 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001353
1354 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001355 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001356 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001357 cur++;
1358 }
Daniel Veillard75bea542001-05-11 17:41:21 +00001359 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001360 /*
1361 * Handle the last piece of text.
1362 */
1363 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1364 xmlNodeAddContentLen(last, q, cur - q);
1365 } else {
1366 node = xmlNewDocTextLen(doc, q, cur - q);
1367 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001368 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001369 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +00001370 } else {
1371 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +00001372 }
1373 }
1374 }
1375 return(ret);
1376}
1377
1378/**
1379 * xmlNodeListGetString:
1380 * @doc: the document
1381 * @list: a Node list
1382 * @inLine: should we replace entity contents or show their external form
1383 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001384 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001385 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001386 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001387 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001388 */
1389xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001390xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1391{
Owen Taylor3473f882001-02-23 17:55:21 +00001392 xmlNodePtr node = list;
1393 xmlChar *ret = NULL;
1394 xmlEntityPtr ent;
1395
Daniel Veillard7646b182002-04-20 06:41:40 +00001396 if (list == NULL)
1397 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001398
1399 while (node != NULL) {
1400 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001401 (node->type == XML_CDATA_SECTION_NODE)) {
1402 if (inLine) {
1403 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001404 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001405 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +00001406
Daniel Veillard7646b182002-04-20 06:41:40 +00001407 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1408 if (buffer != NULL) {
1409 ret = xmlStrcat(ret, buffer);
1410 xmlFree(buffer);
1411 }
1412 }
1413 } else if (node->type == XML_ENTITY_REF_NODE) {
1414 if (inLine) {
1415 ent = xmlGetDocEntity(doc, node->name);
1416 if (ent != NULL) {
1417 xmlChar *buffer;
1418
1419 /* an entity content can be any "well balanced chunk",
1420 * i.e. the result of the content [43] production:
1421 * http://www.w3.org/TR/REC-xml#NT-content.
1422 * So it can contain text, CDATA section or nested
1423 * entity reference nodes (among others).
1424 * -> we recursive call xmlNodeListGetString()
1425 * which handles these types */
1426 buffer = xmlNodeListGetString(doc, ent->children, 1);
1427 if (buffer != NULL) {
1428 ret = xmlStrcat(ret, buffer);
1429 xmlFree(buffer);
1430 }
1431 } else {
1432 ret = xmlStrcat(ret, node->content);
1433 }
1434 } else {
1435 xmlChar buf[2];
1436
1437 buf[0] = '&';
1438 buf[1] = 0;
1439 ret = xmlStrncat(ret, buf, 1);
1440 ret = xmlStrcat(ret, node->name);
1441 buf[0] = ';';
1442 buf[1] = 0;
1443 ret = xmlStrncat(ret, buf, 1);
1444 }
1445 }
1446#if 0
1447 else {
1448 xmlGenericError(xmlGenericErrorContext,
1449 "xmlGetNodeListString : invalid node type %d\n",
1450 node->type);
1451 }
1452#endif
1453 node = node->next;
1454 }
1455 return (ret);
1456}
Owen Taylor3473f882001-02-23 17:55:21 +00001457/**
1458 * xmlNodeListGetRawString:
1459 * @doc: the document
1460 * @list: a Node list
1461 * @inLine: should we replace entity contents or show their external form
1462 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001463 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +00001464 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1465 * this function doesn't do any character encoding handling.
1466 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +00001467 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00001468 */
1469xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00001470xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1471{
Owen Taylor3473f882001-02-23 17:55:21 +00001472 xmlNodePtr node = list;
1473 xmlChar *ret = NULL;
1474 xmlEntityPtr ent;
1475
Daniel Veillard7646b182002-04-20 06:41:40 +00001476 if (list == NULL)
1477 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001478
1479 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +00001480 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001481 (node->type == XML_CDATA_SECTION_NODE)) {
1482 if (inLine) {
1483 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001484 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001485 xmlChar *buffer;
1486
1487 buffer = xmlEncodeSpecialChars(doc, node->content);
1488 if (buffer != NULL) {
1489 ret = xmlStrcat(ret, buffer);
1490 xmlFree(buffer);
1491 }
1492 }
1493 } else if (node->type == XML_ENTITY_REF_NODE) {
1494 if (inLine) {
1495 ent = xmlGetDocEntity(doc, node->name);
1496 if (ent != NULL) {
1497 xmlChar *buffer;
1498
1499 /* an entity content can be any "well balanced chunk",
1500 * i.e. the result of the content [43] production:
1501 * http://www.w3.org/TR/REC-xml#NT-content.
1502 * So it can contain text, CDATA section or nested
1503 * entity reference nodes (among others).
1504 * -> we recursive call xmlNodeListGetRawString()
1505 * which handles these types */
1506 buffer =
1507 xmlNodeListGetRawString(doc, ent->children, 1);
1508 if (buffer != NULL) {
1509 ret = xmlStrcat(ret, buffer);
1510 xmlFree(buffer);
1511 }
1512 } else {
1513 ret = xmlStrcat(ret, node->content);
1514 }
1515 } else {
1516 xmlChar buf[2];
1517
1518 buf[0] = '&';
1519 buf[1] = 0;
1520 ret = xmlStrncat(ret, buf, 1);
1521 ret = xmlStrcat(ret, node->name);
1522 buf[0] = ';';
1523 buf[1] = 0;
1524 ret = xmlStrncat(ret, buf, 1);
1525 }
1526 }
Owen Taylor3473f882001-02-23 17:55:21 +00001527#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001528 else {
1529 xmlGenericError(xmlGenericErrorContext,
1530 "xmlGetNodeListString : invalid node type %d\n",
1531 node->type);
1532 }
Owen Taylor3473f882001-02-23 17:55:21 +00001533#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001534 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001535 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001536 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001537}
1538
1539/**
1540 * xmlNewProp:
1541 * @node: the holding node
1542 * @name: the name of the attribute
1543 * @value: the value of the attribute
1544 *
1545 * Create a new property carried by a node.
1546 * Returns a pointer to the attribute
1547 */
1548xmlAttrPtr
1549xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1550 xmlAttrPtr cur;
1551 xmlDocPtr doc = NULL;
1552
1553 if (name == NULL) {
1554#ifdef DEBUG_TREE
1555 xmlGenericError(xmlGenericErrorContext,
1556 "xmlNewProp : name == NULL\n");
1557#endif
1558 return(NULL);
1559 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00001560 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
1561 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001562
1563 /*
1564 * Allocate a new property and fill the fields.
1565 */
1566 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1567 if (cur == NULL) {
1568 xmlGenericError(xmlGenericErrorContext,
1569 "xmlNewProp : malloc failed\n");
1570 return(NULL);
1571 }
1572 memset(cur, 0, sizeof(xmlAttr));
1573 cur->type = XML_ATTRIBUTE_NODE;
1574
1575 cur->parent = node;
1576 if (node != NULL) {
1577 doc = node->doc;
1578 cur->doc = doc;
1579 }
1580 cur->name = xmlStrdup(name);
1581 if (value != NULL) {
1582 xmlChar *buffer;
1583 xmlNodePtr tmp;
1584
1585 buffer = xmlEncodeEntitiesReentrant(doc, value);
1586 cur->children = xmlStringGetNodeList(doc, buffer);
1587 cur->last = NULL;
1588 tmp = cur->children;
1589 while (tmp != NULL) {
1590 tmp->parent = (xmlNodePtr) cur;
1591 tmp->doc = doc;
1592 if (tmp->next == NULL)
1593 cur->last = tmp;
1594 tmp = tmp->next;
1595 }
1596 xmlFree(buffer);
1597 }
1598
1599 /*
1600 * Add it at the end to preserve parsing order ...
1601 */
1602 if (node != NULL) {
1603 if (node->properties == NULL) {
1604 node->properties = cur;
1605 } else {
1606 xmlAttrPtr prev = node->properties;
1607
1608 while (prev->next != NULL) prev = prev->next;
1609 prev->next = cur;
1610 cur->prev = prev;
1611 }
1612 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001613
Daniel Veillarda880b122003-04-21 21:36:41 +00001614 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001615 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001616 return(cur);
1617}
1618
1619/**
1620 * xmlNewNsProp:
1621 * @node: the holding node
1622 * @ns: the namespace
1623 * @name: the name of the attribute
1624 * @value: the value of the attribute
1625 *
1626 * Create a new property tagged with a namespace and carried by a node.
1627 * Returns a pointer to the attribute
1628 */
1629xmlAttrPtr
1630xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1631 const xmlChar *value) {
1632 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001633 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001634
1635 if (name == NULL) {
1636#ifdef DEBUG_TREE
1637 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001638 "xmlNewNsProp : 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 "xmlNewNsProp : 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->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001656 if (node != NULL) {
1657 doc = node->doc;
1658 cur->doc = doc;
1659 }
Owen Taylor3473f882001-02-23 17:55:21 +00001660 cur->ns = ns;
1661 cur->name = xmlStrdup(name);
1662 if (value != NULL) {
1663 xmlChar *buffer;
1664 xmlNodePtr tmp;
1665
Daniel Veillarda682b212001-06-07 19:59:42 +00001666 buffer = xmlEncodeEntitiesReentrant(doc, value);
1667 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001668 cur->last = NULL;
1669 tmp = cur->children;
1670 while (tmp != NULL) {
1671 tmp->parent = (xmlNodePtr) cur;
1672 if (tmp->next == NULL)
1673 cur->last = tmp;
1674 tmp = tmp->next;
1675 }
1676 xmlFree(buffer);
1677 }
1678
1679 /*
1680 * Add it at the end to preserve parsing order ...
1681 */
1682 if (node != NULL) {
1683 if (node->properties == NULL) {
1684 node->properties = cur;
1685 } else {
1686 xmlAttrPtr prev = node->properties;
1687
1688 while (prev->next != NULL) prev = prev->next;
1689 prev->next = cur;
1690 cur->prev = prev;
1691 }
1692 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001693
Daniel Veillarda880b122003-04-21 21:36:41 +00001694 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001695 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001696 return(cur);
1697}
1698
1699/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001700 * xmlNewNsPropEatName:
1701 * @node: the holding node
1702 * @ns: the namespace
1703 * @name: the name of the attribute
1704 * @value: the value of the attribute
1705 *
1706 * Create a new property tagged with a namespace and carried by a node.
1707 * Returns a pointer to the attribute
1708 */
1709xmlAttrPtr
1710xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1711 const xmlChar *value) {
1712 xmlAttrPtr cur;
1713 xmlDocPtr doc = NULL;
1714
1715 if (name == NULL) {
1716#ifdef DEBUG_TREE
1717 xmlGenericError(xmlGenericErrorContext,
1718 "xmlNewNsPropEatName : name == NULL\n");
1719#endif
1720 return(NULL);
1721 }
1722
1723 /*
1724 * Allocate a new property and fill the fields.
1725 */
1726 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1727 if (cur == NULL) {
1728 xmlGenericError(xmlGenericErrorContext,
1729 "xmlNewNsPropEatName : malloc failed\n");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001730 xmlFree(name);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001731 return(NULL);
1732 }
1733 memset(cur, 0, sizeof(xmlAttr));
1734 cur->type = XML_ATTRIBUTE_NODE;
1735
1736 cur->parent = node;
1737 if (node != NULL) {
1738 doc = node->doc;
1739 cur->doc = doc;
1740 }
1741 cur->ns = ns;
1742 cur->name = name;
1743 if (value != NULL) {
1744 xmlChar *buffer;
1745 xmlNodePtr tmp;
1746
1747 buffer = xmlEncodeEntitiesReentrant(doc, value);
1748 cur->children = xmlStringGetNodeList(doc, buffer);
1749 cur->last = NULL;
1750 tmp = cur->children;
1751 while (tmp != NULL) {
1752 tmp->parent = (xmlNodePtr) cur;
1753 if (tmp->next == NULL)
1754 cur->last = tmp;
1755 tmp = tmp->next;
1756 }
1757 xmlFree(buffer);
1758 }
1759
1760 /*
1761 * Add it at the end to preserve parsing order ...
1762 */
1763 if (node != NULL) {
1764 if (node->properties == NULL) {
1765 node->properties = cur;
1766 } else {
1767 xmlAttrPtr prev = node->properties;
1768
1769 while (prev->next != NULL) prev = prev->next;
1770 prev->next = cur;
1771 cur->prev = prev;
1772 }
1773 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001774
Daniel Veillarda880b122003-04-21 21:36:41 +00001775 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00001776 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00001777 return(cur);
1778}
1779
1780/**
Owen Taylor3473f882001-02-23 17:55:21 +00001781 * xmlNewDocProp:
1782 * @doc: the document
1783 * @name: the name of the attribute
1784 * @value: the value of the attribute
1785 *
1786 * Create a new property carried by a document.
1787 * Returns a pointer to the attribute
1788 */
1789xmlAttrPtr
1790xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1791 xmlAttrPtr cur;
1792
1793 if (name == NULL) {
1794#ifdef DEBUG_TREE
1795 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001796 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001797#endif
1798 return(NULL);
1799 }
1800
1801 /*
1802 * Allocate a new property and fill the fields.
1803 */
1804 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1805 if (cur == NULL) {
1806 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001807 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001808 return(NULL);
1809 }
1810 memset(cur, 0, sizeof(xmlAttr));
1811 cur->type = XML_ATTRIBUTE_NODE;
1812
1813 cur->name = xmlStrdup(name);
1814 cur->doc = doc;
1815 if (value != NULL) {
1816 xmlNodePtr tmp;
1817
1818 cur->children = xmlStringGetNodeList(doc, value);
1819 cur->last = NULL;
1820
1821 tmp = cur->children;
1822 while (tmp != NULL) {
1823 tmp->parent = (xmlNodePtr) cur;
1824 if (tmp->next == NULL)
1825 cur->last = tmp;
1826 tmp = tmp->next;
1827 }
1828 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001829
Daniel Veillarda880b122003-04-21 21:36:41 +00001830 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001831 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001832 return(cur);
1833}
1834
1835/**
1836 * xmlFreePropList:
1837 * @cur: the first property in the list
1838 *
1839 * Free a property and all its siblings, all the children are freed too.
1840 */
1841void
1842xmlFreePropList(xmlAttrPtr cur) {
1843 xmlAttrPtr next;
1844 if (cur == NULL) {
1845#ifdef DEBUG_TREE
1846 xmlGenericError(xmlGenericErrorContext,
1847 "xmlFreePropList : property == NULL\n");
1848#endif
1849 return;
1850 }
1851 while (cur != NULL) {
1852 next = cur->next;
1853 xmlFreeProp(cur);
1854 cur = next;
1855 }
1856}
1857
1858/**
1859 * xmlFreeProp:
1860 * @cur: an attribute
1861 *
1862 * Free one attribute, all the content is freed too
1863 */
1864void
1865xmlFreeProp(xmlAttrPtr cur) {
1866 if (cur == NULL) {
1867#ifdef DEBUG_TREE
1868 xmlGenericError(xmlGenericErrorContext,
1869 "xmlFreeProp : property == NULL\n");
1870#endif
1871 return;
1872 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001873
Daniel Veillarda880b122003-04-21 21:36:41 +00001874 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001875 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1876
Owen Taylor3473f882001-02-23 17:55:21 +00001877 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001878 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1879 ((cur->parent->doc->intSubset != NULL) ||
1880 (cur->parent->doc->extSubset != NULL))) {
1881 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1882 xmlRemoveID(cur->parent->doc, cur);
1883 }
Owen Taylor3473f882001-02-23 17:55:21 +00001884 if (cur->name != NULL) xmlFree((char *) cur->name);
1885 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001886 xmlFree(cur);
1887}
1888
1889/**
1890 * xmlRemoveProp:
1891 * @cur: an attribute
1892 *
1893 * Unlink and free one attribute, all the content is freed too
1894 * Note this doesn't work for namespace definition attributes
1895 *
1896 * Returns 0 if success and -1 in case of error.
1897 */
1898int
1899xmlRemoveProp(xmlAttrPtr cur) {
1900 xmlAttrPtr tmp;
1901 if (cur == NULL) {
1902#ifdef DEBUG_TREE
1903 xmlGenericError(xmlGenericErrorContext,
1904 "xmlRemoveProp : cur == NULL\n");
1905#endif
1906 return(-1);
1907 }
1908 if (cur->parent == NULL) {
1909#ifdef DEBUG_TREE
1910 xmlGenericError(xmlGenericErrorContext,
1911 "xmlRemoveProp : cur->parent == NULL\n");
1912#endif
1913 return(-1);
1914 }
1915 tmp = cur->parent->properties;
1916 if (tmp == cur) {
1917 cur->parent->properties = cur->next;
1918 xmlFreeProp(cur);
1919 return(0);
1920 }
1921 while (tmp != NULL) {
1922 if (tmp->next == cur) {
1923 tmp->next = cur->next;
1924 if (tmp->next != NULL)
1925 tmp->next->prev = tmp;
1926 xmlFreeProp(cur);
1927 return(0);
1928 }
1929 tmp = tmp->next;
1930 }
1931#ifdef DEBUG_TREE
1932 xmlGenericError(xmlGenericErrorContext,
1933 "xmlRemoveProp : attribute not owned by its node\n");
1934#endif
1935 return(-1);
1936}
1937
1938/**
1939 * xmlNewPI:
1940 * @name: the processing instruction name
1941 * @content: the PI content
1942 *
1943 * Creation of a processing instruction element.
1944 * Returns a pointer to the new node object.
1945 */
1946xmlNodePtr
1947xmlNewPI(const xmlChar *name, const xmlChar *content) {
1948 xmlNodePtr cur;
1949
1950 if (name == NULL) {
1951#ifdef DEBUG_TREE
1952 xmlGenericError(xmlGenericErrorContext,
1953 "xmlNewPI : name == NULL\n");
1954#endif
1955 return(NULL);
1956 }
1957
1958 /*
1959 * Allocate a new node and fill the fields.
1960 */
1961 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1962 if (cur == NULL) {
1963 xmlGenericError(xmlGenericErrorContext,
1964 "xmlNewPI : malloc failed\n");
1965 return(NULL);
1966 }
1967 memset(cur, 0, sizeof(xmlNode));
1968 cur->type = XML_PI_NODE;
1969
1970 cur->name = xmlStrdup(name);
1971 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001972 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001973 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00001974
Daniel Veillarda880b122003-04-21 21:36:41 +00001975 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00001976 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001977 return(cur);
1978}
1979
1980/**
1981 * xmlNewNode:
1982 * @ns: namespace if any
1983 * @name: the node name
1984 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001985 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001986 *
1987 * Returns a pointer to the new node object.
1988 */
1989xmlNodePtr
1990xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1991 xmlNodePtr cur;
1992
1993 if (name == NULL) {
1994#ifdef DEBUG_TREE
1995 xmlGenericError(xmlGenericErrorContext,
1996 "xmlNewNode : name == NULL\n");
1997#endif
1998 return(NULL);
1999 }
2000
2001 /*
2002 * Allocate a new node and fill the fields.
2003 */
2004 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2005 if (cur == NULL) {
2006 xmlGenericError(xmlGenericErrorContext,
2007 "xmlNewNode : malloc failed\n");
2008 return(NULL);
2009 }
2010 memset(cur, 0, sizeof(xmlNode));
2011 cur->type = XML_ELEMENT_NODE;
2012
2013 cur->name = xmlStrdup(name);
2014 cur->ns = ns;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002015
Daniel Veillarda880b122003-04-21 21:36:41 +00002016 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002017 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002018 return(cur);
2019}
2020
2021/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00002022 * xmlNewNodeEatName:
2023 * @ns: namespace if any
2024 * @name: the node name
2025 *
2026 * Creation of a new node element. @ns is optional (NULL).
2027 *
2028 * Returns a pointer to the new node object.
2029 */
2030xmlNodePtr
2031xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2032 xmlNodePtr cur;
2033
2034 if (name == NULL) {
2035#ifdef DEBUG_TREE
2036 xmlGenericError(xmlGenericErrorContext,
2037 "xmlNewNode : name == NULL\n");
2038#endif
2039 return(NULL);
2040 }
2041
2042 /*
2043 * Allocate a new node and fill the fields.
2044 */
2045 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2046 if (cur == NULL) {
2047 xmlGenericError(xmlGenericErrorContext,
2048 "xmlNewNode : malloc failed\n");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00002049 xmlFree(name);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002050 return(NULL);
2051 }
2052 memset(cur, 0, sizeof(xmlNode));
2053 cur->type = XML_ELEMENT_NODE;
2054
2055 cur->name = name;
2056 cur->ns = ns;
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002057
Daniel Veillarda880b122003-04-21 21:36:41 +00002058 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00002059 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
Daniel Veillard46de64e2002-05-29 08:21:33 +00002060 return(cur);
2061}
2062
2063/**
Owen Taylor3473f882001-02-23 17:55:21 +00002064 * xmlNewDocNode:
2065 * @doc: the document
2066 * @ns: namespace if any
2067 * @name: the node name
2068 * @content: the XML text content if any
2069 *
2070 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002071 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002072 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2073 * references, but XML special chars need to be escaped first by using
2074 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2075 * need entities support.
2076 *
2077 * Returns a pointer to the new node object.
2078 */
2079xmlNodePtr
2080xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2081 const xmlChar *name, const xmlChar *content) {
2082 xmlNodePtr cur;
2083
2084 cur = xmlNewNode(ns, name);
2085 if (cur != NULL) {
2086 cur->doc = doc;
2087 if (content != NULL) {
2088 cur->children = xmlStringGetNodeList(doc, content);
2089 UPDATE_LAST_CHILD_AND_PARENT(cur)
2090 }
2091 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002092
Owen Taylor3473f882001-02-23 17:55:21 +00002093 return(cur);
2094}
2095
Daniel Veillard46de64e2002-05-29 08:21:33 +00002096/**
2097 * xmlNewDocNodeEatName:
2098 * @doc: the document
2099 * @ns: namespace if any
2100 * @name: the node name
2101 * @content: the XML text content if any
2102 *
2103 * Creation of a new node element within a document. @ns and @content
2104 * are optional (NULL).
2105 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2106 * references, but XML special chars need to be escaped first by using
2107 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2108 * need entities support.
2109 *
2110 * Returns a pointer to the new node object.
2111 */
2112xmlNodePtr
2113xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2114 xmlChar *name, const xmlChar *content) {
2115 xmlNodePtr cur;
2116
2117 cur = xmlNewNodeEatName(ns, name);
2118 if (cur != NULL) {
2119 cur->doc = doc;
2120 if (content != NULL) {
2121 cur->children = xmlStringGetNodeList(doc, content);
2122 UPDATE_LAST_CHILD_AND_PARENT(cur)
2123 }
2124 }
2125 return(cur);
2126}
2127
Owen Taylor3473f882001-02-23 17:55:21 +00002128
2129/**
2130 * xmlNewDocRawNode:
2131 * @doc: the document
2132 * @ns: namespace if any
2133 * @name: the node name
2134 * @content: the text content if any
2135 *
2136 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00002137 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00002138 *
2139 * Returns a pointer to the new node object.
2140 */
2141xmlNodePtr
2142xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2143 const xmlChar *name, const xmlChar *content) {
2144 xmlNodePtr cur;
2145
2146 cur = xmlNewNode(ns, name);
2147 if (cur != NULL) {
2148 cur->doc = doc;
2149 if (content != NULL) {
2150 cur->children = xmlNewDocText(doc, content);
2151 UPDATE_LAST_CHILD_AND_PARENT(cur)
2152 }
2153 }
2154 return(cur);
2155}
2156
2157/**
2158 * xmlNewDocFragment:
2159 * @doc: the document owning the fragment
2160 *
2161 * Creation of a new Fragment node.
2162 * Returns a pointer to the new node object.
2163 */
2164xmlNodePtr
2165xmlNewDocFragment(xmlDocPtr doc) {
2166 xmlNodePtr cur;
2167
2168 /*
2169 * Allocate a new DocumentFragment node and fill the fields.
2170 */
2171 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2172 if (cur == NULL) {
2173 xmlGenericError(xmlGenericErrorContext,
2174 "xmlNewDocFragment : malloc failed\n");
2175 return(NULL);
2176 }
2177 memset(cur, 0, sizeof(xmlNode));
2178 cur->type = XML_DOCUMENT_FRAG_NODE;
2179
2180 cur->doc = doc;
Daniel Veillard5335dc52003-01-01 20:59:38 +00002181
Daniel Veillarda880b122003-04-21 21:36:41 +00002182 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002183 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002184 return(cur);
2185}
2186
2187/**
2188 * xmlNewText:
2189 * @content: the text content
2190 *
2191 * Creation of a new text node.
2192 * Returns a pointer to the new node object.
2193 */
2194xmlNodePtr
2195xmlNewText(const xmlChar *content) {
2196 xmlNodePtr cur;
2197
2198 /*
2199 * Allocate a new node and fill the fields.
2200 */
2201 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2202 if (cur == NULL) {
2203 xmlGenericError(xmlGenericErrorContext,
2204 "xmlNewText : malloc failed\n");
2205 return(NULL);
2206 }
2207 memset(cur, 0, sizeof(xmlNode));
2208 cur->type = XML_TEXT_NODE;
2209
2210 cur->name = xmlStringText;
2211 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002212 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002213 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002214
Daniel Veillarda880b122003-04-21 21:36:41 +00002215 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002216 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002217 return(cur);
2218}
2219
2220/**
2221 * xmlNewTextChild:
2222 * @parent: the parent node
2223 * @ns: a namespace if any
2224 * @name: the name of the child
2225 * @content: the text content of the child if any.
2226 *
2227 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002228 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002229 * a child TEXT node will be created containing the string content.
2230 *
2231 * Returns a pointer to the new node object.
2232 */
2233xmlNodePtr
2234xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2235 const xmlChar *name, const xmlChar *content) {
2236 xmlNodePtr cur, prev;
2237
2238 if (parent == NULL) {
2239#ifdef DEBUG_TREE
2240 xmlGenericError(xmlGenericErrorContext,
2241 "xmlNewTextChild : parent == NULL\n");
2242#endif
2243 return(NULL);
2244 }
2245
2246 if (name == NULL) {
2247#ifdef DEBUG_TREE
2248 xmlGenericError(xmlGenericErrorContext,
2249 "xmlNewTextChild : name == NULL\n");
2250#endif
2251 return(NULL);
2252 }
2253
2254 /*
2255 * Allocate a new node
2256 */
2257 if (ns == NULL)
2258 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2259 else
2260 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2261 if (cur == NULL) return(NULL);
2262
2263 /*
2264 * add the new element at the end of the children list.
2265 */
2266 cur->type = XML_ELEMENT_NODE;
2267 cur->parent = parent;
2268 cur->doc = parent->doc;
2269 if (parent->children == NULL) {
2270 parent->children = cur;
2271 parent->last = cur;
2272 } else {
2273 prev = parent->last;
2274 prev->next = cur;
2275 cur->prev = prev;
2276 parent->last = cur;
2277 }
2278
2279 return(cur);
2280}
2281
2282/**
2283 * xmlNewCharRef:
2284 * @doc: the document
2285 * @name: the char ref string, starting with # or "&# ... ;"
2286 *
2287 * Creation of a new character reference node.
2288 * Returns a pointer to the new node object.
2289 */
2290xmlNodePtr
2291xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2292 xmlNodePtr cur;
2293
2294 /*
2295 * Allocate a new node and fill the fields.
2296 */
2297 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2298 if (cur == NULL) {
2299 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002300 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002301 return(NULL);
2302 }
2303 memset(cur, 0, sizeof(xmlNode));
2304 cur->type = XML_ENTITY_REF_NODE;
2305
2306 cur->doc = doc;
2307 if (name[0] == '&') {
2308 int len;
2309 name++;
2310 len = xmlStrlen(name);
2311 if (name[len - 1] == ';')
2312 cur->name = xmlStrndup(name, len - 1);
2313 else
2314 cur->name = xmlStrndup(name, len);
2315 } else
2316 cur->name = xmlStrdup(name);
Daniel Veillard5335dc52003-01-01 20:59:38 +00002317
Daniel Veillarda880b122003-04-21 21:36:41 +00002318 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002319 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002320 return(cur);
2321}
2322
2323/**
2324 * xmlNewReference:
2325 * @doc: the document
2326 * @name: the reference name, or the reference string with & and ;
2327 *
2328 * Creation of a new reference node.
2329 * Returns a pointer to the new node object.
2330 */
2331xmlNodePtr
2332xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2333 xmlNodePtr cur;
2334 xmlEntityPtr ent;
2335
2336 /*
2337 * Allocate a new node and fill the fields.
2338 */
2339 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2340 if (cur == NULL) {
2341 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002342 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002343 return(NULL);
2344 }
2345 memset(cur, 0, sizeof(xmlNode));
2346 cur->type = XML_ENTITY_REF_NODE;
2347
2348 cur->doc = doc;
2349 if (name[0] == '&') {
2350 int len;
2351 name++;
2352 len = xmlStrlen(name);
2353 if (name[len - 1] == ';')
2354 cur->name = xmlStrndup(name, len - 1);
2355 else
2356 cur->name = xmlStrndup(name, len);
2357 } else
2358 cur->name = xmlStrdup(name);
2359
2360 ent = xmlGetDocEntity(doc, cur->name);
2361 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002362 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00002363 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002364 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00002365 * updated. Not sure if this is 100% correct.
2366 * -George
2367 */
2368 cur->children = (xmlNodePtr) ent;
2369 cur->last = (xmlNodePtr) ent;
2370 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002371
Daniel Veillarda880b122003-04-21 21:36:41 +00002372 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002373 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002374 return(cur);
2375}
2376
2377/**
2378 * xmlNewDocText:
2379 * @doc: the document
2380 * @content: the text content
2381 *
2382 * Creation of a new text node within a document.
2383 * Returns a pointer to the new node object.
2384 */
2385xmlNodePtr
2386xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2387 xmlNodePtr cur;
2388
2389 cur = xmlNewText(content);
2390 if (cur != NULL) cur->doc = doc;
2391 return(cur);
2392}
2393
2394/**
2395 * xmlNewTextLen:
2396 * @content: the text content
2397 * @len: the text len.
2398 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002399 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00002400 * Returns a pointer to the new node object.
2401 */
2402xmlNodePtr
2403xmlNewTextLen(const xmlChar *content, int len) {
2404 xmlNodePtr cur;
2405
2406 /*
2407 * Allocate a new node and fill the fields.
2408 */
2409 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2410 if (cur == NULL) {
2411 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002412 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002413 return(NULL);
2414 }
2415 memset(cur, 0, sizeof(xmlNode));
2416 cur->type = XML_TEXT_NODE;
2417
2418 cur->name = xmlStringText;
2419 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002420 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002421 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002422
Daniel Veillarda880b122003-04-21 21:36:41 +00002423 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002424 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002425 return(cur);
2426}
2427
2428/**
2429 * xmlNewDocTextLen:
2430 * @doc: the document
2431 * @content: the text content
2432 * @len: the text len.
2433 *
Daniel Veillard60087f32001-10-10 09:45:09 +00002434 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00002435 * text node pertain to a given document.
2436 * Returns a pointer to the new node object.
2437 */
2438xmlNodePtr
2439xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2440 xmlNodePtr cur;
2441
2442 cur = xmlNewTextLen(content, len);
2443 if (cur != NULL) cur->doc = doc;
2444 return(cur);
2445}
2446
2447/**
2448 * xmlNewComment:
2449 * @content: the comment content
2450 *
2451 * Creation of a new node containing a comment.
2452 * Returns a pointer to the new node object.
2453 */
2454xmlNodePtr
2455xmlNewComment(const xmlChar *content) {
2456 xmlNodePtr cur;
2457
2458 /*
2459 * Allocate a new node and fill the fields.
2460 */
2461 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2462 if (cur == NULL) {
2463 xmlGenericError(xmlGenericErrorContext,
2464 "xmlNewComment : malloc failed\n");
2465 return(NULL);
2466 }
2467 memset(cur, 0, sizeof(xmlNode));
2468 cur->type = XML_COMMENT_NODE;
2469
2470 cur->name = xmlStringComment;
2471 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002472 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00002473 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002474
Daniel Veillarda880b122003-04-21 21:36:41 +00002475 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002476 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002477 return(cur);
2478}
2479
2480/**
2481 * xmlNewCDataBlock:
2482 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00002483 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00002484 * @len: the length of the block
2485 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002486 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00002487 * Returns a pointer to the new node object.
2488 */
2489xmlNodePtr
2490xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2491 xmlNodePtr cur;
2492
2493 /*
2494 * Allocate a new node and fill the fields.
2495 */
2496 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2497 if (cur == NULL) {
2498 xmlGenericError(xmlGenericErrorContext,
2499 "xmlNewCDataBlock : malloc failed\n");
2500 return(NULL);
2501 }
2502 memset(cur, 0, sizeof(xmlNode));
2503 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002504 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00002505
2506 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002507 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00002508 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00002509
Daniel Veillarda880b122003-04-21 21:36:41 +00002510 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00002511 xmlRegisterNodeDefaultValue(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002512 return(cur);
2513}
2514
2515/**
2516 * xmlNewDocComment:
2517 * @doc: the document
2518 * @content: the comment content
2519 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002520 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00002521 * Returns a pointer to the new node object.
2522 */
2523xmlNodePtr
2524xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2525 xmlNodePtr cur;
2526
2527 cur = xmlNewComment(content);
2528 if (cur != NULL) cur->doc = doc;
2529 return(cur);
2530}
2531
2532/**
2533 * xmlSetTreeDoc:
2534 * @tree: the top element
2535 * @doc: the document
2536 *
2537 * update all nodes under the tree to point to the right document
2538 */
2539void
2540xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002541 xmlAttrPtr prop;
2542
Owen Taylor3473f882001-02-23 17:55:21 +00002543 if (tree == NULL)
2544 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002545 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002546 if(tree->type == XML_ELEMENT_NODE) {
2547 prop = tree->properties;
2548 while (prop != NULL) {
2549 prop->doc = doc;
2550 xmlSetListDoc(prop->children, doc);
2551 prop = prop->next;
2552 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002553 }
Owen Taylor3473f882001-02-23 17:55:21 +00002554 if (tree->children != NULL)
2555 xmlSetListDoc(tree->children, doc);
2556 tree->doc = doc;
2557 }
2558}
2559
2560/**
2561 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002562 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002563 * @doc: the document
2564 *
2565 * update all nodes in the list to point to the right document
2566 */
2567void
2568xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2569 xmlNodePtr cur;
2570
2571 if (list == NULL)
2572 return;
2573 cur = list;
2574 while (cur != NULL) {
2575 if (cur->doc != doc)
2576 xmlSetTreeDoc(cur, doc);
2577 cur = cur->next;
2578 }
2579}
2580
2581
2582/**
2583 * xmlNewChild:
2584 * @parent: the parent node
2585 * @ns: a namespace if any
2586 * @name: the name of the child
2587 * @content: the XML content of the child if any.
2588 *
2589 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002590 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002591 * a child list containing the TEXTs and ENTITY_REFs node will be created.
2592 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2593 * references, but XML special chars need to be escaped first by using
2594 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
2595 * support is not needed.
2596 *
2597 * Returns a pointer to the new node object.
2598 */
2599xmlNodePtr
2600xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2601 const xmlChar *name, const xmlChar *content) {
2602 xmlNodePtr cur, prev;
2603
2604 if (parent == NULL) {
2605#ifdef DEBUG_TREE
2606 xmlGenericError(xmlGenericErrorContext,
2607 "xmlNewChild : parent == NULL\n");
2608#endif
2609 return(NULL);
2610 }
2611
2612 if (name == NULL) {
2613#ifdef DEBUG_TREE
2614 xmlGenericError(xmlGenericErrorContext,
2615 "xmlNewChild : name == NULL\n");
2616#endif
2617 return(NULL);
2618 }
2619
2620 /*
2621 * Allocate a new node
2622 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002623 if (parent->type == XML_ELEMENT_NODE) {
2624 if (ns == NULL)
2625 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2626 else
2627 cur = xmlNewDocNode(parent->doc, ns, name, content);
2628 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2629 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2630 if (ns == NULL)
2631 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2632 else
2633 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002634 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2635 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002636 } else {
2637 return(NULL);
2638 }
Owen Taylor3473f882001-02-23 17:55:21 +00002639 if (cur == NULL) return(NULL);
2640
2641 /*
2642 * add the new element at the end of the children list.
2643 */
2644 cur->type = XML_ELEMENT_NODE;
2645 cur->parent = parent;
2646 cur->doc = parent->doc;
2647 if (parent->children == NULL) {
2648 parent->children = cur;
2649 parent->last = cur;
2650 } else {
2651 prev = parent->last;
2652 prev->next = cur;
2653 cur->prev = prev;
2654 parent->last = cur;
2655 }
2656
2657 return(cur);
2658}
2659
2660/**
2661 * xmlAddNextSibling:
2662 * @cur: the child node
2663 * @elem: the new node
2664 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002665 * Add a new node @elem as the next sibling of @cur
2666 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002667 * first unlinked from its existing context.
2668 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002669 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2670 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002671 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002672 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002673 */
2674xmlNodePtr
2675xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2676 if (cur == NULL) {
2677#ifdef DEBUG_TREE
2678 xmlGenericError(xmlGenericErrorContext,
2679 "xmlAddNextSibling : cur == NULL\n");
2680#endif
2681 return(NULL);
2682 }
2683 if (elem == NULL) {
2684#ifdef DEBUG_TREE
2685 xmlGenericError(xmlGenericErrorContext,
2686 "xmlAddNextSibling : elem == NULL\n");
2687#endif
2688 return(NULL);
2689 }
2690
2691 xmlUnlinkNode(elem);
2692
2693 if (elem->type == XML_TEXT_NODE) {
2694 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002695 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002696 xmlFreeNode(elem);
2697 return(cur);
2698 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002699 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2700 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002701 xmlChar *tmp;
2702
2703 tmp = xmlStrdup(elem->content);
2704 tmp = xmlStrcat(tmp, cur->next->content);
2705 xmlNodeSetContent(cur->next, tmp);
2706 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002707 xmlFreeNode(elem);
2708 return(cur->next);
2709 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002710 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2711 /* check if an attribute with the same name exists */
2712 xmlAttrPtr attr;
2713
2714 if (elem->ns == NULL)
2715 attr = xmlHasProp(cur->parent, elem->name);
2716 else
2717 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2718 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2719 /* different instance, destroy it (attributes must be unique) */
2720 xmlFreeProp(attr);
2721 }
Owen Taylor3473f882001-02-23 17:55:21 +00002722 }
2723
2724 if (elem->doc != cur->doc) {
2725 xmlSetTreeDoc(elem, cur->doc);
2726 }
2727 elem->parent = cur->parent;
2728 elem->prev = cur;
2729 elem->next = cur->next;
2730 cur->next = elem;
2731 if (elem->next != NULL)
2732 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002733 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002734 elem->parent->last = elem;
2735 return(elem);
2736}
2737
2738/**
2739 * xmlAddPrevSibling:
2740 * @cur: the child node
2741 * @elem: the new node
2742 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002743 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002744 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002745 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002746 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002747 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2748 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002749 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002750 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002751 */
2752xmlNodePtr
2753xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2754 if (cur == NULL) {
2755#ifdef DEBUG_TREE
2756 xmlGenericError(xmlGenericErrorContext,
2757 "xmlAddPrevSibling : cur == NULL\n");
2758#endif
2759 return(NULL);
2760 }
2761 if (elem == NULL) {
2762#ifdef DEBUG_TREE
2763 xmlGenericError(xmlGenericErrorContext,
2764 "xmlAddPrevSibling : elem == NULL\n");
2765#endif
2766 return(NULL);
2767 }
2768
2769 xmlUnlinkNode(elem);
2770
2771 if (elem->type == XML_TEXT_NODE) {
2772 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002773 xmlChar *tmp;
2774
2775 tmp = xmlStrdup(elem->content);
2776 tmp = xmlStrcat(tmp, cur->content);
2777 xmlNodeSetContent(cur, tmp);
2778 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002779 xmlFreeNode(elem);
2780 return(cur);
2781 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002782 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2783 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002784 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002785 xmlFreeNode(elem);
2786 return(cur->prev);
2787 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002788 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2789 /* check if an attribute with the same name exists */
2790 xmlAttrPtr attr;
2791
2792 if (elem->ns == NULL)
2793 attr = xmlHasProp(cur->parent, elem->name);
2794 else
2795 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2796 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2797 /* different instance, destroy it (attributes must be unique) */
2798 xmlFreeProp(attr);
2799 }
Owen Taylor3473f882001-02-23 17:55:21 +00002800 }
2801
2802 if (elem->doc != cur->doc) {
2803 xmlSetTreeDoc(elem, cur->doc);
2804 }
2805 elem->parent = cur->parent;
2806 elem->next = cur;
2807 elem->prev = cur->prev;
2808 cur->prev = elem;
2809 if (elem->prev != NULL)
2810 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002811 if (elem->parent != NULL) {
2812 if (elem->type == XML_ATTRIBUTE_NODE) {
2813 if (elem->parent->properties == (xmlAttrPtr) cur) {
2814 elem->parent->properties = (xmlAttrPtr) elem;
2815 }
2816 } else {
2817 if (elem->parent->children == cur) {
2818 elem->parent->children = elem;
2819 }
2820 }
2821 }
Owen Taylor3473f882001-02-23 17:55:21 +00002822 return(elem);
2823}
2824
2825/**
2826 * xmlAddSibling:
2827 * @cur: the child node
2828 * @elem: the new node
2829 *
2830 * Add a new element @elem to the list of siblings of @cur
2831 * merging adjacent TEXT nodes (@elem may be freed)
2832 * If the new element was already inserted in a document it is
2833 * first unlinked from its existing context.
2834 *
2835 * Returns the new element or NULL in case of error.
2836 */
2837xmlNodePtr
2838xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2839 xmlNodePtr parent;
2840
2841 if (cur == NULL) {
2842#ifdef DEBUG_TREE
2843 xmlGenericError(xmlGenericErrorContext,
2844 "xmlAddSibling : cur == NULL\n");
2845#endif
2846 return(NULL);
2847 }
2848
2849 if (elem == NULL) {
2850#ifdef DEBUG_TREE
2851 xmlGenericError(xmlGenericErrorContext,
2852 "xmlAddSibling : elem == NULL\n");
2853#endif
2854 return(NULL);
2855 }
2856
2857 /*
2858 * Constant time is we can rely on the ->parent->last to find
2859 * the last sibling.
2860 */
2861 if ((cur->parent != NULL) &&
2862 (cur->parent->children != NULL) &&
2863 (cur->parent->last != NULL) &&
2864 (cur->parent->last->next == NULL)) {
2865 cur = cur->parent->last;
2866 } else {
2867 while (cur->next != NULL) cur = cur->next;
2868 }
2869
2870 xmlUnlinkNode(elem);
2871
2872 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002873 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002874 xmlFreeNode(elem);
2875 return(cur);
2876 }
2877
2878 if (elem->doc != cur->doc) {
2879 xmlSetTreeDoc(elem, cur->doc);
2880 }
2881 parent = cur->parent;
2882 elem->prev = cur;
2883 elem->next = NULL;
2884 elem->parent = parent;
2885 cur->next = elem;
2886 if (parent != NULL)
2887 parent->last = elem;
2888
2889 return(elem);
2890}
2891
2892/**
2893 * xmlAddChildList:
2894 * @parent: the parent node
2895 * @cur: the first node in the list
2896 *
2897 * Add a list of node at the end of the child list of the parent
2898 * merging adjacent TEXT nodes (@cur may be freed)
2899 *
2900 * Returns the last child or NULL in case of error.
2901 */
2902xmlNodePtr
2903xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2904 xmlNodePtr prev;
2905
2906 if (parent == NULL) {
2907#ifdef DEBUG_TREE
2908 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002909 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002910#endif
2911 return(NULL);
2912 }
2913
2914 if (cur == NULL) {
2915#ifdef DEBUG_TREE
2916 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002917 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002918#endif
2919 return(NULL);
2920 }
2921
2922 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2923 (cur->doc != parent->doc)) {
2924#ifdef DEBUG_TREE
2925 xmlGenericError(xmlGenericErrorContext,
2926 "Elements moved to a different document\n");
2927#endif
2928 }
2929
2930 /*
2931 * add the first element at the end of the children list.
2932 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00002933
Owen Taylor3473f882001-02-23 17:55:21 +00002934 if (parent->children == NULL) {
2935 parent->children = cur;
2936 } else {
2937 /*
2938 * If cur and parent->last both are TEXT nodes, then merge them.
2939 */
2940 if ((cur->type == XML_TEXT_NODE) &&
2941 (parent->last->type == XML_TEXT_NODE) &&
2942 (cur->name == parent->last->name)) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00002943 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002944 /*
2945 * if it's the only child, nothing more to be done.
2946 */
2947 if (cur->next == NULL) {
2948 xmlFreeNode(cur);
2949 return(parent->last);
2950 }
2951 prev = cur;
2952 cur = cur->next;
2953 xmlFreeNode(prev);
2954 }
2955 prev = parent->last;
2956 prev->next = cur;
2957 cur->prev = prev;
2958 }
2959 while (cur->next != NULL) {
2960 cur->parent = parent;
2961 if (cur->doc != parent->doc) {
2962 xmlSetTreeDoc(cur, parent->doc);
2963 }
2964 cur = cur->next;
2965 }
2966 cur->parent = parent;
2967 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2968 parent->last = cur;
2969
2970 return(cur);
2971}
2972
2973/**
2974 * xmlAddChild:
2975 * @parent: the parent node
2976 * @cur: the child node
2977 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002978 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00002979 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002980 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2981 * If there is an attribute with equal name, it is first destroyed.
2982 *
Owen Taylor3473f882001-02-23 17:55:21 +00002983 * Returns the child or NULL in case of error.
2984 */
2985xmlNodePtr
2986xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2987 xmlNodePtr prev;
2988
2989 if (parent == NULL) {
2990#ifdef DEBUG_TREE
2991 xmlGenericError(xmlGenericErrorContext,
2992 "xmlAddChild : parent == NULL\n");
2993#endif
2994 return(NULL);
2995 }
2996
2997 if (cur == NULL) {
2998#ifdef DEBUG_TREE
2999 xmlGenericError(xmlGenericErrorContext,
3000 "xmlAddChild : child == NULL\n");
3001#endif
3002 return(NULL);
3003 }
3004
Owen Taylor3473f882001-02-23 17:55:21 +00003005 /*
3006 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00003007 * cur is then freed.
3008 */
3009 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003010 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003011 (parent->content != NULL) &&
3012 (parent != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003013 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003014 xmlFreeNode(cur);
3015 return(parent);
3016 }
3017 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003018 (parent->last->name == cur->name) &&
3019 (parent->last != cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003020 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00003021 xmlFreeNode(cur);
3022 return(parent->last);
3023 }
3024 }
3025
3026 /*
3027 * add the new element at the end of the children list.
3028 */
Daniel Veillard5335dc52003-01-01 20:59:38 +00003029 prev = cur->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00003030 cur->parent = parent;
3031 if (cur->doc != parent->doc) {
3032 xmlSetTreeDoc(cur, parent->doc);
3033 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003034 /* this check prevents a loop on tree-traversions if a developer
3035 * tries to add a node to its parent multiple times
3036 */
3037 if (prev == parent)
3038 return(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003039
3040 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00003041 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00003042 */
Daniel Veillard7db37732001-07-12 01:20:08 +00003043 if ((parent->type == XML_TEXT_NODE) &&
Daniel Veillard5335dc52003-01-01 20:59:38 +00003044 (parent->content != NULL) &&
3045 (parent != cur)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003046 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003047 xmlFreeNode(cur);
3048 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003049 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003050 if (cur->type == XML_ATTRIBUTE_NODE) {
3051 if (parent->properties == NULL) {
3052 parent->properties = (xmlAttrPtr) cur;
3053 } else {
3054 /* check if an attribute with the same name exists */
3055 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00003056
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003057 if (cur->ns == NULL)
3058 lastattr = xmlHasProp(parent, cur->name);
3059 else
3060 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3061 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
3062 /* different instance, destroy it (attributes must be unique) */
3063 xmlFreeProp(lastattr);
3064 }
3065 /* find the end */
3066 lastattr = parent->properties;
3067 while (lastattr->next != NULL) {
3068 lastattr = lastattr->next;
3069 }
3070 lastattr->next = (xmlAttrPtr) cur;
3071 ((xmlAttrPtr) cur)->prev = lastattr;
3072 }
3073 } else {
3074 if (parent->children == NULL) {
3075 parent->children = cur;
3076 parent->last = cur;
3077 } else {
3078 prev = parent->last;
3079 prev->next = cur;
3080 cur->prev = prev;
3081 parent->last = cur;
3082 }
3083 }
Owen Taylor3473f882001-02-23 17:55:21 +00003084 return(cur);
3085}
3086
3087/**
3088 * xmlGetLastChild:
3089 * @parent: the parent node
3090 *
3091 * Search the last child of a node.
3092 * Returns the last child or NULL if none.
3093 */
3094xmlNodePtr
3095xmlGetLastChild(xmlNodePtr parent) {
3096 if (parent == NULL) {
3097#ifdef DEBUG_TREE
3098 xmlGenericError(xmlGenericErrorContext,
3099 "xmlGetLastChild : parent == NULL\n");
3100#endif
3101 return(NULL);
3102 }
3103 return(parent->last);
3104}
3105
3106/**
3107 * xmlFreeNodeList:
3108 * @cur: the first node in the list
3109 *
3110 * Free a node and all its siblings, this is a recursive behaviour, all
3111 * the children are freed too.
3112 */
3113void
3114xmlFreeNodeList(xmlNodePtr cur) {
3115 xmlNodePtr next;
3116 if (cur == NULL) {
3117#ifdef DEBUG_TREE
3118 xmlGenericError(xmlGenericErrorContext,
3119 "xmlFreeNodeList : node == NULL\n");
3120#endif
3121 return;
3122 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00003123 if (cur->type == XML_NAMESPACE_DECL) {
3124 xmlFreeNsList((xmlNsPtr) cur);
3125 return;
3126 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003127 if ((cur->type == XML_DOCUMENT_NODE) ||
3128#ifdef LIBXML_DOCB_ENABLED
3129 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
Daniel Veillard9adc0462003-03-24 18:39:54 +00003130#endif
Daniel Veillard6560a422003-03-27 21:25:38 +00003131 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003132 xmlFreeDoc((xmlDocPtr) cur);
3133 return;
3134 }
Owen Taylor3473f882001-02-23 17:55:21 +00003135 while (cur != NULL) {
3136 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00003137 /* unroll to speed up freeing the document */
3138 if (cur->type != XML_DTD_NODE) {
Daniel Veillard5335dc52003-01-01 20:59:38 +00003139
Daniel Veillarda880b122003-04-21 21:36:41 +00003140 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003141 xmlDeregisterNodeDefaultValue(cur);
3142
Daniel Veillard02141ea2001-04-30 11:46:40 +00003143 if ((cur->children != NULL) &&
3144 (cur->type != XML_ENTITY_REF_NODE))
3145 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003146 if (((cur->type == XML_ELEMENT_NODE) ||
3147 (cur->type == XML_XINCLUDE_START) ||
3148 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003149 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003150 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003151 if ((cur->type != XML_ELEMENT_NODE) &&
3152 (cur->type != XML_XINCLUDE_START) &&
3153 (cur->type != XML_XINCLUDE_END) &&
3154 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00003155 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003156 }
3157 if (((cur->type == XML_ELEMENT_NODE) ||
3158 (cur->type == XML_XINCLUDE_START) ||
3159 (cur->type == XML_XINCLUDE_END)) &&
3160 (cur->nsDef != NULL))
3161 xmlFreeNsList(cur->nsDef);
3162
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003163 /*
3164 * When a node is a text node or a comment, it uses a global static
3165 * variable for the name of the node.
3166 *
3167 * The xmlStrEqual comparisons need to be done when (happened with
3168 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003169 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00003170 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003171 * the string addresses compare are not sufficient.
3172 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003173 if ((cur->name != NULL) &&
3174 (cur->name != xmlStringText) &&
3175 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00003176 (cur->name != xmlStringComment)) {
3177 if (cur->type == XML_TEXT_NODE) {
3178 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
3179 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
3180 xmlFree((char *) cur->name);
3181 } else if (cur->type == XML_COMMENT_NODE) {
3182 if (!xmlStrEqual(cur->name, xmlStringComment))
3183 xmlFree((char *) cur->name);
3184 } else
3185 xmlFree((char *) cur->name);
3186 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00003187 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00003188 xmlFree(cur);
3189 }
Owen Taylor3473f882001-02-23 17:55:21 +00003190 cur = next;
3191 }
3192}
3193
3194/**
3195 * xmlFreeNode:
3196 * @cur: the node
3197 *
3198 * Free a node, this is a recursive behaviour, all the children are freed too.
3199 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3200 */
3201void
3202xmlFreeNode(xmlNodePtr cur) {
3203 if (cur == NULL) {
3204#ifdef DEBUG_TREE
3205 xmlGenericError(xmlGenericErrorContext,
3206 "xmlFreeNode : node == NULL\n");
3207#endif
3208 return;
3209 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003210
Daniel Veillard02141ea2001-04-30 11:46:40 +00003211 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00003212 if (cur->type == XML_DTD_NODE) {
3213 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00003214 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00003215 }
3216 if (cur->type == XML_NAMESPACE_DECL) {
3217 xmlFreeNs((xmlNsPtr) cur);
3218 return;
3219 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00003220 if (cur->type == XML_ATTRIBUTE_NODE) {
3221 xmlFreeProp((xmlAttrPtr) cur);
3222 return;
3223 }
Daniel Veillard5335dc52003-01-01 20:59:38 +00003224
Daniel Veillarda880b122003-04-21 21:36:41 +00003225 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
Daniel Veillard5335dc52003-01-01 20:59:38 +00003226 xmlDeregisterNodeDefaultValue(cur);
3227
Owen Taylor3473f882001-02-23 17:55:21 +00003228 if ((cur->children != NULL) &&
3229 (cur->type != XML_ENTITY_REF_NODE))
3230 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00003231 if (((cur->type == XML_ELEMENT_NODE) ||
3232 (cur->type == XML_XINCLUDE_START) ||
3233 (cur->type == XML_XINCLUDE_END)) &&
3234 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00003235 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00003236 if ((cur->type != XML_ELEMENT_NODE) &&
3237 (cur->content != NULL) &&
3238 (cur->type != XML_ENTITY_REF_NODE) &&
3239 (cur->type != XML_XINCLUDE_END) &&
3240 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00003241 xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00003242 }
3243
Daniel Veillardacd370f2001-06-09 17:17:51 +00003244 /*
3245 * When a node is a text node or a comment, it uses a global static
3246 * variable for the name of the node.
3247 *
3248 * The xmlStrEqual comparisons need to be done when (happened with
3249 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003250 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00003251 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00003252 * are not sufficient.
3253 */
Owen Taylor3473f882001-02-23 17:55:21 +00003254 if ((cur->name != NULL) &&
3255 (cur->name != xmlStringText) &&
3256 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00003257 (cur->name != xmlStringComment)) {
3258 if (cur->type == XML_TEXT_NODE) {
3259 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
3260 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
3261 xmlFree((char *) cur->name);
3262 } else if (cur->type == XML_COMMENT_NODE) {
3263 if (!xmlStrEqual(cur->name, xmlStringComment))
3264 xmlFree((char *) cur->name);
3265 } else
3266 xmlFree((char *) cur->name);
3267 }
3268
Daniel Veillarde1ca5032002-12-09 14:13:43 +00003269 if (((cur->type == XML_ELEMENT_NODE) ||
3270 (cur->type == XML_XINCLUDE_START) ||
3271 (cur->type == XML_XINCLUDE_END)) &&
3272 (cur->nsDef != NULL))
3273 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00003274 xmlFree(cur);
3275}
3276
3277/**
3278 * xmlUnlinkNode:
3279 * @cur: the node
3280 *
3281 * Unlink a node from it's current context, the node is not freed
3282 */
3283void
3284xmlUnlinkNode(xmlNodePtr cur) {
3285 if (cur == NULL) {
3286#ifdef DEBUG_TREE
3287 xmlGenericError(xmlGenericErrorContext,
3288 "xmlUnlinkNode : node == NULL\n");
3289#endif
3290 return;
3291 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003292 if (cur->type == XML_DTD_NODE) {
3293 xmlDocPtr doc;
3294 doc = cur->doc;
Daniel Veillarda067e652003-05-01 08:03:46 +00003295 if (doc != NULL) {
3296 if (doc->intSubset == (xmlDtdPtr) cur)
3297 doc->intSubset = NULL;
3298 if (doc->extSubset == (xmlDtdPtr) cur)
3299 doc->extSubset = NULL;
3300 }
Daniel Veillard29e43992001-12-13 22:21:58 +00003301 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003302 if (cur->parent != NULL) {
3303 xmlNodePtr parent;
3304 parent = cur->parent;
3305 if (cur->type == XML_ATTRIBUTE_NODE) {
3306 if (parent->properties == (xmlAttrPtr) cur)
3307 parent->properties = ((xmlAttrPtr) cur)->next;
3308 } else {
3309 if (parent->children == cur)
3310 parent->children = cur->next;
3311 if (parent->last == cur)
3312 parent->last = cur->prev;
3313 }
3314 cur->parent = NULL;
3315 }
Owen Taylor3473f882001-02-23 17:55:21 +00003316 if (cur->next != NULL)
3317 cur->next->prev = cur->prev;
3318 if (cur->prev != NULL)
3319 cur->prev->next = cur->next;
3320 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003321}
3322
3323/**
3324 * xmlReplaceNode:
3325 * @old: the old node
3326 * @cur: the node
3327 *
3328 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00003329 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00003330 * first unlinked from its existing context.
3331 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003332 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00003333 */
3334xmlNodePtr
3335xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3336 if (old == NULL) {
3337#ifdef DEBUG_TREE
3338 xmlGenericError(xmlGenericErrorContext,
3339 "xmlReplaceNode : old == NULL\n");
3340#endif
3341 return(NULL);
3342 }
3343 if (cur == NULL) {
3344 xmlUnlinkNode(old);
3345 return(old);
3346 }
3347 if (cur == old) {
3348 return(old);
3349 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003350 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3351#ifdef DEBUG_TREE
3352 xmlGenericError(xmlGenericErrorContext,
3353 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3354#endif
3355 return(old);
3356 }
3357 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3358#ifdef DEBUG_TREE
3359 xmlGenericError(xmlGenericErrorContext,
3360 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3361#endif
3362 return(old);
3363 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00003364 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3365#ifdef DEBUG_TREE
3366 xmlGenericError(xmlGenericErrorContext,
3367 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3368#endif
3369 return(old);
3370 }
3371 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3372#ifdef DEBUG_TREE
3373 xmlGenericError(xmlGenericErrorContext,
3374 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3375#endif
3376 return(old);
3377 }
Owen Taylor3473f882001-02-23 17:55:21 +00003378 xmlUnlinkNode(cur);
3379 cur->doc = old->doc;
3380 cur->parent = old->parent;
3381 cur->next = old->next;
3382 if (cur->next != NULL)
3383 cur->next->prev = cur;
3384 cur->prev = old->prev;
3385 if (cur->prev != NULL)
3386 cur->prev->next = cur;
3387 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00003388 if (cur->type == XML_ATTRIBUTE_NODE) {
3389 if (cur->parent->properties == (xmlAttrPtr)old)
3390 cur->parent->properties = ((xmlAttrPtr) cur);
3391 } else {
3392 if (cur->parent->children == old)
3393 cur->parent->children = cur;
3394 if (cur->parent->last == old)
3395 cur->parent->last = cur;
3396 }
Owen Taylor3473f882001-02-23 17:55:21 +00003397 }
3398 old->next = old->prev = NULL;
3399 old->parent = NULL;
3400 return(old);
3401}
3402
3403/************************************************************************
3404 * *
3405 * Copy operations *
3406 * *
3407 ************************************************************************/
3408
3409/**
3410 * xmlCopyNamespace:
3411 * @cur: the namespace
3412 *
3413 * Do a copy of the namespace.
3414 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003415 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003416 */
3417xmlNsPtr
3418xmlCopyNamespace(xmlNsPtr cur) {
3419 xmlNsPtr ret;
3420
3421 if (cur == NULL) return(NULL);
3422 switch (cur->type) {
3423 case XML_LOCAL_NAMESPACE:
3424 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3425 break;
3426 default:
3427#ifdef DEBUG_TREE
3428 xmlGenericError(xmlGenericErrorContext,
3429 "xmlCopyNamespace: invalid type %d\n", cur->type);
3430#endif
3431 return(NULL);
3432 }
3433 return(ret);
3434}
3435
3436/**
3437 * xmlCopyNamespaceList:
3438 * @cur: the first namespace
3439 *
3440 * Do a copy of an namespace list.
3441 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003442 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003443 */
3444xmlNsPtr
3445xmlCopyNamespaceList(xmlNsPtr cur) {
3446 xmlNsPtr ret = NULL;
3447 xmlNsPtr p = NULL,q;
3448
3449 while (cur != NULL) {
3450 q = xmlCopyNamespace(cur);
3451 if (p == NULL) {
3452 ret = p = q;
3453 } else {
3454 p->next = q;
3455 p = q;
3456 }
3457 cur = cur->next;
3458 }
3459 return(ret);
3460}
3461
3462static xmlNodePtr
3463xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3464/**
3465 * xmlCopyProp:
3466 * @target: the element where the attribute will be grafted
3467 * @cur: the attribute
3468 *
3469 * Do a copy of the attribute.
3470 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003471 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003472 */
3473xmlAttrPtr
3474xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3475 xmlAttrPtr ret;
3476
3477 if (cur == NULL) return(NULL);
3478 if (target != NULL)
3479 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3480 else if (cur->parent != NULL)
3481 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3482 else if (cur->children != NULL)
3483 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3484 else
3485 ret = xmlNewDocProp(NULL, cur->name, NULL);
3486 if (ret == NULL) return(NULL);
3487 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003488
Owen Taylor3473f882001-02-23 17:55:21 +00003489 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00003490 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003491/*
3492 * if (target->doc)
3493 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3494 * else if (cur->doc) / * target may not yet have a doc : KPI * /
3495 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
3496 * else
3497 * ns = NULL;
3498 * ret->ns = ns;
3499 */
3500 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3501 if (ns == NULL) {
3502 /*
3503 * Humm, we are copying an element whose namespace is defined
3504 * out of the new tree scope. Search it in the original tree
3505 * and add it at the top of the new tree
3506 */
3507 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3508 if (ns != NULL) {
3509 xmlNodePtr root = target;
3510 xmlNodePtr pred = NULL;
3511
3512 while (root->parent != NULL) {
3513 pred = root;
3514 root = root->parent;
3515 }
3516 if (root == (xmlNodePtr) target->doc) {
3517 /* correct possibly cycling above the document elt */
3518 root = pred;
3519 }
3520 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3521 }
3522 } else {
3523 /*
3524 * we have to find something appropriate here since
3525 * we cant be sure, that the namespce we found is identified
3526 * by the prefix
3527 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003528 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00003529 /* this is the nice case */
3530 ret->ns = ns;
3531 } else {
3532 /*
3533 * we are in trouble: we need a new reconcilied namespace.
3534 * This is expensive
3535 */
3536 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3537 }
3538 }
3539
Owen Taylor3473f882001-02-23 17:55:21 +00003540 } else
3541 ret->ns = NULL;
3542
3543 if (cur->children != NULL) {
3544 xmlNodePtr tmp;
3545
3546 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3547 ret->last = NULL;
3548 tmp = ret->children;
3549 while (tmp != NULL) {
3550 /* tmp->parent = (xmlNodePtr)ret; */
3551 if (tmp->next == NULL)
3552 ret->last = tmp;
3553 tmp = tmp->next;
3554 }
3555 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003556 /*
3557 * Try to handle IDs
3558 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003559 if ((target!= NULL) && (cur!= NULL) &&
3560 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003561 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3562 if (xmlIsID(cur->doc, cur->parent, cur)) {
3563 xmlChar *id;
3564
3565 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3566 if (id != NULL) {
3567 xmlAddID(NULL, target->doc, id, ret);
3568 xmlFree(id);
3569 }
3570 }
3571 }
Owen Taylor3473f882001-02-23 17:55:21 +00003572 return(ret);
3573}
3574
3575/**
3576 * xmlCopyPropList:
3577 * @target: the element where the attributes will be grafted
3578 * @cur: the first attribute
3579 *
3580 * Do a copy of an attribute list.
3581 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003582 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003583 */
3584xmlAttrPtr
3585xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3586 xmlAttrPtr ret = NULL;
3587 xmlAttrPtr p = NULL,q;
3588
3589 while (cur != NULL) {
3590 q = xmlCopyProp(target, cur);
3591 if (p == NULL) {
3592 ret = p = q;
3593 } else {
3594 p->next = q;
3595 q->prev = p;
3596 p = q;
3597 }
3598 cur = cur->next;
3599 }
3600 return(ret);
3601}
3602
3603/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003604 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003605 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003606 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003607 * tricky reason: namespaces. Doing a direct copy of a node
3608 * say RPM:Copyright without changing the namespace pointer to
3609 * something else can produce stale links. One way to do it is
3610 * to keep a reference counter but this doesn't work as soon
3611 * as one move the element or the subtree out of the scope of
3612 * the existing namespace. The actual solution seems to add
3613 * a copy of the namespace at the top of the copied tree if
3614 * not available in the subtree.
3615 * Hence two functions, the public front-end call the inner ones
3616 */
3617
3618static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003619xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003620 int recursive) {
3621 xmlNodePtr ret;
3622
3623 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003624 switch (node->type) {
3625 case XML_TEXT_NODE:
3626 case XML_CDATA_SECTION_NODE:
3627 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003628 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003629 case XML_ENTITY_REF_NODE:
3630 case XML_ENTITY_NODE:
3631 case XML_PI_NODE:
3632 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003633 case XML_XINCLUDE_START:
3634 case XML_XINCLUDE_END:
3635 break;
3636 case XML_ATTRIBUTE_NODE:
3637 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3638 case XML_NAMESPACE_DECL:
3639 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3640
Daniel Veillard39196eb2001-06-19 18:09:42 +00003641 case XML_DOCUMENT_NODE:
3642 case XML_HTML_DOCUMENT_NODE:
3643#ifdef LIBXML_DOCB_ENABLED
3644 case XML_DOCB_DOCUMENT_NODE:
3645#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003646 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00003647 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003648 case XML_NOTATION_NODE:
3649 case XML_DTD_NODE:
3650 case XML_ELEMENT_DECL:
3651 case XML_ATTRIBUTE_DECL:
3652 case XML_ENTITY_DECL:
3653 return(NULL);
3654 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003655
Owen Taylor3473f882001-02-23 17:55:21 +00003656 /*
3657 * Allocate a new node and fill the fields.
3658 */
3659 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3660 if (ret == NULL) {
3661 xmlGenericError(xmlGenericErrorContext,
3662 "xmlStaticCopyNode : malloc failed\n");
3663 return(NULL);
3664 }
3665 memset(ret, 0, sizeof(xmlNode));
3666 ret->type = node->type;
3667
3668 ret->doc = doc;
3669 ret->parent = parent;
3670 if (node->name == xmlStringText)
3671 ret->name = xmlStringText;
3672 else if (node->name == xmlStringTextNoenc)
3673 ret->name = xmlStringTextNoenc;
3674 else if (node->name == xmlStringComment)
3675 ret->name = xmlStringComment;
3676 else if (node->name != NULL)
3677 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003678 if ((node->type != XML_ELEMENT_NODE) &&
3679 (node->content != NULL) &&
3680 (node->type != XML_ENTITY_REF_NODE) &&
3681 (node->type != XML_XINCLUDE_END) &&
3682 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003683 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003684 }else{
3685 if (node->type == XML_ELEMENT_NODE)
3686 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00003687 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003688 if (parent != NULL) {
3689 xmlNodePtr tmp;
3690
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003691 /*
3692 * this is a tricky part for the node register thing:
3693 * in case ret does get coalesced in xmlAddChild
3694 * the deregister-node callback is called; so we register ret now already
3695 */
Daniel Veillarda880b122003-04-21 21:36:41 +00003696 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003697 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3698
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003699 tmp = xmlAddChild(parent, ret);
3700 /* node could have coalesced */
3701 if (tmp != ret)
3702 return(tmp);
3703 }
Owen Taylor3473f882001-02-23 17:55:21 +00003704
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003705 if (!recursive)
3706 goto out;
Owen Taylor3473f882001-02-23 17:55:21 +00003707 if (node->nsDef != NULL)
3708 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3709
3710 if (node->ns != NULL) {
3711 xmlNsPtr ns;
3712
3713 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3714 if (ns == NULL) {
3715 /*
3716 * Humm, we are copying an element whose namespace is defined
3717 * out of the new tree scope. Search it in the original tree
3718 * and add it at the top of the new tree
3719 */
3720 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3721 if (ns != NULL) {
3722 xmlNodePtr root = ret;
3723
3724 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003725 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003726 }
3727 } else {
3728 /*
3729 * reference the existing namespace definition in our own tree.
3730 */
3731 ret->ns = ns;
3732 }
3733 }
3734 if (node->properties != NULL)
3735 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003736 if (node->type == XML_ENTITY_REF_NODE) {
3737 if ((doc == NULL) || (node->doc != doc)) {
3738 /*
3739 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003740 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003741 * we cannot keep the reference. Try to find it in the
3742 * target document.
3743 */
3744 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3745 } else {
3746 ret->children = node->children;
3747 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003748 ret->last = ret->children;
3749 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003750 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003751 UPDATE_LAST_CHILD_AND_PARENT(ret)
3752 }
Daniel Veillard8a1b1852003-01-05 22:37:17 +00003753
3754out:
3755 /* if parent != NULL we already registered the node above */
3756 if (parent == NULL && xmlRegisterNodeDefaultValue)
3757 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003758 return(ret);
3759}
3760
3761static xmlNodePtr
3762xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3763 xmlNodePtr ret = NULL;
3764 xmlNodePtr p = NULL,q;
3765
3766 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003767 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003768 if (doc == NULL) {
3769 node = node->next;
3770 continue;
3771 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003772 if (doc->intSubset == NULL) {
3773 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3774 q->doc = doc;
3775 q->parent = parent;
3776 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003777 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003778 } else {
3779 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003780 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003781 }
3782 } else
3783 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003784 if (ret == NULL) {
3785 q->prev = NULL;
3786 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003787 } else if (p != q) {
3788 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003789 p->next = q;
3790 q->prev = p;
3791 p = q;
3792 }
3793 node = node->next;
3794 }
3795 return(ret);
3796}
3797
3798/**
3799 * xmlCopyNode:
3800 * @node: the node
3801 * @recursive: if 1 do a recursive copy.
3802 *
3803 * Do a copy of the node.
3804 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003805 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003806 */
3807xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003808xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003809 xmlNodePtr ret;
3810
3811 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3812 return(ret);
3813}
3814
3815/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003816 * xmlDocCopyNode:
3817 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003818 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003819 * @recursive: if 1 do a recursive copy.
3820 *
3821 * Do a copy of the node to a given document.
3822 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003823 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003824 */
3825xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003826xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003827 xmlNodePtr ret;
3828
3829 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3830 return(ret);
3831}
3832
3833/**
Owen Taylor3473f882001-02-23 17:55:21 +00003834 * xmlCopyNodeList:
3835 * @node: the first node in the list.
3836 *
3837 * Do a recursive copy of the node list.
3838 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003839 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003840 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003841xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003842 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3843 return(ret);
3844}
3845
3846/**
Owen Taylor3473f882001-02-23 17:55:21 +00003847 * xmlCopyDtd:
3848 * @dtd: the dtd
3849 *
3850 * Do a copy of the dtd.
3851 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003852 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003853 */
3854xmlDtdPtr
3855xmlCopyDtd(xmlDtdPtr dtd) {
3856 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003857 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003858
3859 if (dtd == NULL) return(NULL);
3860 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3861 if (ret == NULL) return(NULL);
3862 if (dtd->entities != NULL)
3863 ret->entities = (void *) xmlCopyEntitiesTable(
3864 (xmlEntitiesTablePtr) dtd->entities);
3865 if (dtd->notations != NULL)
3866 ret->notations = (void *) xmlCopyNotationTable(
3867 (xmlNotationTablePtr) dtd->notations);
3868 if (dtd->elements != NULL)
3869 ret->elements = (void *) xmlCopyElementTable(
3870 (xmlElementTablePtr) dtd->elements);
3871 if (dtd->attributes != NULL)
3872 ret->attributes = (void *) xmlCopyAttributeTable(
3873 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003874 if (dtd->pentities != NULL)
3875 ret->pentities = (void *) xmlCopyEntitiesTable(
3876 (xmlEntitiesTablePtr) dtd->pentities);
3877
3878 cur = dtd->children;
3879 while (cur != NULL) {
3880 q = NULL;
3881
3882 if (cur->type == XML_ENTITY_DECL) {
3883 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3884 switch (tmp->etype) {
3885 case XML_INTERNAL_GENERAL_ENTITY:
3886 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3887 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3888 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3889 break;
3890 case XML_INTERNAL_PARAMETER_ENTITY:
3891 case XML_EXTERNAL_PARAMETER_ENTITY:
3892 q = (xmlNodePtr)
3893 xmlGetParameterEntityFromDtd(ret, tmp->name);
3894 break;
3895 case XML_INTERNAL_PREDEFINED_ENTITY:
3896 break;
3897 }
3898 } else if (cur->type == XML_ELEMENT_DECL) {
3899 xmlElementPtr tmp = (xmlElementPtr) cur;
3900 q = (xmlNodePtr)
3901 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3902 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3903 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3904 q = (xmlNodePtr)
3905 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3906 } else if (cur->type == XML_COMMENT_NODE) {
3907 q = xmlCopyNode(cur, 0);
3908 }
3909
3910 if (q == NULL) {
3911 cur = cur->next;
3912 continue;
3913 }
3914
3915 if (p == NULL)
3916 ret->children = q;
3917 else
3918 p->next = q;
3919
3920 q->prev = p;
3921 q->parent = (xmlNodePtr) ret;
3922 q->next = NULL;
3923 ret->last = q;
3924 p = q;
3925 cur = cur->next;
3926 }
3927
Owen Taylor3473f882001-02-23 17:55:21 +00003928 return(ret);
3929}
3930
3931/**
3932 * xmlCopyDoc:
3933 * @doc: the document
3934 * @recursive: if 1 do a recursive copy.
3935 *
3936 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003937 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003938 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003939 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003940 */
3941xmlDocPtr
3942xmlCopyDoc(xmlDocPtr doc, int recursive) {
3943 xmlDocPtr ret;
3944
3945 if (doc == NULL) return(NULL);
3946 ret = xmlNewDoc(doc->version);
3947 if (ret == NULL) return(NULL);
3948 if (doc->name != NULL)
3949 ret->name = xmlMemStrdup(doc->name);
3950 if (doc->encoding != NULL)
3951 ret->encoding = xmlStrdup(doc->encoding);
3952 ret->charset = doc->charset;
3953 ret->compression = doc->compression;
3954 ret->standalone = doc->standalone;
3955 if (!recursive) return(ret);
3956
Daniel Veillardb33c2012001-04-25 12:59:04 +00003957 ret->last = NULL;
3958 ret->children = NULL;
3959 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003960 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003961 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003962 ret->intSubset->parent = ret;
3963 }
Owen Taylor3473f882001-02-23 17:55:21 +00003964 if (doc->oldNs != NULL)
3965 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3966 if (doc->children != NULL) {
3967 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003968
3969 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3970 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003971 ret->last = NULL;
3972 tmp = ret->children;
3973 while (tmp != NULL) {
3974 if (tmp->next == NULL)
3975 ret->last = tmp;
3976 tmp = tmp->next;
3977 }
3978 }
3979 return(ret);
3980}
3981
3982/************************************************************************
3983 * *
3984 * Content access functions *
3985 * *
3986 ************************************************************************/
3987
3988/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003989 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003990 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00003991 *
3992 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003993 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003994 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003995 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003996 */
3997long
3998xmlGetLineNo(xmlNodePtr node)
3999{
4000 long result = -1;
4001
4002 if (!node)
4003 return result;
4004 if (node->type == XML_ELEMENT_NODE)
4005 result = (long) node->content;
4006 else if ((node->prev != NULL) &&
4007 ((node->prev->type == XML_ELEMENT_NODE) ||
4008 (node->prev->type == XML_TEXT_NODE)))
4009 result = xmlGetLineNo(node->prev);
4010 else if ((node->parent != NULL) &&
4011 ((node->parent->type == XML_ELEMENT_NODE) ||
4012 (node->parent->type == XML_TEXT_NODE)))
4013 result = xmlGetLineNo(node->parent);
4014
4015 return result;
4016}
4017
4018/**
4019 * xmlGetNodePath:
4020 * @node: a node
4021 *
4022 * Build a structure based Path for the given node
4023 *
4024 * Returns the new path or NULL in case of error. The caller must free
4025 * the returned string
4026 */
4027xmlChar *
4028xmlGetNodePath(xmlNodePtr node)
4029{
4030 xmlNodePtr cur, tmp, next;
4031 xmlChar *buffer = NULL, *temp;
4032 size_t buf_len;
4033 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004034 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00004035 const char *name;
4036 char nametemp[100];
4037 int occur = 0;
4038
4039 if (node == NULL)
4040 return (NULL);
4041
4042 buf_len = 500;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004043 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004044 if (buffer == NULL)
4045 return (NULL);
Daniel Veillard3c908dc2003-04-19 00:07:51 +00004046 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
Daniel Veillard8faa7832001-11-26 15:58:08 +00004047 if (buf == NULL) {
4048 xmlFree(buffer);
4049 return (NULL);
4050 }
4051
4052 buffer[0] = 0;
4053 cur = node;
4054 do {
4055 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004056 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004057 occur = 0;
4058 if ((cur->type == XML_DOCUMENT_NODE) ||
4059 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4060 if (buffer[0] == '/')
4061 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004062 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004063 next = NULL;
4064 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004065 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004066 name = (const char *) cur->name;
4067 if (cur->ns) {
4068 snprintf(nametemp, sizeof(nametemp) - 1,
4069 "%s:%s", cur->ns->prefix, cur->name);
4070 nametemp[sizeof(nametemp) - 1] = 0;
4071 name = nametemp;
4072 }
4073 next = cur->parent;
4074
4075 /*
4076 * Thumbler index computation
Daniel Veillardc00cda82003-04-07 10:22:39 +00004077 * TODO: the ocurence test seems bogus for namespaced names
Daniel Veillard8faa7832001-11-26 15:58:08 +00004078 */
4079 tmp = cur->prev;
4080 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00004081 if ((tmp->type == XML_ELEMENT_NODE) &&
4082 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004083 occur++;
4084 tmp = tmp->prev;
4085 }
4086 if (occur == 0) {
4087 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004088 while (tmp != NULL && occur == 0) {
4089 if ((tmp->type == XML_ELEMENT_NODE) &&
4090 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00004091 occur++;
4092 tmp = tmp->next;
4093 }
4094 if (occur != 0)
4095 occur = 1;
4096 } else
4097 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00004098 } else if (cur->type == XML_COMMENT_NODE) {
4099 sep = "/";
4100 name = "comment()";
4101 next = cur->parent;
4102
4103 /*
4104 * Thumbler index computation
4105 */
4106 tmp = cur->prev;
4107 while (tmp != NULL) {
4108 if (tmp->type == XML_COMMENT_NODE)
4109 occur++;
4110 tmp = tmp->prev;
4111 }
4112 if (occur == 0) {
4113 tmp = cur->next;
4114 while (tmp != NULL && occur == 0) {
4115 if (tmp->type == XML_COMMENT_NODE)
4116 occur++;
4117 tmp = tmp->next;
4118 }
4119 if (occur != 0)
4120 occur = 1;
4121 } else
4122 occur++;
4123 } else if ((cur->type == XML_TEXT_NODE) ||
4124 (cur->type == XML_CDATA_SECTION_NODE)) {
4125 sep = "/";
4126 name = "text()";
4127 next = cur->parent;
4128
4129 /*
4130 * Thumbler index computation
4131 */
4132 tmp = cur->prev;
4133 while (tmp != NULL) {
4134 if ((cur->type == XML_TEXT_NODE) ||
4135 (cur->type == XML_CDATA_SECTION_NODE))
4136 occur++;
4137 tmp = tmp->prev;
4138 }
4139 if (occur == 0) {
4140 tmp = cur->next;
4141 while (tmp != NULL && occur == 0) {
4142 if ((cur->type == XML_TEXT_NODE) ||
4143 (cur->type == XML_CDATA_SECTION_NODE))
4144 occur++;
4145 tmp = tmp->next;
4146 }
4147 if (occur != 0)
4148 occur = 1;
4149 } else
4150 occur++;
4151 } else if (cur->type == XML_PI_NODE) {
4152 sep = "/";
4153 snprintf(nametemp, sizeof(nametemp) - 1,
4154 "processing-instruction('%s')", cur->name);
4155 nametemp[sizeof(nametemp) - 1] = 0;
4156 name = nametemp;
4157
4158 next = cur->parent;
4159
4160 /*
4161 * Thumbler index computation
4162 */
4163 tmp = cur->prev;
4164 while (tmp != NULL) {
4165 if ((tmp->type == XML_PI_NODE) &&
4166 (xmlStrEqual(cur->name, tmp->name)))
4167 occur++;
4168 tmp = tmp->prev;
4169 }
4170 if (occur == 0) {
4171 tmp = cur->next;
4172 while (tmp != NULL && occur == 0) {
4173 if ((tmp->type == XML_PI_NODE) &&
4174 (xmlStrEqual(cur->name, tmp->name)))
4175 occur++;
4176 tmp = tmp->next;
4177 }
4178 if (occur != 0)
4179 occur = 1;
4180 } else
4181 occur++;
4182
Daniel Veillard8faa7832001-11-26 15:58:08 +00004183 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004184 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00004185 name = (const char *) (((xmlAttrPtr) cur)->name);
4186 next = ((xmlAttrPtr) cur)->parent;
4187 } else {
4188 next = cur->parent;
4189 }
4190
4191 /*
4192 * Make sure there is enough room
4193 */
4194 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4195 buf_len =
4196 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4197 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4198 if (temp == NULL) {
4199 xmlFree(buf);
4200 xmlFree(buffer);
4201 return (NULL);
4202 }
4203 buffer = temp;
4204 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4205 if (temp == NULL) {
4206 xmlFree(buf);
4207 xmlFree(buffer);
4208 return (NULL);
4209 }
4210 buf = temp;
4211 }
4212 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004213 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004214 sep, name, (char *) buffer);
4215 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00004216 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00004217 sep, name, occur, (char *) buffer);
4218 snprintf((char *) buffer, buf_len, "%s", buf);
4219 cur = next;
4220 } while (cur != NULL);
4221 xmlFree(buf);
4222 return (buffer);
4223}
4224
4225/**
Owen Taylor3473f882001-02-23 17:55:21 +00004226 * xmlDocGetRootElement:
4227 * @doc: the document
4228 *
4229 * Get the root element of the document (doc->children is a list
4230 * containing possibly comments, PIs, etc ...).
4231 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004232 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00004233 */
4234xmlNodePtr
4235xmlDocGetRootElement(xmlDocPtr doc) {
4236 xmlNodePtr ret;
4237
4238 if (doc == NULL) return(NULL);
4239 ret = doc->children;
4240 while (ret != NULL) {
4241 if (ret->type == XML_ELEMENT_NODE)
4242 return(ret);
4243 ret = ret->next;
4244 }
4245 return(ret);
4246}
4247
4248/**
4249 * xmlDocSetRootElement:
4250 * @doc: the document
4251 * @root: the new document root element
4252 *
4253 * Set the root element of the document (doc->children is a list
4254 * containing possibly comments, PIs, etc ...).
4255 *
4256 * Returns the old root element if any was found
4257 */
4258xmlNodePtr
4259xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4260 xmlNodePtr old = NULL;
4261
4262 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00004263 if (root == NULL)
4264 return(NULL);
4265 xmlUnlinkNode(root);
4266 root->doc = doc;
4267 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00004268 old = doc->children;
4269 while (old != NULL) {
4270 if (old->type == XML_ELEMENT_NODE)
4271 break;
4272 old = old->next;
4273 }
4274 if (old == NULL) {
4275 if (doc->children == NULL) {
4276 doc->children = root;
4277 doc->last = root;
4278 } else {
4279 xmlAddSibling(doc->children, root);
4280 }
4281 } else {
4282 xmlReplaceNode(old, root);
4283 }
4284 return(old);
4285}
4286
4287/**
4288 * xmlNodeSetLang:
4289 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00004290 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00004291 *
4292 * Set the language of a node, i.e. the values of the xml:lang
4293 * attribute.
4294 */
4295void
4296xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004297 xmlNsPtr ns;
4298
Owen Taylor3473f882001-02-23 17:55:21 +00004299 if (cur == NULL) return;
4300 switch(cur->type) {
4301 case XML_TEXT_NODE:
4302 case XML_CDATA_SECTION_NODE:
4303 case XML_COMMENT_NODE:
4304 case XML_DOCUMENT_NODE:
4305 case XML_DOCUMENT_TYPE_NODE:
4306 case XML_DOCUMENT_FRAG_NODE:
4307 case XML_NOTATION_NODE:
4308 case XML_HTML_DOCUMENT_NODE:
4309 case XML_DTD_NODE:
4310 case XML_ELEMENT_DECL:
4311 case XML_ATTRIBUTE_DECL:
4312 case XML_ENTITY_DECL:
4313 case XML_PI_NODE:
4314 case XML_ENTITY_REF_NODE:
4315 case XML_ENTITY_NODE:
4316 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004317#ifdef LIBXML_DOCB_ENABLED
4318 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004319#endif
4320 case XML_XINCLUDE_START:
4321 case XML_XINCLUDE_END:
4322 return;
4323 case XML_ELEMENT_NODE:
4324 case XML_ATTRIBUTE_NODE:
4325 break;
4326 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004327 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4328 if (ns == NULL)
4329 return;
4330 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00004331}
4332
4333/**
4334 * xmlNodeGetLang:
4335 * @cur: the node being checked
4336 *
4337 * Searches the language of a node, i.e. the values of the xml:lang
4338 * attribute or the one carried by the nearest ancestor.
4339 *
4340 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004341 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004342 */
4343xmlChar *
4344xmlNodeGetLang(xmlNodePtr cur) {
4345 xmlChar *lang;
4346
4347 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00004348 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004349 if (lang != NULL)
4350 return(lang);
4351 cur = cur->parent;
4352 }
4353 return(NULL);
4354}
4355
4356
4357/**
4358 * xmlNodeSetSpacePreserve:
4359 * @cur: the node being changed
4360 * @val: the xml:space value ("0": default, 1: "preserve")
4361 *
4362 * Set (or reset) the space preserving behaviour of a node, i.e. the
4363 * value of the xml:space attribute.
4364 */
4365void
4366xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004367 xmlNsPtr ns;
4368
Owen Taylor3473f882001-02-23 17:55:21 +00004369 if (cur == NULL) return;
4370 switch(cur->type) {
4371 case XML_TEXT_NODE:
4372 case XML_CDATA_SECTION_NODE:
4373 case XML_COMMENT_NODE:
4374 case XML_DOCUMENT_NODE:
4375 case XML_DOCUMENT_TYPE_NODE:
4376 case XML_DOCUMENT_FRAG_NODE:
4377 case XML_NOTATION_NODE:
4378 case XML_HTML_DOCUMENT_NODE:
4379 case XML_DTD_NODE:
4380 case XML_ELEMENT_DECL:
4381 case XML_ATTRIBUTE_DECL:
4382 case XML_ENTITY_DECL:
4383 case XML_PI_NODE:
4384 case XML_ENTITY_REF_NODE:
4385 case XML_ENTITY_NODE:
4386 case XML_NAMESPACE_DECL:
4387 case XML_XINCLUDE_START:
4388 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004389#ifdef LIBXML_DOCB_ENABLED
4390 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004391#endif
4392 return;
4393 case XML_ELEMENT_NODE:
4394 case XML_ATTRIBUTE_NODE:
4395 break;
4396 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004397 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4398 if (ns == NULL)
4399 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004400 switch (val) {
4401 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004402 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00004403 break;
4404 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004405 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00004406 break;
4407 }
4408}
4409
4410/**
4411 * xmlNodeGetSpacePreserve:
4412 * @cur: the node being checked
4413 *
4414 * Searches the space preserving behaviour of a node, i.e. the values
4415 * of the xml:space attribute or the one carried by the nearest
4416 * ancestor.
4417 *
Daniel Veillardd1640922001-12-17 15:30:10 +00004418 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00004419 */
4420int
4421xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4422 xmlChar *space;
4423
4424 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004425 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00004426 if (space != NULL) {
4427 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4428 xmlFree(space);
4429 return(1);
4430 }
4431 if (xmlStrEqual(space, BAD_CAST "default")) {
4432 xmlFree(space);
4433 return(0);
4434 }
4435 xmlFree(space);
4436 }
4437 cur = cur->parent;
4438 }
4439 return(-1);
4440}
4441
4442/**
4443 * xmlNodeSetName:
4444 * @cur: the node being changed
4445 * @name: the new tag name
4446 *
4447 * Set (or reset) the name of a node.
4448 */
4449void
4450xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
4451 if (cur == NULL) return;
4452 if (name == NULL) return;
4453 switch(cur->type) {
4454 case XML_TEXT_NODE:
4455 case XML_CDATA_SECTION_NODE:
4456 case XML_COMMENT_NODE:
4457 case XML_DOCUMENT_TYPE_NODE:
4458 case XML_DOCUMENT_FRAG_NODE:
4459 case XML_NOTATION_NODE:
4460 case XML_HTML_DOCUMENT_NODE:
4461 case XML_NAMESPACE_DECL:
4462 case XML_XINCLUDE_START:
4463 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004464#ifdef LIBXML_DOCB_ENABLED
4465 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004466#endif
4467 return;
4468 case XML_ELEMENT_NODE:
4469 case XML_ATTRIBUTE_NODE:
4470 case XML_PI_NODE:
4471 case XML_ENTITY_REF_NODE:
4472 case XML_ENTITY_NODE:
4473 case XML_DTD_NODE:
4474 case XML_DOCUMENT_NODE:
4475 case XML_ELEMENT_DECL:
4476 case XML_ATTRIBUTE_DECL:
4477 case XML_ENTITY_DECL:
4478 break;
4479 }
4480 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4481 cur->name = xmlStrdup(name);
4482}
4483
4484/**
4485 * xmlNodeSetBase:
4486 * @cur: the node being changed
4487 * @uri: the new base URI
4488 *
4489 * Set (or reset) the base URI of a node, i.e. the value of the
4490 * xml:base attribute.
4491 */
4492void
4493xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004494 xmlNsPtr ns;
4495
Owen Taylor3473f882001-02-23 17:55:21 +00004496 if (cur == NULL) return;
4497 switch(cur->type) {
4498 case XML_TEXT_NODE:
4499 case XML_CDATA_SECTION_NODE:
4500 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004501 case XML_DOCUMENT_TYPE_NODE:
4502 case XML_DOCUMENT_FRAG_NODE:
4503 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004504 case XML_DTD_NODE:
4505 case XML_ELEMENT_DECL:
4506 case XML_ATTRIBUTE_DECL:
4507 case XML_ENTITY_DECL:
4508 case XML_PI_NODE:
4509 case XML_ENTITY_REF_NODE:
4510 case XML_ENTITY_NODE:
4511 case XML_NAMESPACE_DECL:
4512 case XML_XINCLUDE_START:
4513 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00004514 return;
4515 case XML_ELEMENT_NODE:
4516 case XML_ATTRIBUTE_NODE:
4517 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00004518 case XML_DOCUMENT_NODE:
4519#ifdef LIBXML_DOCB_ENABLED
4520 case XML_DOCB_DOCUMENT_NODE:
4521#endif
4522 case XML_HTML_DOCUMENT_NODE: {
4523 xmlDocPtr doc = (xmlDocPtr) cur;
4524
4525 if (doc->URL != NULL)
4526 xmlFree((xmlChar *) doc->URL);
4527 if (uri == NULL)
4528 doc->URL = NULL;
4529 else
4530 doc->URL = xmlStrdup(uri);
4531 return;
4532 }
Owen Taylor3473f882001-02-23 17:55:21 +00004533 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004534
4535 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4536 if (ns == NULL)
4537 return;
4538 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00004539}
4540
4541/**
Owen Taylor3473f882001-02-23 17:55:21 +00004542 * xmlNodeGetBase:
4543 * @doc: the document the node pertains to
4544 * @cur: the node being checked
4545 *
4546 * Searches for the BASE URL. The code should work on both XML
4547 * and HTML document even if base mechanisms are completely different.
4548 * It returns the base as defined in RFC 2396 sections
4549 * 5.1.1. Base URI within Document Content
4550 * and
4551 * 5.1.2. Base URI from the Encapsulating Entity
4552 * However it does not return the document base (5.1.3), use
4553 * xmlDocumentGetBase() for this
4554 *
4555 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004556 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004557 */
4558xmlChar *
4559xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004560 xmlChar *oldbase = NULL;
4561 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00004562
4563 if ((cur == NULL) && (doc == NULL))
4564 return(NULL);
4565 if (doc == NULL) doc = cur->doc;
4566 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4567 cur = doc->children;
4568 while ((cur != NULL) && (cur->name != NULL)) {
4569 if (cur->type != XML_ELEMENT_NODE) {
4570 cur = cur->next;
4571 continue;
4572 }
4573 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4574 cur = cur->children;
4575 continue;
4576 }
4577 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4578 cur = cur->children;
4579 continue;
4580 }
4581 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4582 return(xmlGetProp(cur, BAD_CAST "href"));
4583 }
4584 cur = cur->next;
4585 }
4586 return(NULL);
4587 }
4588 while (cur != NULL) {
4589 if (cur->type == XML_ENTITY_DECL) {
4590 xmlEntityPtr ent = (xmlEntityPtr) cur;
4591 return(xmlStrdup(ent->URI));
4592 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004593 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004594 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004595 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004596 if (oldbase != NULL) {
4597 newbase = xmlBuildURI(oldbase, base);
4598 if (newbase != NULL) {
4599 xmlFree(oldbase);
4600 xmlFree(base);
4601 oldbase = newbase;
4602 } else {
4603 xmlFree(oldbase);
4604 xmlFree(base);
4605 return(NULL);
4606 }
4607 } else {
4608 oldbase = base;
4609 }
4610 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4611 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4612 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4613 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004614 }
4615 }
Owen Taylor3473f882001-02-23 17:55:21 +00004616 cur = cur->parent;
4617 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004618 if ((doc != NULL) && (doc->URL != NULL)) {
4619 if (oldbase == NULL)
4620 return(xmlStrdup(doc->URL));
4621 newbase = xmlBuildURI(oldbase, doc->URL);
4622 xmlFree(oldbase);
4623 return(newbase);
4624 }
4625 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004626}
4627
4628/**
4629 * xmlNodeGetContent:
4630 * @cur: the node being read
4631 *
4632 * Read the value of a node, this can be either the text carried
4633 * directly by this node if it's a TEXT node or the aggregate string
4634 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004635 * Entity references are substituted.
4636 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004637 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004638 */
4639xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004640xmlNodeGetContent(xmlNodePtr cur)
4641{
4642 if (cur == NULL)
4643 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004644 switch (cur->type) {
4645 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004646 case XML_ELEMENT_NODE:{
4647 xmlNodePtr tmp = cur;
4648 xmlBufferPtr buffer;
4649 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004650
Daniel Veillard814a76d2003-01-23 18:24:20 +00004651 buffer = xmlBufferCreateSize(64);
Daniel Veillard7646b182002-04-20 06:41:40 +00004652 if (buffer == NULL)
4653 return (NULL);
4654 while (tmp != NULL) {
4655 switch (tmp->type) {
4656 case XML_CDATA_SECTION_NODE:
4657 case XML_TEXT_NODE:
4658 if (tmp->content != NULL)
4659 xmlBufferCat(buffer, tmp->content);
4660 break;
4661 case XML_ENTITY_REF_NODE:{
4662 /* recursive substitution of entity references */
4663 xmlChar *cont = xmlNodeGetContent(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00004664
Daniel Veillard7646b182002-04-20 06:41:40 +00004665 if (cont) {
4666 xmlBufferCat(buffer,
4667 (const xmlChar *) cont);
4668 xmlFree(cont);
4669 }
4670 break;
4671 }
4672 default:
4673 break;
4674 }
4675 /*
4676 * Skip to next node
4677 */
4678 if (tmp->children != NULL) {
4679 if (tmp->children->type != XML_ENTITY_DECL) {
4680 tmp = tmp->children;
4681 continue;
4682 }
4683 }
4684 if (tmp == cur)
4685 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00004686
Daniel Veillard7646b182002-04-20 06:41:40 +00004687 if (tmp->next != NULL) {
4688 tmp = tmp->next;
4689 continue;
4690 }
4691
4692 do {
4693 tmp = tmp->parent;
4694 if (tmp == NULL)
4695 break;
4696 if (tmp == cur) {
4697 tmp = NULL;
4698 break;
4699 }
4700 if (tmp->next != NULL) {
4701 tmp = tmp->next;
4702 break;
4703 }
4704 } while (tmp != NULL);
4705 }
4706 ret = buffer->content;
4707 buffer->content = NULL;
4708 xmlBufferFree(buffer);
4709 return (ret);
4710 }
4711 case XML_ATTRIBUTE_NODE:{
4712 xmlAttrPtr attr = (xmlAttrPtr) cur;
4713
4714 if (attr->parent != NULL)
4715 return (xmlNodeListGetString
4716 (attr->parent->doc, attr->children, 1));
4717 else
4718 return (xmlNodeListGetString(NULL, attr->children, 1));
4719 break;
4720 }
Owen Taylor3473f882001-02-23 17:55:21 +00004721 case XML_COMMENT_NODE:
4722 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004723 if (cur->content != NULL)
4724 return (xmlStrdup(cur->content));
4725 return (NULL);
4726 case XML_ENTITY_REF_NODE:{
4727 xmlEntityPtr ent;
4728 xmlNodePtr tmp;
4729 xmlBufferPtr buffer;
4730 xmlChar *ret;
4731
4732 /* lookup entity declaration */
4733 ent = xmlGetDocEntity(cur->doc, cur->name);
4734 if (ent == NULL)
4735 return (NULL);
4736
4737 buffer = xmlBufferCreate();
4738 if (buffer == NULL)
4739 return (NULL);
4740
4741 /* an entity content can be any "well balanced chunk",
4742 * i.e. the result of the content [43] production:
4743 * http://www.w3.org/TR/REC-xml#NT-content
4744 * -> we iterate through child nodes and recursive call
4745 * xmlNodeGetContent() which handles all possible node types */
4746 tmp = ent->children;
4747 while (tmp) {
4748 xmlChar *cont = xmlNodeGetContent(tmp);
4749
4750 if (cont) {
4751 xmlBufferCat(buffer, (const xmlChar *) cont);
4752 xmlFree(cont);
4753 }
4754 tmp = tmp->next;
4755 }
4756
4757 ret = buffer->content;
4758 buffer->content = NULL;
4759 xmlBufferFree(buffer);
4760 return (ret);
4761 }
Owen Taylor3473f882001-02-23 17:55:21 +00004762 case XML_ENTITY_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004763 case XML_DOCUMENT_TYPE_NODE:
4764 case XML_NOTATION_NODE:
4765 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004766 case XML_XINCLUDE_START:
4767 case XML_XINCLUDE_END:
Daniel Veillard9adc0462003-03-24 18:39:54 +00004768 return (NULL);
4769 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004770#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004771 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004772#endif
Daniel Veillard9adc0462003-03-24 18:39:54 +00004773 case XML_HTML_DOCUMENT_NODE: {
4774 xmlChar *tmp;
4775 xmlChar *res = NULL;
4776
4777 cur = cur->children;
4778 while (cur!= NULL) {
4779 if ((cur->type == XML_ELEMENT_NODE) ||
4780 (cur->type == XML_TEXT_NODE) ||
4781 (cur->type == XML_CDATA_SECTION_NODE)) {
4782 tmp = xmlNodeGetContent(cur);
4783 if (tmp != NULL) {
4784 if (res == NULL)
4785 res = tmp;
4786 else {
4787 res = xmlStrcat(res, tmp);
4788 xmlFree(tmp);
4789 }
4790 }
4791 }
4792 cur = cur->next;
4793 }
4794 return(res);
4795 }
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004796 case XML_NAMESPACE_DECL: {
4797 xmlChar *tmp;
4798
4799 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4800 return (tmp);
4801 }
Owen Taylor3473f882001-02-23 17:55:21 +00004802 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004803 /* TODO !!! */
4804 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004805 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004806 /* TODO !!! */
4807 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004808 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004809 /* TODO !!! */
4810 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004811 case XML_CDATA_SECTION_NODE:
4812 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004813 if (cur->content != NULL)
4814 return (xmlStrdup(cur->content));
4815 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004816 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004817 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004818}
Owen Taylor3473f882001-02-23 17:55:21 +00004819/**
4820 * xmlNodeSetContent:
4821 * @cur: the node being modified
4822 * @content: the new value of the content
4823 *
4824 * Replace the content of a node.
4825 */
4826void
4827xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4828 if (cur == NULL) {
4829#ifdef DEBUG_TREE
4830 xmlGenericError(xmlGenericErrorContext,
4831 "xmlNodeSetContent : node == NULL\n");
4832#endif
4833 return;
4834 }
4835 switch (cur->type) {
4836 case XML_DOCUMENT_FRAG_NODE:
4837 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004838 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004839 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4840 cur->children = xmlStringGetNodeList(cur->doc, content);
4841 UPDATE_LAST_CHILD_AND_PARENT(cur)
4842 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004843 case XML_TEXT_NODE:
4844 case XML_CDATA_SECTION_NODE:
4845 case XML_ENTITY_REF_NODE:
4846 case XML_ENTITY_NODE:
4847 case XML_PI_NODE:
4848 case XML_COMMENT_NODE:
4849 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004850 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004851 }
4852 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4853 cur->last = cur->children = NULL;
4854 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004855 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00004856 } else
4857 cur->content = NULL;
4858 break;
4859 case XML_DOCUMENT_NODE:
4860 case XML_HTML_DOCUMENT_NODE:
4861 case XML_DOCUMENT_TYPE_NODE:
4862 case XML_XINCLUDE_START:
4863 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004864#ifdef LIBXML_DOCB_ENABLED
4865 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004866#endif
4867 break;
4868 case XML_NOTATION_NODE:
4869 break;
4870 case XML_DTD_NODE:
4871 break;
4872 case XML_NAMESPACE_DECL:
4873 break;
4874 case XML_ELEMENT_DECL:
4875 /* TODO !!! */
4876 break;
4877 case XML_ATTRIBUTE_DECL:
4878 /* TODO !!! */
4879 break;
4880 case XML_ENTITY_DECL:
4881 /* TODO !!! */
4882 break;
4883 }
4884}
4885
4886/**
4887 * xmlNodeSetContentLen:
4888 * @cur: the node being modified
4889 * @content: the new value of the content
4890 * @len: the size of @content
4891 *
4892 * Replace the content of a node.
4893 */
4894void
4895xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4896 if (cur == NULL) {
4897#ifdef DEBUG_TREE
4898 xmlGenericError(xmlGenericErrorContext,
4899 "xmlNodeSetContentLen : node == NULL\n");
4900#endif
4901 return;
4902 }
4903 switch (cur->type) {
4904 case XML_DOCUMENT_FRAG_NODE:
4905 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004906 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004907 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4908 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
4909 UPDATE_LAST_CHILD_AND_PARENT(cur)
4910 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004911 case XML_TEXT_NODE:
4912 case XML_CDATA_SECTION_NODE:
4913 case XML_ENTITY_REF_NODE:
4914 case XML_ENTITY_NODE:
4915 case XML_PI_NODE:
4916 case XML_COMMENT_NODE:
4917 case XML_NOTATION_NODE:
4918 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004919 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004920 }
4921 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4922 cur->children = cur->last = NULL;
4923 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004924 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004925 } else
4926 cur->content = NULL;
4927 break;
4928 case XML_DOCUMENT_NODE:
4929 case XML_DTD_NODE:
4930 case XML_HTML_DOCUMENT_NODE:
4931 case XML_DOCUMENT_TYPE_NODE:
4932 case XML_NAMESPACE_DECL:
4933 case XML_XINCLUDE_START:
4934 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004935#ifdef LIBXML_DOCB_ENABLED
4936 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004937#endif
4938 break;
4939 case XML_ELEMENT_DECL:
4940 /* TODO !!! */
4941 break;
4942 case XML_ATTRIBUTE_DECL:
4943 /* TODO !!! */
4944 break;
4945 case XML_ENTITY_DECL:
4946 /* TODO !!! */
4947 break;
4948 }
4949}
4950
4951/**
4952 * xmlNodeAddContentLen:
4953 * @cur: the node being modified
4954 * @content: extra content
4955 * @len: the size of @content
4956 *
4957 * Append the extra substring to the node content.
4958 */
4959void
4960xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4961 if (cur == NULL) {
4962#ifdef DEBUG_TREE
4963 xmlGenericError(xmlGenericErrorContext,
4964 "xmlNodeAddContentLen : node == NULL\n");
4965#endif
4966 return;
4967 }
4968 if (len <= 0) return;
4969 switch (cur->type) {
4970 case XML_DOCUMENT_FRAG_NODE:
4971 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004972 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004973
Daniel Veillard7db37732001-07-12 01:20:08 +00004974 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004975 newNode = xmlNewTextLen(content, len);
4976 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004977 tmp = xmlAddChild(cur, newNode);
4978 if (tmp != newNode)
4979 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004980 if ((last != NULL) && (last->next == newNode)) {
4981 xmlTextMerge(last, newNode);
4982 }
4983 }
4984 break;
4985 }
4986 case XML_ATTRIBUTE_NODE:
4987 break;
4988 case XML_TEXT_NODE:
4989 case XML_CDATA_SECTION_NODE:
4990 case XML_ENTITY_REF_NODE:
4991 case XML_ENTITY_NODE:
4992 case XML_PI_NODE:
4993 case XML_COMMENT_NODE:
4994 case XML_NOTATION_NODE:
4995 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004996 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004997 }
4998 case XML_DOCUMENT_NODE:
4999 case XML_DTD_NODE:
5000 case XML_HTML_DOCUMENT_NODE:
5001 case XML_DOCUMENT_TYPE_NODE:
5002 case XML_NAMESPACE_DECL:
5003 case XML_XINCLUDE_START:
5004 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005005#ifdef LIBXML_DOCB_ENABLED
5006 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005007#endif
5008 break;
5009 case XML_ELEMENT_DECL:
5010 case XML_ATTRIBUTE_DECL:
5011 case XML_ENTITY_DECL:
5012 break;
5013 }
5014}
5015
5016/**
5017 * xmlNodeAddContent:
5018 * @cur: the node being modified
5019 * @content: extra content
5020 *
5021 * Append the extra substring to the node content.
5022 */
5023void
5024xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5025 int len;
5026
5027 if (cur == NULL) {
5028#ifdef DEBUG_TREE
5029 xmlGenericError(xmlGenericErrorContext,
5030 "xmlNodeAddContent : node == NULL\n");
5031#endif
5032 return;
5033 }
5034 if (content == NULL) return;
5035 len = xmlStrlen(content);
5036 xmlNodeAddContentLen(cur, content, len);
5037}
5038
5039/**
5040 * xmlTextMerge:
5041 * @first: the first text node
5042 * @second: the second text node being merged
5043 *
5044 * Merge two text nodes into one
5045 * Returns the first text node augmented
5046 */
5047xmlNodePtr
5048xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5049 if (first == NULL) return(second);
5050 if (second == NULL) return(first);
5051 if (first->type != XML_TEXT_NODE) return(first);
5052 if (second->type != XML_TEXT_NODE) return(first);
5053 if (second->name != first->name)
5054 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00005055 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00005056 xmlUnlinkNode(second);
5057 xmlFreeNode(second);
5058 return(first);
5059}
5060
5061/**
5062 * xmlGetNsList:
5063 * @doc: the document
5064 * @node: the current node
5065 *
5066 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00005067 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00005068 * that need to be freed by the caller or NULL if no
5069 * namespace if defined
5070 */
5071xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00005072xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5073{
Owen Taylor3473f882001-02-23 17:55:21 +00005074 xmlNsPtr cur;
5075 xmlNsPtr *ret = NULL;
5076 int nbns = 0;
5077 int maxns = 10;
5078 int i;
5079
5080 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00005081 if (node->type == XML_ELEMENT_NODE) {
5082 cur = node->nsDef;
5083 while (cur != NULL) {
5084 if (ret == NULL) {
5085 ret =
5086 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5087 sizeof(xmlNsPtr));
5088 if (ret == NULL) {
5089 xmlGenericError(xmlGenericErrorContext,
5090 "xmlGetNsList : out of memory!\n");
5091 return (NULL);
5092 }
5093 ret[nbns] = NULL;
5094 }
5095 for (i = 0; i < nbns; i++) {
5096 if ((cur->prefix == ret[i]->prefix) ||
5097 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5098 break;
5099 }
5100 if (i >= nbns) {
5101 if (nbns >= maxns) {
5102 maxns *= 2;
5103 ret = (xmlNsPtr *) xmlRealloc(ret,
5104 (maxns +
5105 1) *
5106 sizeof(xmlNsPtr));
5107 if (ret == NULL) {
5108 xmlGenericError(xmlGenericErrorContext,
5109 "xmlGetNsList : realloc failed!\n");
5110 return (NULL);
5111 }
5112 }
5113 ret[nbns++] = cur;
5114 ret[nbns] = NULL;
5115 }
Owen Taylor3473f882001-02-23 17:55:21 +00005116
Daniel Veillard77044732001-06-29 21:31:07 +00005117 cur = cur->next;
5118 }
5119 }
5120 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00005121 }
Daniel Veillard77044732001-06-29 21:31:07 +00005122 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005123}
5124
5125/**
5126 * xmlSearchNs:
5127 * @doc: the document
5128 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00005129 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00005130 *
5131 * Search a Ns registered under a given name space for a document.
5132 * recurse on the parents until it finds the defined namespace
5133 * or return NULL otherwise.
5134 * @nameSpace can be NULL, this is a search for the default namespace.
5135 * We don't allow to cross entities boundaries. If you don't declare
5136 * the namespace within those you will be in troubles !!! A warning
5137 * is generated to cover this case.
5138 *
5139 * Returns the namespace pointer or NULL.
5140 */
5141xmlNsPtr
5142xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
5143 xmlNsPtr cur;
5144
5145 if (node == NULL) return(NULL);
5146 if ((nameSpace != NULL) &&
5147 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005148 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5149 /*
5150 * The XML-1.0 namespace is normally held on the root
5151 * element. In this case exceptionally create it on the
5152 * node element.
5153 */
5154 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5155 if (cur == NULL) {
5156 xmlGenericError(xmlGenericErrorContext,
5157 "xmlSearchNs : malloc failed\n");
5158 return(NULL);
5159 }
5160 memset(cur, 0, sizeof(xmlNs));
5161 cur->type = XML_LOCAL_NAMESPACE;
5162 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5163 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5164 cur->next = node->nsDef;
5165 node->nsDef = cur;
5166 return(cur);
5167 }
Owen Taylor3473f882001-02-23 17:55:21 +00005168 if (doc->oldNs == NULL) {
5169 /*
5170 * Allocate a new Namespace and fill the fields.
5171 */
5172 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5173 if (doc->oldNs == NULL) {
5174 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005175 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005176 return(NULL);
5177 }
5178 memset(doc->oldNs, 0, sizeof(xmlNs));
5179 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5180
5181 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5182 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5183 }
5184 return(doc->oldNs);
5185 }
5186 while (node != NULL) {
5187 if ((node->type == XML_ENTITY_REF_NODE) ||
5188 (node->type == XML_ENTITY_NODE) ||
5189 (node->type == XML_ENTITY_DECL))
5190 return(NULL);
5191 if (node->type == XML_ELEMENT_NODE) {
5192 cur = node->nsDef;
5193 while (cur != NULL) {
5194 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5195 (cur->href != NULL))
5196 return(cur);
5197 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5198 (cur->href != NULL) &&
5199 (xmlStrEqual(cur->prefix, nameSpace)))
5200 return(cur);
5201 cur = cur->next;
5202 }
5203 }
5204 node = node->parent;
5205 }
5206 return(NULL);
5207}
5208
5209/**
5210 * xmlSearchNsByHref:
5211 * @doc: the document
5212 * @node: the current node
5213 * @href: the namespace value
5214 *
5215 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5216 * the defined namespace or return NULL otherwise.
5217 * Returns the namespace pointer or NULL.
5218 */
5219xmlNsPtr
5220xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
5221 xmlNsPtr cur;
5222 xmlNodePtr orig = node;
5223
5224 if ((node == NULL) || (href == NULL)) return(NULL);
5225 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00005226 /*
5227 * Only the document can hold the XML spec namespace.
5228 */
Daniel Veillardc1a0da32002-08-14 08:32:18 +00005229 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5230 /*
5231 * The XML-1.0 namespace is normally held on the root
5232 * element. In this case exceptionally create it on the
5233 * node element.
5234 */
5235 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5236 if (cur == NULL) {
5237 xmlGenericError(xmlGenericErrorContext,
5238 "xmlSearchNs : malloc failed\n");
5239 return(NULL);
5240 }
5241 memset(cur, 0, sizeof(xmlNs));
5242 cur->type = XML_LOCAL_NAMESPACE;
5243 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5244 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5245 cur->next = node->nsDef;
5246 node->nsDef = cur;
5247 return(cur);
5248 }
Owen Taylor3473f882001-02-23 17:55:21 +00005249 if (doc->oldNs == NULL) {
5250 /*
5251 * Allocate a new Namespace and fill the fields.
5252 */
5253 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5254 if (doc->oldNs == NULL) {
5255 xmlGenericError(xmlGenericErrorContext,
5256 "xmlSearchNsByHref : malloc failed\n");
5257 return(NULL);
5258 }
5259 memset(doc->oldNs, 0, sizeof(xmlNs));
5260 doc->oldNs->type = XML_LOCAL_NAMESPACE;
5261
5262 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
5263 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
5264 }
5265 return(doc->oldNs);
5266 }
5267 while (node != NULL) {
5268 cur = node->nsDef;
5269 while (cur != NULL) {
5270 if ((cur->href != NULL) && (href != NULL) &&
5271 (xmlStrEqual(cur->href, href))) {
5272 /*
5273 * Check that the prefix is not shadowed between orig and node
5274 */
5275 xmlNodePtr check = orig;
5276 xmlNsPtr tst;
5277
5278 while (check != node) {
5279 tst = check->nsDef;
5280 while (tst != NULL) {
5281 if ((tst->prefix == NULL) && (cur->prefix == NULL))
5282 goto shadowed;
5283 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
5284 (xmlStrEqual(tst->prefix, cur->prefix)))
5285 goto shadowed;
5286 tst = tst->next;
5287 }
5288 check = check->parent;
5289 }
5290 return(cur);
5291 }
5292shadowed:
5293 cur = cur->next;
5294 }
5295 node = node->parent;
5296 }
5297 return(NULL);
5298}
5299
5300/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005301 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005302 * @doc: the document
5303 * @tree: a node expected to hold the new namespace
5304 * @ns: the original namespace
5305 *
5306 * This function tries to locate a namespace definition in a tree
5307 * ancestors, or create a new namespace definition node similar to
5308 * @ns trying to reuse the same prefix. However if the given prefix is
5309 * null (default namespace) or reused within the subtree defined by
5310 * @tree or on one of its ancestors then a new prefix is generated.
5311 * Returns the (new) namespace definition or NULL in case of error
5312 */
5313xmlNsPtr
5314xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5315 xmlNsPtr def;
5316 xmlChar prefix[50];
5317 int counter = 1;
5318
5319 if (tree == NULL) {
5320#ifdef DEBUG_TREE
5321 xmlGenericError(xmlGenericErrorContext,
5322 "xmlNewReconciliedNs : tree == NULL\n");
5323#endif
5324 return(NULL);
5325 }
5326 if (ns == NULL) {
5327#ifdef DEBUG_TREE
5328 xmlGenericError(xmlGenericErrorContext,
5329 "xmlNewReconciliedNs : ns == NULL\n");
5330#endif
5331 return(NULL);
5332 }
5333 /*
5334 * Search an existing namespace definition inherited.
5335 */
5336 def = xmlSearchNsByHref(doc, tree, ns->href);
5337 if (def != NULL)
5338 return(def);
5339
5340 /*
5341 * Find a close prefix which is not already in use.
5342 * Let's strip namespace prefixes longer than 20 chars !
5343 */
Daniel Veillardf742d342002-03-07 00:05:35 +00005344 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005345 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00005346 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005347 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00005348
Owen Taylor3473f882001-02-23 17:55:21 +00005349 def = xmlSearchNs(doc, tree, prefix);
5350 while (def != NULL) {
5351 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00005352 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005353 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00005354 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00005355 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00005356 def = xmlSearchNs(doc, tree, prefix);
5357 }
5358
5359 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005360 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00005361 */
5362 def = xmlNewNs(tree, ns->href, prefix);
5363 return(def);
5364}
5365
5366/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005367 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00005368 * @doc: the document
5369 * @tree: a node defining the subtree to reconciliate
5370 *
5371 * This function checks that all the namespaces declared within the given
5372 * tree are properly declared. This is needed for example after Copy or Cut
5373 * and then paste operations. The subtree may still hold pointers to
5374 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00005375 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00005376 * the new environment. If not possible the new namespaces are redeclared
5377 * on @tree at the top of the given subtree.
5378 * Returns the number of namespace declarations created or -1 in case of error.
5379 */
5380int
5381xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5382 xmlNsPtr *oldNs = NULL;
5383 xmlNsPtr *newNs = NULL;
5384 int sizeCache = 0;
5385 int nbCache = 0;
5386
5387 xmlNsPtr n;
5388 xmlNodePtr node = tree;
5389 xmlAttrPtr attr;
5390 int ret = 0, i;
5391
5392 while (node != NULL) {
5393 /*
5394 * Reconciliate the node namespace
5395 */
5396 if (node->ns != NULL) {
5397 /*
5398 * initialize the cache if needed
5399 */
5400 if (sizeCache == 0) {
5401 sizeCache = 10;
5402 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5403 sizeof(xmlNsPtr));
5404 if (oldNs == NULL) {
5405 xmlGenericError(xmlGenericErrorContext,
5406 "xmlReconciliateNs : memory pbm\n");
5407 return(-1);
5408 }
5409 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5410 sizeof(xmlNsPtr));
5411 if (newNs == NULL) {
5412 xmlGenericError(xmlGenericErrorContext,
5413 "xmlReconciliateNs : memory pbm\n");
5414 xmlFree(oldNs);
5415 return(-1);
5416 }
5417 }
5418 for (i = 0;i < nbCache;i++) {
5419 if (oldNs[i] == node->ns) {
5420 node->ns = newNs[i];
5421 break;
5422 }
5423 }
5424 if (i == nbCache) {
5425 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005426 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005427 */
5428 n = xmlNewReconciliedNs(doc, tree, node->ns);
5429 if (n != NULL) { /* :-( what if else ??? */
5430 /*
5431 * check if we need to grow the cache buffers.
5432 */
5433 if (sizeCache <= nbCache) {
5434 sizeCache *= 2;
5435 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5436 sizeof(xmlNsPtr));
5437 if (oldNs == NULL) {
5438 xmlGenericError(xmlGenericErrorContext,
5439 "xmlReconciliateNs : memory pbm\n");
5440 xmlFree(newNs);
5441 return(-1);
5442 }
5443 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5444 sizeof(xmlNsPtr));
5445 if (newNs == NULL) {
5446 xmlGenericError(xmlGenericErrorContext,
5447 "xmlReconciliateNs : memory pbm\n");
5448 xmlFree(oldNs);
5449 return(-1);
5450 }
5451 }
5452 newNs[nbCache] = n;
5453 oldNs[nbCache++] = node->ns;
5454 node->ns = n;
5455 }
5456 }
5457 }
5458 /*
5459 * now check for namespace hold by attributes on the node.
5460 */
5461 attr = node->properties;
5462 while (attr != NULL) {
5463 if (attr->ns != NULL) {
5464 /*
5465 * initialize the cache if needed
5466 */
5467 if (sizeCache == 0) {
5468 sizeCache = 10;
5469 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5470 sizeof(xmlNsPtr));
5471 if (oldNs == NULL) {
5472 xmlGenericError(xmlGenericErrorContext,
5473 "xmlReconciliateNs : memory pbm\n");
5474 return(-1);
5475 }
5476 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5477 sizeof(xmlNsPtr));
5478 if (newNs == NULL) {
5479 xmlGenericError(xmlGenericErrorContext,
5480 "xmlReconciliateNs : memory pbm\n");
5481 xmlFree(oldNs);
5482 return(-1);
5483 }
5484 }
5485 for (i = 0;i < nbCache;i++) {
5486 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00005487 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00005488 break;
5489 }
5490 }
5491 if (i == nbCache) {
5492 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00005493 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00005494 */
5495 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5496 if (n != NULL) { /* :-( what if else ??? */
5497 /*
5498 * check if we need to grow the cache buffers.
5499 */
5500 if (sizeCache <= nbCache) {
5501 sizeCache *= 2;
5502 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5503 sizeof(xmlNsPtr));
5504 if (oldNs == NULL) {
5505 xmlGenericError(xmlGenericErrorContext,
5506 "xmlReconciliateNs : memory pbm\n");
5507 xmlFree(newNs);
5508 return(-1);
5509 }
5510 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5511 sizeof(xmlNsPtr));
5512 if (newNs == NULL) {
5513 xmlGenericError(xmlGenericErrorContext,
5514 "xmlReconciliateNs : memory pbm\n");
5515 xmlFree(oldNs);
5516 return(-1);
5517 }
5518 }
5519 newNs[nbCache] = n;
5520 oldNs[nbCache++] = attr->ns;
5521 attr->ns = n;
5522 }
5523 }
5524 }
5525 attr = attr->next;
5526 }
5527
5528 /*
5529 * Browse the full subtree, deep first
5530 */
5531 if (node->children != NULL) {
5532 /* deep first */
5533 node = node->children;
5534 } else if ((node != tree) && (node->next != NULL)) {
5535 /* then siblings */
5536 node = node->next;
5537 } else if (node != tree) {
5538 /* go up to parents->next if needed */
5539 while (node != tree) {
5540 if (node->parent != NULL)
5541 node = node->parent;
5542 if ((node != tree) && (node->next != NULL)) {
5543 node = node->next;
5544 break;
5545 }
5546 if (node->parent == NULL) {
5547 node = NULL;
5548 break;
5549 }
5550 }
5551 /* exit condition */
5552 if (node == tree)
5553 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00005554 } else
5555 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005556 }
Daniel Veillardf742d342002-03-07 00:05:35 +00005557 if (oldNs != NULL)
5558 xmlFree(oldNs);
5559 if (newNs != NULL)
5560 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00005561 return(ret);
5562}
5563
5564/**
5565 * xmlHasProp:
5566 * @node: the node
5567 * @name: the attribute name
5568 *
5569 * Search an attribute associated to a node
5570 * This function also looks in DTD attribute declaration for #FIXED or
5571 * default declaration values unless DTD use has been turned off.
5572 *
5573 * Returns the attribute or the attribute declaration or NULL if
5574 * neither was found.
5575 */
5576xmlAttrPtr
5577xmlHasProp(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 (xmlStrEqual(prop->name, name)) {
5588 return(prop);
5589 }
5590 prop = prop->next;
5591 }
5592 if (!xmlCheckDTD) return(NULL);
5593
5594 /*
5595 * Check if there is a default declaration in the internal
5596 * or external subsets
5597 */
5598 doc = node->doc;
5599 if (doc != NULL) {
5600 xmlAttributePtr attrDecl;
5601 if (doc->intSubset != NULL) {
5602 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5603 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5604 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005605 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5606 /* return attribute declaration only if a default value is given
5607 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005608 return((xmlAttrPtr) attrDecl);
5609 }
5610 }
5611 return(NULL);
5612}
5613
5614/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005615 * xmlHasNsProp:
5616 * @node: the node
5617 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005618 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005619 *
5620 * Search for an attribute associated to a node
5621 * This attribute has to be anchored in the namespace specified.
5622 * This does the entity substitution.
5623 * This function looks in DTD attribute declaration for #FIXED or
5624 * default declaration values unless DTD use has been turned off.
5625 *
5626 * Returns the attribute or the attribute declaration or NULL
5627 * if neither was found.
5628 */
5629xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005630xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005631 xmlAttrPtr prop;
5632 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005633
5634 if (node == NULL)
5635 return(NULL);
5636
5637 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005638 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005639 return(xmlHasProp(node, name));
5640 while (prop != NULL) {
5641 /*
5642 * One need to have
5643 * - same attribute names
5644 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005645 */
5646 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005647 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5648 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005649 }
5650 prop = prop->next;
5651 }
5652 if (!xmlCheckDTD) return(NULL);
5653
5654 /*
5655 * Check if there is a default declaration in the internal
5656 * or external subsets
5657 */
5658 doc = node->doc;
5659 if (doc != NULL) {
5660 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005661 xmlAttributePtr attrDecl = NULL;
5662 xmlNsPtr *nsList, *cur;
5663 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005664
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005665 nsList = xmlGetNsList(node->doc, node);
5666 if (nsList == NULL)
5667 return(NULL);
5668 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5669 ename = xmlStrdup(node->ns->prefix);
5670 ename = xmlStrcat(ename, BAD_CAST ":");
5671 ename = xmlStrcat(ename, node->name);
5672 } else {
5673 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005674 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005675 if (ename == NULL) {
5676 xmlFree(nsList);
5677 return(NULL);
5678 }
5679
5680 cur = nsList;
5681 while (*cur != NULL) {
5682 if (xmlStrEqual((*cur)->href, nameSpace)) {
5683 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5684 name, (*cur)->prefix);
5685 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5686 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5687 name, (*cur)->prefix);
5688 }
5689 cur++;
5690 }
5691 xmlFree(nsList);
5692 xmlFree(ename);
5693 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005694 }
5695 }
5696 return(NULL);
5697}
5698
5699/**
Owen Taylor3473f882001-02-23 17:55:21 +00005700 * xmlGetProp:
5701 * @node: the node
5702 * @name: the attribute name
5703 *
5704 * Search and get the value of an attribute associated to a node
5705 * This does the entity substitution.
5706 * This function looks in DTD attribute declaration for #FIXED or
5707 * default declaration values unless DTD use has been turned off.
Daniel Veillard784b9352003-02-16 15:50:27 +00005708 * NOTE: this function acts independently of namespaces associated
Daniel Veillard71531f32003-02-05 13:19:53 +00005709 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
5710 * for namespace aware processing.
Owen Taylor3473f882001-02-23 17:55:21 +00005711 *
5712 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005713 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005714 */
5715xmlChar *
5716xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5717 xmlAttrPtr prop;
5718 xmlDocPtr doc;
5719
5720 if ((node == NULL) || (name == NULL)) return(NULL);
5721 /*
5722 * Check on the properties attached to the node
5723 */
5724 prop = node->properties;
5725 while (prop != NULL) {
5726 if (xmlStrEqual(prop->name, name)) {
5727 xmlChar *ret;
5728
5729 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5730 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5731 return(ret);
5732 }
5733 prop = prop->next;
5734 }
5735 if (!xmlCheckDTD) return(NULL);
5736
5737 /*
5738 * Check if there is a default declaration in the internal
5739 * or external subsets
5740 */
5741 doc = node->doc;
5742 if (doc != NULL) {
5743 xmlAttributePtr attrDecl;
5744 if (doc->intSubset != NULL) {
5745 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5746 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5747 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005748 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5749 /* return attribute declaration only if a default value is given
5750 (that includes #FIXED declarations) */
Owen Taylor3473f882001-02-23 17:55:21 +00005751 return(xmlStrdup(attrDecl->defaultValue));
5752 }
5753 }
5754 return(NULL);
5755}
5756
5757/**
Daniel Veillard71531f32003-02-05 13:19:53 +00005758 * xmlGetNoNsProp:
5759 * @node: the node
5760 * @name: the attribute name
5761 *
5762 * Search and get the value of an attribute associated to a node
5763 * This does the entity substitution.
5764 * This function looks in DTD attribute declaration for #FIXED or
5765 * default declaration values unless DTD use has been turned off.
5766 * This function is similar to xmlGetProp except it will accept only
5767 * an attribute in no namespace.
5768 *
5769 * Returns the attribute value or NULL if not found.
5770 * It's up to the caller to free the memory with xmlFree().
5771 */
5772xmlChar *
5773xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
5774 xmlAttrPtr prop;
5775 xmlDocPtr doc;
5776
5777 if ((node == NULL) || (name == NULL)) return(NULL);
5778 /*
5779 * Check on the properties attached to the node
5780 */
5781 prop = node->properties;
5782 while (prop != NULL) {
5783 if ((prop->ns == NULL) && (xmlStrEqual(prop->name, name))) {
5784 xmlChar *ret;
5785
5786 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5787 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5788 return(ret);
5789 }
5790 prop = prop->next;
5791 }
5792 if (!xmlCheckDTD) return(NULL);
5793
5794 /*
5795 * Check if there is a default declaration in the internal
5796 * or external subsets
5797 */
5798 doc = node->doc;
5799 if (doc != NULL) {
5800 xmlAttributePtr attrDecl;
5801 if (doc->intSubset != NULL) {
5802 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5803 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5804 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillard75eb1ad2003-07-07 14:42:44 +00005805 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
5806 /* return attribute declaration only if a default value is given
5807 (that includes #FIXED declarations) */
Daniel Veillard71531f32003-02-05 13:19:53 +00005808 return(xmlStrdup(attrDecl->defaultValue));
5809 }
5810 }
5811 return(NULL);
5812}
5813
5814/**
Owen Taylor3473f882001-02-23 17:55:21 +00005815 * xmlGetNsProp:
5816 * @node: the node
5817 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005818 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005819 *
5820 * Search and get the value of an attribute associated to a node
5821 * This attribute has to be anchored in the namespace specified.
5822 * This does the entity substitution.
5823 * This function looks in DTD attribute declaration for #FIXED or
5824 * default declaration values unless DTD use has been turned off.
5825 *
5826 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005827 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005828 */
5829xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00005830xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00005831 xmlAttrPtr prop;
5832 xmlDocPtr doc;
5833 xmlNsPtr ns;
5834
5835 if (node == NULL)
5836 return(NULL);
5837
5838 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005839 if (nameSpace == NULL)
Daniel Veillard71531f32003-02-05 13:19:53 +00005840 return(xmlGetNoNsProp(node, name));
Owen Taylor3473f882001-02-23 17:55:21 +00005841 while (prop != NULL) {
5842 /*
5843 * One need to have
5844 * - same attribute names
5845 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005846 */
5847 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00005848 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00005849 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005850 xmlChar *ret;
5851
5852 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5853 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5854 return(ret);
5855 }
5856 prop = prop->next;
5857 }
5858 if (!xmlCheckDTD) return(NULL);
5859
5860 /*
5861 * Check if there is a default declaration in the internal
5862 * or external subsets
5863 */
5864 doc = node->doc;
5865 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005866 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00005867 xmlAttributePtr attrDecl;
5868
Owen Taylor3473f882001-02-23 17:55:21 +00005869 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5870 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5871 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5872
5873 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
5874 /*
5875 * The DTD declaration only allows a prefix search
5876 */
5877 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00005878 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00005879 return(xmlStrdup(attrDecl->defaultValue));
5880 }
5881 }
5882 }
5883 return(NULL);
5884}
5885
5886/**
5887 * xmlSetProp:
5888 * @node: the node
5889 * @name: the attribute name
5890 * @value: the attribute value
5891 *
5892 * Set (or reset) an attribute carried by a node.
5893 * Returns the attribute pointer.
5894 */
5895xmlAttrPtr
5896xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005897 xmlAttrPtr prop;
5898 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00005899
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00005900 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00005901 return(NULL);
5902 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005903 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00005904 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005905 if ((xmlStrEqual(prop->name, name)) &&
5906 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005907 xmlNodePtr oldprop = prop->children;
5908
Owen Taylor3473f882001-02-23 17:55:21 +00005909 prop->children = NULL;
5910 prop->last = NULL;
5911 if (value != NULL) {
5912 xmlChar *buffer;
5913 xmlNodePtr tmp;
5914
5915 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5916 prop->children = xmlStringGetNodeList(node->doc, buffer);
5917 prop->last = NULL;
5918 prop->doc = doc;
5919 tmp = prop->children;
5920 while (tmp != NULL) {
5921 tmp->parent = (xmlNodePtr) prop;
5922 tmp->doc = doc;
5923 if (tmp->next == NULL)
5924 prop->last = tmp;
5925 tmp = tmp->next;
5926 }
5927 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00005928 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005929 if (oldprop != NULL)
5930 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00005931 return(prop);
5932 }
5933 prop = prop->next;
5934 }
5935 prop = xmlNewProp(node, name, value);
5936 return(prop);
5937}
5938
5939/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005940 * xmlUnsetProp:
5941 * @node: the node
5942 * @name: the attribute name
5943 *
5944 * Remove an attribute carried by a node.
5945 * Returns 0 if successful, -1 if not found
5946 */
5947int
5948xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
Daniel Veillard814a76d2003-01-23 18:24:20 +00005949 xmlAttrPtr prop, prev = NULL;;
Daniel Veillard75bea542001-05-11 17:41:21 +00005950
5951 if ((node == NULL) || (name == NULL))
5952 return(-1);
Daniel Veillard814a76d2003-01-23 18:24:20 +00005953 prop = node->properties;
Daniel Veillard75bea542001-05-11 17:41:21 +00005954 while (prop != NULL) {
5955 if ((xmlStrEqual(prop->name, name)) &&
5956 (prop->ns == NULL)) {
5957 if (prev == NULL)
5958 node->properties = prop->next;
5959 else
5960 prev->next = prop->next;
5961 xmlFreeProp(prop);
5962 return(0);
5963 }
5964 prev = prop;
5965 prop = prop->next;
5966 }
5967 return(-1);
5968}
5969
5970/**
Owen Taylor3473f882001-02-23 17:55:21 +00005971 * xmlSetNsProp:
5972 * @node: the node
5973 * @ns: the namespace definition
5974 * @name: the attribute name
5975 * @value: the attribute value
5976 *
5977 * Set (or reset) an attribute carried by a node.
5978 * The ns structure must be in scope, this is not checked.
5979 *
5980 * Returns the attribute pointer.
5981 */
5982xmlAttrPtr
5983xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
5984 const xmlChar *value) {
5985 xmlAttrPtr prop;
5986
5987 if ((node == NULL) || (name == NULL))
5988 return(NULL);
5989
5990 if (ns == NULL)
5991 return(xmlSetProp(node, name, value));
5992 if (ns->href == NULL)
5993 return(NULL);
5994 prop = node->properties;
5995
5996 while (prop != NULL) {
5997 /*
5998 * One need to have
5999 * - same attribute names
6000 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00006001 */
6002 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00006003 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00006004 if (prop->children != NULL)
6005 xmlFreeNodeList(prop->children);
6006 prop->children = NULL;
6007 prop->last = NULL;
6008 prop->ns = ns;
6009 if (value != NULL) {
6010 xmlChar *buffer;
6011 xmlNodePtr tmp;
6012
6013 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6014 prop->children = xmlStringGetNodeList(node->doc, buffer);
6015 prop->last = NULL;
6016 tmp = prop->children;
6017 while (tmp != NULL) {
6018 tmp->parent = (xmlNodePtr) prop;
6019 if (tmp->next == NULL)
6020 prop->last = tmp;
6021 tmp = tmp->next;
6022 }
6023 xmlFree(buffer);
6024 }
6025 return(prop);
6026 }
6027 prop = prop->next;
6028 }
6029 prop = xmlNewNsProp(node, ns, name, value);
6030 return(prop);
6031}
6032
6033/**
Daniel Veillard75bea542001-05-11 17:41:21 +00006034 * xmlUnsetNsProp:
6035 * @node: the node
6036 * @ns: the namespace definition
6037 * @name: the attribute name
6038 *
6039 * Remove an attribute carried by a node.
6040 * Returns 0 if successful, -1 if not found
6041 */
6042int
6043xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
6044 xmlAttrPtr prop = node->properties, prev = NULL;;
6045
6046 if ((node == NULL) || (name == NULL))
6047 return(-1);
6048 if (ns == NULL)
6049 return(xmlUnsetProp(node, name));
6050 if (ns->href == NULL)
6051 return(-1);
6052 while (prop != NULL) {
6053 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00006054 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00006055 if (prev == NULL)
6056 node->properties = prop->next;
6057 else
6058 prev->next = prop->next;
6059 xmlFreeProp(prop);
6060 return(0);
6061 }
6062 prev = prop;
6063 prop = prop->next;
6064 }
6065 return(-1);
6066}
6067
6068/**
Owen Taylor3473f882001-02-23 17:55:21 +00006069 * xmlNodeIsText:
6070 * @node: the node
6071 *
6072 * Is this node a Text node ?
6073 * Returns 1 yes, 0 no
6074 */
6075int
6076xmlNodeIsText(xmlNodePtr node) {
6077 if (node == NULL) return(0);
6078
6079 if (node->type == XML_TEXT_NODE) return(1);
6080 return(0);
6081}
6082
6083/**
6084 * xmlIsBlankNode:
6085 * @node: the node
6086 *
6087 * Checks whether this node is an empty or whitespace only
6088 * (and possibly ignorable) text-node.
6089 *
6090 * Returns 1 yes, 0 no
6091 */
6092int
6093xmlIsBlankNode(xmlNodePtr node) {
6094 const xmlChar *cur;
6095 if (node == NULL) return(0);
6096
Daniel Veillard7db37732001-07-12 01:20:08 +00006097 if ((node->type != XML_TEXT_NODE) &&
6098 (node->type != XML_CDATA_SECTION_NODE))
6099 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006100 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006101 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00006102 while (*cur != 0) {
6103 if (!IS_BLANK(*cur)) return(0);
6104 cur++;
6105 }
6106
6107 return(1);
6108}
6109
6110/**
6111 * xmlTextConcat:
6112 * @node: the node
6113 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00006114 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00006115 *
6116 * Concat the given string at the end of the existing node content
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006117 *
6118 * Returns -1 in case of error, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00006119 */
6120
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006121int
Owen Taylor3473f882001-02-23 17:55:21 +00006122xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006123 if (node == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006124
6125 if ((node->type != XML_TEXT_NODE) &&
6126 (node->type != XML_CDATA_SECTION_NODE)) {
6127#ifdef DEBUG_TREE
6128 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006129 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006130#endif
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006131 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006132 }
Owen Taylor3473f882001-02-23 17:55:21 +00006133 node->content = xmlStrncat(node->content, content, len);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00006134 if (node->content == NULL)
6135 return(-1);
6136 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006137}
6138
6139/************************************************************************
6140 * *
6141 * Output : to a FILE or in memory *
6142 * *
6143 ************************************************************************/
6144
Owen Taylor3473f882001-02-23 17:55:21 +00006145/**
6146 * xmlBufferCreate:
6147 *
6148 * routine to create an XML buffer.
6149 * returns the new structure.
6150 */
6151xmlBufferPtr
6152xmlBufferCreate(void) {
6153 xmlBufferPtr ret;
6154
6155 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6156 if (ret == NULL) {
6157 xmlGenericError(xmlGenericErrorContext,
6158 "xmlBufferCreate : out of memory!\n");
6159 return(NULL);
6160 }
6161 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00006162 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00006163 ret->alloc = xmlBufferAllocScheme;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006164 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006165 if (ret->content == NULL) {
6166 xmlGenericError(xmlGenericErrorContext,
6167 "xmlBufferCreate : out of memory!\n");
6168 xmlFree(ret);
6169 return(NULL);
6170 }
6171 ret->content[0] = 0;
6172 return(ret);
6173}
6174
6175/**
6176 * xmlBufferCreateSize:
6177 * @size: initial size of buffer
6178 *
6179 * routine to create an XML buffer.
6180 * returns the new structure.
6181 */
6182xmlBufferPtr
6183xmlBufferCreateSize(size_t size) {
6184 xmlBufferPtr ret;
6185
6186 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6187 if (ret == NULL) {
6188 xmlGenericError(xmlGenericErrorContext,
6189 "xmlBufferCreate : out of memory!\n");
6190 return(NULL);
6191 }
6192 ret->use = 0;
6193 ret->alloc = xmlBufferAllocScheme;
6194 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6195 if (ret->size){
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006196 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006197 if (ret->content == NULL) {
6198 xmlGenericError(xmlGenericErrorContext,
6199 "xmlBufferCreate : out of memory!\n");
6200 xmlFree(ret);
6201 return(NULL);
6202 }
6203 ret->content[0] = 0;
6204 } else
6205 ret->content = NULL;
6206 return(ret);
6207}
6208
6209/**
6210 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00006211 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00006212 * @scheme: allocation scheme to use
6213 *
6214 * Sets the allocation scheme for this buffer
6215 */
6216void
6217xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6218 xmlBufferAllocationScheme scheme) {
6219 if (buf == NULL) {
6220#ifdef DEBUG_BUFFER
6221 xmlGenericError(xmlGenericErrorContext,
6222 "xmlBufferSetAllocationScheme: buf == NULL\n");
6223#endif
6224 return;
6225 }
6226
6227 buf->alloc = scheme;
6228}
6229
6230/**
6231 * xmlBufferFree:
6232 * @buf: the buffer to free
6233 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00006234 * Frees an XML buffer. It frees both the content and the structure which
6235 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00006236 */
6237void
6238xmlBufferFree(xmlBufferPtr buf) {
6239 if (buf == NULL) {
6240#ifdef DEBUG_BUFFER
6241 xmlGenericError(xmlGenericErrorContext,
6242 "xmlBufferFree: buf == NULL\n");
6243#endif
6244 return;
6245 }
Daniel Veillard561b7f82002-03-20 21:55:57 +00006246 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006247 xmlFree(buf->content);
6248 }
Owen Taylor3473f882001-02-23 17:55:21 +00006249 xmlFree(buf);
6250}
6251
6252/**
6253 * xmlBufferEmpty:
6254 * @buf: the buffer
6255 *
6256 * empty a buffer.
6257 */
6258void
6259xmlBufferEmpty(xmlBufferPtr buf) {
6260 if (buf->content == NULL) return;
6261 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006262 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00006263}
6264
6265/**
6266 * xmlBufferShrink:
6267 * @buf: the buffer to dump
6268 * @len: the number of xmlChar to remove
6269 *
6270 * Remove the beginning of an XML buffer.
6271 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006272 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00006273 */
6274int
6275xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
6276 if (len == 0) return(0);
6277 if (len > buf->use) return(-1);
6278
6279 buf->use -= len;
6280 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6281
6282 buf->content[buf->use] = 0;
6283 return(len);
6284}
6285
6286/**
6287 * xmlBufferGrow:
6288 * @buf: the buffer
6289 * @len: the minimum free size to allocate
6290 *
6291 * Grow the available space of an XML buffer.
6292 *
6293 * Returns the new available space or -1 in case of error
6294 */
6295int
6296xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6297 int size;
6298 xmlChar *newbuf;
6299
6300 if (len + buf->use < buf->size) return(0);
6301
6302 size = buf->use + len + 100;
6303
6304 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
6305 if (newbuf == NULL) return(-1);
6306 buf->content = newbuf;
6307 buf->size = size;
6308 return(buf->size - buf->use);
6309}
6310
6311/**
6312 * xmlBufferDump:
6313 * @file: the file output
6314 * @buf: the buffer to dump
6315 *
6316 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00006317 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00006318 */
6319int
6320xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6321 int ret;
6322
6323 if (buf == NULL) {
6324#ifdef DEBUG_BUFFER
6325 xmlGenericError(xmlGenericErrorContext,
6326 "xmlBufferDump: buf == NULL\n");
6327#endif
6328 return(0);
6329 }
6330 if (buf->content == NULL) {
6331#ifdef DEBUG_BUFFER
6332 xmlGenericError(xmlGenericErrorContext,
6333 "xmlBufferDump: buf->content == NULL\n");
6334#endif
6335 return(0);
6336 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00006337 if (file == NULL)
6338 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00006339 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6340 return(ret);
6341}
6342
6343/**
6344 * xmlBufferContent:
6345 * @buf: the buffer
6346 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006347 * Function to extract the content of a buffer
6348 *
Owen Taylor3473f882001-02-23 17:55:21 +00006349 * Returns the internal content
6350 */
6351
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006352const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006353xmlBufferContent(const xmlBufferPtr buf)
6354{
6355 if(!buf)
6356 return NULL;
6357
6358 return buf->content;
6359}
6360
6361/**
6362 * xmlBufferLength:
6363 * @buf: the buffer
6364 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006365 * Function to get the length of a buffer
6366 *
Owen Taylor3473f882001-02-23 17:55:21 +00006367 * Returns the length of data in the internal content
6368 */
6369
6370int
6371xmlBufferLength(const xmlBufferPtr buf)
6372{
6373 if(!buf)
6374 return 0;
6375
6376 return buf->use;
6377}
6378
6379/**
6380 * xmlBufferResize:
6381 * @buf: the buffer to resize
6382 * @size: the desired size
6383 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006384 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00006385 *
6386 * Returns 0 in case of problems, 1 otherwise
6387 */
6388int
6389xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6390{
6391 unsigned int newSize;
6392 xmlChar* rebuf = NULL;
6393
6394 /*take care of empty case*/
6395 newSize = (buf->size ? buf->size*2 : size);
6396
6397 /* Don't resize if we don't have to */
6398 if (size < buf->size)
6399 return 1;
6400
6401 /* figure out new size */
6402 switch (buf->alloc){
6403 case XML_BUFFER_ALLOC_DOUBLEIT:
6404 while (size > newSize) newSize *= 2;
6405 break;
6406 case XML_BUFFER_ALLOC_EXACT:
6407 newSize = size+10;
6408 break;
6409 default:
6410 newSize = size+10;
6411 break;
6412 }
6413
6414 if (buf->content == NULL)
Daniel Veillard3c908dc2003-04-19 00:07:51 +00006415 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +00006416 else
6417 rebuf = (xmlChar *) xmlRealloc(buf->content,
6418 newSize * sizeof(xmlChar));
6419 if (rebuf == NULL) {
6420 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006421 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006422 return 0;
6423 }
6424 buf->content = rebuf;
6425 buf->size = newSize;
6426
6427 return 1;
6428}
6429
6430/**
6431 * xmlBufferAdd:
6432 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006433 * @str: the #xmlChar string
6434 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006435 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006436 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00006437 * str is recomputed.
6438 */
6439void
6440xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6441 unsigned int needSize;
6442
6443 if (str == NULL) {
6444#ifdef DEBUG_BUFFER
6445 xmlGenericError(xmlGenericErrorContext,
6446 "xmlBufferAdd: str == NULL\n");
6447#endif
6448 return;
6449 }
6450 if (len < -1) {
6451#ifdef DEBUG_BUFFER
6452 xmlGenericError(xmlGenericErrorContext,
6453 "xmlBufferAdd: len < 0\n");
6454#endif
6455 return;
6456 }
6457 if (len == 0) return;
6458
6459 if (len < 0)
6460 len = xmlStrlen(str);
6461
6462 if (len <= 0) return;
6463
6464 needSize = buf->use + len + 2;
6465 if (needSize > buf->size){
6466 if (!xmlBufferResize(buf, needSize)){
6467 xmlGenericError(xmlGenericErrorContext,
6468 "xmlBufferAdd : out of memory!\n");
6469 return;
6470 }
6471 }
6472
6473 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6474 buf->use += len;
6475 buf->content[buf->use] = 0;
6476}
6477
6478/**
6479 * xmlBufferAddHead:
6480 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00006481 * @str: the #xmlChar string
6482 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00006483 *
6484 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00006485 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00006486 */
6487void
6488xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
6489 unsigned int needSize;
6490
6491 if (str == NULL) {
6492#ifdef DEBUG_BUFFER
6493 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006494 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006495#endif
6496 return;
6497 }
6498 if (len < -1) {
6499#ifdef DEBUG_BUFFER
6500 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006501 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006502#endif
6503 return;
6504 }
6505 if (len == 0) return;
6506
6507 if (len < 0)
6508 len = xmlStrlen(str);
6509
6510 if (len <= 0) return;
6511
6512 needSize = buf->use + len + 2;
6513 if (needSize > buf->size){
6514 if (!xmlBufferResize(buf, needSize)){
6515 xmlGenericError(xmlGenericErrorContext,
6516 "xmlBufferAddHead : out of memory!\n");
6517 return;
6518 }
6519 }
6520
6521 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
6522 memmove(&buf->content[0], str, len * sizeof(xmlChar));
6523 buf->use += len;
6524 buf->content[buf->use] = 0;
6525}
6526
6527/**
6528 * xmlBufferCat:
6529 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00006530 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00006531 *
6532 * Append a zero terminated string to an XML buffer.
6533 */
6534void
6535xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
6536 if (str != NULL)
6537 xmlBufferAdd(buf, str, -1);
6538}
6539
6540/**
6541 * xmlBufferCCat:
6542 * @buf: the buffer to dump
6543 * @str: the C char string
6544 *
6545 * Append a zero terminated C string to an XML buffer.
6546 */
6547void
6548xmlBufferCCat(xmlBufferPtr buf, const char *str) {
6549 const char *cur;
6550
6551 if (str == NULL) {
6552#ifdef DEBUG_BUFFER
6553 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006554 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006555#endif
6556 return;
6557 }
6558 for (cur = str;*cur != 0;cur++) {
6559 if (buf->use + 10 >= buf->size) {
6560 if (!xmlBufferResize(buf, buf->use+10)){
6561 xmlGenericError(xmlGenericErrorContext,
6562 "xmlBufferCCat : out of memory!\n");
6563 return;
6564 }
6565 }
6566 buf->content[buf->use++] = *cur;
6567 }
6568 buf->content[buf->use] = 0;
6569}
6570
6571/**
6572 * xmlBufferWriteCHAR:
6573 * @buf: the XML buffer
6574 * @string: the string to add
6575 *
6576 * routine which manages and grows an output buffer. This one adds
6577 * xmlChars at the end of the buffer.
6578 */
6579void
Owen Taylor3473f882001-02-23 17:55:21 +00006580xmlBufferWriteCHAR
Owen Taylor3473f882001-02-23 17:55:21 +00006581(xmlBufferPtr buf, const xmlChar *string) {
6582 xmlBufferCat(buf, string);
6583}
6584
6585/**
6586 * xmlBufferWriteChar:
6587 * @buf: the XML buffer output
6588 * @string: the string to add
6589 *
6590 * routine which manage and grows an output buffer. This one add
6591 * C chars at the end of the array.
6592 */
6593void
6594xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
6595 xmlBufferCCat(buf, string);
6596}
6597
6598
6599/**
6600 * xmlBufferWriteQuotedString:
6601 * @buf: the XML buffer output
6602 * @string: the string to add
6603 *
6604 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00006605 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00006606 * quote or double-quotes internally
6607 */
6608void
6609xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
6610 if (xmlStrchr(string, '"')) {
6611 if (xmlStrchr(string, '\'')) {
6612#ifdef DEBUG_BUFFER
6613 xmlGenericError(xmlGenericErrorContext,
6614 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
6615#endif
6616 }
6617 xmlBufferCCat(buf, "'");
6618 xmlBufferCat(buf, string);
6619 xmlBufferCCat(buf, "'");
6620 } else {
6621 xmlBufferCCat(buf, "\"");
6622 xmlBufferCat(buf, string);
6623 xmlBufferCCat(buf, "\"");
6624 }
6625}
6626
6627
6628/************************************************************************
6629 * *
6630 * Dumping XML tree content to a simple buffer *
6631 * *
6632 ************************************************************************/
6633
Owen Taylor3473f882001-02-23 17:55:21 +00006634/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00006635 * xmlAttrSerializeContent:
6636 * @buf: the XML buffer output
6637 * @doc: the document
6638 * @attr: the attribute pointer
6639 *
6640 * Serialize the attribute in the buffer
6641 */
6642static void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006643xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr)
6644{
Daniel Veillarda6d05382002-02-13 13:07:41 +00006645 const xmlChar *cur, *base;
6646 xmlNodePtr children;
6647
6648 children = attr->children;
6649 while (children != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006650 switch (children->type) {
6651 case XML_TEXT_NODE:
6652 base = cur = children->content;
6653 while (*cur != 0) {
6654 if (*cur == '\n') {
6655 if (base != cur)
6656 xmlBufferAdd(buf, base, cur - base);
6657 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
6658 cur++;
6659 base = cur;
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006660 } else if (*cur == '\r') {
6661 if (base != cur)
6662 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006663 xmlBufferAdd(buf, BAD_CAST "&#13;", 5);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006664 cur++;
6665 base = cur;
6666 } else if (*cur == '\t') {
6667 if (base != cur)
6668 xmlBufferAdd(buf, base, cur - base);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006669 xmlBufferAdd(buf, BAD_CAST "&#9;", 4);
Daniel Veillard0046c0f2003-02-23 13:52:30 +00006670 cur++;
6671 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006672#if 0
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006673 } else if (*cur == '\'') {
6674 if (base != cur)
6675 xmlBufferAdd(buf, base, cur - base);
6676 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
6677 cur++;
6678 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006679#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006680 } else if (*cur == '"') {
6681 if (base != cur)
6682 xmlBufferAdd(buf, base, cur - base);
6683 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6684 cur++;
6685 base = cur;
6686 } else if (*cur == '<') {
6687 if (base != cur)
6688 xmlBufferAdd(buf, base, cur - base);
6689 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
6690 cur++;
6691 base = cur;
6692 } else if (*cur == '>') {
6693 if (base != cur)
6694 xmlBufferAdd(buf, base, cur - base);
6695 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
6696 cur++;
6697 base = cur;
6698 } else if (*cur == '&') {
6699 if (base != cur)
6700 xmlBufferAdd(buf, base, cur - base);
6701 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
6702 cur++;
6703 base = cur;
6704 } else if ((*cur >= 0x80) && ((doc == NULL) ||
6705 (doc->encoding ==
6706 NULL))) {
6707 /*
6708 * We assume we have UTF-8 content.
6709 */
6710 char tmp[10];
6711 int val = 0, l = 1;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006712
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006713 if (base != cur)
6714 xmlBufferAdd(buf, base, cur - base);
6715 if (*cur < 0xC0) {
6716 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6d05382002-02-13 13:07:41 +00006717 "xmlAttrSerializeContent : input not UTF-8\n");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006718 if (doc != NULL)
6719 doc->encoding =
6720 xmlStrdup(BAD_CAST "ISO-8859-1");
6721 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6722 tmp[sizeof(tmp) - 1] = 0;
6723 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6724 cur++;
6725 base = cur;
6726 continue;
6727 } else if (*cur < 0xE0) {
6728 val = (cur[0]) & 0x1F;
6729 val <<= 6;
6730 val |= (cur[1]) & 0x3F;
6731 l = 2;
6732 } else if (*cur < 0xF0) {
6733 val = (cur[0]) & 0x0F;
6734 val <<= 6;
6735 val |= (cur[1]) & 0x3F;
6736 val <<= 6;
6737 val |= (cur[2]) & 0x3F;
6738 l = 3;
6739 } else if (*cur < 0xF8) {
6740 val = (cur[0]) & 0x07;
6741 val <<= 6;
6742 val |= (cur[1]) & 0x3F;
6743 val <<= 6;
6744 val |= (cur[2]) & 0x3F;
6745 val <<= 6;
6746 val |= (cur[3]) & 0x3F;
6747 l = 4;
6748 }
6749 if ((l == 1) || (!IS_CHAR(val))) {
6750 xmlGenericError(xmlGenericErrorContext,
6751 "xmlAttrSerializeContent : char out of range\n");
6752 if (doc != NULL)
6753 doc->encoding =
6754 xmlStrdup(BAD_CAST "ISO-8859-1");
6755 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6756 tmp[sizeof(tmp) - 1] = 0;
6757 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6758 cur++;
6759 base = cur;
6760 continue;
6761 }
6762 /*
6763 * We could do multiple things here. Just save
6764 * as a char ref
6765 */
6766 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
6767 tmp[sizeof(tmp) - 1] = 0;
6768 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6769 cur += l;
6770 base = cur;
6771 } else {
6772 cur++;
6773 }
6774 }
6775 if (base != cur)
6776 xmlBufferAdd(buf, base, cur - base);
6777 break;
6778 case XML_ENTITY_REF_NODE:
6779 xmlBufferAdd(buf, BAD_CAST "&", 1);
6780 xmlBufferAdd(buf, children->name,
6781 xmlStrlen(children->name));
6782 xmlBufferAdd(buf, BAD_CAST ";", 1);
6783 break;
6784 default:
6785 /* should not happen unless we have a badly built tree */
6786 break;
6787 }
6788 children = children->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006789 }
6790}
6791
6792/**
6793 * xmlNodeDump:
6794 * @buf: the XML buffer output
6795 * @doc: the document
6796 * @cur: the current node
6797 * @level: the imbrication level for indenting
6798 * @format: is formatting allowed
6799 *
6800 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00006801 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006802 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006803 *
6804 * Returns the number of bytes written to the buffer or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00006805 */
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006806int
Owen Taylor3473f882001-02-23 17:55:21 +00006807xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006808 int format)
6809{
6810 unsigned int use;
6811 int ret;
6812 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006813
6814 if (cur == NULL) {
6815#ifdef DEBUG_TREE
6816 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006817 "xmlNodeDump : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006818#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006819 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006820 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006821 if (buf == NULL) {
6822#ifdef DEBUG_TREE
6823 xmlGenericError(xmlGenericErrorContext,
6824 "xmlNodeDump : buf == NULL\n");
6825#endif
6826 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006827 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006828 outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
6829 if (outbuf == NULL) {
6830 xmlGenericError(xmlGenericErrorContext,
6831 "xmlNodeDump: out of memory!\n");
6832 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006833 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006834 memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
6835 outbuf->buffer = buf;
6836 outbuf->encoder = NULL;
6837 outbuf->writecallback = NULL;
6838 outbuf->closecallback = NULL;
6839 outbuf->context = NULL;
6840 outbuf->written = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006841
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006842 use = buf->use;
6843 xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
6844 xmlFree(outbuf);
6845 ret = buf->use - use;
6846 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006847}
6848
6849/**
6850 * xmlElemDump:
6851 * @f: the FILE * for the output
6852 * @doc: the document
6853 * @cur: the current node
6854 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006855 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006856 */
6857void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006858xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur)
6859{
6860 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006861
6862 if (cur == NULL) {
6863#ifdef DEBUG_TREE
6864 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006865 "xmlElemDump : cur == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006866#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006867 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006868 }
Owen Taylor3473f882001-02-23 17:55:21 +00006869#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006870 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006871 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006872 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006873 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006874#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006875
6876 outbuf = xmlOutputBufferCreateFile(f, NULL);
6877 if (outbuf == NULL)
6878 return;
6879 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006880#ifdef LIBXML_HTML_ENABLED
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006881 htmlNodeDumpOutput(outbuf, doc, cur, NULL);
6882#else
6883 xmlGenericError(xmlGenericErrorContext,
6884 "HTML support not compiled in\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006885#endif /* LIBXML_HTML_ENABLED */
6886 } else
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006887 xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL);
6888 xmlOutputBufferClose(outbuf);
Owen Taylor3473f882001-02-23 17:55:21 +00006889}
6890
6891/************************************************************************
6892 * *
6893 * Dumping XML tree content to an I/O output buffer *
6894 * *
6895 ************************************************************************/
6896
Owen Taylor3473f882001-02-23 17:55:21 +00006897static void
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006898xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6899 int level, int format, const char *encoding);
6900static void
Owen Taylor3473f882001-02-23 17:55:21 +00006901xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6902 int level, int format, const char *encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006903static void
6904xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
6905 xmlNodePtr cur, int level, int format, const char *encoding);
6906
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00006907void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
6908
Owen Taylor3473f882001-02-23 17:55:21 +00006909/**
6910 * xmlNsDumpOutput:
6911 * @buf: the XML buffer output
6912 * @cur: a namespace
6913 *
6914 * Dump a local Namespace definition.
6915 * Should be called in the context of attributes dumps.
6916 */
6917static void
6918xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6919 if (cur == NULL) {
6920#ifdef DEBUG_TREE
6921 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006922 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006923#endif
6924 return;
6925 }
6926 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00006927 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
6928 return;
6929
Owen Taylor3473f882001-02-23 17:55:21 +00006930 /* Within the context of an element attributes */
6931 if (cur->prefix != NULL) {
6932 xmlOutputBufferWriteString(buf, " xmlns:");
6933 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6934 } else
6935 xmlOutputBufferWriteString(buf, " xmlns");
6936 xmlOutputBufferWriteString(buf, "=");
6937 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6938 }
6939}
6940
6941/**
6942 * xmlNsListDumpOutput:
6943 * @buf: the XML buffer output
6944 * @cur: the first namespace
6945 *
6946 * Dump a list of local Namespace definitions.
6947 * Should be called in the context of attributes dumps.
6948 */
Daniel Veillard5ecaf7f2003-01-09 13:19:33 +00006949void
Owen Taylor3473f882001-02-23 17:55:21 +00006950xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6951 while (cur != NULL) {
6952 xmlNsDumpOutput(buf, cur);
6953 cur = cur->next;
6954 }
6955}
6956
6957/**
6958 * xmlDtdDumpOutput:
6959 * @buf: the XML buffer output
6960 * @doc: the document
6961 * @encoding: an optional encoding string
6962 *
6963 * Dump the XML document DTD, if any.
6964 */
6965static void
6966xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6967 if (dtd == NULL) {
6968#ifdef DEBUG_TREE
6969 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006970 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006971#endif
6972 return;
6973 }
6974 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6975 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6976 if (dtd->ExternalID != NULL) {
6977 xmlOutputBufferWriteString(buf, " PUBLIC ");
6978 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6979 xmlOutputBufferWriteString(buf, " ");
6980 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6981 } else if (dtd->SystemID != NULL) {
6982 xmlOutputBufferWriteString(buf, " SYSTEM ");
6983 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6984 }
6985 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6986 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6987 xmlOutputBufferWriteString(buf, ">");
6988 return;
6989 }
6990 xmlOutputBufferWriteString(buf, " [\n");
6991 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6992 xmlOutputBufferWriteString(buf, "]>");
6993}
6994
6995/**
6996 * xmlAttrDumpOutput:
6997 * @buf: the XML buffer output
6998 * @doc: the document
6999 * @cur: the attribute pointer
7000 * @encoding: an optional encoding string
7001 *
7002 * Dump an XML attribute
7003 */
7004static void
7005xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00007006 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00007007 if (cur == NULL) {
7008#ifdef DEBUG_TREE
7009 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007010 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007011#endif
7012 return;
7013 }
7014 xmlOutputBufferWriteString(buf, " ");
7015 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7016 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7017 xmlOutputBufferWriteString(buf, ":");
7018 }
7019 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00007020 xmlOutputBufferWriteString(buf, "=\"");
7021 xmlAttrSerializeContent(buf->buffer, doc, cur);
7022 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00007023}
7024
7025/**
7026 * xmlAttrListDumpOutput:
7027 * @buf: the XML buffer output
7028 * @doc: the document
7029 * @cur: the first attribute pointer
7030 * @encoding: an optional encoding string
7031 *
7032 * Dump a list of XML attributes
7033 */
7034static void
7035xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7036 xmlAttrPtr cur, const char *encoding) {
7037 if (cur == NULL) {
7038#ifdef DEBUG_TREE
7039 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007040 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007041#endif
7042 return;
7043 }
7044 while (cur != NULL) {
7045 xmlAttrDumpOutput(buf, doc, cur, encoding);
7046 cur = cur->next;
7047 }
7048}
7049
7050
7051
7052/**
7053 * xmlNodeListDumpOutput:
7054 * @buf: the XML buffer output
7055 * @doc: the document
7056 * @cur: the first node
7057 * @level: the imbrication level for indenting
7058 * @format: is formatting allowed
7059 * @encoding: an optional encoding string
7060 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007061 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007062 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007063 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007064 */
7065static void
7066xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7067 xmlNodePtr cur, int level, int format, const char *encoding) {
7068 int i;
7069
7070 if (cur == NULL) {
7071#ifdef DEBUG_TREE
7072 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007073 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007074#endif
7075 return;
7076 }
7077 while (cur != NULL) {
7078 if ((format) && (xmlIndentTreeOutput) &&
7079 (cur->type == XML_ELEMENT_NODE))
7080 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007081 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007082 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007083 if (format) {
7084 xmlOutputBufferWriteString(buf, "\n");
7085 }
7086 cur = cur->next;
7087 }
7088}
7089
7090/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007091 * xmlNodeDumpOutputInternal:
Owen Taylor3473f882001-02-23 17:55:21 +00007092 * @buf: the XML buffer output
7093 * @doc: the document
7094 * @cur: the current node
7095 * @level: the imbrication level for indenting
7096 * @format: is formatting allowed
7097 * @encoding: an optional encoding string
7098 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007099 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007100 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007101 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007102 */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007103static void
7104xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
7105 xmlNodePtr cur, int level, int format, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007106 int i;
7107 xmlNodePtr tmp;
7108
7109 if (cur == NULL) {
7110#ifdef DEBUG_TREE
7111 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007112 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007113#endif
7114 return;
7115 }
7116 if (cur->type == XML_XINCLUDE_START)
7117 return;
7118 if (cur->type == XML_XINCLUDE_END)
7119 return;
7120 if (cur->type == XML_DTD_NODE) {
7121 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7122 return;
7123 }
7124 if (cur->type == XML_ELEMENT_DECL) {
7125 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7126 return;
7127 }
7128 if (cur->type == XML_ATTRIBUTE_DECL) {
7129 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7130 return;
7131 }
7132 if (cur->type == XML_ENTITY_DECL) {
7133 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7134 return;
7135 }
7136 if (cur->type == XML_TEXT_NODE) {
7137 if (cur->content != NULL) {
7138 if ((cur->name == xmlStringText) ||
7139 (cur->name != xmlStringTextNoenc)) {
7140 xmlChar *buffer;
7141
Owen Taylor3473f882001-02-23 17:55:21 +00007142 if (encoding == NULL)
7143 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7144 else
7145 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007146 if (buffer != NULL) {
7147 xmlOutputBufferWriteString(buf, (const char *)buffer);
7148 xmlFree(buffer);
7149 }
7150 } else {
7151 /*
7152 * Disable escaping, needed for XSLT
7153 */
Owen Taylor3473f882001-02-23 17:55:21 +00007154 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007155 }
7156 }
7157
7158 return;
7159 }
7160 if (cur->type == XML_PI_NODE) {
7161 if (cur->content != NULL) {
7162 xmlOutputBufferWriteString(buf, "<?");
7163 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7164 if (cur->content != NULL) {
7165 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00007166 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007167 }
7168 xmlOutputBufferWriteString(buf, "?>");
7169 } else {
7170 xmlOutputBufferWriteString(buf, "<?");
7171 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7172 xmlOutputBufferWriteString(buf, "?>");
7173 }
7174 return;
7175 }
7176 if (cur->type == XML_COMMENT_NODE) {
7177 if (cur->content != NULL) {
7178 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00007179 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007180 xmlOutputBufferWriteString(buf, "-->");
7181 }
7182 return;
7183 }
7184 if (cur->type == XML_ENTITY_REF_NODE) {
7185 xmlOutputBufferWriteString(buf, "&");
7186 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7187 xmlOutputBufferWriteString(buf, ";");
7188 return;
7189 }
7190 if (cur->type == XML_CDATA_SECTION_NODE) {
7191 xmlOutputBufferWriteString(buf, "<![CDATA[");
7192 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007193 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007194 xmlOutputBufferWriteString(buf, "]]>");
7195 return;
7196 }
Daniel Veillard7b72ee52003-02-27 23:24:53 +00007197 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillarda1a9d042003-03-18 16:53:17 +00007198 xmlAttrDumpOutput(buf,doc, (xmlAttrPtr) cur,encoding);
Daniel Veillard7b72ee52003-02-27 23:24:53 +00007199 return;
7200 }
Daniel Veillard6aa2f602003-02-10 00:01:56 +00007201 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007202 xmlNsDumpOutput(buf, (xmlNsPtr) cur);
Daniel Veillard6aa2f602003-02-10 00:01:56 +00007203 return;
7204 }
Owen Taylor3473f882001-02-23 17:55:21 +00007205
7206 if (format == 1) {
7207 tmp = cur->children;
7208 while (tmp != NULL) {
7209 if ((tmp->type == XML_TEXT_NODE) ||
7210 (tmp->type == XML_ENTITY_REF_NODE)) {
7211 format = 0;
7212 break;
7213 }
7214 tmp = tmp->next;
7215 }
7216 }
7217 xmlOutputBufferWriteString(buf, "<");
7218 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7219 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7220 xmlOutputBufferWriteString(buf, ":");
7221 }
7222
7223 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7224 if (cur->nsDef)
7225 xmlNsListDumpOutput(buf, cur->nsDef);
7226 if (cur->properties != NULL)
7227 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7228
Daniel Veillard7db37732001-07-12 01:20:08 +00007229 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
7230 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007231 xmlOutputBufferWriteString(buf, "/>");
7232 return;
7233 }
7234 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00007235 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007236 xmlChar *buffer;
7237
Owen Taylor3473f882001-02-23 17:55:21 +00007238 if (encoding == NULL)
7239 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7240 else
7241 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00007242 if (buffer != NULL) {
7243 xmlOutputBufferWriteString(buf, (const char *)buffer);
7244 xmlFree(buffer);
7245 }
7246 }
7247 if (cur->children != NULL) {
7248 if (format) xmlOutputBufferWriteString(buf, "\n");
7249 xmlNodeListDumpOutput(buf, doc, cur->children,
7250 (level >= 0?level+1:-1), format, encoding);
7251 if ((xmlIndentTreeOutput) && (format))
7252 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00007253 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00007254 }
7255 xmlOutputBufferWriteString(buf, "</");
7256 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7257 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7258 xmlOutputBufferWriteString(buf, ":");
7259 }
7260
7261 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7262 xmlOutputBufferWriteString(buf, ">");
7263}
7264
7265/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007266 * xmlNodeDumpOutput:
7267 * @buf: the XML buffer output
7268 * @doc: the document
7269 * @cur: the current node
7270 * @level: the imbrication level for indenting
7271 * @format: is formatting allowed
7272 * @encoding: an optional encoding string
7273 *
7274 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007275 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007276 * or xmlKeepBlanksDefault(0) was called
7277 */
7278void
7279xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007280 int level, int format, const char *encoding)
7281{
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007282#ifdef LIBXML_HTML_ENABLED
7283 xmlDtdPtr dtd;
7284 int is_xhtml = 0;
7285
7286 dtd = xmlGetIntSubset(doc);
7287 if (dtd != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007288 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7289 if (is_xhtml < 0)
7290 is_xhtml = 0;
7291 if ((is_xhtml) && (cur->parent == (xmlNodePtr) doc) &&
7292 (cur->type == XML_ELEMENT_NODE) &&
7293 (xmlStrEqual(cur->name, BAD_CAST "html"))) {
7294 if (encoding != NULL)
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007295 htmlSetMetaEncoding((htmlDocPtr) doc,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007296 (const xmlChar *) encoding);
7297 else
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00007298 htmlSetMetaEncoding((htmlDocPtr) doc, BAD_CAST "UTF-8");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007299 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007300 }
7301
7302 if (is_xhtml)
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007303 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007304 else
7305#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00007306 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007307}
7308
7309/**
Owen Taylor3473f882001-02-23 17:55:21 +00007310 * xmlDocContentDumpOutput:
7311 * @buf: the XML buffer output
7312 * @cur: the document
7313 * @encoding: an optional encoding string
7314 * @format: should formatting spaces been added
7315 *
7316 * Dump an XML document.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007317 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007318 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007319 */
7320static void
7321xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
7322 const char *encoding, int format) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007323#ifdef LIBXML_HTML_ENABLED
7324 xmlDtdPtr dtd;
7325 int is_xhtml = 0;
7326#endif
7327
Owen Taylor3473f882001-02-23 17:55:21 +00007328 xmlOutputBufferWriteString(buf, "<?xml version=");
7329 if (cur->version != NULL)
7330 xmlBufferWriteQuotedString(buf->buffer, cur->version);
7331 else
7332 xmlOutputBufferWriteString(buf, "\"1.0\"");
7333 if (encoding == NULL) {
7334 if (cur->encoding != NULL)
7335 encoding = (const char *) cur->encoding;
7336 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
7337 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
7338 }
7339 if (encoding != NULL) {
7340 xmlOutputBufferWriteString(buf, " encoding=");
7341 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
7342 }
7343 switch (cur->standalone) {
7344 case 0:
7345 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
7346 break;
7347 case 1:
7348 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
7349 break;
7350 }
7351 xmlOutputBufferWriteString(buf, "?>\n");
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007352
7353#ifdef LIBXML_HTML_ENABLED
7354 dtd = xmlGetIntSubset(cur);
7355 if (dtd != NULL) {
7356 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
7357 if (is_xhtml < 0) is_xhtml = 0;
7358 }
7359 if (is_xhtml) {
7360 if (encoding != NULL)
7361 htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
7362 else
7363 htmlSetMetaEncoding(cur, BAD_CAST "UTF-8");
7364 }
7365#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007366 if (cur->children != NULL) {
7367 xmlNodePtr child = cur->children;
7368
7369 while (child != NULL) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007370#ifdef LIBXML_HTML_ENABLED
7371 if (is_xhtml)
7372 xhtmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
7373 else
7374#endif
7375 xmlNodeDumpOutputInternal(buf, cur, child, 0, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007376 xmlOutputBufferWriteString(buf, "\n");
7377 child = child->next;
7378 }
7379 }
7380}
7381
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007382#ifdef LIBXML_HTML_ENABLED
7383/************************************************************************
7384 * *
7385 * Functions specific to XHTML serialization *
7386 * *
7387 ************************************************************************/
7388
7389#define XHTML_STRICT_PUBLIC_ID BAD_CAST \
7390 "-//W3C//DTD XHTML 1.0 Strict//EN"
7391#define XHTML_STRICT_SYSTEM_ID BAD_CAST \
7392 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
7393#define XHTML_FRAME_PUBLIC_ID BAD_CAST \
7394 "-//W3C//DTD XHTML 1.0 Frameset//EN"
7395#define XHTML_FRAME_SYSTEM_ID BAD_CAST \
7396 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
7397#define XHTML_TRANS_PUBLIC_ID BAD_CAST \
7398 "-//W3C//DTD XHTML 1.0 Transitional//EN"
7399#define XHTML_TRANS_SYSTEM_ID BAD_CAST \
7400 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
7401
7402#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
7403/**
7404 * xmlIsXHTML:
7405 * @systemID: the system identifier
7406 * @publicID: the public identifier
7407 *
7408 * Try to find if the document correspond to an XHTML DTD
7409 *
7410 * Returns 1 if true, 0 if not and -1 in case of error
7411 */
7412int
7413xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) {
7414 if ((systemID == NULL) && (publicID == NULL))
7415 return(-1);
7416 if (publicID != NULL) {
7417 if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1);
7418 if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1);
7419 if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1);
7420 }
7421 if (systemID != NULL) {
7422 if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1);
7423 if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1);
7424 if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1);
7425 }
7426 return(0);
7427}
7428
7429/**
7430 * xhtmlIsEmpty:
7431 * @node: the node
7432 *
7433 * Check if a node is an empty xhtml node
7434 *
7435 * Returns 1 if the node is an empty node, 0 if not and -1 in case of error
7436 */
7437static int
7438xhtmlIsEmpty(xmlNodePtr node) {
7439 if (node == NULL)
7440 return(-1);
7441 if (node->type != XML_ELEMENT_NODE)
7442 return(0);
7443 if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME)))
7444 return(0);
7445 if (node->children != NULL)
7446 return(0);
7447 switch (node->name[0]) {
7448 case 'a':
7449 if (xmlStrEqual(node->name, BAD_CAST "area"))
7450 return(1);
7451 return(0);
7452 case 'b':
7453 if (xmlStrEqual(node->name, BAD_CAST "br"))
7454 return(1);
7455 if (xmlStrEqual(node->name, BAD_CAST "base"))
7456 return(1);
7457 if (xmlStrEqual(node->name, BAD_CAST "basefont"))
7458 return(1);
7459 return(0);
7460 case 'c':
7461 if (xmlStrEqual(node->name, BAD_CAST "col"))
7462 return(1);
7463 return(0);
7464 case 'f':
7465 if (xmlStrEqual(node->name, BAD_CAST "frame"))
7466 return(1);
7467 return(0);
7468 case 'h':
7469 if (xmlStrEqual(node->name, BAD_CAST "hr"))
7470 return(1);
7471 return(0);
7472 case 'i':
7473 if (xmlStrEqual(node->name, BAD_CAST "img"))
7474 return(1);
7475 if (xmlStrEqual(node->name, BAD_CAST "input"))
7476 return(1);
7477 if (xmlStrEqual(node->name, BAD_CAST "isindex"))
7478 return(1);
7479 return(0);
7480 case 'l':
7481 if (xmlStrEqual(node->name, BAD_CAST "link"))
7482 return(1);
7483 return(0);
7484 case 'm':
7485 if (xmlStrEqual(node->name, BAD_CAST "meta"))
7486 return(1);
7487 return(0);
7488 case 'p':
7489 if (xmlStrEqual(node->name, BAD_CAST "param"))
7490 return(1);
7491 return(0);
7492 }
7493 return(0);
7494}
7495
7496/**
7497 * xhtmlAttrListDumpOutput:
7498 * @buf: the XML buffer output
7499 * @doc: the document
7500 * @cur: the first attribute pointer
7501 * @encoding: an optional encoding string
7502 *
7503 * Dump a list of XML attributes
7504 */
7505static void
7506xhtmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7507 xmlAttrPtr cur, const char *encoding) {
7508 xmlAttrPtr xml_lang = NULL;
7509 xmlAttrPtr lang = NULL;
7510 xmlAttrPtr name = NULL;
7511 xmlAttrPtr id = NULL;
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007512 xmlNodePtr parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007513
7514 if (cur == NULL) {
7515#ifdef DEBUG_TREE
7516 xmlGenericError(xmlGenericErrorContext,
7517 "xmlAttrListDumpOutput : property == NULL\n");
7518#endif
7519 return;
7520 }
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007521 parent = cur->parent;
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007522 while (cur != NULL) {
7523 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id")))
7524 id = cur;
7525 else
7526 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name")))
7527 name = cur;
7528 else
7529 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")))
7530 lang = cur;
7531 else
7532 if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) &&
7533 (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml")))
7534 xml_lang = cur;
7535 else if ((cur->ns == NULL) &&
7536 ((cur->children == NULL) ||
7537 (cur->children->content == NULL) ||
7538 (cur->children->content[0] == 0)) &&
7539 (htmlIsBooleanAttr(cur->name))) {
7540 if (cur->children != NULL)
7541 xmlFreeNode(cur->children);
7542 cur->children = xmlNewText(cur->name);
7543 if (cur->children != NULL)
7544 cur->children->parent = (xmlNodePtr) cur;
7545 }
7546 xmlAttrDumpOutput(buf, doc, cur, encoding);
7547 cur = cur->next;
7548 }
7549 /*
7550 * C.8
7551 */
7552 if ((name != NULL) && (id == NULL)) {
Daniel Veillardfd7ce5f2003-02-10 16:12:39 +00007553 if ((parent != NULL) && (parent->name != NULL) &&
7554 ((xmlStrEqual(parent->name, BAD_CAST "a")) ||
7555 (xmlStrEqual(parent->name, BAD_CAST "p")) ||
7556 (xmlStrEqual(parent->name, BAD_CAST "div")) ||
7557 (xmlStrEqual(parent->name, BAD_CAST "img")) ||
7558 (xmlStrEqual(parent->name, BAD_CAST "map")) ||
7559 (xmlStrEqual(parent->name, BAD_CAST "applet")) ||
7560 (xmlStrEqual(parent->name, BAD_CAST "form")) ||
7561 (xmlStrEqual(parent->name, BAD_CAST "frame")) ||
7562 (xmlStrEqual(parent->name, BAD_CAST "iframe")))) {
7563 xmlOutputBufferWriteString(buf, " id=\"");
7564 xmlAttrSerializeContent(buf->buffer, doc, name);
7565 xmlOutputBufferWriteString(buf, "\"");
7566 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007567 }
7568 /*
7569 * C.7.
7570 */
7571 if ((lang != NULL) && (xml_lang == NULL)) {
7572 xmlOutputBufferWriteString(buf, " xml:lang=\"");
7573 xmlAttrSerializeContent(buf->buffer, doc, lang);
7574 xmlOutputBufferWriteString(buf, "\"");
7575 } else
7576 if ((xml_lang != NULL) && (lang == NULL)) {
7577 xmlOutputBufferWriteString(buf, " lang=\"");
7578 xmlAttrSerializeContent(buf->buffer, doc, xml_lang);
7579 xmlOutputBufferWriteString(buf, "\"");
7580 }
7581}
7582
7583/**
7584 * xhtmlNodeListDumpOutput:
7585 * @buf: the XML buffer output
7586 * @doc: the XHTML document
7587 * @cur: the first node
7588 * @level: the imbrication level for indenting
7589 * @format: is formatting allowed
7590 * @encoding: an optional encoding string
7591 *
7592 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007593 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007594 * or xmlKeepBlanksDefault(0) was called
7595 */
7596static void
7597xhtmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7598 xmlNodePtr cur, int level, int format, const char *encoding) {
7599 int i;
7600
7601 if (cur == NULL) {
7602#ifdef DEBUG_TREE
7603 xmlGenericError(xmlGenericErrorContext,
7604 "xhtmlNodeListDumpOutput : node == NULL\n");
7605#endif
7606 return;
7607 }
7608 while (cur != NULL) {
7609 if ((format) && (xmlIndentTreeOutput) &&
7610 (cur->type == XML_ELEMENT_NODE))
7611 for (i = 0;i < level;i++)
7612 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7613 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
7614 if (format) {
7615 xmlOutputBufferWriteString(buf, "\n");
7616 }
7617 cur = cur->next;
7618 }
7619}
7620
7621/**
7622 * xhtmlNodeDumpOutput:
7623 * @buf: the XML buffer output
7624 * @doc: the XHTML document
7625 * @cur: the current node
7626 * @level: the imbrication level for indenting
7627 * @format: is formatting allowed
7628 * @encoding: an optional encoding string
7629 *
7630 * Dump an XHTML node, recursive behaviour, children are printed too.
Daniel Veillard7424eb62003-01-24 14:14:52 +00007631 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007632 * or xmlKeepBlanksDefault(0) was called
7633 */
7634static void
7635xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7636 int level, int format, const char *encoding) {
7637 int i;
7638 xmlNodePtr tmp;
7639
7640 if (cur == NULL) {
7641#ifdef DEBUG_TREE
7642 xmlGenericError(xmlGenericErrorContext,
7643 "xmlNodeDumpOutput : node == NULL\n");
7644#endif
7645 return;
7646 }
7647 if (cur->type == XML_XINCLUDE_START)
7648 return;
7649 if (cur->type == XML_XINCLUDE_END)
7650 return;
7651 if (cur->type == XML_DTD_NODE) {
7652 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7653 return;
7654 }
7655 if (cur->type == XML_ELEMENT_DECL) {
7656 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7657 return;
7658 }
7659 if (cur->type == XML_ATTRIBUTE_DECL) {
7660 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7661 return;
7662 }
7663 if (cur->type == XML_ENTITY_DECL) {
7664 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7665 return;
7666 }
7667 if (cur->type == XML_TEXT_NODE) {
7668 if (cur->content != NULL) {
7669 if ((cur->name == xmlStringText) ||
7670 (cur->name != xmlStringTextNoenc)) {
7671 xmlChar *buffer;
7672
7673 if (encoding == NULL)
7674 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7675 else
7676 buffer = xmlEncodeSpecialChars(doc, cur->content);
7677 if (buffer != NULL) {
7678 xmlOutputBufferWriteString(buf, (const char *)buffer);
7679 xmlFree(buffer);
7680 }
7681 } else {
7682 /*
7683 * Disable escaping, needed for XSLT
7684 */
7685 xmlOutputBufferWriteString(buf, (const char *) cur->content);
7686 }
7687 }
7688
7689 return;
7690 }
7691 if (cur->type == XML_PI_NODE) {
7692 if (cur->content != NULL) {
7693 xmlOutputBufferWriteString(buf, "<?");
7694 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7695 if (cur->content != NULL) {
7696 xmlOutputBufferWriteString(buf, " ");
7697 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7698 }
7699 xmlOutputBufferWriteString(buf, "?>");
7700 } else {
7701 xmlOutputBufferWriteString(buf, "<?");
7702 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7703 xmlOutputBufferWriteString(buf, "?>");
7704 }
7705 return;
7706 }
7707 if (cur->type == XML_COMMENT_NODE) {
7708 if (cur->content != NULL) {
7709 xmlOutputBufferWriteString(buf, "<!--");
7710 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7711 xmlOutputBufferWriteString(buf, "-->");
7712 }
7713 return;
7714 }
7715 if (cur->type == XML_ENTITY_REF_NODE) {
7716 xmlOutputBufferWriteString(buf, "&");
7717 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7718 xmlOutputBufferWriteString(buf, ";");
7719 return;
7720 }
7721 if (cur->type == XML_CDATA_SECTION_NODE) {
7722 xmlOutputBufferWriteString(buf, "<![CDATA[");
7723 if (cur->content != NULL)
7724 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7725 xmlOutputBufferWriteString(buf, "]]>");
7726 return;
7727 }
7728
7729 if (format == 1) {
7730 tmp = cur->children;
7731 while (tmp != NULL) {
7732 if ((tmp->type == XML_TEXT_NODE) ||
7733 (tmp->type == XML_ENTITY_REF_NODE)) {
7734 format = 0;
7735 break;
7736 }
7737 tmp = tmp->next;
7738 }
7739 }
7740 xmlOutputBufferWriteString(buf, "<");
7741 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7742 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7743 xmlOutputBufferWriteString(buf, ":");
7744 }
7745
7746 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7747 if (cur->nsDef)
7748 xmlNsListDumpOutput(buf, cur->nsDef);
7749 if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
7750 (cur->ns == NULL) && (cur->nsDef == NULL))) {
7751 /*
7752 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
7753 */
7754 xmlOutputBufferWriteString(buf,
7755 " xmlns=\"http://www.w3.org/1999/xhtml\"");
7756 }
7757 if (cur->properties != NULL)
7758 xhtmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7759
7760 if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) {
7761 if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
7762 (xhtmlIsEmpty(cur) == 1)) {
7763 /*
7764 * C.2. Empty Elements
7765 */
7766 xmlOutputBufferWriteString(buf, " />");
7767 } else {
7768 /*
7769 * C.3. Element Minimization and Empty Element Content
7770 */
7771 xmlOutputBufferWriteString(buf, "></");
7772 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7773 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7774 xmlOutputBufferWriteString(buf, ":");
7775 }
7776 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7777 xmlOutputBufferWriteString(buf, ">");
7778 }
7779 return;
7780 }
7781 xmlOutputBufferWriteString(buf, ">");
7782 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
7783 xmlChar *buffer;
7784
7785 if (encoding == NULL)
7786 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7787 else
7788 buffer = xmlEncodeSpecialChars(doc, cur->content);
7789 if (buffer != NULL) {
7790 xmlOutputBufferWriteString(buf, (const char *)buffer);
7791 xmlFree(buffer);
7792 }
7793 }
7794
7795 /*
7796 * 4.8. Script and Style elements
7797 */
7798 if ((cur->type == XML_ELEMENT_NODE) &&
7799 ((xmlStrEqual(cur->name, BAD_CAST "script")) ||
7800 (xmlStrEqual(cur->name, BAD_CAST "style"))) &&
7801 ((cur->ns == NULL) ||
7802 (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) {
7803 xmlNodePtr child = cur->children;
7804
7805 while (child != NULL) {
7806 if ((child->type == XML_TEXT_NODE) ||
7807 (child->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard64b35282002-12-04 15:10:40 +00007808 /*
7809 * Apparently CDATA escaping for style just break on IE,
7810 * mozilla and galeon, so ...
7811 */
7812 if (xmlStrEqual(cur->name, BAD_CAST "style") &&
7813 (xmlStrchr(child->content, '<') == NULL) &&
7814 (xmlStrchr(child->content, '>') == NULL) &&
7815 (xmlStrchr(child->content, '&') == NULL)) {
7816 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7817 } else {
7818 xmlOutputBufferWriteString(buf, "<![CDATA[");
7819 if (child->content != NULL)
7820 xmlOutputBufferWriteString(buf,
7821 (const char *)child->content);
7822 xmlOutputBufferWriteString(buf, "]]>");
7823 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007824 } else {
7825 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7826 }
7827 child = child->next;
7828 }
7829 } else if (cur->children != NULL) {
7830 if (format) xmlOutputBufferWriteString(buf, "\n");
7831 xhtmlNodeListDumpOutput(buf, doc, cur->children,
7832 (level >= 0?level+1:-1), format, encoding);
7833 if ((xmlIndentTreeOutput) && (format))
7834 for (i = 0;i < level;i++)
7835 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7836 }
7837 xmlOutputBufferWriteString(buf, "</");
7838 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7839 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7840 xmlOutputBufferWriteString(buf, ":");
7841 }
7842
7843 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7844 xmlOutputBufferWriteString(buf, ">");
7845}
7846#endif
7847
Owen Taylor3473f882001-02-23 17:55:21 +00007848/************************************************************************
7849 * *
7850 * Saving functions front-ends *
7851 * *
7852 ************************************************************************/
7853
7854/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00007855 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00007856 * @out_doc: Document to generate XML text from
7857 * @doc_txt_ptr: Memory pointer for allocated XML text
7858 * @doc_txt_len: Length of the generated XML text
7859 * @txt_encoding: Character encoding to use when generating XML text
7860 * @format: should formatting spaces been added
7861 *
7862 * Dump the current DOM tree into memory using the character encoding specified
7863 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007864 * allocated memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00007865 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007866 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007867 */
7868
7869void
7870xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007871 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007872 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007873 int dummy = 0;
7874
Owen Taylor3473f882001-02-23 17:55:21 +00007875 xmlOutputBufferPtr out_buff = NULL;
7876 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
7877
7878 if (doc_txt_len == NULL) {
7879 doc_txt_len = &dummy; /* Continue, caller just won't get length */
7880 }
7881
7882 if (doc_txt_ptr == NULL) {
7883 *doc_txt_len = 0;
7884 xmlGenericError(xmlGenericErrorContext,
7885 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
7886 return;
7887 }
7888
7889 *doc_txt_ptr = NULL;
7890 *doc_txt_len = 0;
7891
7892 if (out_doc == NULL) {
7893 /* No document, no output */
7894 xmlGenericError(xmlGenericErrorContext,
7895 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
7896 return;
7897 }
7898
7899 /*
7900 * Validate the encoding value, if provided.
7901 * This logic is copied from xmlSaveFileEnc.
7902 */
7903
7904 if (txt_encoding == NULL)
7905 txt_encoding = (const char *) out_doc->encoding;
7906 if (txt_encoding != NULL) {
Daniel Veillarde1326112003-06-05 09:32:20 +00007907 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00007908 if ( conv_hdlr == NULL ) {
7909 xmlGenericError(xmlGenericErrorContext,
7910 "%s: %s %s '%s'\n",
7911 "xmlDocDumpFormatMemoryEnc",
7912 "Failed to identify encoding handler for",
7913 "character set",
7914 txt_encoding);
7915 return;
7916 }
7917 }
Owen Taylor3473f882001-02-23 17:55:21 +00007918
7919 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
7920 xmlGenericError(xmlGenericErrorContext,
7921 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
7922 return;
7923 }
7924
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007925 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007926 xmlOutputBufferFlush(out_buff);
7927 if (out_buff->conv != NULL) {
7928 *doc_txt_len = out_buff->conv->use;
7929 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
7930 } else {
7931 *doc_txt_len = out_buff->buffer->use;
7932 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
7933 }
7934 (void)xmlOutputBufferClose(out_buff);
7935
7936 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
7937 *doc_txt_len = 0;
7938 xmlGenericError(xmlGenericErrorContext,
7939 "xmlDocDumpFormatMemoryEnc: %s\n",
7940 "Failed to allocate memory for document text representation.");
7941 }
7942
7943 return;
7944}
7945
7946/**
7947 * xmlDocDumpMemory:
7948 * @cur: the document
7949 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007950 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007951 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007952 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007953 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007954 */
7955void
7956xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
7957 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
7958}
7959
7960/**
7961 * xmlDocDumpFormatMemory:
7962 * @cur: the document
7963 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007964 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007965 * @format: should formatting spaces been added
7966 *
7967 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007968 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007969 * It's up to the caller to free the memory with xmlFree().
Daniel Veillard7424eb62003-01-24 14:14:52 +00007970 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007971 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007972 */
7973void
7974xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
7975 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
7976}
7977
7978/**
7979 * xmlDocDumpMemoryEnc:
7980 * @out_doc: Document to generate XML text from
7981 * @doc_txt_ptr: Memory pointer for allocated XML text
7982 * @doc_txt_len: Length of the generated XML text
7983 * @txt_encoding: Character encoding to use when generating XML text
7984 *
7985 * Dump the current DOM tree into memory using the character encoding specified
7986 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007987 * allocated memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007988 */
7989
7990void
7991xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
7992 int * doc_txt_len, const char * txt_encoding) {
7993 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007994 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007995}
7996
7997/**
7998 * xmlGetDocCompressMode:
7999 * @doc: the document
8000 *
8001 * get the compression ratio for a document, ZLIB based
8002 * Returns 0 (uncompressed) to 9 (max compression)
8003 */
8004int
8005xmlGetDocCompressMode (xmlDocPtr doc) {
8006 if (doc == NULL) return(-1);
8007 return(doc->compression);
8008}
8009
8010/**
8011 * xmlSetDocCompressMode:
8012 * @doc: the document
8013 * @mode: the compression ratio
8014 *
8015 * set the compression ratio for a document, ZLIB based
8016 * Correct values: 0 (uncompressed) to 9 (max compression)
8017 */
8018void
8019xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
8020 if (doc == NULL) return;
8021 if (mode < 0) doc->compression = 0;
8022 else if (mode > 9) doc->compression = 9;
8023 else doc->compression = mode;
8024}
8025
8026/**
8027 * xmlGetCompressMode:
8028 *
8029 * get the default compression mode used, ZLIB based.
8030 * Returns 0 (uncompressed) to 9 (max compression)
8031 */
8032int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008033xmlGetCompressMode(void)
8034{
8035 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00008036}
8037
8038/**
8039 * xmlSetCompressMode:
8040 * @mode: the compression ratio
8041 *
8042 * set the default compression mode used, ZLIB based
8043 * Correct values: 0 (uncompressed) to 9 (max compression)
8044 */
8045void
8046xmlSetCompressMode(int mode) {
8047 if (mode < 0) xmlCompressMode = 0;
8048 else if (mode > 9) xmlCompressMode = 9;
8049 else xmlCompressMode = mode;
8050}
8051
8052/**
Daniel Veillard9e412302002-06-10 15:59:44 +00008053 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00008054 * @f: the FILE*
8055 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00008056 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00008057 *
8058 * Dump an XML document to an open FILE.
8059 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008060 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008061 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8062 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008063 */
8064int
Daniel Veillard9e412302002-06-10 15:59:44 +00008065xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00008066 xmlOutputBufferPtr buf;
8067 const char * encoding;
8068 xmlCharEncodingHandlerPtr handler = NULL;
8069 int ret;
8070
8071 if (cur == NULL) {
8072#ifdef DEBUG_TREE
8073 xmlGenericError(xmlGenericErrorContext,
8074 "xmlDocDump : document == NULL\n");
8075#endif
8076 return(-1);
8077 }
8078 encoding = (const char *) cur->encoding;
8079
8080 if (encoding != NULL) {
Daniel Veillarde1326112003-06-05 09:32:20 +00008081 handler = xmlFindCharEncodingHandler(encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00008082 if (handler == NULL) {
8083 xmlFree((char *) cur->encoding);
8084 cur->encoding = NULL;
8085 }
8086 }
Owen Taylor3473f882001-02-23 17:55:21 +00008087 buf = xmlOutputBufferCreateFile(f, handler);
8088 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00008089 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008090
8091 ret = xmlOutputBufferClose(buf);
8092 return(ret);
8093}
8094
8095/**
Daniel Veillard9e412302002-06-10 15:59:44 +00008096 * xmlDocDump:
8097 * @f: the FILE*
8098 * @cur: the document
8099 *
8100 * Dump an XML document to an open FILE.
8101 *
8102 * returns: the number of bytes written or -1 in case of failure.
8103 */
8104int
8105xmlDocDump(FILE *f, xmlDocPtr cur) {
8106 return(xmlDocFormatDump (f, cur, 0));
8107}
8108
8109/**
Owen Taylor3473f882001-02-23 17:55:21 +00008110 * xmlSaveFileTo:
8111 * @buf: an output I/O buffer
8112 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00008113 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00008114 *
8115 * Dump an XML document to an I/O buffer.
8116 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008117 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008118 */
8119int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00008120xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00008121 int ret;
8122
8123 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00008124 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008125 ret = xmlOutputBufferClose(buf);
8126 return(ret);
8127}
8128
8129/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00008130 * xmlSaveFormatFileTo:
8131 * @buf: an output I/O buffer
8132 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00008133 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00008134 * @format: should formatting spaces been added
8135 *
8136 * Dump an XML document to an I/O buffer.
8137 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008138 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008139 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8140 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardeefd4492001-04-28 16:55:50 +00008141 */
8142int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00008143xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00008144 int ret;
8145
8146 if (buf == NULL) return(0);
8147 xmlDocContentDumpOutput(buf, cur, encoding, format);
8148 ret = xmlOutputBufferClose(buf);
8149 return(ret);
8150}
8151
8152/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00008153 * xmlSaveFormatFileEnc:
Daniel Veillardf012a642001-07-23 19:10:52 +00008154 * @filename: the filename or URL to output
8155 * @cur: the document being saved
8156 * @encoding: the name of the encoding to use or NULL.
8157 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00008158 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00008159 * Dump an XML document to a file or an URL.
8160 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008161 * Returns the number of bytes written or -1 in case of error.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008162 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8163 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00008164 */
8165int
Daniel Veillardf012a642001-07-23 19:10:52 +00008166xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
8167 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00008168 xmlOutputBufferPtr buf;
8169 xmlCharEncodingHandlerPtr handler = NULL;
8170 int ret;
8171
Daniel Veillard4dbe77a2003-01-14 00:17:42 +00008172 if (cur == NULL)
8173 return(-1);
8174
Daniel Veillardfb25a512002-01-13 20:32:08 +00008175 if (encoding == NULL)
8176 encoding = (const char *) cur->encoding;
8177
Owen Taylor3473f882001-02-23 17:55:21 +00008178 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00008179
Owen Taylor3473f882001-02-23 17:55:21 +00008180 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00008181 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00008182 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00008183 }
8184
Daniel Veillardf012a642001-07-23 19:10:52 +00008185#ifdef HAVE_ZLIB_H
8186 if (cur->compression < 0) cur->compression = xmlCompressMode;
8187#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008188 /*
8189 * save the content to a temp buffer.
8190 */
Daniel Veillardf012a642001-07-23 19:10:52 +00008191 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00008192 if (buf == NULL) return(-1);
8193
Daniel Veillardf012a642001-07-23 19:10:52 +00008194 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00008195
8196 ret = xmlOutputBufferClose(buf);
8197 return(ret);
8198}
8199
Daniel Veillardf012a642001-07-23 19:10:52 +00008200
8201/**
8202 * xmlSaveFileEnc:
8203 * @filename: the filename (or URL)
8204 * @cur: the document
8205 * @encoding: the name of an encoding (or NULL)
8206 *
8207 * Dump an XML document, converting it to the given encoding
8208 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008209 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00008210 */
8211int
8212xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
8213 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
8214}
8215
Owen Taylor3473f882001-02-23 17:55:21 +00008216/**
Daniel Veillard67fee942001-04-26 18:59:03 +00008217 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00008218 * @filename: the filename (or URL)
8219 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00008220 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00008221 *
8222 * Dump an XML document to a file. Will use compression if
8223 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00008224 * used. If @format is set then the document will be indented on output.
Daniel Veillard7424eb62003-01-24 14:14:52 +00008225 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
8226 * or xmlKeepBlanksDefault(0) was called
Daniel Veillard67fee942001-04-26 18:59:03 +00008227 *
Daniel Veillardd1640922001-12-17 15:30:10 +00008228 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00008229 */
8230int
Daniel Veillard67fee942001-04-26 18:59:03 +00008231xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008232 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00008233}
8234
Daniel Veillard67fee942001-04-26 18:59:03 +00008235/**
8236 * xmlSaveFile:
8237 * @filename: the filename (or URL)
8238 * @cur: the document
8239 *
8240 * Dump an XML document to a file. Will use compression if
8241 * compiled in and enabled. If @filename is "-" the stdout file is
8242 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00008243 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00008244 */
8245int
8246xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00008247 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00008248}
8249