VirtualBox

source: vbox/trunk/src/libs/libxml2-2.6.30/tree.c@ 23598

最後變更 在這個檔案從23598是 16778,由 vboxsync 提交於 16 年 前

libxml2: some fixes from upstream

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Date Revision Author Id
檔案大小: 238.8 KB
 
1/*
2 * tree.c : implementation of access function for an XML tree.
3 *
4 * References:
5 * XHTML 1.0 W3C REC: http://www.w3.org/TR/2002/REC-xhtml1-20020801/
6 *
7 * See Copyright for the status of this software.
8 *
9 * [email protected]
10 *
11 */
12
13#define IN_LIBXML
14#include "libxml.h"
15
16#include <string.h> /* for memset() only ! */
17#include <limits.h>
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>
31#include <libxml/uri.h>
32#include <libxml/entities.h>
33#include <libxml/valid.h>
34#include <libxml/xmlerror.h>
35#include <libxml/parserInternals.h>
36#include <libxml/globals.h>
37#ifdef LIBXML_HTML_ENABLED
38#include <libxml/HTMLtree.h>
39#endif
40#ifdef LIBXML_DEBUG_ENABLED
41#include <libxml/debugXML.h>
42#endif
43
44int __xmlRegisterCallbacks = 0;
45
46/************************************************************************
47 * *
48 * Forward declarations *
49 * *
50 ************************************************************************/
51
52xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
53
54static xmlChar* xmlGetPropNodeValueInternal(xmlAttrPtr prop);
55
56/************************************************************************
57 * *
58 * Tree memory error handler *
59 * *
60 ************************************************************************/
61/**
62 * xmlTreeErrMemory:
63 * @extra: extra informations
64 *
65 * Handle an out of memory condition
66 */
67static void
68xmlTreeErrMemory(const char *extra)
69{
70 __xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra);
71}
72
73/**
74 * xmlTreeErr:
75 * @code: the error number
76 * @extra: extra informations
77 *
78 * Handle an out of memory condition
79 */
80static void
81xmlTreeErr(int code, xmlNodePtr node, const char *extra)
82{
83 const char *msg = NULL;
84
85 switch(code) {
86 case XML_TREE_INVALID_HEX:
87 msg = "invalid hexadecimal character value\n";
88 break;
89 case XML_TREE_INVALID_DEC:
90 msg = "invalid decimal character value\n";
91 break;
92 case XML_TREE_UNTERMINATED_ENTITY:
93 msg = "unterminated entity reference %15s\n";
94 break;
95 default:
96 msg = "unexpected error number\n";
97 }
98 __xmlSimpleError(XML_FROM_TREE, code, node, msg, extra);
99}
100
101/************************************************************************
102 * *
103 * A few static variables and macros *
104 * *
105 ************************************************************************/
106/* #undef xmlStringText */
107const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
108/* #undef xmlStringTextNoenc */
109const xmlChar xmlStringTextNoenc[] =
110 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
111/* #undef xmlStringComment */
112const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
113
114static int xmlCompressMode = 0;
115static int xmlCheckDTD = 1;
116
117#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
118 xmlNodePtr ulccur = (n)->children; \
119 if (ulccur == NULL) { \
120 (n)->last = NULL; \
121 } else { \
122 while (ulccur->next != NULL) { \
123 ulccur->parent = (n); \
124 ulccur = ulccur->next; \
125 } \
126 ulccur->parent = (n); \
127 (n)->last = ulccur; \
128}}
129
130#define IS_STR_XML(str) ((str != NULL) && (str[0] == 'x') && \
131 (str[1] == 'm') && (str[2] == 'l') && (str[3] == 0))
132
133/* #define DEBUG_BUFFER */
134/* #define DEBUG_TREE */
135
136/************************************************************************
137 * *
138 * Functions to move to entities.c once the *
139 * API freeze is smoothen and they can be made public. *
140 * *
141 ************************************************************************/
142#include <libxml/hash.h>
143
144#ifdef LIBXML_TREE_ENABLED
145/**
146 * xmlGetEntityFromDtd:
147 * @dtd: A pointer to the DTD to search
148 * @name: The entity name
149 *
150 * Do an entity lookup in the DTD entity hash table and
151 * return the corresponding entity, if found.
152 *
153 * Returns A pointer to the entity structure or NULL if not found.
154 */
155static xmlEntityPtr
156xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
157 xmlEntitiesTablePtr table;
158
159 if((dtd != NULL) && (dtd->entities != NULL)) {
160 table = (xmlEntitiesTablePtr) dtd->entities;
161 return((xmlEntityPtr) xmlHashLookup(table, name));
162 /* return(xmlGetEntityFromTable(table, name)); */
163 }
164 return(NULL);
165}
166/**
167 * xmlGetParameterEntityFromDtd:
168 * @dtd: A pointer to the DTD to search
169 * @name: The entity name
170 *
171 * Do an entity lookup in the DTD pararmeter entity hash table and
172 * return the corresponding entity, if found.
173 *
174 * Returns A pointer to the entity structure or NULL if not found.
175 */
176static xmlEntityPtr
177xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
178 xmlEntitiesTablePtr table;
179
180 if ((dtd != NULL) && (dtd->pentities != NULL)) {
181 table = (xmlEntitiesTablePtr) dtd->pentities;
182 return((xmlEntityPtr) xmlHashLookup(table, name));
183 /* return(xmlGetEntityFromTable(table, name)); */
184 }
185 return(NULL);
186}
187#endif /* LIBXML_TREE_ENABLED */
188
189/************************************************************************
190 * *
191 * QName handling helper *
192 * *
193 ************************************************************************/
194
195/**
196 * xmlBuildQName:
197 * @ncname: the Name
198 * @prefix: the prefix
199 * @memory: preallocated memory
200 * @len: preallocated memory length
201 *
202 * Builds the QName @prefix:@ncname in @memory if there is enough space
203 * and prefix is not NULL nor empty, otherwise allocate a new string.
204 * If prefix is NULL or empty it returns ncname.
205 *
206 * Returns the new string which must be freed by the caller if different from
207 * @memory and @ncname or NULL in case of error
208 */
209xmlChar *
210xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix,
211 xmlChar *memory, int len) {
212 int lenn, lenp;
213 xmlChar *ret;
214
215 if (ncname == NULL) return(NULL);
216 if (prefix == NULL) return((xmlChar *) ncname);
217
218 lenn = strlen((char *) ncname);
219 lenp = strlen((char *) prefix);
220
221 if ((memory == NULL) || (len < lenn + lenp + 2)) {
222 ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
223 if (ret == NULL) {
224 xmlTreeErrMemory("building QName");
225 return(NULL);
226 }
227 } else {
228 ret = memory;
229 }
230 memcpy(&ret[0], prefix, lenp);
231 ret[lenp] = ':';
232 memcpy(&ret[lenp + 1], ncname, lenn);
233 ret[lenn + lenp + 1] = 0;
234 return(ret);
235}
236
237/**
238 * xmlSplitQName2:
239 * @name: the full QName
240 * @prefix: a xmlChar **
241 *
242 * parse an XML qualified name string
243 *
244 * [NS 5] QName ::= (Prefix ':')? LocalPart
245 *
246 * [NS 6] Prefix ::= NCName
247 *
248 * [NS 7] LocalPart ::= NCName
249 *
250 * Returns NULL if not a QName, otherwise the local part, and prefix
251 * is updated to get the Prefix if any.
252 */
253
254xmlChar *
255xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
256 int len = 0;
257 xmlChar *ret = NULL;
258
259 if (prefix == NULL) return(NULL);
260 *prefix = NULL;
261 if (name == NULL) return(NULL);
262
263#ifndef XML_XML_NAMESPACE
264 /* xml: prefix is not really a namespace */
265 if ((name[0] == 'x') && (name[1] == 'm') &&
266 (name[2] == 'l') && (name[3] == ':'))
267 return(NULL);
268#endif
269
270 /* nasty but valid */
271 if (name[0] == ':')
272 return(NULL);
273
274 /*
275 * we are not trying to validate but just to cut, and yes it will
276 * work even if this is as set of UTF-8 encoded chars
277 */
278 while ((name[len] != 0) && (name[len] != ':'))
279 len++;
280
281 if (name[len] == 0)
282 return(NULL);
283
284 *prefix = xmlStrndup(name, len);
285 if (*prefix == NULL) {
286 xmlTreeErrMemory("QName split");
287 return(NULL);
288 }
289 ret = xmlStrdup(&name[len + 1]);
290 if (ret == NULL) {
291 xmlTreeErrMemory("QName split");
292 if (*prefix != NULL) {
293 xmlFree(*prefix);
294 *prefix = NULL;
295 }
296 return(NULL);
297 }
298
299 return(ret);
300}
301
302/**
303 * xmlSplitQName3:
304 * @name: the full QName
305 * @len: an int *
306 *
307 * parse an XML qualified name string,i
308 *
309 * returns NULL if it is not a Qualified Name, otherwise, update len
310 * with the lenght in byte of the prefix and return a pointer
311 * to the start of the name without the prefix
312 */
313
314const xmlChar *
315xmlSplitQName3(const xmlChar *name, int *len) {
316 int l = 0;
317
318 if (name == NULL) return(NULL);
319 if (len == NULL) return(NULL);
320
321 /* nasty but valid */
322 if (name[0] == ':')
323 return(NULL);
324
325 /*
326 * we are not trying to validate but just to cut, and yes it will
327 * work even if this is as set of UTF-8 encoded chars
328 */
329 while ((name[l] != 0) && (name[l] != ':'))
330 l++;
331
332 if (name[l] == 0)
333 return(NULL);
334
335 *len = l;
336
337 return(&name[l+1]);
338}
339
340/************************************************************************
341 * *
342 * Check Name, NCName and QName strings *
343 * *
344 ************************************************************************/
345
346#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
347
348#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_DEBUG_ENABLED) || defined (LIBXML_HTML_ENABLED) || defined(LIBXML_SAX1_ENABLED) || defined(LIBXML_HTML_ENABLED) || defined(LIBXML_WRITER_ENABLED) || defined(LIBXML_DOCB_ENABLED)
349/**
350 * xmlValidateNCName:
351 * @value: the value to check
352 * @space: allow spaces in front and end of the string
353 *
354 * Check that a value conforms to the lexical space of NCName
355 *
356 * Returns 0 if this validates, a positive error code number otherwise
357 * and -1 in case of internal or API error.
358 */
359int
360xmlValidateNCName(const xmlChar *value, int space) {
361 const xmlChar *cur = value;
362 int c,l;
363
364 if (value == NULL)
365 return(-1);
366
367 /*
368 * First quick algorithm for ASCII range
369 */
370 if (space)
371 while (IS_BLANK_CH(*cur)) cur++;
372 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
373 (*cur == '_'))
374 cur++;
375 else
376 goto try_complex;
377 while (((*cur >= 'a') && (*cur <= 'z')) ||
378 ((*cur >= 'A') && (*cur <= 'Z')) ||
379 ((*cur >= '0') && (*cur <= '9')) ||
380 (*cur == '_') || (*cur == '-') || (*cur == '.'))
381 cur++;
382 if (space)
383 while (IS_BLANK_CH(*cur)) cur++;
384 if (*cur == 0)
385 return(0);
386
387try_complex:
388 /*
389 * Second check for chars outside the ASCII range
390 */
391 cur = value;
392 c = CUR_SCHAR(cur, l);
393 if (space) {
394 while (IS_BLANK(c)) {
395 cur += l;
396 c = CUR_SCHAR(cur, l);
397 }
398 }
399 if ((!IS_LETTER(c)) && (c != '_'))
400 return(1);
401 cur += l;
402 c = CUR_SCHAR(cur, l);
403 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
404 (c == '-') || (c == '_') || IS_COMBINING(c) ||
405 IS_EXTENDER(c)) {
406 cur += l;
407 c = CUR_SCHAR(cur, l);
408 }
409 if (space) {
410 while (IS_BLANK(c)) {
411 cur += l;
412 c = CUR_SCHAR(cur, l);
413 }
414 }
415 if (c != 0)
416 return(1);
417
418 return(0);
419}
420#endif
421
422#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
423/**
424 * xmlValidateQName:
425 * @value: the value to check
426 * @space: allow spaces in front and end of the string
427 *
428 * Check that a value conforms to the lexical space of QName
429 *
430 * Returns 0 if this validates, a positive error code number otherwise
431 * and -1 in case of internal or API error.
432 */
433int
434xmlValidateQName(const xmlChar *value, int space) {
435 const xmlChar *cur = value;
436 int c,l;
437
438 if (value == NULL)
439 return(-1);
440 /*
441 * First quick algorithm for ASCII range
442 */
443 if (space)
444 while (IS_BLANK_CH(*cur)) cur++;
445 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
446 (*cur == '_'))
447 cur++;
448 else
449 goto try_complex;
450 while (((*cur >= 'a') && (*cur <= 'z')) ||
451 ((*cur >= 'A') && (*cur <= 'Z')) ||
452 ((*cur >= '0') && (*cur <= '9')) ||
453 (*cur == '_') || (*cur == '-') || (*cur == '.'))
454 cur++;
455 if (*cur == ':') {
456 cur++;
457 if (((*cur >= 'a') && (*cur <= 'z')) ||
458 ((*cur >= 'A') && (*cur <= 'Z')) ||
459 (*cur == '_'))
460 cur++;
461 else
462 goto try_complex;
463 while (((*cur >= 'a') && (*cur <= 'z')) ||
464 ((*cur >= 'A') && (*cur <= 'Z')) ||
465 ((*cur >= '0') && (*cur <= '9')) ||
466 (*cur == '_') || (*cur == '-') || (*cur == '.'))
467 cur++;
468 }
469 if (space)
470 while (IS_BLANK_CH(*cur)) cur++;
471 if (*cur == 0)
472 return(0);
473
474try_complex:
475 /*
476 * Second check for chars outside the ASCII range
477 */
478 cur = value;
479 c = CUR_SCHAR(cur, l);
480 if (space) {
481 while (IS_BLANK(c)) {
482 cur += l;
483 c = CUR_SCHAR(cur, l);
484 }
485 }
486 if ((!IS_LETTER(c)) && (c != '_'))
487 return(1);
488 cur += l;
489 c = CUR_SCHAR(cur, l);
490 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
491 (c == '-') || (c == '_') || IS_COMBINING(c) ||
492 IS_EXTENDER(c)) {
493 cur += l;
494 c = CUR_SCHAR(cur, l);
495 }
496 if (c == ':') {
497 cur += l;
498 c = CUR_SCHAR(cur, l);
499 if ((!IS_LETTER(c)) && (c != '_'))
500 return(1);
501 cur += l;
502 c = CUR_SCHAR(cur, l);
503 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
504 (c == '-') || (c == '_') || IS_COMBINING(c) ||
505 IS_EXTENDER(c)) {
506 cur += l;
507 c = CUR_SCHAR(cur, l);
508 }
509 }
510 if (space) {
511 while (IS_BLANK(c)) {
512 cur += l;
513 c = CUR_SCHAR(cur, l);
514 }
515 }
516 if (c != 0)
517 return(1);
518 return(0);
519}
520
521/**
522 * xmlValidateName:
523 * @value: the value to check
524 * @space: allow spaces in front and end of the string
525 *
526 * Check that a value conforms to the lexical space of Name
527 *
528 * Returns 0 if this validates, a positive error code number otherwise
529 * and -1 in case of internal or API error.
530 */
531int
532xmlValidateName(const xmlChar *value, int space) {
533 const xmlChar *cur = value;
534 int c,l;
535
536 if (value == NULL)
537 return(-1);
538 /*
539 * First quick algorithm for ASCII range
540 */
541 if (space)
542 while (IS_BLANK_CH(*cur)) cur++;
543 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
544 (*cur == '_') || (*cur == ':'))
545 cur++;
546 else
547 goto try_complex;
548 while (((*cur >= 'a') && (*cur <= 'z')) ||
549 ((*cur >= 'A') && (*cur <= 'Z')) ||
550 ((*cur >= '0') && (*cur <= '9')) ||
551 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
552 cur++;
553 if (space)
554 while (IS_BLANK_CH(*cur)) cur++;
555 if (*cur == 0)
556 return(0);
557
558try_complex:
559 /*
560 * Second check for chars outside the ASCII range
561 */
562 cur = value;
563 c = CUR_SCHAR(cur, l);
564 if (space) {
565 while (IS_BLANK(c)) {
566 cur += l;
567 c = CUR_SCHAR(cur, l);
568 }
569 }
570 if ((!IS_LETTER(c)) && (c != '_') && (c != ':'))
571 return(1);
572 cur += l;
573 c = CUR_SCHAR(cur, l);
574 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
575 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
576 cur += l;
577 c = CUR_SCHAR(cur, l);
578 }
579 if (space) {
580 while (IS_BLANK(c)) {
581 cur += l;
582 c = CUR_SCHAR(cur, l);
583 }
584 }
585 if (c != 0)
586 return(1);
587 return(0);
588}
589
590/**
591 * xmlValidateNMToken:
592 * @value: the value to check
593 * @space: allow spaces in front and end of the string
594 *
595 * Check that a value conforms to the lexical space of NMToken
596 *
597 * Returns 0 if this validates, a positive error code number otherwise
598 * and -1 in case of internal or API error.
599 */
600int
601xmlValidateNMToken(const xmlChar *value, int space) {
602 const xmlChar *cur = value;
603 int c,l;
604
605 if (value == NULL)
606 return(-1);
607 /*
608 * First quick algorithm for ASCII range
609 */
610 if (space)
611 while (IS_BLANK_CH(*cur)) cur++;
612 if (((*cur >= 'a') && (*cur <= 'z')) ||
613 ((*cur >= 'A') && (*cur <= 'Z')) ||
614 ((*cur >= '0') && (*cur <= '9')) ||
615 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
616 cur++;
617 else
618 goto try_complex;
619 while (((*cur >= 'a') && (*cur <= 'z')) ||
620 ((*cur >= 'A') && (*cur <= 'Z')) ||
621 ((*cur >= '0') && (*cur <= '9')) ||
622 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
623 cur++;
624 if (space)
625 while (IS_BLANK_CH(*cur)) cur++;
626 if (*cur == 0)
627 return(0);
628
629try_complex:
630 /*
631 * Second check for chars outside the ASCII range
632 */
633 cur = value;
634 c = CUR_SCHAR(cur, l);
635 if (space) {
636 while (IS_BLANK(c)) {
637 cur += l;
638 c = CUR_SCHAR(cur, l);
639 }
640 }
641 if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
642 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)))
643 return(1);
644 cur += l;
645 c = CUR_SCHAR(cur, l);
646 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
647 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
648 cur += l;
649 c = CUR_SCHAR(cur, l);
650 }
651 if (space) {
652 while (IS_BLANK(c)) {
653 cur += l;
654 c = CUR_SCHAR(cur, l);
655 }
656 }
657 if (c != 0)
658 return(1);
659 return(0);
660}
661#endif /* LIBXML_TREE_ENABLED */
662
663/************************************************************************
664 * *
665 * Allocation and deallocation of basic structures *
666 * *
667 ************************************************************************/
668
669/**
670 * xmlSetBufferAllocationScheme:
671 * @scheme: allocation method to use
672 *
673 * Set the buffer allocation method. Types are
674 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
675 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
676 * improves performance
677 */
678void
679xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
680 xmlBufferAllocScheme = scheme;
681}
682
683/**
684 * xmlGetBufferAllocationScheme:
685 *
686 * Types are
687 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
688 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
689 * improves performance
690 *
691 * Returns the current allocation scheme
692 */
693xmlBufferAllocationScheme
694xmlGetBufferAllocationScheme(void) {
695 return(xmlBufferAllocScheme);
696}
697
698/**
699 * xmlNewNs:
700 * @node: the element carrying the namespace
701 * @href: the URI associated
702 * @prefix: the prefix for the namespace
703 *
704 * Creation of a new Namespace. This function will refuse to create
705 * a namespace with a similar prefix than an existing one present on this
706 * node.
707 * We use href==NULL in the case of an element creation where the namespace
708 * was not defined.
709 * Returns a new namespace pointer or NULL
710 */
711xmlNsPtr
712xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
713 xmlNsPtr cur;
714
715 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
716 return(NULL);
717
718 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
719 return(NULL);
720
721 /*
722 * Allocate a new Namespace and fill the fields.
723 */
724 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
725 if (cur == NULL) {
726 xmlTreeErrMemory("building namespace");
727 return(NULL);
728 }
729 memset(cur, 0, sizeof(xmlNs));
730 cur->type = XML_LOCAL_NAMESPACE;
731
732 if (href != NULL)
733 cur->href = xmlStrdup(href);
734 if (prefix != NULL)
735 cur->prefix = xmlStrdup(prefix);
736
737 /*
738 * Add it at the end to preserve parsing order ...
739 * and checks for existing use of the prefix
740 */
741 if (node != NULL) {
742 if (node->nsDef == NULL) {
743 node->nsDef = cur;
744 } else {
745 xmlNsPtr prev = node->nsDef;
746
747 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
748 (xmlStrEqual(prev->prefix, cur->prefix))) {
749 xmlFreeNs(cur);
750 return(NULL);
751 }
752 while (prev->next != NULL) {
753 prev = prev->next;
754 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
755 (xmlStrEqual(prev->prefix, cur->prefix))) {
756 xmlFreeNs(cur);
757 return(NULL);
758 }
759 }
760 prev->next = cur;
761 }
762 }
763 return(cur);
764}
765
766/**
767 * xmlSetNs:
768 * @node: a node in the document
769 * @ns: a namespace pointer
770 *
771 * Associate a namespace to a node, a posteriori.
772 */
773void
774xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
775 if (node == NULL) {
776#ifdef DEBUG_TREE
777 xmlGenericError(xmlGenericErrorContext,
778 "xmlSetNs: node == NULL\n");
779#endif
780 return;
781 }
782 node->ns = ns;
783}
784
785/**
786 * xmlFreeNs:
787 * @cur: the namespace pointer
788 *
789 * Free up the structures associated to a namespace
790 */
791void
792xmlFreeNs(xmlNsPtr cur) {
793 if (cur == NULL) {
794#ifdef DEBUG_TREE
795 xmlGenericError(xmlGenericErrorContext,
796 "xmlFreeNs : ns == NULL\n");
797#endif
798 return;
799 }
800 if (cur->href != NULL) xmlFree((char *) cur->href);
801 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
802 xmlFree(cur);
803}
804
805/**
806 * xmlFreeNsList:
807 * @cur: the first namespace pointer
808 *
809 * Free up all the structures associated to the chained namespaces.
810 */
811void
812xmlFreeNsList(xmlNsPtr cur) {
813 xmlNsPtr next;
814 if (cur == NULL) {
815#ifdef DEBUG_TREE
816 xmlGenericError(xmlGenericErrorContext,
817 "xmlFreeNsList : ns == NULL\n");
818#endif
819 return;
820 }
821 while (cur != NULL) {
822 next = cur->next;
823 xmlFreeNs(cur);
824 cur = next;
825 }
826}
827
828/**
829 * xmlNewDtd:
830 * @doc: the document pointer
831 * @name: the DTD name
832 * @ExternalID: the external ID
833 * @SystemID: the system ID
834 *
835 * Creation of a new DTD for the external subset. To create an
836 * internal subset, use xmlCreateIntSubset().
837 *
838 * Returns a pointer to the new DTD structure
839 */
840xmlDtdPtr
841xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
842 const xmlChar *ExternalID, const xmlChar *SystemID) {
843 xmlDtdPtr cur;
844
845 if ((doc != NULL) && (doc->extSubset != NULL)) {
846#ifdef DEBUG_TREE
847 xmlGenericError(xmlGenericErrorContext,
848 "xmlNewDtd(%s): document %s already have a DTD %s\n",
849 /* !!! */ (char *) name, doc->name,
850 /* !!! */ (char *)doc->extSubset->name);
851#endif
852 return(NULL);
853 }
854
855 /*
856 * Allocate a new DTD and fill the fields.
857 */
858 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
859 if (cur == NULL) {
860 xmlTreeErrMemory("building DTD");
861 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->extSubset = cur;
874 cur->doc = doc;
875
876 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
877 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
878 return(cur);
879}
880
881/**
882 * xmlGetIntSubset:
883 * @doc: the document pointer
884 *
885 * Get the internal subset of a document
886 * Returns a pointer to the DTD structure or NULL if not found
887 */
888
889xmlDtdPtr
890xmlGetIntSubset(xmlDocPtr doc) {
891 xmlNodePtr cur;
892
893 if (doc == NULL)
894 return(NULL);
895 cur = doc->children;
896 while (cur != NULL) {
897 if (cur->type == XML_DTD_NODE)
898 return((xmlDtdPtr) cur);
899 cur = cur->next;
900 }
901 return((xmlDtdPtr) doc->intSubset);
902}
903
904/**
905 * xmlCreateIntSubset:
906 * @doc: the document pointer
907 * @name: the DTD name
908 * @ExternalID: the external (PUBLIC) ID
909 * @SystemID: the system ID
910 *
911 * Create the internal subset of a document
912 * Returns a pointer to the new DTD structure
913 */
914xmlDtdPtr
915xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
916 const xmlChar *ExternalID, const xmlChar *SystemID) {
917 xmlDtdPtr cur;
918
919 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
920#ifdef DEBUG_TREE
921 xmlGenericError(xmlGenericErrorContext,
922
923 "xmlCreateIntSubset(): document %s already have an internal subset\n",
924 doc->name);
925#endif
926 return(NULL);
927 }
928
929 /*
930 * Allocate a new DTD and fill the fields.
931 */
932 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
933 if (cur == NULL) {
934 xmlTreeErrMemory("building internal subset");
935 return(NULL);
936 }
937 memset(cur, 0, sizeof(xmlDtd));
938 cur->type = XML_DTD_NODE;
939
940 if (name != NULL) {
941 cur->name = xmlStrdup(name);
942 if (cur->name == NULL) {
943 xmlTreeErrMemory("building internal subset");
944 xmlFree(cur);
945 return(NULL);
946 }
947 }
948 if (ExternalID != NULL) {
949 cur->ExternalID = xmlStrdup(ExternalID);
950 if (cur->ExternalID == NULL) {
951 xmlTreeErrMemory("building internal subset");
952 if (cur->name != NULL)
953 xmlFree((char *)cur->name);
954 xmlFree(cur);
955 return(NULL);
956 }
957 }
958 if (SystemID != NULL) {
959 cur->SystemID = xmlStrdup(SystemID);
960 if (cur->SystemID == NULL) {
961 xmlTreeErrMemory("building internal subset");
962 if (cur->name != NULL)
963 xmlFree((char *)cur->name);
964 if (cur->ExternalID != NULL)
965 xmlFree((char *)cur->ExternalID);
966 xmlFree(cur);
967 return(NULL);
968 }
969 }
970 if (doc != NULL) {
971 doc->intSubset = cur;
972 cur->parent = doc;
973 cur->doc = doc;
974 if (doc->children == NULL) {
975 doc->children = (xmlNodePtr) cur;
976 doc->last = (xmlNodePtr) cur;
977 } else {
978 if (doc->type == XML_HTML_DOCUMENT_NODE) {
979 xmlNodePtr prev;
980
981 prev = doc->children;
982 prev->prev = (xmlNodePtr) cur;
983 cur->next = prev;
984 doc->children = (xmlNodePtr) cur;
985 } else {
986 xmlNodePtr next;
987
988 next = doc->children;
989 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
990 next = next->next;
991 if (next == NULL) {
992 cur->prev = doc->last;
993 cur->prev->next = (xmlNodePtr) cur;
994 cur->next = NULL;
995 doc->last = (xmlNodePtr) cur;
996 } else {
997 cur->next = next;
998 cur->prev = next->prev;
999 if (cur->prev == NULL)
1000 doc->children = (xmlNodePtr) cur;
1001 else
1002 cur->prev->next = (xmlNodePtr) cur;
1003 next->prev = (xmlNodePtr) cur;
1004 }
1005 }
1006 }
1007 }
1008
1009 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
1010 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
1011 return(cur);
1012}
1013
1014/**
1015 * DICT_FREE:
1016 * @str: a string
1017 *
1018 * Free a string if it is not owned by the "dict" dictionnary in the
1019 * current scope
1020 */
1021#define DICT_FREE(str) \
1022 if ((str) && ((!dict) || \
1023 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
1024 xmlFree((char *)(str));
1025
1026
1027/**
1028 * DICT_COPY:
1029 * @str: a string
1030 *
1031 * Copy a string using a "dict" dictionnary in the current scope,
1032 * if availabe.
1033 */
1034#define DICT_COPY(str, cpy) \
1035 if (str) { \
1036 if (dict) { \
1037 if (xmlDictOwns(dict, (const xmlChar *)(str))) \
1038 cpy = (xmlChar *) (str); \
1039 else \
1040 cpy = (xmlChar *) xmlDictLookup((dict), (const xmlChar *)(str), -1); \
1041 } else \
1042 cpy = xmlStrdup((const xmlChar *)(str)); }
1043
1044/**
1045 * DICT_CONST_COPY:
1046 * @str: a string
1047 *
1048 * Copy a string using a "dict" dictionnary in the current scope,
1049 * if availabe.
1050 */
1051#define DICT_CONST_COPY(str, cpy) \
1052 if (str) { \
1053 if (dict) { \
1054 if (xmlDictOwns(dict, (const xmlChar *)(str))) \
1055 cpy = (const xmlChar *) (str); \
1056 else \
1057 cpy = xmlDictLookup((dict), (const xmlChar *)(str), -1); \
1058 } else \
1059 cpy = (const xmlChar *) xmlStrdup((const xmlChar *)(str)); }
1060
1061
1062/**
1063 * xmlFreeDtd:
1064 * @cur: the DTD structure to free up
1065 *
1066 * Free a DTD structure.
1067 */
1068void
1069xmlFreeDtd(xmlDtdPtr cur) {
1070 xmlDictPtr dict = NULL;
1071
1072 if (cur == NULL) {
1073 return;
1074 }
1075 if (cur->doc != NULL) dict = cur->doc->dict;
1076
1077 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
1078 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1079
1080 if (cur->children != NULL) {
1081 xmlNodePtr next, c = cur->children;
1082
1083 /*
1084 * Cleanup all nodes which are not part of the specific lists
1085 * of notations, elements, attributes and entities.
1086 */
1087 while (c != NULL) {
1088 next = c->next;
1089 if ((c->type != XML_NOTATION_NODE) &&
1090 (c->type != XML_ELEMENT_DECL) &&
1091 (c->type != XML_ATTRIBUTE_DECL) &&
1092 (c->type != XML_ENTITY_DECL)) {
1093 xmlUnlinkNode(c);
1094 xmlFreeNode(c);
1095 }
1096 c = next;
1097 }
1098 }
1099 DICT_FREE(cur->name)
1100 DICT_FREE(cur->SystemID)
1101 DICT_FREE(cur->ExternalID)
1102 /* TODO !!! */
1103 if (cur->notations != NULL)
1104 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
1105
1106 if (cur->elements != NULL)
1107 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
1108 if (cur->attributes != NULL)
1109 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
1110 if (cur->entities != NULL)
1111 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
1112 if (cur->pentities != NULL)
1113 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
1114
1115 xmlFree(cur);
1116}
1117
1118/**
1119 * xmlNewDoc:
1120 * @version: xmlChar string giving the version of XML "1.0"
1121 *
1122 * Creates a new XML document
1123 *
1124 * Returns a new document
1125 */
1126xmlDocPtr
1127xmlNewDoc(const xmlChar *version) {
1128 xmlDocPtr cur;
1129
1130 if (version == NULL)
1131 version = (const xmlChar *) "1.0";
1132
1133 /*
1134 * Allocate a new document and fill the fields.
1135 */
1136 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
1137 if (cur == NULL) {
1138 xmlTreeErrMemory("building doc");
1139 return(NULL);
1140 }
1141 memset(cur, 0, sizeof(xmlDoc));
1142 cur->type = XML_DOCUMENT_NODE;
1143
1144 cur->version = xmlStrdup(version);
1145 if (cur->version == NULL) {
1146 xmlTreeErrMemory("building doc");
1147 xmlFree(cur);
1148 return(NULL);
1149 }
1150 cur->standalone = -1;
1151 cur->compression = -1; /* not initialized */
1152 cur->doc = cur;
1153 /*
1154 * The in memory encoding is always UTF8
1155 * This field will never change and would
1156 * be obsolete if not for binary compatibility.
1157 */
1158 cur->charset = XML_CHAR_ENCODING_UTF8;
1159
1160 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
1161 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
1162 return(cur);
1163}
1164
1165/**
1166 * xmlFreeDoc:
1167 * @cur: pointer to the document
1168 *
1169 * Free up all the structures used by a document, tree included.
1170 */
1171void
1172xmlFreeDoc(xmlDocPtr cur) {
1173 xmlDtdPtr extSubset, intSubset;
1174 xmlDictPtr dict = NULL;
1175
1176 if (cur == NULL) {
1177#ifdef DEBUG_TREE
1178 xmlGenericError(xmlGenericErrorContext,
1179 "xmlFreeDoc : document == NULL\n");
1180#endif
1181 return;
1182 }
1183#ifdef LIBXML_DEBUG_RUNTIME
1184#ifdef LIBXML_DEBUG_ENABLED
1185 xmlDebugCheckDocument(stderr, cur);
1186#endif
1187#endif
1188
1189 if (cur != NULL) dict = cur->dict;
1190
1191 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
1192 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1193
1194 /*
1195 * Do this before freeing the children list to avoid ID lookups
1196 */
1197 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1198 cur->ids = NULL;
1199 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1200 cur->refs = NULL;
1201 extSubset = cur->extSubset;
1202 intSubset = cur->intSubset;
1203 if (intSubset == extSubset)
1204 extSubset = NULL;
1205 if (extSubset != NULL) {
1206 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
1207 cur->extSubset = NULL;
1208 xmlFreeDtd(extSubset);
1209 }
1210 if (intSubset != NULL) {
1211 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
1212 cur->intSubset = NULL;
1213 xmlFreeDtd(intSubset);
1214 }
1215
1216 if (cur->children != NULL) xmlFreeNodeList(cur->children);
1217 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
1218
1219 DICT_FREE(cur->version)
1220 DICT_FREE(cur->name)
1221 DICT_FREE(cur->encoding)
1222 DICT_FREE(cur->URL)
1223 xmlFree(cur);
1224 if (dict) xmlDictFree(dict);
1225}
1226
1227/**
1228 * xmlStringLenGetNodeList:
1229 * @doc: the document
1230 * @value: the value of the text
1231 * @len: the length of the string value
1232 *
1233 * Parse the value string and build the node list associated. Should
1234 * produce a flat tree with only TEXTs and ENTITY_REFs.
1235 * Returns a pointer to the first child
1236 */
1237xmlNodePtr
1238xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
1239 xmlNodePtr ret = NULL, last = NULL;
1240 xmlNodePtr node;
1241 xmlChar *val;
1242 const xmlChar *cur = value, *end = cur + len;
1243 const xmlChar *q;
1244 xmlEntityPtr ent;
1245
1246 if (value == NULL) return(NULL);
1247
1248 q = cur;
1249 while ((cur < end) && (*cur != 0)) {
1250 if (cur[0] == '&') {
1251 int charval = 0;
1252 xmlChar tmp;
1253
1254 /*
1255 * Save the current text.
1256 */
1257 if (cur != q) {
1258 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1259 xmlNodeAddContentLen(last, q, cur - q);
1260 } else {
1261 node = xmlNewDocTextLen(doc, q, cur - q);
1262 if (node == NULL) return(ret);
1263 if (last == NULL)
1264 last = ret = node;
1265 else {
1266 last->next = node;
1267 node->prev = last;
1268 last = node;
1269 }
1270 }
1271 }
1272 q = cur;
1273 if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
1274 cur += 3;
1275 if (cur < end)
1276 tmp = *cur;
1277 else
1278 tmp = 0;
1279 while (tmp != ';') { /* Non input consuming loop */
1280 if ((tmp >= '0') && (tmp <= '9'))
1281 charval = charval * 16 + (tmp - '0');
1282 else if ((tmp >= 'a') && (tmp <= 'f'))
1283 charval = charval * 16 + (tmp - 'a') + 10;
1284 else if ((tmp >= 'A') && (tmp <= 'F'))
1285 charval = charval * 16 + (tmp - 'A') + 10;
1286 else {
1287 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1288 NULL);
1289 charval = 0;
1290 break;
1291 }
1292 cur++;
1293 if (cur < end)
1294 tmp = *cur;
1295 else
1296 tmp = 0;
1297 }
1298 if (tmp == ';')
1299 cur++;
1300 q = cur;
1301 } else if ((cur + 1 < end) && (cur[1] == '#')) {
1302 cur += 2;
1303 if (cur < end)
1304 tmp = *cur;
1305 else
1306 tmp = 0;
1307 while (tmp != ';') { /* Non input consuming loops */
1308 if ((tmp >= '0') && (tmp <= '9'))
1309 charval = charval * 10 + (tmp - '0');
1310 else {
1311 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1312 NULL);
1313 charval = 0;
1314 break;
1315 }
1316 cur++;
1317 if (cur < end)
1318 tmp = *cur;
1319 else
1320 tmp = 0;
1321 }
1322 if (tmp == ';')
1323 cur++;
1324 q = cur;
1325 } else {
1326 /*
1327 * Read the entity string
1328 */
1329 cur++;
1330 q = cur;
1331 while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1332 if ((cur >= end) || (*cur == 0)) {
1333 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc,
1334 (const char *) q);
1335 return(ret);
1336 }
1337 if (cur != q) {
1338 /*
1339 * Predefined entities don't generate nodes
1340 */
1341 val = xmlStrndup(q, cur - q);
1342 ent = xmlGetDocEntity(doc, val);
1343 if ((ent != NULL) &&
1344 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1345 if (last == NULL) {
1346 node = xmlNewDocText(doc, ent->content);
1347 last = ret = node;
1348 } else if (last->type != XML_TEXT_NODE) {
1349 node = xmlNewDocText(doc, ent->content);
1350 last = xmlAddNextSibling(last, node);
1351 } else
1352 xmlNodeAddContent(last, ent->content);
1353
1354 } else {
1355 /*
1356 * Create a new REFERENCE_REF node
1357 */
1358 node = xmlNewReference(doc, val);
1359 if (node == NULL) {
1360 if (val != NULL) xmlFree(val);
1361 return(ret);
1362 }
1363 else if ((ent != NULL) && (ent->children == NULL)) {
1364 xmlNodePtr temp;
1365
1366 ent->children = xmlStringGetNodeList(doc,
1367 (const xmlChar*)node->content);
1368 ent->owner = 1;
1369 temp = ent->children;
1370 while (temp) {
1371 temp->parent = (xmlNodePtr)ent;
1372 ent->last = temp;
1373 temp = temp->next;
1374 }
1375 }
1376 if (last == NULL) {
1377 last = ret = node;
1378 } else {
1379 last = xmlAddNextSibling(last, node);
1380 }
1381 }
1382 xmlFree(val);
1383 }
1384 cur++;
1385 q = cur;
1386 }
1387 if (charval != 0) {
1388 xmlChar buf[10];
1389 int l;
1390
1391 l = xmlCopyCharMultiByte(buf, charval);
1392 buf[l] = 0;
1393 node = xmlNewDocText(doc, buf);
1394 if (node != NULL) {
1395 if (last == NULL) {
1396 last = ret = node;
1397 } else {
1398 last = xmlAddNextSibling(last, node);
1399 }
1400 }
1401 charval = 0;
1402 }
1403 } else
1404 cur++;
1405 }
1406 if ((cur != q) || (ret == NULL)) {
1407 /*
1408 * Handle the last piece of text.
1409 */
1410 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1411 xmlNodeAddContentLen(last, q, cur - q);
1412 } else {
1413 node = xmlNewDocTextLen(doc, q, cur - q);
1414 if (node == NULL) return(ret);
1415 if (last == NULL) {
1416 last = ret = node;
1417 } else {
1418 last = xmlAddNextSibling(last, node);
1419 }
1420 }
1421 }
1422 return(ret);
1423}
1424
1425/**
1426 * xmlStringGetNodeList:
1427 * @doc: the document
1428 * @value: the value of the attribute
1429 *
1430 * Parse the value string and build the node list associated. Should
1431 * produce a flat tree with only TEXTs and ENTITY_REFs.
1432 * Returns a pointer to the first child
1433 */
1434xmlNodePtr
1435xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
1436 xmlNodePtr ret = NULL, last = NULL;
1437 xmlNodePtr node;
1438 xmlChar *val;
1439 const xmlChar *cur = value;
1440 const xmlChar *q;
1441 xmlEntityPtr ent;
1442
1443 if (value == NULL) return(NULL);
1444
1445 q = cur;
1446 while (*cur != 0) {
1447 if (cur[0] == '&') {
1448 int charval = 0;
1449 xmlChar tmp;
1450
1451 /*
1452 * Save the current text.
1453 */
1454 if (cur != q) {
1455 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1456 xmlNodeAddContentLen(last, q, cur - q);
1457 } else {
1458 node = xmlNewDocTextLen(doc, q, cur - q);
1459 if (node == NULL) return(ret);
1460 if (last == NULL)
1461 last = ret = node;
1462 else {
1463 last->next = node;
1464 node->prev = last;
1465 last = node;
1466 }
1467 }
1468 }
1469 q = cur;
1470 if ((cur[1] == '#') && (cur[2] == 'x')) {
1471 cur += 3;
1472 tmp = *cur;
1473 while (tmp != ';') { /* Non input consuming loop */
1474 if ((tmp >= '0') && (tmp <= '9'))
1475 charval = charval * 16 + (tmp - '0');
1476 else if ((tmp >= 'a') && (tmp <= 'f'))
1477 charval = charval * 16 + (tmp - 'a') + 10;
1478 else if ((tmp >= 'A') && (tmp <= 'F'))
1479 charval = charval * 16 + (tmp - 'A') + 10;
1480 else {
1481 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1482 NULL);
1483 charval = 0;
1484 break;
1485 }
1486 cur++;
1487 tmp = *cur;
1488 }
1489 if (tmp == ';')
1490 cur++;
1491 q = cur;
1492 } else if (cur[1] == '#') {
1493 cur += 2;
1494 tmp = *cur;
1495 while (tmp != ';') { /* Non input consuming loops */
1496 if ((tmp >= '0') && (tmp <= '9'))
1497 charval = charval * 10 + (tmp - '0');
1498 else {
1499 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1500 NULL);
1501 charval = 0;
1502 break;
1503 }
1504 cur++;
1505 tmp = *cur;
1506 }
1507 if (tmp == ';')
1508 cur++;
1509 q = cur;
1510 } else {
1511 /*
1512 * Read the entity string
1513 */
1514 cur++;
1515 q = cur;
1516 while ((*cur != 0) && (*cur != ';')) cur++;
1517 if (*cur == 0) {
1518 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY,
1519 (xmlNodePtr) doc, (const char *) q);
1520 return(ret);
1521 }
1522 if (cur != q) {
1523 /*
1524 * Predefined entities don't generate nodes
1525 */
1526 val = xmlStrndup(q, cur - q);
1527 ent = xmlGetDocEntity(doc, val);
1528 if ((ent != NULL) &&
1529 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1530 if (last == NULL) {
1531 node = xmlNewDocText(doc, ent->content);
1532 last = ret = node;
1533 } else if (last->type != XML_TEXT_NODE) {
1534 node = xmlNewDocText(doc, ent->content);
1535 last = xmlAddNextSibling(last, node);
1536 } else
1537 xmlNodeAddContent(last, ent->content);
1538
1539 } else {
1540 /*
1541 * Create a new REFERENCE_REF node
1542 */
1543 node = xmlNewReference(doc, val);
1544 if (node == NULL) {
1545 if (val != NULL) xmlFree(val);
1546 return(ret);
1547 }
1548 else if ((ent != NULL) && (ent->children == NULL)) {
1549 xmlNodePtr temp;
1550
1551 ent->children = xmlStringGetNodeList(doc,
1552 (const xmlChar*)node->content);
1553 ent->owner = 1;
1554 temp = ent->children;
1555 while (temp) {
1556 temp->parent = (xmlNodePtr)ent;
1557 temp = temp->next;
1558 }
1559 }
1560 if (last == NULL) {
1561 last = ret = node;
1562 } else {
1563 last = xmlAddNextSibling(last, node);
1564 }
1565 }
1566 xmlFree(val);
1567 }
1568 cur++;
1569 q = cur;
1570 }
1571 if (charval != 0) {
1572 xmlChar buf[10];
1573 int len;
1574
1575 len = xmlCopyCharMultiByte(buf, charval);
1576 buf[len] = 0;
1577 node = xmlNewDocText(doc, buf);
1578 if (node != NULL) {
1579 if (last == NULL) {
1580 last = ret = node;
1581 } else {
1582 last = xmlAddNextSibling(last, node);
1583 }
1584 }
1585
1586 charval = 0;
1587 }
1588 } else
1589 cur++;
1590 }
1591 if ((cur != q) || (ret == NULL)) {
1592 /*
1593 * Handle the last piece of text.
1594 */
1595 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
1596 xmlNodeAddContentLen(last, q, cur - q);
1597 } else {
1598 node = xmlNewDocTextLen(doc, q, cur - q);
1599 if (node == NULL) return(ret);
1600 if (last == NULL) {
1601 last = ret = node;
1602 } else {
1603 last = xmlAddNextSibling(last, node);
1604 }
1605 }
1606 }
1607 return(ret);
1608}
1609
1610/**
1611 * xmlNodeListGetString:
1612 * @doc: the document
1613 * @list: a Node list
1614 * @inLine: should we replace entity contents or show their external form
1615 *
1616 * Build the string equivalent to the text contained in the Node list
1617 * made of TEXTs and ENTITY_REFs
1618 *
1619 * Returns a pointer to the string copy, the caller must free it with xmlFree().
1620 */
1621xmlChar *
1622xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1623{
1624 xmlNodePtr node = list;
1625 xmlChar *ret = NULL;
1626 xmlEntityPtr ent;
1627
1628 if (list == NULL)
1629 return (NULL);
1630
1631 while (node != NULL) {
1632 if ((node->type == XML_TEXT_NODE) ||
1633 (node->type == XML_CDATA_SECTION_NODE)) {
1634 if (inLine) {
1635 ret = xmlStrcat(ret, node->content);
1636 } else {
1637 xmlChar *buffer;
1638
1639 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1640 if (buffer != NULL) {
1641 ret = xmlStrcat(ret, buffer);
1642 xmlFree(buffer);
1643 }
1644 }
1645 } else if (node->type == XML_ENTITY_REF_NODE) {
1646 if (inLine) {
1647 ent = xmlGetDocEntity(doc, node->name);
1648 if (ent != NULL) {
1649 xmlChar *buffer;
1650
1651 /* an entity content can be any "well balanced chunk",
1652 * i.e. the result of the content [43] production:
1653 * http://www.w3.org/TR/REC-xml#NT-content.
1654 * So it can contain text, CDATA section or nested
1655 * entity reference nodes (among others).
1656 * -> we recursive call xmlNodeListGetString()
1657 * which handles these types */
1658 buffer = xmlNodeListGetString(doc, ent->children, 1);
1659 if (buffer != NULL) {
1660 ret = xmlStrcat(ret, buffer);
1661 xmlFree(buffer);
1662 }
1663 } else {
1664 ret = xmlStrcat(ret, node->content);
1665 }
1666 } else {
1667 xmlChar buf[2];
1668
1669 buf[0] = '&';
1670 buf[1] = 0;
1671 ret = xmlStrncat(ret, buf, 1);
1672 ret = xmlStrcat(ret, node->name);
1673 buf[0] = ';';
1674 buf[1] = 0;
1675 ret = xmlStrncat(ret, buf, 1);
1676 }
1677 }
1678#if 0
1679 else {
1680 xmlGenericError(xmlGenericErrorContext,
1681 "xmlGetNodeListString : invalid node type %d\n",
1682 node->type);
1683 }
1684#endif
1685 node = node->next;
1686 }
1687 return (ret);
1688}
1689
1690#ifdef LIBXML_TREE_ENABLED
1691/**
1692 * xmlNodeListGetRawString:
1693 * @doc: the document
1694 * @list: a Node list
1695 * @inLine: should we replace entity contents or show their external form
1696 *
1697 * Builds the string equivalent to the text contained in the Node list
1698 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1699 * this function doesn't do any character encoding handling.
1700 *
1701 * Returns a pointer to the string copy, the caller must free it with xmlFree().
1702 */
1703xmlChar *
1704xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
1705{
1706 xmlNodePtr node = list;
1707 xmlChar *ret = NULL;
1708 xmlEntityPtr ent;
1709
1710 if (list == NULL)
1711 return (NULL);
1712
1713 while (node != NULL) {
1714 if ((node->type == XML_TEXT_NODE) ||
1715 (node->type == XML_CDATA_SECTION_NODE)) {
1716 if (inLine) {
1717 ret = xmlStrcat(ret, node->content);
1718 } else {
1719 xmlChar *buffer;
1720
1721 buffer = xmlEncodeSpecialChars(doc, node->content);
1722 if (buffer != NULL) {
1723 ret = xmlStrcat(ret, buffer);
1724 xmlFree(buffer);
1725 }
1726 }
1727 } else if (node->type == XML_ENTITY_REF_NODE) {
1728 if (inLine) {
1729 ent = xmlGetDocEntity(doc, node->name);
1730 if (ent != NULL) {
1731 xmlChar *buffer;
1732
1733 /* an entity content can be any "well balanced chunk",
1734 * i.e. the result of the content [43] production:
1735 * http://www.w3.org/TR/REC-xml#NT-content.
1736 * So it can contain text, CDATA section or nested
1737 * entity reference nodes (among others).
1738 * -> we recursive call xmlNodeListGetRawString()
1739 * which handles these types */
1740 buffer =
1741 xmlNodeListGetRawString(doc, ent->children, 1);
1742 if (buffer != NULL) {
1743 ret = xmlStrcat(ret, buffer);
1744 xmlFree(buffer);
1745 }
1746 } else {
1747 ret = xmlStrcat(ret, node->content);
1748 }
1749 } else {
1750 xmlChar buf[2];
1751
1752 buf[0] = '&';
1753 buf[1] = 0;
1754 ret = xmlStrncat(ret, buf, 1);
1755 ret = xmlStrcat(ret, node->name);
1756 buf[0] = ';';
1757 buf[1] = 0;
1758 ret = xmlStrncat(ret, buf, 1);
1759 }
1760 }
1761#if 0
1762 else {
1763 xmlGenericError(xmlGenericErrorContext,
1764 "xmlGetNodeListString : invalid node type %d\n",
1765 node->type);
1766 }
1767#endif
1768 node = node->next;
1769 }
1770 return (ret);
1771}
1772#endif /* LIBXML_TREE_ENABLED */
1773
1774static xmlAttrPtr
1775xmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns,
1776 const xmlChar * name, const xmlChar * value,
1777 int eatname)
1778{
1779 xmlAttrPtr cur;
1780 xmlDocPtr doc = NULL;
1781
1782 if ((node != NULL) && (node->type != XML_ELEMENT_NODE)) {
1783 if (eatname == 1)
1784 xmlFree((xmlChar *) name);
1785 return (NULL);
1786 }
1787
1788 /*
1789 * Allocate a new property and fill the fields.
1790 */
1791 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1792 if (cur == NULL) {
1793 if (eatname == 1)
1794 xmlFree((xmlChar *) name);
1795 xmlTreeErrMemory("building attribute");
1796 return (NULL);
1797 }
1798 memset(cur, 0, sizeof(xmlAttr));
1799 cur->type = XML_ATTRIBUTE_NODE;
1800
1801 cur->parent = node;
1802 if (node != NULL) {
1803 doc = node->doc;
1804 cur->doc = doc;
1805 }
1806 cur->ns = ns;
1807
1808 if (eatname == 0) {
1809 if ((doc != NULL) && (doc->dict != NULL))
1810 cur->name = (xmlChar *) xmlDictLookup(doc->dict, name, -1);
1811 else
1812 cur->name = xmlStrdup(name);
1813 } else
1814 cur->name = name;
1815
1816 if (value != NULL) {
1817 xmlChar *buffer;
1818 xmlNodePtr tmp;
1819
1820 buffer = xmlEncodeEntitiesReentrant(doc, value);
1821 cur->children = xmlStringGetNodeList(doc, buffer);
1822 cur->last = NULL;
1823 tmp = cur->children;
1824 while (tmp != NULL) {
1825 tmp->parent = (xmlNodePtr) cur;
1826 if (tmp->next == NULL)
1827 cur->last = tmp;
1828 tmp = tmp->next;
1829 }
1830 xmlFree(buffer);
1831 }
1832
1833 /*
1834 * Add it at the end to preserve parsing order ...
1835 */
1836 if (node != NULL) {
1837 if (node->properties == NULL) {
1838 node->properties = cur;
1839 } else {
1840 xmlAttrPtr prev = node->properties;
1841
1842 while (prev->next != NULL)
1843 prev = prev->next;
1844 prev->next = cur;
1845 cur->prev = prev;
1846 }
1847 }
1848
1849 if (xmlIsID((node == NULL) ? NULL : node->doc, node, cur) == 1)
1850 xmlAddID(NULL, node->doc, value, cur);
1851
1852 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
1853 xmlRegisterNodeDefaultValue((xmlNodePtr) cur);
1854 return (cur);
1855}
1856
1857#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
1858 defined(LIBXML_SCHEMAS_ENABLED)
1859/**
1860 * xmlNewProp:
1861 * @node: the holding node
1862 * @name: the name of the attribute
1863 * @value: the value of the attribute
1864 *
1865 * Create a new property carried by a node.
1866 * Returns a pointer to the attribute
1867 */
1868xmlAttrPtr
1869xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1870
1871 if (name == NULL) {
1872#ifdef DEBUG_TREE
1873 xmlGenericError(xmlGenericErrorContext,
1874 "xmlNewProp : name == NULL\n");
1875#endif
1876 return(NULL);
1877 }
1878
1879 return xmlNewPropInternal(node, NULL, name, value, 0);
1880}
1881#endif /* LIBXML_TREE_ENABLED */
1882
1883/**
1884 * xmlNewNsProp:
1885 * @node: the holding node
1886 * @ns: the namespace
1887 * @name: the name of the attribute
1888 * @value: the value of the attribute
1889 *
1890 * Create a new property tagged with a namespace and carried by a node.
1891 * Returns a pointer to the attribute
1892 */
1893xmlAttrPtr
1894xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1895 const xmlChar *value) {
1896
1897 if (name == NULL) {
1898#ifdef DEBUG_TREE
1899 xmlGenericError(xmlGenericErrorContext,
1900 "xmlNewNsProp : name == NULL\n");
1901#endif
1902 return(NULL);
1903 }
1904
1905 return xmlNewPropInternal(node, ns, name, value, 0);
1906}
1907
1908/**
1909 * xmlNewNsPropEatName:
1910 * @node: the holding node
1911 * @ns: the namespace
1912 * @name: the name of the attribute
1913 * @value: the value of the attribute
1914 *
1915 * Create a new property tagged with a namespace and carried by a node.
1916 * Returns a pointer to the attribute
1917 */
1918xmlAttrPtr
1919xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1920 const xmlChar *value) {
1921
1922 if (name == NULL) {
1923#ifdef DEBUG_TREE
1924 xmlGenericError(xmlGenericErrorContext,
1925 "xmlNewNsPropEatName : name == NULL\n");
1926#endif
1927 return(NULL);
1928 }
1929
1930 return xmlNewPropInternal(node, ns, name, value, 1);
1931}
1932
1933/**
1934 * xmlNewDocProp:
1935 * @doc: the document
1936 * @name: the name of the attribute
1937 * @value: the value of the attribute
1938 *
1939 * Create a new property carried by a document.
1940 * Returns a pointer to the attribute
1941 */
1942xmlAttrPtr
1943xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1944 xmlAttrPtr cur;
1945
1946 if (name == NULL) {
1947#ifdef DEBUG_TREE
1948 xmlGenericError(xmlGenericErrorContext,
1949 "xmlNewDocProp : name == NULL\n");
1950#endif
1951 return(NULL);
1952 }
1953
1954 /*
1955 * Allocate a new property and fill the fields.
1956 */
1957 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1958 if (cur == NULL) {
1959 xmlTreeErrMemory("building attribute");
1960 return(NULL);
1961 }
1962 memset(cur, 0, sizeof(xmlAttr));
1963 cur->type = XML_ATTRIBUTE_NODE;
1964
1965 if ((doc != NULL) && (doc->dict != NULL))
1966 cur->name = xmlDictLookup(doc->dict, name, -1);
1967 else
1968 cur->name = xmlStrdup(name);
1969 cur->doc = doc;
1970 if (value != NULL) {
1971 xmlNodePtr tmp;
1972
1973 cur->children = xmlStringGetNodeList(doc, value);
1974 cur->last = NULL;
1975
1976 tmp = cur->children;
1977 while (tmp != NULL) {
1978 tmp->parent = (xmlNodePtr) cur;
1979 if (tmp->next == NULL)
1980 cur->last = tmp;
1981 tmp = tmp->next;
1982 }
1983 }
1984
1985 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
1986 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
1987 return(cur);
1988}
1989
1990/**
1991 * xmlFreePropList:
1992 * @cur: the first property in the list
1993 *
1994 * Free a property and all its siblings, all the children are freed too.
1995 */
1996void
1997xmlFreePropList(xmlAttrPtr cur) {
1998 xmlAttrPtr next;
1999 if (cur == NULL) return;
2000 while (cur != NULL) {
2001 next = cur->next;
2002 xmlFreeProp(cur);
2003 cur = next;
2004 }
2005}
2006
2007/**
2008 * xmlFreeProp:
2009 * @cur: an attribute
2010 *
2011 * Free one attribute, all the content is freed too
2012 */
2013void
2014xmlFreeProp(xmlAttrPtr cur) {
2015 xmlDictPtr dict = NULL;
2016 if (cur == NULL) return;
2017
2018 if (cur->doc != NULL) dict = cur->doc->dict;
2019
2020 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
2021 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
2022
2023 /* Check for ID removal -> leading to invalid references ! */
2024 if ((cur->doc != NULL) && (cur->atype == XML_ATTRIBUTE_ID)) {
2025 xmlRemoveID(cur->doc, cur);
2026 }
2027 if (cur->children != NULL) xmlFreeNodeList(cur->children);
2028 DICT_FREE(cur->name)
2029 xmlFree(cur);
2030}
2031
2032/**
2033 * xmlRemoveProp:
2034 * @cur: an attribute
2035 *
2036 * Unlink and free one attribute, all the content is freed too
2037 * Note this doesn't work for namespace definition attributes
2038 *
2039 * Returns 0 if success and -1 in case of error.
2040 */
2041int
2042xmlRemoveProp(xmlAttrPtr cur) {
2043 xmlAttrPtr tmp;
2044 if (cur == NULL) {
2045#ifdef DEBUG_TREE
2046 xmlGenericError(xmlGenericErrorContext,
2047 "xmlRemoveProp : cur == NULL\n");
2048#endif
2049 return(-1);
2050 }
2051 if (cur->parent == NULL) {
2052#ifdef DEBUG_TREE
2053 xmlGenericError(xmlGenericErrorContext,
2054 "xmlRemoveProp : cur->parent == NULL\n");
2055#endif
2056 return(-1);
2057 }
2058 tmp = cur->parent->properties;
2059 if (tmp == cur) {
2060 cur->parent->properties = cur->next;
2061 if (cur->next != NULL)
2062 cur->next->prev = NULL;
2063 xmlFreeProp(cur);
2064 return(0);
2065 }
2066 while (tmp != NULL) {
2067 if (tmp->next == cur) {
2068 tmp->next = cur->next;
2069 if (tmp->next != NULL)
2070 tmp->next->prev = tmp;
2071 xmlFreeProp(cur);
2072 return(0);
2073 }
2074 tmp = tmp->next;
2075 }
2076#ifdef DEBUG_TREE
2077 xmlGenericError(xmlGenericErrorContext,
2078 "xmlRemoveProp : attribute not owned by its node\n");
2079#endif
2080 return(-1);
2081}
2082
2083/**
2084 * xmlNewDocPI:
2085 * @doc: the target document
2086 * @name: the processing instruction name
2087 * @content: the PI content
2088 *
2089 * Creation of a processing instruction element.
2090 * Returns a pointer to the new node object.
2091 */
2092xmlNodePtr
2093xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) {
2094 xmlNodePtr cur;
2095
2096 if (name == NULL) {
2097#ifdef DEBUG_TREE
2098 xmlGenericError(xmlGenericErrorContext,
2099 "xmlNewPI : name == NULL\n");
2100#endif
2101 return(NULL);
2102 }
2103
2104 /*
2105 * Allocate a new node and fill the fields.
2106 */
2107 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2108 if (cur == NULL) {
2109 xmlTreeErrMemory("building PI");
2110 return(NULL);
2111 }
2112 memset(cur, 0, sizeof(xmlNode));
2113 cur->type = XML_PI_NODE;
2114
2115 if ((doc != NULL) && (doc->dict != NULL))
2116 cur->name = xmlDictLookup(doc->dict, name, -1);
2117 else
2118 cur->name = xmlStrdup(name);
2119 if (content != NULL) {
2120 cur->content = xmlStrdup(content);
2121 }
2122 cur->doc = doc;
2123
2124 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2125 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
2126 return(cur);
2127}
2128
2129/**
2130 * xmlNewPI:
2131 * @name: the processing instruction name
2132 * @content: the PI content
2133 *
2134 * Creation of a processing instruction element.
2135 * Use xmlDocNewPI preferably to get string interning
2136 *
2137 * Returns a pointer to the new node object.
2138 */
2139xmlNodePtr
2140xmlNewPI(const xmlChar *name, const xmlChar *content) {
2141 return(xmlNewDocPI(NULL, name, content));
2142}
2143
2144/**
2145 * xmlNewNode:
2146 * @ns: namespace if any
2147 * @name: the node name
2148 *
2149 * Creation of a new node element. @ns is optional (NULL).
2150 *
2151 * Returns a pointer to the new node object. Uses xmlStrdup() to make
2152 * copy of @name.
2153 */
2154xmlNodePtr
2155xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2156 xmlNodePtr cur;
2157
2158 if (name == NULL) {
2159#ifdef DEBUG_TREE
2160 xmlGenericError(xmlGenericErrorContext,
2161 "xmlNewNode : name == NULL\n");
2162#endif
2163 return(NULL);
2164 }
2165
2166 /*
2167 * Allocate a new node and fill the fields.
2168 */
2169 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2170 if (cur == NULL) {
2171 xmlTreeErrMemory("building node");
2172 return(NULL);
2173 }
2174 memset(cur, 0, sizeof(xmlNode));
2175 cur->type = XML_ELEMENT_NODE;
2176
2177 cur->name = xmlStrdup(name);
2178 cur->ns = ns;
2179
2180 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2181 xmlRegisterNodeDefaultValue(cur);
2182 return(cur);
2183}
2184
2185/**
2186 * xmlNewNodeEatName:
2187 * @ns: namespace if any
2188 * @name: the node name
2189 *
2190 * Creation of a new node element. @ns is optional (NULL).
2191 *
2192 * Returns a pointer to the new node object, with pointer @name as
2193 * new node's name. Use xmlNewNode() if a copy of @name string is
2194 * is needed as new node's name.
2195 */
2196xmlNodePtr
2197xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2198 xmlNodePtr cur;
2199
2200 if (name == NULL) {
2201#ifdef DEBUG_TREE
2202 xmlGenericError(xmlGenericErrorContext,
2203 "xmlNewNode : name == NULL\n");
2204#endif
2205 return(NULL);
2206 }
2207
2208 /*
2209 * Allocate a new node and fill the fields.
2210 */
2211 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2212 if (cur == NULL) {
2213 xmlFree(name);
2214 xmlTreeErrMemory("building node");
2215 return(NULL);
2216 }
2217 memset(cur, 0, sizeof(xmlNode));
2218 cur->type = XML_ELEMENT_NODE;
2219
2220 cur->name = name;
2221 cur->ns = ns;
2222
2223 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2224 xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
2225 return(cur);
2226}
2227
2228/**
2229 * xmlNewDocNode:
2230 * @doc: the document
2231 * @ns: namespace if any
2232 * @name: the node name
2233 * @content: the XML text content if any
2234 *
2235 * Creation of a new node element within a document. @ns and @content
2236 * are optional (NULL).
2237 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2238 * references, but XML special chars need to be escaped first by using
2239 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2240 * need entities support.
2241 *
2242 * Returns a pointer to the new node object.
2243 */
2244xmlNodePtr
2245xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2246 const xmlChar *name, const xmlChar *content) {
2247 xmlNodePtr cur;
2248
2249 if ((doc != NULL) && (doc->dict != NULL))
2250 cur = xmlNewNodeEatName(ns, (xmlChar *)
2251 xmlDictLookup(doc->dict, name, -1));
2252 else
2253 cur = xmlNewNode(ns, name);
2254 if (cur != NULL) {
2255 cur->doc = doc;
2256 if (content != NULL) {
2257 cur->children = xmlStringGetNodeList(doc, content);
2258 UPDATE_LAST_CHILD_AND_PARENT(cur)
2259 }
2260 }
2261
2262 return(cur);
2263}
2264
2265/**
2266 * xmlNewDocNodeEatName:
2267 * @doc: the document
2268 * @ns: namespace if any
2269 * @name: the node name
2270 * @content: the XML text content if any
2271 *
2272 * Creation of a new node element within a document. @ns and @content
2273 * are optional (NULL).
2274 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2275 * references, but XML special chars need to be escaped first by using
2276 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2277 * need entities support.
2278 *
2279 * Returns a pointer to the new node object.
2280 */
2281xmlNodePtr
2282xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2283 xmlChar *name, const xmlChar *content) {
2284 xmlNodePtr cur;
2285
2286 cur = xmlNewNodeEatName(ns, name);
2287 if (cur != NULL) {
2288 cur->doc = doc;
2289 if (content != NULL) {
2290 cur->children = xmlStringGetNodeList(doc, content);
2291 UPDATE_LAST_CHILD_AND_PARENT(cur)
2292 }
2293 }
2294 return(cur);
2295}
2296
2297#ifdef LIBXML_TREE_ENABLED
2298/**
2299 * xmlNewDocRawNode:
2300 * @doc: the document
2301 * @ns: namespace if any
2302 * @name: the node name
2303 * @content: the text content if any
2304 *
2305 * Creation of a new node element within a document. @ns and @content
2306 * are optional (NULL).
2307 *
2308 * Returns a pointer to the new node object.
2309 */
2310xmlNodePtr
2311xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2312 const xmlChar *name, const xmlChar *content) {
2313 xmlNodePtr cur;
2314
2315 cur = xmlNewDocNode(doc, ns, name, NULL);
2316 if (cur != NULL) {
2317 cur->doc = doc;
2318 if (content != NULL) {
2319 cur->children = xmlNewDocText(doc, content);
2320 UPDATE_LAST_CHILD_AND_PARENT(cur)
2321 }
2322 }
2323 return(cur);
2324}
2325
2326/**
2327 * xmlNewDocFragment:
2328 * @doc: the document owning the fragment
2329 *
2330 * Creation of a new Fragment node.
2331 * Returns a pointer to the new node object.
2332 */
2333xmlNodePtr
2334xmlNewDocFragment(xmlDocPtr doc) {
2335 xmlNodePtr cur;
2336
2337 /*
2338 * Allocate a new DocumentFragment node and fill the fields.
2339 */
2340 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2341 if (cur == NULL) {
2342 xmlTreeErrMemory("building fragment");
2343 return(NULL);
2344 }
2345 memset(cur, 0, sizeof(xmlNode));
2346 cur->type = XML_DOCUMENT_FRAG_NODE;
2347
2348 cur->doc = doc;
2349
2350 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2351 xmlRegisterNodeDefaultValue(cur);
2352 return(cur);
2353}
2354#endif /* LIBXML_TREE_ENABLED */
2355
2356/**
2357 * xmlNewText:
2358 * @content: the text content
2359 *
2360 * Creation of a new text node.
2361 * Returns a pointer to the new node object.
2362 */
2363xmlNodePtr
2364xmlNewText(const xmlChar *content) {
2365 xmlNodePtr cur;
2366
2367 /*
2368 * Allocate a new node and fill the fields.
2369 */
2370 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2371 if (cur == NULL) {
2372 xmlTreeErrMemory("building text");
2373 return(NULL);
2374 }
2375 memset(cur, 0, sizeof(xmlNode));
2376 cur->type = XML_TEXT_NODE;
2377
2378 cur->name = xmlStringText;
2379 if (content != NULL) {
2380 cur->content = xmlStrdup(content);
2381 }
2382
2383 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2384 xmlRegisterNodeDefaultValue(cur);
2385 return(cur);
2386}
2387
2388#ifdef LIBXML_TREE_ENABLED
2389/**
2390 * xmlNewTextChild:
2391 * @parent: the parent node
2392 * @ns: a namespace if any
2393 * @name: the name of the child
2394 * @content: the text content of the child if any.
2395 *
2396 * Creation of a new child element, added at the end of @parent children list.
2397 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2398 * created element inherits the namespace of @parent. If @content is non NULL,
2399 * a child TEXT node will be created containing the string @content.
2400 * NOTE: Use xmlNewChild() if @content will contain entities that need to be
2401 * preserved. Use this function, xmlNewTextChild(), if you need to ensure that
2402 * reserved XML chars that might appear in @content, such as the ampersand,
2403 * greater-than or less-than signs, are automatically replaced by their XML
2404 * escaped entity representations.
2405 *
2406 * Returns a pointer to the new node object.
2407 */
2408xmlNodePtr
2409xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2410 const xmlChar *name, const xmlChar *content) {
2411 xmlNodePtr cur, prev;
2412
2413 if (parent == NULL) {
2414#ifdef DEBUG_TREE
2415 xmlGenericError(xmlGenericErrorContext,
2416 "xmlNewTextChild : parent == NULL\n");
2417#endif
2418 return(NULL);
2419 }
2420
2421 if (name == NULL) {
2422#ifdef DEBUG_TREE
2423 xmlGenericError(xmlGenericErrorContext,
2424 "xmlNewTextChild : name == NULL\n");
2425#endif
2426 return(NULL);
2427 }
2428
2429 /*
2430 * Allocate a new node
2431 */
2432 if (parent->type == XML_ELEMENT_NODE) {
2433 if (ns == NULL)
2434 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2435 else
2436 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2437 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2438 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2439 if (ns == NULL)
2440 cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2441 else
2442 cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2443 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2444 cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2445 } else {
2446 return(NULL);
2447 }
2448 if (cur == NULL) return(NULL);
2449
2450 /*
2451 * add the new element at the end of the children list.
2452 */
2453 cur->type = XML_ELEMENT_NODE;
2454 cur->parent = parent;
2455 cur->doc = parent->doc;
2456 if (parent->children == NULL) {
2457 parent->children = cur;
2458 parent->last = cur;
2459 } else {
2460 prev = parent->last;
2461 prev->next = cur;
2462 cur->prev = prev;
2463 parent->last = cur;
2464 }
2465
2466 return(cur);
2467}
2468#endif /* LIBXML_TREE_ENABLED */
2469
2470/**
2471 * xmlNewCharRef:
2472 * @doc: the document
2473 * @name: the char ref string, starting with # or "&# ... ;"
2474 *
2475 * Creation of a new character reference node.
2476 * Returns a pointer to the new node object.
2477 */
2478xmlNodePtr
2479xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2480 xmlNodePtr cur;
2481
2482 if (name == NULL)
2483 return(NULL);
2484
2485 /*
2486 * Allocate a new node and fill the fields.
2487 */
2488 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2489 if (cur == NULL) {
2490 xmlTreeErrMemory("building character reference");
2491 return(NULL);
2492 }
2493 memset(cur, 0, sizeof(xmlNode));
2494 cur->type = XML_ENTITY_REF_NODE;
2495
2496 cur->doc = doc;
2497 if (name[0] == '&') {
2498 int len;
2499 name++;
2500 len = xmlStrlen(name);
2501 if (name[len - 1] == ';')
2502 cur->name = xmlStrndup(name, len - 1);
2503 else
2504 cur->name = xmlStrndup(name, len);
2505 } else
2506 cur->name = xmlStrdup(name);
2507
2508 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2509 xmlRegisterNodeDefaultValue(cur);
2510 return(cur);
2511}
2512
2513/**
2514 * xmlNewReference:
2515 * @doc: the document
2516 * @name: the reference name, or the reference string with & and ;
2517 *
2518 * Creation of a new reference node.
2519 * Returns a pointer to the new node object.
2520 */
2521xmlNodePtr
2522xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
2523 xmlNodePtr cur;
2524 xmlEntityPtr ent;
2525
2526 if (name == NULL)
2527 return(NULL);
2528
2529 /*
2530 * Allocate a new node and fill the fields.
2531 */
2532 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2533 if (cur == NULL) {
2534 xmlTreeErrMemory("building reference");
2535 return(NULL);
2536 }
2537 memset(cur, 0, sizeof(xmlNode));
2538 cur->type = XML_ENTITY_REF_NODE;
2539
2540 cur->doc = doc;
2541 if (name[0] == '&') {
2542 int len;
2543 name++;
2544 len = xmlStrlen(name);
2545 if (name[len - 1] == ';')
2546 cur->name = xmlStrndup(name, len - 1);
2547 else
2548 cur->name = xmlStrndup(name, len);
2549 } else
2550 cur->name = xmlStrdup(name);
2551
2552 ent = xmlGetDocEntity(doc, cur->name);
2553 if (ent != NULL) {
2554 cur->content = ent->content;
2555 /*
2556 * The parent pointer in entity is a DTD pointer and thus is NOT
2557 * updated. Not sure if this is 100% correct.
2558 * -George
2559 */
2560 cur->children = (xmlNodePtr) ent;
2561 cur->last = (xmlNodePtr) ent;
2562 }
2563
2564 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2565 xmlRegisterNodeDefaultValue(cur);
2566 return(cur);
2567}
2568
2569/**
2570 * xmlNewDocText:
2571 * @doc: the document
2572 * @content: the text content
2573 *
2574 * Creation of a new text node within a document.
2575 * Returns a pointer to the new node object.
2576 */
2577xmlNodePtr
2578xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
2579 xmlNodePtr cur;
2580
2581 cur = xmlNewText(content);
2582 if (cur != NULL) cur->doc = doc;
2583 return(cur);
2584}
2585
2586/**
2587 * xmlNewTextLen:
2588 * @content: the text content
2589 * @len: the text len.
2590 *
2591 * Creation of a new text node with an extra parameter for the content's length
2592 * Returns a pointer to the new node object.
2593 */
2594xmlNodePtr
2595xmlNewTextLen(const xmlChar *content, int len) {
2596 xmlNodePtr cur;
2597
2598 /*
2599 * Allocate a new node and fill the fields.
2600 */
2601 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2602 if (cur == NULL) {
2603 xmlTreeErrMemory("building text");
2604 return(NULL);
2605 }
2606 memset(cur, 0, sizeof(xmlNode));
2607 cur->type = XML_TEXT_NODE;
2608
2609 cur->name = xmlStringText;
2610 if (content != NULL) {
2611 cur->content = xmlStrndup(content, len);
2612 }
2613
2614 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2615 xmlRegisterNodeDefaultValue(cur);
2616 return(cur);
2617}
2618
2619/**
2620 * xmlNewDocTextLen:
2621 * @doc: the document
2622 * @content: the text content
2623 * @len: the text len.
2624 *
2625 * Creation of a new text node with an extra content length parameter. The
2626 * text node pertain to a given document.
2627 * Returns a pointer to the new node object.
2628 */
2629xmlNodePtr
2630xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2631 xmlNodePtr cur;
2632
2633 cur = xmlNewTextLen(content, len);
2634 if (cur != NULL) cur->doc = doc;
2635 return(cur);
2636}
2637
2638/**
2639 * xmlNewComment:
2640 * @content: the comment content
2641 *
2642 * Creation of a new node containing a comment.
2643 * Returns a pointer to the new node object.
2644 */
2645xmlNodePtr
2646xmlNewComment(const xmlChar *content) {
2647 xmlNodePtr cur;
2648
2649 /*
2650 * Allocate a new node and fill the fields.
2651 */
2652 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2653 if (cur == NULL) {
2654 xmlTreeErrMemory("building comment");
2655 return(NULL);
2656 }
2657 memset(cur, 0, sizeof(xmlNode));
2658 cur->type = XML_COMMENT_NODE;
2659
2660 cur->name = xmlStringComment;
2661 if (content != NULL) {
2662 cur->content = xmlStrdup(content);
2663 }
2664
2665 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2666 xmlRegisterNodeDefaultValue(cur);
2667 return(cur);
2668}
2669
2670/**
2671 * xmlNewCDataBlock:
2672 * @doc: the document
2673 * @content: the CDATA block content content
2674 * @len: the length of the block
2675 *
2676 * Creation of a new node containing a CDATA block.
2677 * Returns a pointer to the new node object.
2678 */
2679xmlNodePtr
2680xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2681 xmlNodePtr cur;
2682
2683 /*
2684 * Allocate a new node and fill the fields.
2685 */
2686 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2687 if (cur == NULL) {
2688 xmlTreeErrMemory("building CDATA");
2689 return(NULL);
2690 }
2691 memset(cur, 0, sizeof(xmlNode));
2692 cur->type = XML_CDATA_SECTION_NODE;
2693 cur->doc = doc;
2694
2695 if (content != NULL) {
2696 cur->content = xmlStrndup(content, len);
2697 }
2698
2699 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2700 xmlRegisterNodeDefaultValue(cur);
2701 return(cur);
2702}
2703
2704/**
2705 * xmlNewDocComment:
2706 * @doc: the document
2707 * @content: the comment content
2708 *
2709 * Creation of a new node containing a comment within a document.
2710 * Returns a pointer to the new node object.
2711 */
2712xmlNodePtr
2713xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2714 xmlNodePtr cur;
2715
2716 cur = xmlNewComment(content);
2717 if (cur != NULL) cur->doc = doc;
2718 return(cur);
2719}
2720
2721/**
2722 * xmlSetTreeDoc:
2723 * @tree: the top element
2724 * @doc: the document
2725 *
2726 * update all nodes under the tree to point to the right document
2727 */
2728void
2729xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
2730 xmlAttrPtr prop;
2731
2732 if (tree == NULL)
2733 return;
2734 if (tree->doc != doc) {
2735 if(tree->type == XML_ELEMENT_NODE) {
2736 prop = tree->properties;
2737 while (prop != NULL) {
2738 prop->doc = doc;
2739 xmlSetListDoc(prop->children, doc);
2740 prop = prop->next;
2741 }
2742 }
2743 if (tree->children != NULL)
2744 xmlSetListDoc(tree->children, doc);
2745 tree->doc = doc;
2746 }
2747}
2748
2749/**
2750 * xmlSetListDoc:
2751 * @list: the first element
2752 * @doc: the document
2753 *
2754 * update all nodes in the list to point to the right document
2755 */
2756void
2757xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2758 xmlNodePtr cur;
2759
2760 if (list == NULL)
2761 return;
2762 cur = list;
2763 while (cur != NULL) {
2764 if (cur->doc != doc)
2765 xmlSetTreeDoc(cur, doc);
2766 cur = cur->next;
2767 }
2768}
2769
2770#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
2771/**
2772 * xmlNewChild:
2773 * @parent: the parent node
2774 * @ns: a namespace if any
2775 * @name: the name of the child
2776 * @content: the XML content of the child if any.
2777 *
2778 * Creation of a new child element, added at the end of @parent children list.
2779 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2780 * created element inherits the namespace of @parent. If @content is non NULL,
2781 * a child list containing the TEXTs and ENTITY_REFs node will be created.
2782 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
2783 * references. XML special chars must be escaped first by using
2784 * xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used.
2785 *
2786 * Returns a pointer to the new node object.
2787 */
2788xmlNodePtr
2789xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2790 const xmlChar *name, const xmlChar *content) {
2791 xmlNodePtr cur, prev;
2792
2793 if (parent == NULL) {
2794#ifdef DEBUG_TREE
2795 xmlGenericError(xmlGenericErrorContext,
2796 "xmlNewChild : parent == NULL\n");
2797#endif
2798 return(NULL);
2799 }
2800
2801 if (name == NULL) {
2802#ifdef DEBUG_TREE
2803 xmlGenericError(xmlGenericErrorContext,
2804 "xmlNewChild : name == NULL\n");
2805#endif
2806 return(NULL);
2807 }
2808
2809 /*
2810 * Allocate a new node
2811 */
2812 if (parent->type == XML_ELEMENT_NODE) {
2813 if (ns == NULL)
2814 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2815 else
2816 cur = xmlNewDocNode(parent->doc, ns, name, content);
2817 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2818 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2819 if (ns == NULL)
2820 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2821 else
2822 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
2823 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2824 cur = xmlNewDocNode( parent->doc, ns, name, content);
2825 } else {
2826 return(NULL);
2827 }
2828 if (cur == NULL) return(NULL);
2829
2830 /*
2831 * add the new element at the end of the children list.
2832 */
2833 cur->type = XML_ELEMENT_NODE;
2834 cur->parent = parent;
2835 cur->doc = parent->doc;
2836 if (parent->children == NULL) {
2837 parent->children = cur;
2838 parent->last = cur;
2839 } else {
2840 prev = parent->last;
2841 prev->next = cur;
2842 cur->prev = prev;
2843 parent->last = cur;
2844 }
2845
2846 return(cur);
2847}
2848#endif /* LIBXML_TREE_ENABLED */
2849
2850/**
2851 * xmlAddPropSibling:
2852 * @prev: the attribute to which @prop is added after
2853 * @cur: the base attribute passed to calling function
2854 * @prop: the new attribute
2855 *
2856 * Add a new attribute after @prev using @cur as base attribute.
2857 * When inserting before @cur, @prev is passed as @cur->prev.
2858 * When inserting after @cur, @prev is passed as @cur.
2859 * If an existing attribute is found it is detroyed prior to adding @prop.
2860 *
2861 * Returns the attribute being inserted or NULL in case of error.
2862 */
2863static xmlNodePtr
2864xmlAddPropSibling(xmlNodePtr prev, xmlNodePtr cur, xmlNodePtr prop) {
2865 xmlAttrPtr attr;
2866
2867 if (cur->type != XML_ATTRIBUTE_NODE)
2868 return(NULL);
2869
2870 /* check if an attribute with the same name exists */
2871 if (prop->ns == NULL)
2872 attr = xmlHasNsProp(cur->parent, prop->name, NULL);
2873 else
2874 attr = xmlHasNsProp(cur->parent, prop->name, prop->ns->href);
2875
2876 if (prop->doc != cur->doc) {
2877 xmlSetTreeDoc(prop, cur->doc);
2878 }
2879 prop->parent = cur->parent;
2880 prop->prev = prev;
2881 if (prev != NULL) {
2882 prop->next = prev->next;
2883 prev->next = prop;
2884 if (prop->next)
2885 prop->next->prev = prop;
2886 } else {
2887 prop->next = cur;
2888 cur->prev = prop;
2889 }
2890 if (prop->prev == NULL && prop->parent != NULL)
2891 prop->parent->properties = (xmlAttrPtr) prop;
2892 if ((attr != NULL) && (attr->type != XML_ATTRIBUTE_DECL)) {
2893 /* different instance, destroy it (attributes must be unique) */
2894 xmlRemoveProp((xmlAttrPtr) attr);
2895 }
2896 return prop;
2897}
2898
2899/**
2900 * xmlAddNextSibling:
2901 * @cur: the child node
2902 * @elem: the new node
2903 *
2904 * Add a new node @elem as the next sibling of @cur
2905 * If the new node was already inserted in a document it is
2906 * first unlinked from its existing context.
2907 * As a result of text merging @elem may be freed.
2908 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2909 * If there is an attribute with equal name, it is first destroyed.
2910 *
2911 * Returns the new node or NULL in case of error.
2912 */
2913xmlNodePtr
2914xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2915 if (cur == NULL) {
2916#ifdef DEBUG_TREE
2917 xmlGenericError(xmlGenericErrorContext,
2918 "xmlAddNextSibling : cur == NULL\n");
2919#endif
2920 return(NULL);
2921 }
2922 if (elem == NULL) {
2923#ifdef DEBUG_TREE
2924 xmlGenericError(xmlGenericErrorContext,
2925 "xmlAddNextSibling : elem == NULL\n");
2926#endif
2927 return(NULL);
2928 }
2929
2930 if (cur == elem) {
2931#ifdef DEBUG_TREE
2932 xmlGenericError(xmlGenericErrorContext,
2933 "xmlAddNextSibling : cur == elem\n");
2934#endif
2935 return(NULL);
2936 }
2937
2938 xmlUnlinkNode(elem);
2939
2940 if (elem->type == XML_TEXT_NODE) {
2941 if (cur->type == XML_TEXT_NODE) {
2942 xmlNodeAddContent(cur, elem->content);
2943 xmlFreeNode(elem);
2944 return(cur);
2945 }
2946 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2947 (cur->name == cur->next->name)) {
2948 xmlChar *tmp;
2949
2950 tmp = xmlStrdup(elem->content);
2951 tmp = xmlStrcat(tmp, cur->next->content);
2952 xmlNodeSetContent(cur->next, tmp);
2953 xmlFree(tmp);
2954 xmlFreeNode(elem);
2955 return(cur->next);
2956 }
2957 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2958 return xmlAddPropSibling(cur, cur, elem);
2959 }
2960
2961 if (elem->doc != cur->doc) {
2962 xmlSetTreeDoc(elem, cur->doc);
2963 }
2964 elem->parent = cur->parent;
2965 elem->prev = cur;
2966 elem->next = cur->next;
2967 cur->next = elem;
2968 if (elem->next != NULL)
2969 elem->next->prev = elem;
2970 if ((elem->parent != NULL) && (elem->parent->last == cur))
2971 elem->parent->last = elem;
2972 return(elem);
2973}
2974
2975#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
2976 defined(LIBXML_SCHEMAS_ENABLED)
2977/**
2978 * xmlAddPrevSibling:
2979 * @cur: the child node
2980 * @elem: the new node
2981 *
2982 * Add a new node @elem as the previous sibling of @cur
2983 * merging adjacent TEXT nodes (@elem may be freed)
2984 * If the new node was already inserted in a document it is
2985 * first unlinked from its existing context.
2986 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2987 * If there is an attribute with equal name, it is first destroyed.
2988 *
2989 * Returns the new node or NULL in case of error.
2990 */
2991xmlNodePtr
2992xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2993 if (cur == NULL) {
2994#ifdef DEBUG_TREE
2995 xmlGenericError(xmlGenericErrorContext,
2996 "xmlAddPrevSibling : cur == NULL\n");
2997#endif
2998 return(NULL);
2999 }
3000 if (elem == NULL) {
3001#ifdef DEBUG_TREE
3002 xmlGenericError(xmlGenericErrorContext,
3003 "xmlAddPrevSibling : elem == NULL\n");
3004#endif
3005 return(NULL);
3006 }
3007
3008 if (cur == elem) {
3009#ifdef DEBUG_TREE
3010 xmlGenericError(xmlGenericErrorContext,
3011 "xmlAddPrevSibling : cur == elem\n");
3012#endif
3013 return(NULL);
3014 }
3015
3016 xmlUnlinkNode(elem);
3017
3018 if (elem->type == XML_TEXT_NODE) {
3019 if (cur->type == XML_TEXT_NODE) {
3020 xmlChar *tmp;
3021
3022 tmp = xmlStrdup(elem->content);
3023 tmp = xmlStrcat(tmp, cur->content);
3024 xmlNodeSetContent(cur, tmp);
3025 xmlFree(tmp);
3026 xmlFreeNode(elem);
3027 return(cur);
3028 }
3029 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
3030 (cur->name == cur->prev->name)) {
3031 xmlNodeAddContent(cur->prev, elem->content);
3032 xmlFreeNode(elem);
3033 return(cur->prev);
3034 }
3035 } else if (elem->type == XML_ATTRIBUTE_NODE) {
3036 return xmlAddPropSibling(cur->prev, cur, elem);
3037 }
3038
3039 if (elem->doc != cur->doc) {
3040 xmlSetTreeDoc(elem, cur->doc);
3041 }
3042 elem->parent = cur->parent;
3043 elem->next = cur;
3044 elem->prev = cur->prev;
3045 cur->prev = elem;
3046 if (elem->prev != NULL)
3047 elem->prev->next = elem;
3048 if ((elem->parent != NULL) && (elem->parent->children == cur)) {
3049 elem->parent->children = elem;
3050 }
3051 return(elem);
3052}
3053#endif /* LIBXML_TREE_ENABLED */
3054
3055/**
3056 * xmlAddSibling:
3057 * @cur: the child node
3058 * @elem: the new node
3059 *
3060 * Add a new element @elem to the list of siblings of @cur
3061 * merging adjacent TEXT nodes (@elem may be freed)
3062 * If the new element was already inserted in a document it is
3063 * first unlinked from its existing context.
3064 *
3065 * Returns the new element or NULL in case of error.
3066 */
3067xmlNodePtr
3068xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
3069 xmlNodePtr parent;
3070
3071 if (cur == NULL) {
3072#ifdef DEBUG_TREE
3073 xmlGenericError(xmlGenericErrorContext,
3074 "xmlAddSibling : cur == NULL\n");
3075#endif
3076 return(NULL);
3077 }
3078
3079 if (elem == NULL) {
3080#ifdef DEBUG_TREE
3081 xmlGenericError(xmlGenericErrorContext,
3082 "xmlAddSibling : elem == NULL\n");
3083#endif
3084 return(NULL);
3085 }
3086
3087 /*
3088 * Constant time is we can rely on the ->parent->last to find
3089 * the last sibling.
3090 */
3091 if ((cur->type != XML_ATTRIBUTE_NODE) && (cur->parent != NULL) &&
3092 (cur->parent->children != NULL) &&
3093 (cur->parent->last != NULL) &&
3094 (cur->parent->last->next == NULL)) {
3095 cur = cur->parent->last;
3096 } else {
3097 while (cur->next != NULL) cur = cur->next;
3098 }
3099
3100 xmlUnlinkNode(elem);
3101
3102 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3103 (cur->name == elem->name)) {
3104 xmlNodeAddContent(cur, elem->content);
3105 xmlFreeNode(elem);
3106 return(cur);
3107 } else if (elem->type == XML_ATTRIBUTE_NODE) {
3108 return xmlAddPropSibling(cur, cur, elem);
3109 }
3110
3111 if (elem->doc != cur->doc) {
3112 xmlSetTreeDoc(elem, cur->doc);
3113 }
3114 parent = cur->parent;
3115 elem->prev = cur;
3116 elem->next = NULL;
3117 elem->parent = parent;
3118 cur->next = elem;
3119 if (parent != NULL)
3120 parent->last = elem;
3121
3122 return(elem);
3123}
3124
3125/**
3126 * xmlAddChildList:
3127 * @parent: the parent node
3128 * @cur: the first node in the list
3129 *
3130 * Add a list of node at the end of the child list of the parent
3131 * merging adjacent TEXT nodes (@cur may be freed)
3132 *
3133 * Returns the last child or NULL in case of error.
3134 */
3135xmlNodePtr
3136xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3137 xmlNodePtr prev;
3138
3139 if (parent == NULL) {
3140#ifdef DEBUG_TREE
3141 xmlGenericError(xmlGenericErrorContext,
3142 "xmlAddChildList : parent == NULL\n");
3143#endif
3144 return(NULL);
3145 }
3146
3147 if (cur == NULL) {
3148#ifdef DEBUG_TREE
3149 xmlGenericError(xmlGenericErrorContext,
3150 "xmlAddChildList : child == NULL\n");
3151#endif
3152 return(NULL);
3153 }
3154
3155 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3156 (cur->doc != parent->doc)) {
3157#ifdef DEBUG_TREE
3158 xmlGenericError(xmlGenericErrorContext,
3159 "Elements moved to a different document\n");
3160#endif
3161 }
3162
3163 /*
3164 * add the first element at the end of the children list.
3165 */
3166
3167 if (parent->children == NULL) {
3168 parent->children = cur;
3169 } else {
3170 /*
3171 * If cur and parent->last both are TEXT nodes, then merge them.
3172 */
3173 if ((cur->type == XML_TEXT_NODE) &&
3174 (parent->last->type == XML_TEXT_NODE) &&
3175 (cur->name == parent->last->name)) {
3176 xmlNodeAddContent(parent->last, cur->content);
3177 /*
3178 * if it's the only child, nothing more to be done.
3179 */
3180 if (cur->next == NULL) {
3181 xmlFreeNode(cur);
3182 return(parent->last);
3183 }
3184 prev = cur;
3185 cur = cur->next;
3186 xmlFreeNode(prev);
3187 }
3188 prev = parent->last;
3189 prev->next = cur;
3190 cur->prev = prev;
3191 }
3192 while (cur->next != NULL) {
3193 cur->parent = parent;
3194 if (cur->doc != parent->doc) {
3195 xmlSetTreeDoc(cur, parent->doc);
3196 }
3197 cur = cur->next;
3198 }
3199 cur->parent = parent;
3200 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
3201 parent->last = cur;
3202
3203 return(cur);
3204}
3205
3206/**
3207 * xmlAddChild:
3208 * @parent: the parent node
3209 * @cur: the child node
3210 *
3211 * Add a new node to @parent, at the end of the child (or property) list
3212 * merging adjacent TEXT nodes (in which case @cur is freed)
3213 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3214 * If there is an attribute with equal name, it is first destroyed.
3215 *
3216 * Returns the child or NULL in case of error.
3217 */
3218xmlNodePtr
3219xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3220 xmlNodePtr prev;
3221
3222 if (parent == NULL) {
3223#ifdef DEBUG_TREE
3224 xmlGenericError(xmlGenericErrorContext,
3225 "xmlAddChild : parent == NULL\n");
3226#endif
3227 return(NULL);
3228 }
3229
3230 if (cur == NULL) {
3231#ifdef DEBUG_TREE
3232 xmlGenericError(xmlGenericErrorContext,
3233 "xmlAddChild : child == NULL\n");
3234#endif
3235 return(NULL);
3236 }
3237
3238 if (parent == cur) {
3239#ifdef DEBUG_TREE
3240 xmlGenericError(xmlGenericErrorContext,
3241 "xmlAddChild : parent == cur\n");
3242#endif
3243 return(NULL);
3244 }
3245 /*
3246 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
3247 * cur is then freed.
3248 */
3249 if (cur->type == XML_TEXT_NODE) {
3250 if ((parent->type == XML_TEXT_NODE) &&
3251 (parent->content != NULL) &&
3252 (parent->name == cur->name)) {
3253 xmlNodeAddContent(parent, cur->content);
3254 xmlFreeNode(cur);
3255 return(parent);
3256 }
3257 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
3258 (parent->last->name == cur->name) &&
3259 (parent->last != cur)) {
3260 xmlNodeAddContent(parent->last, cur->content);
3261 xmlFreeNode(cur);
3262 return(parent->last);
3263 }
3264 }
3265
3266 /*
3267 * add the new element at the end of the children list.
3268 */
3269 prev = cur->parent;
3270 cur->parent = parent;
3271 if (cur->doc != parent->doc) {
3272 xmlSetTreeDoc(cur, parent->doc);
3273 }
3274 /* this check prevents a loop on tree-traversions if a developer
3275 * tries to add a node to its parent multiple times
3276 */
3277 if (prev == parent)
3278 return(cur);
3279
3280 /*
3281 * Coalescing
3282 */
3283 if ((parent->type == XML_TEXT_NODE) &&
3284 (parent->content != NULL) &&
3285 (parent != cur)) {
3286 xmlNodeAddContent(parent, cur->content);
3287 xmlFreeNode(cur);
3288 return(parent);
3289 }
3290 if (cur->type == XML_ATTRIBUTE_NODE) {
3291 if (parent->type != XML_ELEMENT_NODE)
3292 return(NULL);
3293 if (parent->properties == NULL) {
3294 parent->properties = (xmlAttrPtr) cur;
3295 } else {
3296 /* check if an attribute with the same name exists */
3297 xmlAttrPtr lastattr;
3298
3299 if (cur->ns == NULL)
3300 lastattr = xmlHasNsProp(parent, cur->name, NULL);
3301 else
3302 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3303 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur) && (lastattr->type != XML_ATTRIBUTE_DECL)) {
3304 /* different instance, destroy it (attributes must be unique) */
3305 xmlUnlinkNode((xmlNodePtr) lastattr);
3306 xmlFreeProp(lastattr);
3307 }
3308 if (lastattr == (xmlAttrPtr) cur)
3309 return(cur);
3310 /* find the end */
3311 lastattr = parent->properties;
3312 while (lastattr->next != NULL) {
3313 lastattr = lastattr->next;
3314 }
3315 lastattr->next = (xmlAttrPtr) cur;
3316 ((xmlAttrPtr) cur)->prev = lastattr;
3317 }
3318 } else {
3319 if (parent->children == NULL) {
3320 parent->children = cur;
3321 parent->last = cur;
3322 } else {
3323 prev = parent->last;
3324 prev->next = cur;
3325 cur->prev = prev;
3326 parent->last = cur;
3327 }
3328 }
3329 return(cur);
3330}
3331
3332/**
3333 * xmlGetLastChild:
3334 * @parent: the parent node
3335 *
3336 * Search the last child of a node.
3337 * Returns the last child or NULL if none.
3338 */
3339xmlNodePtr
3340xmlGetLastChild(xmlNodePtr parent) {
3341 if (parent == NULL) {
3342#ifdef DEBUG_TREE
3343 xmlGenericError(xmlGenericErrorContext,
3344 "xmlGetLastChild : parent == NULL\n");
3345#endif
3346 return(NULL);
3347 }
3348 return(parent->last);
3349}
3350
3351/**
3352 * xmlFreeNodeList:
3353 * @cur: the first node in the list
3354 *
3355 * Free a node and all its siblings, this is a recursive behaviour, all
3356 * the children are freed too.
3357 */
3358void
3359xmlFreeNodeList(xmlNodePtr cur) {
3360 xmlNodePtr next;
3361 xmlDictPtr dict = NULL;
3362
3363 if (cur == NULL) return;
3364 if (cur->type == XML_NAMESPACE_DECL) {
3365 xmlFreeNsList((xmlNsPtr) cur);
3366 return;
3367 }
3368 if ((cur->type == XML_DOCUMENT_NODE) ||
3369#ifdef LIBXML_DOCB_ENABLED
3370 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
3371#endif
3372 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3373 xmlFreeDoc((xmlDocPtr) cur);
3374 return;
3375 }
3376 if (cur->doc != NULL) dict = cur->doc->dict;
3377 while (cur != NULL) {
3378 next = cur->next;
3379 if (cur->type != XML_DTD_NODE) {
3380
3381 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
3382 xmlDeregisterNodeDefaultValue(cur);
3383
3384 if ((cur->children != NULL) &&
3385 (cur->type != XML_ENTITY_REF_NODE))
3386 xmlFreeNodeList(cur->children);
3387 if (((cur->type == XML_ELEMENT_NODE) ||
3388 (cur->type == XML_XINCLUDE_START) ||
3389 (cur->type == XML_XINCLUDE_END)) &&
3390 (cur->properties != NULL))
3391 xmlFreePropList(cur->properties);
3392 if ((cur->type != XML_ELEMENT_NODE) &&
3393 (cur->type != XML_XINCLUDE_START) &&
3394 (cur->type != XML_XINCLUDE_END) &&
3395 (cur->type != XML_ENTITY_REF_NODE) &&
3396 (cur->content != (xmlChar *) &(cur->properties))) {
3397 DICT_FREE(cur->content)
3398 }
3399 if (((cur->type == XML_ELEMENT_NODE) ||
3400 (cur->type == XML_XINCLUDE_START) ||
3401 (cur->type == XML_XINCLUDE_END)) &&
3402 (cur->nsDef != NULL))
3403 xmlFreeNsList(cur->nsDef);
3404
3405 /*
3406 * When a node is a text node or a comment, it uses a global static
3407 * variable for the name of the node.
3408 * Otherwise the node name might come from the document's
3409 * dictionnary
3410 */
3411 if ((cur->name != NULL) &&
3412 (cur->type != XML_TEXT_NODE) &&
3413 (cur->type != XML_COMMENT_NODE))
3414 DICT_FREE(cur->name)
3415 xmlFree(cur);
3416 }
3417 cur = next;
3418 }
3419}
3420
3421/**
3422 * xmlFreeNode:
3423 * @cur: the node
3424 *
3425 * Free a node, this is a recursive behaviour, all the children are freed too.
3426 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3427 */
3428void
3429xmlFreeNode(xmlNodePtr cur) {
3430 xmlDictPtr dict = NULL;
3431
3432 if (cur == NULL) return;
3433
3434 /* use xmlFreeDtd for DTD nodes */
3435 if (cur->type == XML_DTD_NODE) {
3436 xmlFreeDtd((xmlDtdPtr) cur);
3437 return;
3438 }
3439 if (cur->type == XML_NAMESPACE_DECL) {
3440 xmlFreeNs((xmlNsPtr) cur);
3441 return;
3442 }
3443 if (cur->type == XML_ATTRIBUTE_NODE) {
3444 xmlFreeProp((xmlAttrPtr) cur);
3445 return;
3446 }
3447
3448 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
3449 xmlDeregisterNodeDefaultValue(cur);
3450
3451 if (cur->doc != NULL) dict = cur->doc->dict;
3452
3453 if ((cur->children != NULL) &&
3454 (cur->type != XML_ENTITY_REF_NODE))
3455 xmlFreeNodeList(cur->children);
3456 if (((cur->type == XML_ELEMENT_NODE) ||
3457 (cur->type == XML_XINCLUDE_START) ||
3458 (cur->type == XML_XINCLUDE_END)) &&
3459 (cur->properties != NULL))
3460 xmlFreePropList(cur->properties);
3461 if ((cur->type != XML_ELEMENT_NODE) &&
3462 (cur->content != NULL) &&
3463 (cur->type != XML_ENTITY_REF_NODE) &&
3464 (cur->type != XML_XINCLUDE_END) &&
3465 (cur->type != XML_XINCLUDE_START) &&
3466 (cur->content != (xmlChar *) &(cur->properties))) {
3467 DICT_FREE(cur->content)
3468 }
3469
3470 /*
3471 * When a node is a text node or a comment, it uses a global static
3472 * variable for the name of the node.
3473 * Otherwise the node name might come from the document's dictionnary
3474 */
3475 if ((cur->name != NULL) &&
3476 (cur->type != XML_TEXT_NODE) &&
3477 (cur->type != XML_COMMENT_NODE))
3478 DICT_FREE(cur->name)
3479
3480 if (((cur->type == XML_ELEMENT_NODE) ||
3481 (cur->type == XML_XINCLUDE_START) ||
3482 (cur->type == XML_XINCLUDE_END)) &&
3483 (cur->nsDef != NULL))
3484 xmlFreeNsList(cur->nsDef);
3485 xmlFree(cur);
3486}
3487
3488/**
3489 * xmlUnlinkNode:
3490 * @cur: the node
3491 *
3492 * Unlink a node from it's current context, the node is not freed
3493 */
3494void
3495xmlUnlinkNode(xmlNodePtr cur) {
3496 if (cur == NULL) {
3497#ifdef DEBUG_TREE
3498 xmlGenericError(xmlGenericErrorContext,
3499 "xmlUnlinkNode : node == NULL\n");
3500#endif
3501 return;
3502 }
3503 if (cur->type == XML_DTD_NODE) {
3504 xmlDocPtr doc;
3505 doc = cur->doc;
3506 if (doc != NULL) {
3507 if (doc->intSubset == (xmlDtdPtr) cur)
3508 doc->intSubset = NULL;
3509 if (doc->extSubset == (xmlDtdPtr) cur)
3510 doc->extSubset = NULL;
3511 }
3512 }
3513 if (cur->parent != NULL) {
3514 xmlNodePtr parent;
3515 parent = cur->parent;
3516 if (cur->type == XML_ATTRIBUTE_NODE) {
3517 if (parent->properties == (xmlAttrPtr) cur)
3518 parent->properties = ((xmlAttrPtr) cur)->next;
3519 } else {
3520 if (parent->children == cur)
3521 parent->children = cur->next;
3522 if (parent->last == cur)
3523 parent->last = cur->prev;
3524 }
3525 cur->parent = NULL;
3526 }
3527 if (cur->next != NULL)
3528 cur->next->prev = cur->prev;
3529 if (cur->prev != NULL)
3530 cur->prev->next = cur->next;
3531 cur->next = cur->prev = NULL;
3532}
3533
3534#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
3535/**
3536 * xmlReplaceNode:
3537 * @old: the old node
3538 * @cur: the node
3539 *
3540 * Unlink the old node from its current context, prune the new one
3541 * at the same place. If @cur was already inserted in a document it is
3542 * first unlinked from its existing context.
3543 *
3544 * Returns the @old node
3545 */
3546xmlNodePtr
3547xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3548 if (old == cur) return(NULL);
3549 if ((old == NULL) || (old->parent == NULL)) {
3550#ifdef DEBUG_TREE
3551 xmlGenericError(xmlGenericErrorContext,
3552 "xmlReplaceNode : old == NULL or without parent\n");
3553#endif
3554 return(NULL);
3555 }
3556 if (cur == NULL) {
3557 xmlUnlinkNode(old);
3558 return(old);
3559 }
3560 if (cur == old) {
3561 return(old);
3562 }
3563 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3564#ifdef DEBUG_TREE
3565 xmlGenericError(xmlGenericErrorContext,
3566 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3567#endif
3568 return(old);
3569 }
3570 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3571#ifdef DEBUG_TREE
3572 xmlGenericError(xmlGenericErrorContext,
3573 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3574#endif
3575 return(old);
3576 }
3577 xmlUnlinkNode(cur);
3578 xmlSetTreeDoc(cur, old->doc);
3579 cur->parent = old->parent;
3580 cur->next = old->next;
3581 if (cur->next != NULL)
3582 cur->next->prev = cur;
3583 cur->prev = old->prev;
3584 if (cur->prev != NULL)
3585 cur->prev->next = cur;
3586 if (cur->parent != NULL) {
3587 if (cur->type == XML_ATTRIBUTE_NODE) {
3588 if (cur->parent->properties == (xmlAttrPtr)old)
3589 cur->parent->properties = ((xmlAttrPtr) cur);
3590 } else {
3591 if (cur->parent->children == old)
3592 cur->parent->children = cur;
3593 if (cur->parent->last == old)
3594 cur->parent->last = cur;
3595 }
3596 }
3597 old->next = old->prev = NULL;
3598 old->parent = NULL;
3599 return(old);
3600}
3601#endif /* LIBXML_TREE_ENABLED */
3602
3603/************************************************************************
3604 * *
3605 * Copy operations *
3606 * *
3607 ************************************************************************/
3608
3609/**
3610 * xmlCopyNamespace:
3611 * @cur: the namespace
3612 *
3613 * Do a copy of the namespace.
3614 *
3615 * Returns: a new #xmlNsPtr, or NULL in case of error.
3616 */
3617xmlNsPtr
3618xmlCopyNamespace(xmlNsPtr cur) {
3619 xmlNsPtr ret;
3620
3621 if (cur == NULL) return(NULL);
3622 switch (cur->type) {
3623 case XML_LOCAL_NAMESPACE:
3624 ret = xmlNewNs(NULL, cur->href, cur->prefix);
3625 break;
3626 default:
3627#ifdef DEBUG_TREE
3628 xmlGenericError(xmlGenericErrorContext,
3629 "xmlCopyNamespace: invalid type %d\n", cur->type);
3630#endif
3631 return(NULL);
3632 }
3633 return(ret);
3634}
3635
3636/**
3637 * xmlCopyNamespaceList:
3638 * @cur: the first namespace
3639 *
3640 * Do a copy of an namespace list.
3641 *
3642 * Returns: a new #xmlNsPtr, or NULL in case of error.
3643 */
3644xmlNsPtr
3645xmlCopyNamespaceList(xmlNsPtr cur) {
3646 xmlNsPtr ret = NULL;
3647 xmlNsPtr p = NULL,q;
3648
3649 while (cur != NULL) {
3650 q = xmlCopyNamespace(cur);
3651 if (p == NULL) {
3652 ret = p = q;
3653 } else {
3654 p->next = q;
3655 p = q;
3656 }
3657 cur = cur->next;
3658 }
3659 return(ret);
3660}
3661
3662static xmlNodePtr
3663xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
3664
3665static xmlAttrPtr
3666xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) {
3667 xmlAttrPtr ret;
3668
3669 if (cur == NULL) return(NULL);
3670 if (target != NULL)
3671 ret = xmlNewDocProp(target->doc, cur->name, NULL);
3672 else if (doc != NULL)
3673 ret = xmlNewDocProp(doc, cur->name, NULL);
3674 else if (cur->parent != NULL)
3675 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3676 else if (cur->children != NULL)
3677 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3678 else
3679 ret = xmlNewDocProp(NULL, cur->name, NULL);
3680 if (ret == NULL) return(NULL);
3681 ret->parent = target;
3682
3683 if ((cur->ns != NULL) && (target != NULL)) {
3684 xmlNsPtr ns;
3685
3686 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
3687 if (ns == NULL) {
3688 /*
3689 * Humm, we are copying an element whose namespace is defined
3690 * out of the new tree scope. Search it in the original tree
3691 * and add it at the top of the new tree
3692 */
3693 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
3694 if (ns != NULL) {
3695 xmlNodePtr root = target;
3696 xmlNodePtr pred = NULL;
3697
3698 while (root->parent != NULL) {
3699 pred = root;
3700 root = root->parent;
3701 }
3702 if (root == (xmlNodePtr) target->doc) {
3703 /* correct possibly cycling above the document elt */
3704 root = pred;
3705 }
3706 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3707 }
3708 } else {
3709 /*
3710 * we have to find something appropriate here since
3711 * we cant be sure, that the namespce we found is identified
3712 * by the prefix
3713 */
3714 if (xmlStrEqual(ns->href, cur->ns->href)) {
3715 /* this is the nice case */
3716 ret->ns = ns;
3717 } else {
3718 /*
3719 * we are in trouble: we need a new reconcilied namespace.
3720 * This is expensive
3721 */
3722 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
3723 }
3724 }
3725
3726 } else
3727 ret->ns = NULL;
3728
3729 if (cur->children != NULL) {
3730 xmlNodePtr tmp;
3731
3732 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
3733 ret->last = NULL;
3734 tmp = ret->children;
3735 while (tmp != NULL) {
3736 /* tmp->parent = (xmlNodePtr)ret; */
3737 if (tmp->next == NULL)
3738 ret->last = tmp;
3739 tmp = tmp->next;
3740 }
3741 }
3742 /*
3743 * Try to handle IDs
3744 */
3745 if ((target!= NULL) && (cur!= NULL) &&
3746 (target->doc != NULL) && (cur->doc != NULL) &&
3747 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3748 if (xmlIsID(cur->doc, cur->parent, cur)) {
3749 xmlChar *id;
3750
3751 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3752 if (id != NULL) {
3753 xmlAddID(NULL, target->doc, id, ret);
3754 xmlFree(id);
3755 }
3756 }
3757 }
3758 return(ret);
3759}
3760
3761/**
3762 * xmlCopyProp:
3763 * @target: the element where the attribute will be grafted
3764 * @cur: the attribute
3765 *
3766 * Do a copy of the attribute.
3767 *
3768 * Returns: a new #xmlAttrPtr, or NULL in case of error.
3769 */
3770xmlAttrPtr
3771xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
3772 return xmlCopyPropInternal(NULL, target, cur);
3773}
3774
3775/**
3776 * xmlCopyPropList:
3777 * @target: the element where the attributes will be grafted
3778 * @cur: the first attribute
3779 *
3780 * Do a copy of an attribute list.
3781 *
3782 * Returns: a new #xmlAttrPtr, or NULL in case of error.
3783 */
3784xmlAttrPtr
3785xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3786 xmlAttrPtr ret = NULL;
3787 xmlAttrPtr p = NULL,q;
3788
3789 while (cur != NULL) {
3790 q = xmlCopyProp(target, cur);
3791 if (q == NULL)
3792 return(NULL);
3793 if (p == NULL) {
3794 ret = p = q;
3795 } else {
3796 p->next = q;
3797 q->prev = p;
3798 p = q;
3799 }
3800 cur = cur->next;
3801 }
3802 return(ret);
3803}
3804
3805/*
3806 * NOTE about the CopyNode operations !
3807 *
3808 * They are split into external and internal parts for one
3809 * tricky reason: namespaces. Doing a direct copy of a node
3810 * say RPM:Copyright without changing the namespace pointer to
3811 * something else can produce stale links. One way to do it is
3812 * to keep a reference counter but this doesn't work as soon
3813 * as one move the element or the subtree out of the scope of
3814 * the existing namespace. The actual solution seems to add
3815 * a copy of the namespace at the top of the copied tree if
3816 * not available in the subtree.
3817 * Hence two functions, the public front-end call the inner ones
3818 * The argument "recursive" normally indicates a recursive copy
3819 * of the node with values 0 (no) and 1 (yes). For XInclude,
3820 * however, we allow a value of 2 to indicate copy properties and
3821 * namespace info, but don't recurse on children.
3822 */
3823
3824static xmlNodePtr
3825xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
3826 int extended) {
3827 xmlNodePtr ret;
3828
3829 if (node == NULL) return(NULL);
3830 switch (node->type) {
3831 case XML_TEXT_NODE:
3832 case XML_CDATA_SECTION_NODE:
3833 case XML_ELEMENT_NODE:
3834 case XML_DOCUMENT_FRAG_NODE:
3835 case XML_ENTITY_REF_NODE:
3836 case XML_ENTITY_NODE:
3837 case XML_PI_NODE:
3838 case XML_COMMENT_NODE:
3839 case XML_XINCLUDE_START:
3840 case XML_XINCLUDE_END:
3841 break;
3842 case XML_ATTRIBUTE_NODE:
3843 return((xmlNodePtr) xmlCopyPropInternal(doc, parent, (xmlAttrPtr) node));
3844 case XML_NAMESPACE_DECL:
3845 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3846
3847 case XML_DOCUMENT_NODE:
3848 case XML_HTML_DOCUMENT_NODE:
3849#ifdef LIBXML_DOCB_ENABLED
3850 case XML_DOCB_DOCUMENT_NODE:
3851#endif
3852#ifdef LIBXML_TREE_ENABLED
3853 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
3854#endif /* LIBXML_TREE_ENABLED */
3855 case XML_DOCUMENT_TYPE_NODE:
3856 case XML_NOTATION_NODE:
3857 case XML_DTD_NODE:
3858 case XML_ELEMENT_DECL:
3859 case XML_ATTRIBUTE_DECL:
3860 case XML_ENTITY_DECL:
3861 return(NULL);
3862 }
3863
3864 /*
3865 * Allocate a new node and fill the fields.
3866 */
3867 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3868 if (ret == NULL) {
3869 xmlTreeErrMemory("copying node");
3870 return(NULL);
3871 }
3872 memset(ret, 0, sizeof(xmlNode));
3873 ret->type = node->type;
3874
3875 ret->doc = doc;
3876 ret->parent = parent;
3877 if (node->name == xmlStringText)
3878 ret->name = xmlStringText;
3879 else if (node->name == xmlStringTextNoenc)
3880 ret->name = xmlStringTextNoenc;
3881 else if (node->name == xmlStringComment)
3882 ret->name = xmlStringComment;
3883 else if (node->name != NULL) {
3884 if ((doc != NULL) && (doc->dict != NULL))
3885 ret->name = xmlDictLookup(doc->dict, node->name, -1);
3886 else
3887 ret->name = xmlStrdup(node->name);
3888 }
3889 if ((node->type != XML_ELEMENT_NODE) &&
3890 (node->content != NULL) &&
3891 (node->type != XML_ENTITY_REF_NODE) &&
3892 (node->type != XML_XINCLUDE_END) &&
3893 (node->type != XML_XINCLUDE_START)) {
3894 ret->content = xmlStrdup(node->content);
3895 }else{
3896 if (node->type == XML_ELEMENT_NODE)
3897 ret->line = node->line;
3898 }
3899 if (parent != NULL) {
3900 xmlNodePtr tmp;
3901
3902 /*
3903 * this is a tricky part for the node register thing:
3904 * in case ret does get coalesced in xmlAddChild
3905 * the deregister-node callback is called; so we register ret now already
3906 */
3907 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
3908 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3909
3910 tmp = xmlAddChild(parent, ret);
3911 /* node could have coalesced */
3912 if (tmp != ret)
3913 return(tmp);
3914 }
3915
3916 if (!extended)
3917 goto out;
3918 if ((node->type == XML_ELEMENT_NODE) && (node->nsDef != NULL))
3919 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3920
3921 if (node->ns != NULL) {
3922 xmlNsPtr ns;
3923
3924 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3925 if (ns == NULL) {
3926 /*
3927 * Humm, we are copying an element whose namespace is defined
3928 * out of the new tree scope. Search it in the original tree
3929 * and add it at the top of the new tree
3930 */
3931 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3932 if (ns != NULL) {
3933 xmlNodePtr root = ret;
3934
3935 while (root->parent != NULL) root = root->parent;
3936 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
3937 }
3938 } else {
3939 /*
3940 * reference the existing namespace definition in our own tree.
3941 */
3942 ret->ns = ns;
3943 }
3944 }
3945 if ((node->type == XML_ELEMENT_NODE) && (node->properties != NULL))
3946 ret->properties = xmlCopyPropList(ret, node->properties);
3947 if (node->type == XML_ENTITY_REF_NODE) {
3948 if ((doc == NULL) || (node->doc != doc)) {
3949 /*
3950 * The copied node will go into a separate document, so
3951 * to avoid dangling references to the ENTITY_DECL node
3952 * we cannot keep the reference. Try to find it in the
3953 * target document.
3954 */
3955 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3956 } else {
3957 ret->children = node->children;
3958 }
3959 ret->last = ret->children;
3960 } else if ((node->children != NULL) && (extended != 2)) {
3961 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
3962 UPDATE_LAST_CHILD_AND_PARENT(ret)
3963 }
3964
3965out:
3966 /* if parent != NULL we already registered the node above */
3967 if ((parent == NULL) &&
3968 ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)))
3969 xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
3970 return(ret);
3971}
3972
3973static xmlNodePtr
3974xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3975 xmlNodePtr ret = NULL;
3976 xmlNodePtr p = NULL,q;
3977
3978 while (node != NULL) {
3979#ifdef LIBXML_TREE_ENABLED
3980 if (node->type == XML_DTD_NODE ) {
3981 if (doc == NULL) {
3982 node = node->next;
3983 continue;
3984 }
3985 if (doc->intSubset == NULL) {
3986 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3987 q->doc = doc;
3988 q->parent = parent;
3989 doc->intSubset = (xmlDtdPtr) q;
3990 xmlAddChild(parent, q);
3991 } else {
3992 q = (xmlNodePtr) doc->intSubset;
3993 xmlAddChild(parent, q);
3994 }
3995 } else
3996#endif /* LIBXML_TREE_ENABLED */
3997 q = xmlStaticCopyNode(node, doc, parent, 1);
3998 if (ret == NULL) {
3999 q->prev = NULL;
4000 ret = p = q;
4001 } else if (p != q) {
4002 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
4003 p->next = q;
4004 q->prev = p;
4005 p = q;
4006 }
4007 node = node->next;
4008 }
4009 return(ret);
4010}
4011
4012/**
4013 * xmlCopyNode:
4014 * @node: the node
4015 * @extended: if 1 do a recursive copy (properties, namespaces and children
4016 * when applicable)
4017 * if 2 copy properties and namespaces (when applicable)
4018 *
4019 * Do a copy of the node.
4020 *
4021 * Returns: a new #xmlNodePtr, or NULL in case of error.
4022 */
4023xmlNodePtr
4024xmlCopyNode(const xmlNodePtr node, int extended) {
4025 xmlNodePtr ret;
4026
4027 ret = xmlStaticCopyNode(node, NULL, NULL, extended);
4028 return(ret);
4029}
4030
4031/**
4032 * xmlDocCopyNode:
4033 * @node: the node
4034 * @doc: the document
4035 * @extended: if 1 do a recursive copy (properties, namespaces and children
4036 * when applicable)
4037 * if 2 copy properties and namespaces (when applicable)
4038 *
4039 * Do a copy of the node to a given document.
4040 *
4041 * Returns: a new #xmlNodePtr, or NULL in case of error.
4042 */
4043xmlNodePtr
4044xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int extended) {
4045 xmlNodePtr ret;
4046
4047 ret = xmlStaticCopyNode(node, doc, NULL, extended);
4048 return(ret);
4049}
4050
4051/**
4052 * xmlDocCopyNodeList:
4053 * @doc: the target document
4054 * @node: the first node in the list.
4055 *
4056 * Do a recursive copy of the node list.
4057 *
4058 * Returns: a new #xmlNodePtr, or NULL in case of error.
4059 */
4060xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, const xmlNodePtr node) {
4061 xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL);
4062 return(ret);
4063}
4064
4065/**
4066 * xmlCopyNodeList:
4067 * @node: the first node in the list.
4068 *
4069 * Do a recursive copy of the node list.
4070 * Use xmlDocCopyNodeList() if possible to ensure string interning.
4071 *
4072 * Returns: a new #xmlNodePtr, or NULL in case of error.
4073 */
4074xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
4075 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
4076 return(ret);
4077}
4078
4079#if defined(LIBXML_TREE_ENABLED)
4080/**
4081 * xmlCopyDtd:
4082 * @dtd: the dtd
4083 *
4084 * Do a copy of the dtd.
4085 *
4086 * Returns: a new #xmlDtdPtr, or NULL in case of error.
4087 */
4088xmlDtdPtr
4089xmlCopyDtd(xmlDtdPtr dtd) {
4090 xmlDtdPtr ret;
4091 xmlNodePtr cur, p = NULL, q;
4092
4093 if (dtd == NULL) return(NULL);
4094 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
4095 if (ret == NULL) return(NULL);
4096 if (dtd->entities != NULL)
4097 ret->entities = (void *) xmlCopyEntitiesTable(
4098 (xmlEntitiesTablePtr) dtd->entities);
4099 if (dtd->notations != NULL)
4100 ret->notations = (void *) xmlCopyNotationTable(
4101 (xmlNotationTablePtr) dtd->notations);
4102 if (dtd->elements != NULL)
4103 ret->elements = (void *) xmlCopyElementTable(
4104 (xmlElementTablePtr) dtd->elements);
4105 if (dtd->attributes != NULL)
4106 ret->attributes = (void *) xmlCopyAttributeTable(
4107 (xmlAttributeTablePtr) dtd->attributes);
4108 if (dtd->pentities != NULL)
4109 ret->pentities = (void *) xmlCopyEntitiesTable(
4110 (xmlEntitiesTablePtr) dtd->pentities);
4111
4112 cur = dtd->children;
4113 while (cur != NULL) {
4114 q = NULL;
4115
4116 if (cur->type == XML_ENTITY_DECL) {
4117 xmlEntityPtr tmp = (xmlEntityPtr) cur;
4118 switch (tmp->etype) {
4119 case XML_INTERNAL_GENERAL_ENTITY:
4120 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
4121 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
4122 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4123 break;
4124 case XML_INTERNAL_PARAMETER_ENTITY:
4125 case XML_EXTERNAL_PARAMETER_ENTITY:
4126 q = (xmlNodePtr)
4127 xmlGetParameterEntityFromDtd(ret, tmp->name);
4128 break;
4129 case XML_INTERNAL_PREDEFINED_ENTITY:
4130 break;
4131 }
4132 } else if (cur->type == XML_ELEMENT_DECL) {
4133 xmlElementPtr tmp = (xmlElementPtr) cur;
4134 q = (xmlNodePtr)
4135 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4136 } else if (cur->type == XML_ATTRIBUTE_DECL) {
4137 xmlAttributePtr tmp = (xmlAttributePtr) cur;
4138 q = (xmlNodePtr)
4139 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4140 } else if (cur->type == XML_COMMENT_NODE) {
4141 q = xmlCopyNode(cur, 0);
4142 }
4143
4144 if (q == NULL) {
4145 cur = cur->next;
4146 continue;
4147 }
4148
4149 if (p == NULL)
4150 ret->children = q;
4151 else
4152 p->next = q;
4153
4154 q->prev = p;
4155 q->parent = (xmlNodePtr) ret;
4156 q->next = NULL;
4157 ret->last = q;
4158 p = q;
4159 cur = cur->next;
4160 }
4161
4162 return(ret);
4163}
4164#endif
4165
4166#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
4167/**
4168 * xmlCopyDoc:
4169 * @doc: the document
4170 * @recursive: if not zero do a recursive copy.
4171 *
4172 * Do a copy of the document info. If recursive, the content tree will
4173 * be copied too as well as DTD, namespaces and entities.
4174 *
4175 * Returns: a new #xmlDocPtr, or NULL in case of error.
4176 */
4177xmlDocPtr
4178xmlCopyDoc(xmlDocPtr doc, int recursive) {
4179 xmlDocPtr ret;
4180
4181 if (doc == NULL) return(NULL);
4182 ret = xmlNewDoc(doc->version);
4183 if (ret == NULL) return(NULL);
4184 if (doc->name != NULL)
4185 ret->name = xmlMemStrdup(doc->name);
4186 if (doc->encoding != NULL)
4187 ret->encoding = xmlStrdup(doc->encoding);
4188 if (doc->URL != NULL)
4189 ret->URL = xmlStrdup(doc->URL);
4190 ret->charset = doc->charset;
4191 ret->compression = doc->compression;
4192 ret->standalone = doc->standalone;
4193 if (!recursive) return(ret);
4194
4195 ret->last = NULL;
4196 ret->children = NULL;
4197#ifdef LIBXML_TREE_ENABLED
4198 if (doc->intSubset != NULL) {
4199 ret->intSubset = xmlCopyDtd(doc->intSubset);
4200 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
4201 ret->intSubset->parent = ret;
4202 }
4203#endif
4204 if (doc->oldNs != NULL)
4205 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4206 if (doc->children != NULL) {
4207 xmlNodePtr tmp;
4208
4209 ret->children = xmlStaticCopyNodeList(doc->children, ret,
4210 (xmlNodePtr)ret);
4211 ret->last = NULL;
4212 tmp = ret->children;
4213 while (tmp != NULL) {
4214 if (tmp->next == NULL)
4215 ret->last = tmp;
4216 tmp = tmp->next;
4217 }
4218 }
4219 return(ret);
4220}
4221#endif /* LIBXML_TREE_ENABLED */
4222
4223/************************************************************************
4224 * *
4225 * Content access functions *
4226 * *
4227 ************************************************************************/
4228
4229/**
4230 * xmlGetLineNo:
4231 * @node: valid node
4232 *
4233 * Get line number of @node. This requires activation of this option
4234 * before invoking the parser by calling xmlLineNumbersDefault(1)
4235 *
4236 * Returns the line number if successful, -1 otherwise
4237 */
4238long
4239xmlGetLineNo(xmlNodePtr node)
4240{
4241 long result = -1;
4242
4243 if (!node)
4244 return result;
4245 if ((node->type == XML_ELEMENT_NODE) ||
4246 (node->type == XML_TEXT_NODE) ||
4247 (node->type == XML_COMMENT_NODE) ||
4248 (node->type == XML_PI_NODE))
4249 result = (long) node->line;
4250 else if ((node->prev != NULL) &&
4251 ((node->prev->type == XML_ELEMENT_NODE) ||
4252 (node->prev->type == XML_TEXT_NODE) ||
4253 (node->prev->type == XML_COMMENT_NODE) ||
4254 (node->prev->type == XML_PI_NODE)))
4255 result = xmlGetLineNo(node->prev);
4256 else if ((node->parent != NULL) &&
4257 (node->parent->type == XML_ELEMENT_NODE))
4258 result = xmlGetLineNo(node->parent);
4259
4260 return result;
4261}
4262
4263#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
4264/**
4265 * xmlGetNodePath:
4266 * @node: a node
4267 *
4268 * Build a structure based Path for the given node
4269 *
4270 * Returns the new path or NULL in case of error. The caller must free
4271 * the returned string
4272 */
4273xmlChar *
4274xmlGetNodePath(xmlNodePtr node)
4275{
4276 xmlNodePtr cur, tmp, next;
4277 xmlChar *buffer = NULL, *temp;
4278 size_t buf_len;
4279 xmlChar *buf;
4280 const char *sep;
4281 const char *name;
4282 char nametemp[100];
4283 int occur = 0, generic;
4284
4285 if (node == NULL)
4286 return (NULL);
4287
4288 buf_len = 500;
4289 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
4290 if (buffer == NULL) {
4291 xmlTreeErrMemory("getting node path");
4292 return (NULL);
4293 }
4294 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
4295 if (buf == NULL) {
4296 xmlTreeErrMemory("getting node path");
4297 xmlFree(buffer);
4298 return (NULL);
4299 }
4300
4301 buffer[0] = 0;
4302 cur = node;
4303 do {
4304 name = "";
4305 sep = "?";
4306 occur = 0;
4307 if ((cur->type == XML_DOCUMENT_NODE) ||
4308 (cur->type == XML_HTML_DOCUMENT_NODE)) {
4309 if (buffer[0] == '/')
4310 break;
4311 sep = "/";
4312 next = NULL;
4313 } else if (cur->type == XML_ELEMENT_NODE) {
4314 generic = 0;
4315 sep = "/";
4316 name = (const char *) cur->name;
4317 if (cur->ns) {
4318 if (cur->ns->prefix != NULL) {
4319 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4320 (char *)cur->ns->prefix, (char *)cur->name);
4321 nametemp[sizeof(nametemp) - 1] = 0;
4322 name = nametemp;
4323 } else {
4324 /*
4325 * We cannot express named elements in the default
4326 * namespace, so use "*".
4327 */
4328 generic = 1;
4329 name = "*";
4330 }
4331 }
4332 next = cur->parent;
4333
4334 /*
4335 * Thumbler index computation
4336 * TODO: the ocurence test seems bogus for namespaced names
4337 */
4338 tmp = cur->prev;
4339 while (tmp != NULL) {
4340 if ((tmp->type == XML_ELEMENT_NODE) &&
4341 (generic ||
4342 (xmlStrEqual(cur->name, tmp->name) &&
4343 ((tmp->ns == cur->ns) ||
4344 ((tmp->ns != NULL) && (cur->ns != NULL) &&
4345 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))))
4346 occur++;
4347 tmp = tmp->prev;
4348 }
4349 if (occur == 0) {
4350 tmp = cur->next;
4351 while (tmp != NULL && occur == 0) {
4352 if ((tmp->type == XML_ELEMENT_NODE) &&
4353 (generic ||
4354 (xmlStrEqual(cur->name, tmp->name) &&
4355 ((tmp->ns == cur->ns) ||
4356 ((tmp->ns != NULL) && (cur->ns != NULL) &&
4357 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))))
4358 occur++;
4359 tmp = tmp->next;
4360 }
4361 if (occur != 0)
4362 occur = 1;
4363 } else
4364 occur++;
4365 } else if (cur->type == XML_COMMENT_NODE) {
4366 sep = "/";
4367 name = "comment()";
4368 next = cur->parent;
4369
4370 /*
4371 * Thumbler index computation
4372 */
4373 tmp = cur->prev;
4374 while (tmp != NULL) {
4375 if (tmp->type == XML_COMMENT_NODE)
4376 occur++;
4377 tmp = tmp->prev;
4378 }
4379 if (occur == 0) {
4380 tmp = cur->next;
4381 while (tmp != NULL && occur == 0) {
4382 if (tmp->type == XML_COMMENT_NODE)
4383 occur++;
4384 tmp = tmp->next;
4385 }
4386 if (occur != 0)
4387 occur = 1;
4388 } else
4389 occur++;
4390 } else if ((cur->type == XML_TEXT_NODE) ||
4391 (cur->type == XML_CDATA_SECTION_NODE)) {
4392 sep = "/";
4393 name = "text()";
4394 next = cur->parent;
4395
4396 /*
4397 * Thumbler index computation
4398 */
4399 tmp = cur->prev;
4400 while (tmp != NULL) {
4401 if ((tmp->type == XML_TEXT_NODE) ||
4402 (tmp->type == XML_CDATA_SECTION_NODE))
4403 occur++;
4404 tmp = tmp->prev;
4405 }
4406 /*
4407 * Evaluate if this is the only text- or CDATA-section-node;
4408 * if yes, then we'll get "text()", otherwise "text()[1]".
4409 */
4410 if (occur == 0) {
4411 tmp = cur->next;
4412 while (tmp != NULL) {
4413 if ((tmp->type == XML_TEXT_NODE) ||
4414 (tmp->type == XML_CDATA_SECTION_NODE))
4415 {
4416 occur = 1;
4417 break;
4418 }
4419 tmp = tmp->next;
4420 }
4421 } else
4422 occur++;
4423 } else if (cur->type == XML_PI_NODE) {
4424 sep = "/";
4425 snprintf(nametemp, sizeof(nametemp) - 1,
4426 "processing-instruction('%s')", (char *)cur->name);
4427 nametemp[sizeof(nametemp) - 1] = 0;
4428 name = nametemp;
4429
4430 next = cur->parent;
4431
4432 /*
4433 * Thumbler index computation
4434 */
4435 tmp = cur->prev;
4436 while (tmp != NULL) {
4437 if ((tmp->type == XML_PI_NODE) &&
4438 (xmlStrEqual(cur->name, tmp->name)))
4439 occur++;
4440 tmp = tmp->prev;
4441 }
4442 if (occur == 0) {
4443 tmp = cur->next;
4444 while (tmp != NULL && occur == 0) {
4445 if ((tmp->type == XML_PI_NODE) &&
4446 (xmlStrEqual(cur->name, tmp->name)))
4447 occur++;
4448 tmp = tmp->next;
4449 }
4450 if (occur != 0)
4451 occur = 1;
4452 } else
4453 occur++;
4454
4455 } else if (cur->type == XML_ATTRIBUTE_NODE) {
4456 sep = "/@";
4457 name = (const char *) (((xmlAttrPtr) cur)->name);
4458 if (cur->ns) {
4459 if (cur->ns->prefix != NULL)
4460 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4461 (char *)cur->ns->prefix, (char *)cur->name);
4462 else
4463 snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4464 (char *)cur->name);
4465 nametemp[sizeof(nametemp) - 1] = 0;
4466 name = nametemp;
4467 }
4468 next = ((xmlAttrPtr) cur)->parent;
4469 } else {
4470 next = cur->parent;
4471 }
4472
4473 /*
4474 * Make sure there is enough room
4475 */
4476 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4477 buf_len =
4478 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4479 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4480 if (temp == NULL) {
4481 xmlTreeErrMemory("getting node path");
4482 xmlFree(buf);
4483 xmlFree(buffer);
4484 return (NULL);
4485 }
4486 buffer = temp;
4487 temp = (xmlChar *) xmlRealloc(buf, buf_len);
4488 if (temp == NULL) {
4489 xmlTreeErrMemory("getting node path");
4490 xmlFree(buf);
4491 xmlFree(buffer);
4492 return (NULL);
4493 }
4494 buf = temp;
4495 }
4496 if (occur == 0)
4497 snprintf((char *) buf, buf_len, "%s%s%s",
4498 sep, name, (char *) buffer);
4499 else
4500 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
4501 sep, name, occur, (char *) buffer);
4502 snprintf((char *) buffer, buf_len, "%s", (char *)buf);
4503 cur = next;
4504 } while (cur != NULL);
4505 xmlFree(buf);
4506 return (buffer);
4507}
4508#endif /* LIBXML_TREE_ENABLED */
4509
4510/**
4511 * xmlDocGetRootElement:
4512 * @doc: the document
4513 *
4514 * Get the root element of the document (doc->children is a list
4515 * containing possibly comments, PIs, etc ...).
4516 *
4517 * Returns the #xmlNodePtr for the root or NULL
4518 */
4519xmlNodePtr
4520xmlDocGetRootElement(xmlDocPtr doc) {
4521 xmlNodePtr ret;
4522
4523 if (doc == NULL) return(NULL);
4524 ret = doc->children;
4525 while (ret != NULL) {
4526 if (ret->type == XML_ELEMENT_NODE)
4527 return(ret);
4528 ret = ret->next;
4529 }
4530 return(ret);
4531}
4532
4533#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
4534/**
4535 * xmlDocSetRootElement:
4536 * @doc: the document
4537 * @root: the new document root element, if root is NULL no action is taken,
4538 * to remove a node from a document use xmlUnlinkNode(root) instead.
4539 *
4540 * Set the root element of the document (doc->children is a list
4541 * containing possibly comments, PIs, etc ...).
4542 *
4543 * Returns the old root element if any was found, NULL if root was NULL
4544 */
4545xmlNodePtr
4546xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4547 xmlNodePtr old = NULL;
4548
4549 if (doc == NULL) return(NULL);
4550 if (root == NULL)
4551 return(NULL);
4552 xmlUnlinkNode(root);
4553 xmlSetTreeDoc(root, doc);
4554 root->parent = (xmlNodePtr) doc;
4555 old = doc->children;
4556 while (old != NULL) {
4557 if (old->type == XML_ELEMENT_NODE)
4558 break;
4559 old = old->next;
4560 }
4561 if (old == NULL) {
4562 if (doc->children == NULL) {
4563 doc->children = root;
4564 doc->last = root;
4565 } else {
4566 xmlAddSibling(doc->children, root);
4567 }
4568 } else {
4569 xmlReplaceNode(old, root);
4570 }
4571 return(old);
4572}
4573#endif
4574
4575#if defined(LIBXML_TREE_ENABLED)
4576/**
4577 * xmlNodeSetLang:
4578 * @cur: the node being changed
4579 * @lang: the language description
4580 *
4581 * Set the language of a node, i.e. the values of the xml:lang
4582 * attribute.
4583 */
4584void
4585xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
4586 xmlNsPtr ns;
4587
4588 if (cur == NULL) return;
4589 switch(cur->type) {
4590 case XML_TEXT_NODE:
4591 case XML_CDATA_SECTION_NODE:
4592 case XML_COMMENT_NODE:
4593 case XML_DOCUMENT_NODE:
4594 case XML_DOCUMENT_TYPE_NODE:
4595 case XML_DOCUMENT_FRAG_NODE:
4596 case XML_NOTATION_NODE:
4597 case XML_HTML_DOCUMENT_NODE:
4598 case XML_DTD_NODE:
4599 case XML_ELEMENT_DECL:
4600 case XML_ATTRIBUTE_DECL:
4601 case XML_ENTITY_DECL:
4602 case XML_PI_NODE:
4603 case XML_ENTITY_REF_NODE:
4604 case XML_ENTITY_NODE:
4605 case XML_NAMESPACE_DECL:
4606#ifdef LIBXML_DOCB_ENABLED
4607 case XML_DOCB_DOCUMENT_NODE:
4608#endif
4609 case XML_XINCLUDE_START:
4610 case XML_XINCLUDE_END:
4611 return;
4612 case XML_ELEMENT_NODE:
4613 case XML_ATTRIBUTE_NODE:
4614 break;
4615 }
4616 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4617 if (ns == NULL)
4618 return;
4619 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
4620}
4621#endif /* LIBXML_TREE_ENABLED */
4622
4623/**
4624 * xmlNodeGetLang:
4625 * @cur: the node being checked
4626 *
4627 * Searches the language of a node, i.e. the values of the xml:lang
4628 * attribute or the one carried by the nearest ancestor.
4629 *
4630 * Returns a pointer to the lang value, or NULL if not found
4631 * It's up to the caller to free the memory with xmlFree().
4632 */
4633xmlChar *
4634xmlNodeGetLang(xmlNodePtr cur) {
4635 xmlChar *lang;
4636
4637 while (cur != NULL) {
4638 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
4639 if (lang != NULL)
4640 return(lang);
4641 cur = cur->parent;
4642 }
4643 return(NULL);
4644}
4645
4646
4647#ifdef LIBXML_TREE_ENABLED
4648/**
4649 * xmlNodeSetSpacePreserve:
4650 * @cur: the node being changed
4651 * @val: the xml:space value ("0": default, 1: "preserve")
4652 *
4653 * Set (or reset) the space preserving behaviour of a node, i.e. the
4654 * value of the xml:space attribute.
4655 */
4656void
4657xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
4658 xmlNsPtr ns;
4659
4660 if (cur == NULL) return;
4661 switch(cur->type) {
4662 case XML_TEXT_NODE:
4663 case XML_CDATA_SECTION_NODE:
4664 case XML_COMMENT_NODE:
4665 case XML_DOCUMENT_NODE:
4666 case XML_DOCUMENT_TYPE_NODE:
4667 case XML_DOCUMENT_FRAG_NODE:
4668 case XML_NOTATION_NODE:
4669 case XML_HTML_DOCUMENT_NODE:
4670 case XML_DTD_NODE:
4671 case XML_ELEMENT_DECL:
4672 case XML_ATTRIBUTE_DECL:
4673 case XML_ENTITY_DECL:
4674 case XML_PI_NODE:
4675 case XML_ENTITY_REF_NODE:
4676 case XML_ENTITY_NODE:
4677 case XML_NAMESPACE_DECL:
4678 case XML_XINCLUDE_START:
4679 case XML_XINCLUDE_END:
4680#ifdef LIBXML_DOCB_ENABLED
4681 case XML_DOCB_DOCUMENT_NODE:
4682#endif
4683 return;
4684 case XML_ELEMENT_NODE:
4685 case XML_ATTRIBUTE_NODE:
4686 break;
4687 }
4688 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4689 if (ns == NULL)
4690 return;
4691 switch (val) {
4692 case 0:
4693 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
4694 break;
4695 case 1:
4696 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
4697 break;
4698 }
4699}
4700#endif /* LIBXML_TREE_ENABLED */
4701
4702/**
4703 * xmlNodeGetSpacePreserve:
4704 * @cur: the node being checked
4705 *
4706 * Searches the space preserving behaviour of a node, i.e. the values
4707 * of the xml:space attribute or the one carried by the nearest
4708 * ancestor.
4709 *
4710 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
4711 */
4712int
4713xmlNodeGetSpacePreserve(xmlNodePtr cur) {
4714 xmlChar *space;
4715
4716 while (cur != NULL) {
4717 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
4718 if (space != NULL) {
4719 if (xmlStrEqual(space, BAD_CAST "preserve")) {
4720 xmlFree(space);
4721 return(1);
4722 }
4723 if (xmlStrEqual(space, BAD_CAST "default")) {
4724 xmlFree(space);
4725 return(0);
4726 }
4727 xmlFree(space);
4728 }
4729 cur = cur->parent;
4730 }
4731 return(-1);
4732}
4733
4734#ifdef LIBXML_TREE_ENABLED
4735/**
4736 * xmlNodeSetName:
4737 * @cur: the node being changed
4738 * @name: the new tag name
4739 *
4740 * Set (or reset) the name of a node.
4741 */
4742void
4743xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
4744 xmlDocPtr doc;
4745 xmlDictPtr dict;
4746
4747 if (cur == NULL) return;
4748 if (name == NULL) return;
4749 switch(cur->type) {
4750 case XML_TEXT_NODE:
4751 case XML_CDATA_SECTION_NODE:
4752 case XML_COMMENT_NODE:
4753 case XML_DOCUMENT_TYPE_NODE:
4754 case XML_DOCUMENT_FRAG_NODE:
4755 case XML_NOTATION_NODE:
4756 case XML_HTML_DOCUMENT_NODE:
4757 case XML_NAMESPACE_DECL:
4758 case XML_XINCLUDE_START:
4759 case XML_XINCLUDE_END:
4760#ifdef LIBXML_DOCB_ENABLED
4761 case XML_DOCB_DOCUMENT_NODE:
4762#endif
4763 return;
4764 case XML_ELEMENT_NODE:
4765 case XML_ATTRIBUTE_NODE:
4766 case XML_PI_NODE:
4767 case XML_ENTITY_REF_NODE:
4768 case XML_ENTITY_NODE:
4769 case XML_DTD_NODE:
4770 case XML_DOCUMENT_NODE:
4771 case XML_ELEMENT_DECL:
4772 case XML_ATTRIBUTE_DECL:
4773 case XML_ENTITY_DECL:
4774 break;
4775 }
4776 doc = cur->doc;
4777 if (doc != NULL)
4778 dict = doc->dict;
4779 else
4780 dict = NULL;
4781 if (dict != NULL) {
4782 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
4783 xmlFree((xmlChar *) cur->name);
4784 cur->name = xmlDictLookup(dict, name, -1);
4785 } else {
4786 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
4787 cur->name = xmlStrdup(name);
4788 }
4789}
4790#endif
4791
4792#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
4793/**
4794 * xmlNodeSetBase:
4795 * @cur: the node being changed
4796 * @uri: the new base URI
4797 *
4798 * Set (or reset) the base URI of a node, i.e. the value of the
4799 * xml:base attribute.
4800 */
4801void
4802xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
4803 xmlNsPtr ns;
4804 const xmlChar* fixed;
4805
4806 if (cur == NULL) return;
4807 switch(cur->type) {
4808 case XML_TEXT_NODE:
4809 case XML_CDATA_SECTION_NODE:
4810 case XML_COMMENT_NODE:
4811 case XML_DOCUMENT_TYPE_NODE:
4812 case XML_DOCUMENT_FRAG_NODE:
4813 case XML_NOTATION_NODE:
4814 case XML_DTD_NODE:
4815 case XML_ELEMENT_DECL:
4816 case XML_ATTRIBUTE_DECL:
4817 case XML_ENTITY_DECL:
4818 case XML_PI_NODE:
4819 case XML_ENTITY_REF_NODE:
4820 case XML_ENTITY_NODE:
4821 case XML_NAMESPACE_DECL:
4822 case XML_XINCLUDE_START:
4823 case XML_XINCLUDE_END:
4824 return;
4825 case XML_ELEMENT_NODE:
4826 case XML_ATTRIBUTE_NODE:
4827 break;
4828 case XML_DOCUMENT_NODE:
4829#ifdef LIBXML_DOCB_ENABLED
4830 case XML_DOCB_DOCUMENT_NODE:
4831#endif
4832 case XML_HTML_DOCUMENT_NODE: {
4833 xmlDocPtr doc = (xmlDocPtr) cur;
4834
4835 if (doc->URL != NULL)
4836 xmlFree((xmlChar *) doc->URL);
4837 if (uri == NULL)
4838 doc->URL = NULL;
4839 else
4840 doc->URL = xmlPathToURI(uri);
4841 return;
4842 }
4843 }
4844
4845 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
4846 if (ns == NULL)
4847 return;
4848 fixed = xmlPathToURI(uri);
4849 if (fixed != NULL) {
4850 xmlSetNsProp(cur, ns, BAD_CAST "base", fixed);
4851 xmlFree((xmlChar *)fixed);
4852 } else {
4853 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
4854 }
4855}
4856#endif /* LIBXML_TREE_ENABLED */
4857
4858/**
4859 * xmlNodeGetBase:
4860 * @doc: the document the node pertains to
4861 * @cur: the node being checked
4862 *
4863 * Searches for the BASE URL. The code should work on both XML
4864 * and HTML document even if base mechanisms are completely different.
4865 * It returns the base as defined in RFC 2396 sections
4866 * 5.1.1. Base URI within Document Content
4867 * and
4868 * 5.1.2. Base URI from the Encapsulating Entity
4869 * However it does not return the document base (5.1.3), use
4870 * xmlDocumentGetBase() for this
4871 *
4872 * Returns a pointer to the base URL, or NULL if not found
4873 * It's up to the caller to free the memory with xmlFree().
4874 */
4875xmlChar *
4876xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
4877 xmlChar *oldbase = NULL;
4878 xmlChar *base, *newbase;
4879
4880 if ((cur == NULL) && (doc == NULL))
4881 return(NULL);
4882 if (doc == NULL) doc = cur->doc;
4883 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
4884 cur = doc->children;
4885 while ((cur != NULL) && (cur->name != NULL)) {
4886 if (cur->type != XML_ELEMENT_NODE) {
4887 cur = cur->next;
4888 continue;
4889 }
4890 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4891 cur = cur->children;
4892 continue;
4893 }
4894 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4895 cur = cur->children;
4896 continue;
4897 }
4898 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4899 return(xmlGetProp(cur, BAD_CAST "href"));
4900 }
4901 cur = cur->next;
4902 }
4903 return(NULL);
4904 }
4905 while (cur != NULL) {
4906 if (cur->type == XML_ENTITY_DECL) {
4907 xmlEntityPtr ent = (xmlEntityPtr) cur;
4908 return(xmlStrdup(ent->URI));
4909 }
4910 if (cur->type == XML_ELEMENT_NODE) {
4911 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
4912 if (base != NULL) {
4913 if (oldbase != NULL) {
4914 newbase = xmlBuildURI(oldbase, base);
4915 if (newbase != NULL) {
4916 xmlFree(oldbase);
4917 xmlFree(base);
4918 oldbase = newbase;
4919 } else {
4920 xmlFree(oldbase);
4921 xmlFree(base);
4922 return(NULL);
4923 }
4924 } else {
4925 oldbase = base;
4926 }
4927 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4928 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4929 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4930 return(oldbase);
4931 }
4932 }
4933 cur = cur->parent;
4934 }
4935 if ((doc != NULL) && (doc->URL != NULL)) {
4936 if (oldbase == NULL)
4937 return(xmlStrdup(doc->URL));
4938 newbase = xmlBuildURI(oldbase, doc->URL);
4939 xmlFree(oldbase);
4940 return(newbase);
4941 }
4942 return(oldbase);
4943}
4944
4945/**
4946 * xmlNodeBufGetContent:
4947 * @buffer: a buffer
4948 * @cur: the node being read
4949 *
4950 * Read the value of a node @cur, this can be either the text carried
4951 * directly by this node if it's a TEXT node or the aggregate string
4952 * of the values carried by this node child's (TEXT and ENTITY_REF).
4953 * Entity references are substituted.
4954 * Fills up the buffer @buffer with this value
4955 *
4956 * Returns 0 in case of success and -1 in case of error.
4957 */
4958int
4959xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur)
4960{
4961 if ((cur == NULL) || (buffer == NULL)) return(-1);
4962 switch (cur->type) {
4963 case XML_CDATA_SECTION_NODE:
4964 case XML_TEXT_NODE:
4965 xmlBufferCat(buffer, cur->content);
4966 break;
4967 case XML_DOCUMENT_FRAG_NODE:
4968 case XML_ELEMENT_NODE:{
4969 xmlNodePtr tmp = cur;
4970
4971 while (tmp != NULL) {
4972 switch (tmp->type) {
4973 case XML_CDATA_SECTION_NODE:
4974 case XML_TEXT_NODE:
4975 if (tmp->content != NULL)
4976 xmlBufferCat(buffer, tmp->content);
4977 break;
4978 case XML_ENTITY_REF_NODE:
4979 xmlNodeBufGetContent(buffer, tmp);
4980 break;
4981 default:
4982 break;
4983 }
4984 /*
4985 * Skip to next node
4986 */
4987 if (tmp->children != NULL) {
4988 if (tmp->children->type != XML_ENTITY_DECL) {
4989 tmp = tmp->children;
4990 continue;
4991 }
4992 }
4993 if (tmp == cur)
4994 break;
4995
4996 if (tmp->next != NULL) {
4997 tmp = tmp->next;
4998 continue;
4999 }
5000
5001 do {
5002 tmp = tmp->parent;
5003 if (tmp == NULL)
5004 break;
5005 if (tmp == cur) {
5006 tmp = NULL;
5007 break;
5008 }
5009 if (tmp->next != NULL) {
5010 tmp = tmp->next;
5011 break;
5012 }
5013 } while (tmp != NULL);
5014 }
5015 break;
5016 }
5017 case XML_ATTRIBUTE_NODE:{
5018 xmlAttrPtr attr = (xmlAttrPtr) cur;
5019 xmlNodePtr tmp = attr->children;
5020
5021 while (tmp != NULL) {
5022 if (tmp->type == XML_TEXT_NODE)
5023 xmlBufferCat(buffer, tmp->content);
5024 else
5025 xmlNodeBufGetContent(buffer, tmp);
5026 tmp = tmp->next;
5027 }
5028 break;
5029 }
5030 case XML_COMMENT_NODE:
5031 case XML_PI_NODE:
5032 xmlBufferCat(buffer, cur->content);
5033 break;
5034 case XML_ENTITY_REF_NODE:{
5035 xmlEntityPtr ent;
5036 xmlNodePtr tmp;
5037
5038 /* lookup entity declaration */
5039 ent = xmlGetDocEntity(cur->doc, cur->name);
5040 if (ent == NULL)
5041 return(-1);
5042
5043 /* an entity content can be any "well balanced chunk",
5044 * i.e. the result of the content [43] production:
5045 * http://www.w3.org/TR/REC-xml#NT-content
5046 * -> we iterate through child nodes and recursive call
5047 * xmlNodeGetContent() which handles all possible node types */
5048 tmp = ent->children;
5049 while (tmp) {
5050 xmlNodeBufGetContent(buffer, tmp);
5051 tmp = tmp->next;
5052 }
5053 break;
5054 }
5055 case XML_ENTITY_NODE:
5056 case XML_DOCUMENT_TYPE_NODE:
5057 case XML_NOTATION_NODE:
5058 case XML_DTD_NODE:
5059 case XML_XINCLUDE_START:
5060 case XML_XINCLUDE_END:
5061 break;
5062 case XML_DOCUMENT_NODE:
5063#ifdef LIBXML_DOCB_ENABLED
5064 case XML_DOCB_DOCUMENT_NODE:
5065#endif
5066 case XML_HTML_DOCUMENT_NODE:
5067 cur = cur->children;
5068 while (cur!= NULL) {
5069 if ((cur->type == XML_ELEMENT_NODE) ||
5070 (cur->type == XML_TEXT_NODE) ||
5071 (cur->type == XML_CDATA_SECTION_NODE)) {
5072 xmlNodeBufGetContent(buffer, cur);
5073 }
5074 cur = cur->next;
5075 }
5076 break;
5077 case XML_NAMESPACE_DECL:
5078 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href);
5079 break;
5080 case XML_ELEMENT_DECL:
5081 case XML_ATTRIBUTE_DECL:
5082 case XML_ENTITY_DECL:
5083 break;
5084 }
5085 return(0);
5086}
5087/**
5088 * xmlNodeGetContent:
5089 * @cur: the node being read
5090 *
5091 * Read the value of a node, this can be either the text carried
5092 * directly by this node if it's a TEXT node or the aggregate string
5093 * of the values carried by this node child's (TEXT and ENTITY_REF).
5094 * Entity references are substituted.
5095 * Returns a new #xmlChar * or NULL if no content is available.
5096 * It's up to the caller to free the memory with xmlFree().
5097 */
5098xmlChar *
5099xmlNodeGetContent(xmlNodePtr cur)
5100{
5101 if (cur == NULL)
5102 return (NULL);
5103 switch (cur->type) {
5104 case XML_DOCUMENT_FRAG_NODE:
5105 case XML_ELEMENT_NODE:{
5106 xmlBufferPtr buffer;
5107 xmlChar *ret;
5108
5109 buffer = xmlBufferCreateSize(64);
5110 if (buffer == NULL)
5111 return (NULL);
5112 xmlNodeBufGetContent(buffer, cur);
5113 ret = buffer->content;
5114 buffer->content = NULL;
5115 xmlBufferFree(buffer);
5116 return (ret);
5117 }
5118 case XML_ATTRIBUTE_NODE:
5119 return(xmlGetPropNodeValueInternal((xmlAttrPtr) cur));
5120 case XML_COMMENT_NODE:
5121 case XML_PI_NODE:
5122 if (cur->content != NULL)
5123 return (xmlStrdup(cur->content));
5124 return (NULL);
5125 case XML_ENTITY_REF_NODE:{
5126 xmlEntityPtr ent;
5127 xmlBufferPtr buffer;
5128 xmlChar *ret;
5129
5130 /* lookup entity declaration */
5131 ent = xmlGetDocEntity(cur->doc, cur->name);
5132 if (ent == NULL)
5133 return (NULL);
5134
5135 buffer = xmlBufferCreate();
5136 if (buffer == NULL)
5137 return (NULL);
5138
5139 xmlNodeBufGetContent(buffer, cur);
5140
5141 ret = buffer->content;
5142 buffer->content = NULL;
5143 xmlBufferFree(buffer);
5144 return (ret);
5145 }
5146 case XML_ENTITY_NODE:
5147 case XML_DOCUMENT_TYPE_NODE:
5148 case XML_NOTATION_NODE:
5149 case XML_DTD_NODE:
5150 case XML_XINCLUDE_START:
5151 case XML_XINCLUDE_END:
5152 return (NULL);
5153 case XML_DOCUMENT_NODE:
5154#ifdef LIBXML_DOCB_ENABLED
5155 case XML_DOCB_DOCUMENT_NODE:
5156#endif
5157 case XML_HTML_DOCUMENT_NODE: {
5158 xmlBufferPtr buffer;
5159 xmlChar *ret;
5160
5161 buffer = xmlBufferCreate();
5162 if (buffer == NULL)
5163 return (NULL);
5164
5165 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur);
5166
5167 ret = buffer->content;
5168 buffer->content = NULL;
5169 xmlBufferFree(buffer);
5170 return (ret);
5171 }
5172 case XML_NAMESPACE_DECL: {
5173 xmlChar *tmp;
5174
5175 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
5176 return (tmp);
5177 }
5178 case XML_ELEMENT_DECL:
5179 /* TODO !!! */
5180 return (NULL);
5181 case XML_ATTRIBUTE_DECL:
5182 /* TODO !!! */
5183 return (NULL);
5184 case XML_ENTITY_DECL:
5185 /* TODO !!! */
5186 return (NULL);
5187 case XML_CDATA_SECTION_NODE:
5188 case XML_TEXT_NODE:
5189 if (cur->content != NULL)
5190 return (xmlStrdup(cur->content));
5191 return (NULL);
5192 }
5193 return (NULL);
5194}
5195
5196/**
5197 * xmlNodeSetContent:
5198 * @cur: the node being modified
5199 * @content: the new value of the content
5200 *
5201 * Replace the content of a node.
5202 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
5203 * references, but XML special chars need to be escaped first by using
5204 * xmlEncodeEntitiesReentrant() resp. xmlEncodeSpecialChars().
5205 */
5206void
5207xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5208 if (cur == NULL) {
5209#ifdef DEBUG_TREE
5210 xmlGenericError(xmlGenericErrorContext,
5211 "xmlNodeSetContent : node == NULL\n");
5212#endif
5213 return;
5214 }
5215 switch (cur->type) {
5216 case XML_DOCUMENT_FRAG_NODE:
5217 case XML_ELEMENT_NODE:
5218 case XML_ATTRIBUTE_NODE:
5219 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5220 cur->children = xmlStringGetNodeList(cur->doc, content);
5221 UPDATE_LAST_CHILD_AND_PARENT(cur)
5222 break;
5223 case XML_TEXT_NODE:
5224 case XML_CDATA_SECTION_NODE:
5225 case XML_ENTITY_REF_NODE:
5226 case XML_ENTITY_NODE:
5227 case XML_PI_NODE:
5228 case XML_COMMENT_NODE:
5229 if ((cur->content != NULL) &&
5230 (cur->content != (xmlChar *) &(cur->properties))) {
5231 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5232 (xmlDictOwns(cur->doc->dict, cur->content))))
5233 xmlFree(cur->content);
5234 }
5235 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5236 cur->last = cur->children = NULL;
5237 if (content != NULL) {
5238 cur->content = xmlStrdup(content);
5239 } else
5240 cur->content = NULL;
5241 cur->properties = NULL;
5242 cur->nsDef = NULL;
5243 break;
5244 case XML_DOCUMENT_NODE:
5245 case XML_HTML_DOCUMENT_NODE:
5246 case XML_DOCUMENT_TYPE_NODE:
5247 case XML_XINCLUDE_START:
5248 case XML_XINCLUDE_END:
5249#ifdef LIBXML_DOCB_ENABLED
5250 case XML_DOCB_DOCUMENT_NODE:
5251#endif
5252 break;
5253 case XML_NOTATION_NODE:
5254 break;
5255 case XML_DTD_NODE:
5256 break;
5257 case XML_NAMESPACE_DECL:
5258 break;
5259 case XML_ELEMENT_DECL:
5260 /* TODO !!! */
5261 break;
5262 case XML_ATTRIBUTE_DECL:
5263 /* TODO !!! */
5264 break;
5265 case XML_ENTITY_DECL:
5266 /* TODO !!! */
5267 break;
5268 }
5269}
5270
5271#ifdef LIBXML_TREE_ENABLED
5272/**
5273 * xmlNodeSetContentLen:
5274 * @cur: the node being modified
5275 * @content: the new value of the content
5276 * @len: the size of @content
5277 *
5278 * Replace the content of a node.
5279 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
5280 * references, but XML special chars need to be escaped first by using
5281 * xmlEncodeEntitiesReentrant() resp. xmlEncodeSpecialChars().
5282 */
5283void
5284xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5285 if (cur == NULL) {
5286#ifdef DEBUG_TREE
5287 xmlGenericError(xmlGenericErrorContext,
5288 "xmlNodeSetContentLen : node == NULL\n");
5289#endif
5290 return;
5291 }
5292 switch (cur->type) {
5293 case XML_DOCUMENT_FRAG_NODE:
5294 case XML_ELEMENT_NODE:
5295 case XML_ATTRIBUTE_NODE:
5296 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5297 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5298 UPDATE_LAST_CHILD_AND_PARENT(cur)
5299 break;
5300 case XML_TEXT_NODE:
5301 case XML_CDATA_SECTION_NODE:
5302 case XML_ENTITY_REF_NODE:
5303 case XML_ENTITY_NODE:
5304 case XML_PI_NODE:
5305 case XML_COMMENT_NODE:
5306 case XML_NOTATION_NODE:
5307 if ((cur->content != NULL) &&
5308 (cur->content != (xmlChar *) &(cur->properties))) {
5309 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5310 (xmlDictOwns(cur->doc->dict, cur->content))))
5311 xmlFree(cur->content);
5312 }
5313 if (cur->children != NULL) xmlFreeNodeList(cur->children);
5314 cur->children = cur->last = NULL;
5315 if (content != NULL) {
5316 cur->content = xmlStrndup(content, len);
5317 } else
5318 cur->content = NULL;
5319 cur->properties = NULL;
5320 cur->nsDef = NULL;
5321 break;
5322 case XML_DOCUMENT_NODE:
5323 case XML_DTD_NODE:
5324 case XML_HTML_DOCUMENT_NODE:
5325 case XML_DOCUMENT_TYPE_NODE:
5326 case XML_NAMESPACE_DECL:
5327 case XML_XINCLUDE_START:
5328 case XML_XINCLUDE_END:
5329#ifdef LIBXML_DOCB_ENABLED
5330 case XML_DOCB_DOCUMENT_NODE:
5331#endif
5332 break;
5333 case XML_ELEMENT_DECL:
5334 /* TODO !!! */
5335 break;
5336 case XML_ATTRIBUTE_DECL:
5337 /* TODO !!! */
5338 break;
5339 case XML_ENTITY_DECL:
5340 /* TODO !!! */
5341 break;
5342 }
5343}
5344#endif /* LIBXML_TREE_ENABLED */
5345
5346/**
5347 * xmlNodeAddContentLen:
5348 * @cur: the node being modified
5349 * @content: extra content
5350 * @len: the size of @content
5351 *
5352 * Append the extra substring to the node content.
5353 * NOTE: In contrast to xmlNodeSetContentLen(), @content is supposed to be
5354 * raw text, so unescaped XML special chars are allowed, entity
5355 * references are not supported.
5356 */
5357void
5358xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5359 if (cur == NULL) {
5360#ifdef DEBUG_TREE
5361 xmlGenericError(xmlGenericErrorContext,
5362 "xmlNodeAddContentLen : node == NULL\n");
5363#endif
5364 return;
5365 }
5366 if (len <= 0) return;
5367 switch (cur->type) {
5368 case XML_DOCUMENT_FRAG_NODE:
5369 case XML_ELEMENT_NODE: {
5370 xmlNodePtr last, newNode, tmp;
5371
5372 last = cur->last;
5373 newNode = xmlNewTextLen(content, len);
5374 if (newNode != NULL) {
5375 tmp = xmlAddChild(cur, newNode);
5376 if (tmp != newNode)
5377 return;
5378 if ((last != NULL) && (last->next == newNode)) {
5379 xmlTextMerge(last, newNode);
5380 }
5381 }
5382 break;
5383 }
5384 case XML_ATTRIBUTE_NODE:
5385 break;
5386 case XML_TEXT_NODE:
5387 case XML_CDATA_SECTION_NODE:
5388 case XML_ENTITY_REF_NODE:
5389 case XML_ENTITY_NODE:
5390 case XML_PI_NODE:
5391 case XML_COMMENT_NODE:
5392 case XML_NOTATION_NODE:
5393 if (content != NULL) {
5394 if ((cur->content == (xmlChar *) &(cur->properties)) ||
5395 ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5396 xmlDictOwns(cur->doc->dict, cur->content))) {
5397 cur->content = xmlStrncatNew(cur->content, content, len);
5398 cur->properties = NULL;
5399 cur->nsDef = NULL;
5400 break;
5401 }
5402 cur->content = xmlStrncat(cur->content, content, len);
5403 }
5404 case XML_DOCUMENT_NODE:
5405 case XML_DTD_NODE:
5406 case XML_HTML_DOCUMENT_NODE:
5407 case XML_DOCUMENT_TYPE_NODE:
5408 case XML_NAMESPACE_DECL:
5409 case XML_XINCLUDE_START:
5410 case XML_XINCLUDE_END:
5411#ifdef LIBXML_DOCB_ENABLED
5412 case XML_DOCB_DOCUMENT_NODE:
5413#endif
5414 break;
5415 case XML_ELEMENT_DECL:
5416 case XML_ATTRIBUTE_DECL:
5417 case XML_ENTITY_DECL:
5418 break;
5419 }
5420}
5421
5422/**
5423 * xmlNodeAddContent:
5424 * @cur: the node being modified
5425 * @content: extra content
5426 *
5427 * Append the extra substring to the node content.
5428 * NOTE: In contrast to xmlNodeSetContent(), @content is supposed to be
5429 * raw text, so unescaped XML special chars are allowed, entity
5430 * references are not supported.
5431 */
5432void
5433xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5434 int len;
5435
5436 if (cur == NULL) {
5437#ifdef DEBUG_TREE
5438 xmlGenericError(xmlGenericErrorContext,
5439 "xmlNodeAddContent : node == NULL\n");
5440#endif
5441 return;
5442 }
5443 if (content == NULL) return;
5444 len = xmlStrlen(content);
5445 xmlNodeAddContentLen(cur, content, len);
5446}
5447
5448/**
5449 * xmlTextMerge:
5450 * @first: the first text node
5451 * @second: the second text node being merged
5452 *
5453 * Merge two text nodes into one
5454 * Returns the first text node augmented
5455 */
5456xmlNodePtr
5457xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5458 if (first == NULL) return(second);
5459 if (second == NULL) return(first);
5460 if (first->type != XML_TEXT_NODE) return(first);
5461 if (second->type != XML_TEXT_NODE) return(first);
5462 if (second->name != first->name)
5463 return(first);
5464 xmlNodeAddContent(first, second->content);
5465 xmlUnlinkNode(second);
5466 xmlFreeNode(second);
5467 return(first);
5468}
5469
5470#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
5471/**
5472 * xmlGetNsList:
5473 * @doc: the document
5474 * @node: the current node
5475 *
5476 * Search all the namespace applying to a given element.
5477 * Returns an NULL terminated array of all the #xmlNsPtr found
5478 * that need to be freed by the caller or NULL if no
5479 * namespace if defined
5480 */
5481xmlNsPtr *
5482xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
5483{
5484 xmlNsPtr cur;
5485 xmlNsPtr *ret = NULL;
5486 int nbns = 0;
5487 int maxns = 10;
5488 int i;
5489
5490 while (node != NULL) {
5491 if (node->type == XML_ELEMENT_NODE) {
5492 cur = node->nsDef;
5493 while (cur != NULL) {
5494 if (ret == NULL) {
5495 ret =
5496 (xmlNsPtr *) xmlMalloc((maxns + 1) *
5497 sizeof(xmlNsPtr));
5498 if (ret == NULL) {
5499 xmlTreeErrMemory("getting namespace list");
5500 return (NULL);
5501 }
5502 ret[nbns] = NULL;
5503 }
5504 for (i = 0; i < nbns; i++) {
5505 if ((cur->prefix == ret[i]->prefix) ||
5506 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5507 break;
5508 }
5509 if (i >= nbns) {
5510 if (nbns >= maxns) {
5511 maxns *= 2;
5512 ret = (xmlNsPtr *) xmlRealloc(ret,
5513 (maxns +
5514 1) *
5515 sizeof(xmlNsPtr));
5516 if (ret == NULL) {
5517 xmlTreeErrMemory("getting namespace list");
5518 return (NULL);
5519 }
5520 }
5521 ret[nbns++] = cur;
5522 ret[nbns] = NULL;
5523 }
5524
5525 cur = cur->next;
5526 }
5527 }
5528 node = node->parent;
5529 }
5530 return (ret);
5531}
5532#endif /* LIBXML_TREE_ENABLED */
5533
5534/*
5535* xmlTreeEnsureXMLDecl:
5536* @doc: the doc
5537*
5538* Ensures that there is an XML namespace declaration on the doc.
5539*
5540* Returns the XML ns-struct or NULL on API and internal errors.
5541*/
5542static xmlNsPtr
5543xmlTreeEnsureXMLDecl(xmlDocPtr doc)
5544{
5545 if (doc == NULL)
5546 return (NULL);
5547 if (doc->oldNs != NULL)
5548 return (doc->oldNs);
5549 {
5550 xmlNsPtr ns;
5551 ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5552 if (ns == NULL) {
5553 xmlTreeErrMemory(
5554 "allocating the XML namespace");
5555 return (NULL);
5556 }
5557 memset(ns, 0, sizeof(xmlNs));
5558 ns->type = XML_LOCAL_NAMESPACE;
5559 ns->href = xmlStrdup(XML_XML_NAMESPACE);
5560 ns->prefix = xmlStrdup((const xmlChar *)"xml");
5561 doc->oldNs = ns;
5562 return (ns);
5563 }
5564}
5565
5566/**
5567 * xmlSearchNs:
5568 * @doc: the document
5569 * @node: the current node
5570 * @nameSpace: the namespace prefix
5571 *
5572 * Search a Ns registered under a given name space for a document.
5573 * recurse on the parents until it finds the defined namespace
5574 * or return NULL otherwise.
5575 * @nameSpace can be NULL, this is a search for the default namespace.
5576 * We don't allow to cross entities boundaries. If you don't declare
5577 * the namespace within those you will be in troubles !!! A warning
5578 * is generated to cover this case.
5579 *
5580 * Returns the namespace pointer or NULL.
5581 */
5582xmlNsPtr
5583xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
5584
5585 xmlNsPtr cur;
5586 xmlNodePtr orig = node;
5587
5588 if (node == NULL) return(NULL);
5589 if ((nameSpace != NULL) &&
5590 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
5591 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5592 /*
5593 * The XML-1.0 namespace is normally held on the root
5594 * element. In this case exceptionally create it on the
5595 * node element.
5596 */
5597 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5598 if (cur == NULL) {
5599 xmlTreeErrMemory("searching namespace");
5600 return(NULL);
5601 }
5602 memset(cur, 0, sizeof(xmlNs));
5603 cur->type = XML_LOCAL_NAMESPACE;
5604 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5605 cur->prefix = xmlStrdup((const xmlChar *)"xml");
5606 cur->next = node->nsDef;
5607 node->nsDef = cur;
5608 return(cur);
5609 }
5610 if (doc == NULL) {
5611 doc = node->doc;
5612 if (doc == NULL)
5613 return(NULL);
5614 }
5615 /*
5616 * Return the XML namespace declaration held by the doc.
5617 */
5618 if (doc->oldNs == NULL)
5619 return(xmlTreeEnsureXMLDecl(doc));
5620 else
5621 return(doc->oldNs);
5622 }
5623 while (node != NULL) {
5624 if ((node->type == XML_ENTITY_REF_NODE) ||
5625 (node->type == XML_ENTITY_NODE) ||
5626 (node->type == XML_ENTITY_DECL))
5627 return(NULL);
5628 if (node->type == XML_ELEMENT_NODE) {
5629 cur = node->nsDef;
5630 while (cur != NULL) {
5631 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5632 (cur->href != NULL))
5633 return(cur);
5634 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5635 (cur->href != NULL) &&
5636 (xmlStrEqual(cur->prefix, nameSpace)))
5637 return(cur);
5638 cur = cur->next;
5639 }
5640 if (orig != node) {
5641 cur = node->ns;
5642 if (cur != NULL) {
5643 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
5644 (cur->href != NULL))
5645 return(cur);
5646 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
5647 (cur->href != NULL) &&
5648 (xmlStrEqual(cur->prefix, nameSpace)))
5649 return(cur);
5650 }
5651 }
5652 }
5653 node = node->parent;
5654 }
5655 return(NULL);
5656}
5657
5658/**
5659 * xmlNsInScope:
5660 * @doc: the document
5661 * @node: the current node
5662 * @ancestor: the ancestor carrying the namespace
5663 * @prefix: the namespace prefix
5664 *
5665 * Verify that the given namespace held on @ancestor is still in scope
5666 * on node.
5667 *
5668 * Returns 1 if true, 0 if false and -1 in case of error.
5669 */
5670static int
5671xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
5672 xmlNodePtr ancestor, const xmlChar * prefix)
5673{
5674 xmlNsPtr tst;
5675
5676 while ((node != NULL) && (node != ancestor)) {
5677 if ((node->type == XML_ENTITY_REF_NODE) ||
5678 (node->type == XML_ENTITY_NODE) ||
5679 (node->type == XML_ENTITY_DECL))
5680 return (-1);
5681 if (node->type == XML_ELEMENT_NODE) {
5682 tst = node->nsDef;
5683 while (tst != NULL) {
5684 if ((tst->prefix == NULL)
5685 && (prefix == NULL))
5686 return (0);
5687 if ((tst->prefix != NULL)
5688 && (prefix != NULL)
5689 && (xmlStrEqual(tst->prefix, prefix)))
5690 return (0);
5691 tst = tst->next;
5692 }
5693 }
5694 node = node->parent;
5695 }
5696 if (node != ancestor)
5697 return (-1);
5698 return (1);
5699}
5700
5701/**
5702 * xmlSearchNsByHref:
5703 * @doc: the document
5704 * @node: the current node
5705 * @href: the namespace value
5706 *
5707 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
5708 * the defined namespace or return NULL otherwise.
5709 * Returns the namespace pointer or NULL.
5710 */
5711xmlNsPtr
5712xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
5713{
5714 xmlNsPtr cur;
5715 xmlNodePtr orig = node;
5716 int is_attr;
5717
5718 if ((node == NULL) || (href == NULL))
5719 return (NULL);
5720 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
5721 /*
5722 * Only the document can hold the XML spec namespace.
5723 */
5724 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
5725 /*
5726 * The XML-1.0 namespace is normally held on the root
5727 * element. In this case exceptionally create it on the
5728 * node element.
5729 */
5730 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5731 if (cur == NULL) {
5732 xmlTreeErrMemory("searching namespace");
5733 return (NULL);
5734 }
5735 memset(cur, 0, sizeof(xmlNs));
5736 cur->type = XML_LOCAL_NAMESPACE;
5737 cur->href = xmlStrdup(XML_XML_NAMESPACE);
5738 cur->prefix = xmlStrdup((const xmlChar *) "xml");
5739 cur->next = node->nsDef;
5740 node->nsDef = cur;
5741 return (cur);
5742 }
5743 if (doc == NULL) {
5744 doc = node->doc;
5745 if (doc == NULL)
5746 return(NULL);
5747 }
5748 /*
5749 * Return the XML namespace declaration held by the doc.
5750 */
5751 if (doc->oldNs == NULL)
5752 return(xmlTreeEnsureXMLDecl(doc));
5753 else
5754 return(doc->oldNs);
5755 }
5756 is_attr = (node->type == XML_ATTRIBUTE_NODE);
5757 while (node != NULL) {
5758 if ((node->type == XML_ENTITY_REF_NODE) ||
5759 (node->type == XML_ENTITY_NODE) ||
5760 (node->type == XML_ENTITY_DECL))
5761 return (NULL);
5762 if (node->type == XML_ELEMENT_NODE) {
5763 cur = node->nsDef;
5764 while (cur != NULL) {
5765 if ((cur->href != NULL) && (href != NULL) &&
5766 (xmlStrEqual(cur->href, href))) {
5767 if (((!is_attr) || (cur->prefix != NULL)) &&
5768 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
5769 return (cur);
5770 }
5771 cur = cur->next;
5772 }
5773 if (orig != node) {
5774 cur = node->ns;
5775 if (cur != NULL) {
5776 if ((cur->href != NULL) && (href != NULL) &&
5777 (xmlStrEqual(cur->href, href))) {
5778 if (((!is_attr) || (cur->prefix != NULL)) &&
5779 (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
5780 return (cur);
5781 }
5782 }
5783 }
5784 }
5785 node = node->parent;
5786 }
5787 return (NULL);
5788}
5789
5790/**
5791 * xmlNewReconciliedNs:
5792 * @doc: the document
5793 * @tree: a node expected to hold the new namespace
5794 * @ns: the original namespace
5795 *
5796 * This function tries to locate a namespace definition in a tree
5797 * ancestors, or create a new namespace definition node similar to
5798 * @ns trying to reuse the same prefix. However if the given prefix is
5799 * null (default namespace) or reused within the subtree defined by
5800 * @tree or on one of its ancestors then a new prefix is generated.
5801 * Returns the (new) namespace definition or NULL in case of error
5802 */
5803xmlNsPtr
5804xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
5805 xmlNsPtr def;
5806 xmlChar prefix[50];
5807 int counter = 1;
5808
5809 if (tree == NULL) {
5810#ifdef DEBUG_TREE
5811 xmlGenericError(xmlGenericErrorContext,
5812 "xmlNewReconciliedNs : tree == NULL\n");
5813#endif
5814 return(NULL);
5815 }
5816 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) {
5817#ifdef DEBUG_TREE
5818 xmlGenericError(xmlGenericErrorContext,
5819 "xmlNewReconciliedNs : ns == NULL\n");
5820#endif
5821 return(NULL);
5822 }
5823 /*
5824 * Search an existing namespace definition inherited.
5825 */
5826 def = xmlSearchNsByHref(doc, tree, ns->href);
5827 if (def != NULL)
5828 return(def);
5829
5830 /*
5831 * Find a close prefix which is not already in use.
5832 * Let's strip namespace prefixes longer than 20 chars !
5833 */
5834 if (ns->prefix == NULL)
5835 snprintf((char *) prefix, sizeof(prefix), "default");
5836 else
5837 snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix);
5838
5839 def = xmlSearchNs(doc, tree, prefix);
5840 while (def != NULL) {
5841 if (counter > 1000) return(NULL);
5842 if (ns->prefix == NULL)
5843 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
5844 else
5845 snprintf((char *) prefix, sizeof(prefix), "%.20s%d",
5846 (char *)ns->prefix, counter++);
5847 def = xmlSearchNs(doc, tree, prefix);
5848 }
5849
5850 /*
5851 * OK, now we are ready to create a new one.
5852 */
5853 def = xmlNewNs(tree, ns->href, prefix);
5854 return(def);
5855}
5856
5857#ifdef LIBXML_TREE_ENABLED
5858/**
5859 * xmlReconciliateNs:
5860 * @doc: the document
5861 * @tree: a node defining the subtree to reconciliate
5862 *
5863 * This function checks that all the namespaces declared within the given
5864 * tree are properly declared. This is needed for example after Copy or Cut
5865 * and then paste operations. The subtree may still hold pointers to
5866 * namespace declarations outside the subtree or invalid/masked. As much
5867 * as possible the function try to reuse the existing namespaces found in
5868 * the new environment. If not possible the new namespaces are redeclared
5869 * on @tree at the top of the given subtree.
5870 * Returns the number of namespace declarations created or -1 in case of error.
5871 */
5872int
5873xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
5874 xmlNsPtr *oldNs = NULL;
5875 xmlNsPtr *newNs = NULL;
5876 int sizeCache = 0;
5877 int nbCache = 0;
5878
5879 xmlNsPtr n;
5880 xmlNodePtr node = tree;
5881 xmlAttrPtr attr;
5882 int ret = 0, i;
5883
5884 if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1);
5885 if ((doc == NULL) || (doc->type != XML_DOCUMENT_NODE)) return(-1);
5886 if (node->doc != doc) return(-1);
5887 while (node != NULL) {
5888 /*
5889 * Reconciliate the node namespace
5890 */
5891 if (node->ns != NULL) {
5892 /*
5893 * initialize the cache if needed
5894 */
5895 if (sizeCache == 0) {
5896 sizeCache = 10;
5897 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5898 sizeof(xmlNsPtr));
5899 if (oldNs == NULL) {
5900 xmlTreeErrMemory("fixing namespaces");
5901 return(-1);
5902 }
5903 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5904 sizeof(xmlNsPtr));
5905 if (newNs == NULL) {
5906 xmlTreeErrMemory("fixing namespaces");
5907 xmlFree(oldNs);
5908 return(-1);
5909 }
5910 }
5911 for (i = 0;i < nbCache;i++) {
5912 if (oldNs[i] == node->ns) {
5913 node->ns = newNs[i];
5914 break;
5915 }
5916 }
5917 if (i == nbCache) {
5918 /*
5919 * OK we need to recreate a new namespace definition
5920 */
5921 n = xmlNewReconciliedNs(doc, tree, node->ns);
5922 if (n != NULL) { /* :-( what if else ??? */
5923 /*
5924 * check if we need to grow the cache buffers.
5925 */
5926 if (sizeCache <= nbCache) {
5927 sizeCache *= 2;
5928 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
5929 sizeof(xmlNsPtr));
5930 if (oldNs == NULL) {
5931 xmlTreeErrMemory("fixing namespaces");
5932 xmlFree(newNs);
5933 return(-1);
5934 }
5935 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
5936 sizeof(xmlNsPtr));
5937 if (newNs == NULL) {
5938 xmlTreeErrMemory("fixing namespaces");
5939 xmlFree(oldNs);
5940 return(-1);
5941 }
5942 }
5943 newNs[nbCache] = n;
5944 oldNs[nbCache++] = node->ns;
5945 node->ns = n;
5946 }
5947 }
5948 }
5949 /*
5950 * now check for namespace hold by attributes on the node.
5951 */
5952 if (node->type == XML_ELEMENT_NODE) {
5953 attr = node->properties;
5954 while (attr != NULL) {
5955 if (attr->ns != NULL) {
5956 /*
5957 * initialize the cache if needed
5958 */
5959 if (sizeCache == 0) {
5960 sizeCache = 10;
5961 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5962 sizeof(xmlNsPtr));
5963 if (oldNs == NULL) {
5964 xmlTreeErrMemory("fixing namespaces");
5965 return(-1);
5966 }
5967 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
5968 sizeof(xmlNsPtr));
5969 if (newNs == NULL) {
5970 xmlTreeErrMemory("fixing namespaces");
5971 xmlFree(oldNs);
5972 return(-1);
5973 }
5974 }
5975 for (i = 0;i < nbCache;i++) {
5976 if (oldNs[i] == attr->ns) {
5977 attr->ns = newNs[i];
5978 break;
5979 }
5980 }
5981 if (i == nbCache) {
5982 /*
5983 * OK we need to recreate a new namespace definition
5984 */
5985 n = xmlNewReconciliedNs(doc, tree, attr->ns);
5986 if (n != NULL) { /* :-( what if else ??? */
5987 /*
5988 * check if we need to grow the cache buffers.
5989 */
5990 if (sizeCache <= nbCache) {
5991 sizeCache *= 2;
5992 oldNs = (xmlNsPtr *) xmlRealloc(oldNs,
5993 sizeCache * sizeof(xmlNsPtr));
5994 if (oldNs == NULL) {
5995 xmlTreeErrMemory("fixing namespaces");
5996 xmlFree(newNs);
5997 return(-1);
5998 }
5999 newNs = (xmlNsPtr *) xmlRealloc(newNs,
6000 sizeCache * sizeof(xmlNsPtr));
6001 if (newNs == NULL) {
6002 xmlTreeErrMemory("fixing namespaces");
6003 xmlFree(oldNs);
6004 return(-1);
6005 }
6006 }
6007 newNs[nbCache] = n;
6008 oldNs[nbCache++] = attr->ns;
6009 attr->ns = n;
6010 }
6011 }
6012 }
6013 attr = attr->next;
6014 }
6015 }
6016
6017 /*
6018 * Browse the full subtree, deep first
6019 */
6020 if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
6021 /* deep first */
6022 node = node->children;
6023 } else if ((node != tree) && (node->next != NULL)) {
6024 /* then siblings */
6025 node = node->next;
6026 } else if (node != tree) {
6027 /* go up to parents->next if needed */
6028 while (node != tree) {
6029 if (node->parent != NULL)
6030 node = node->parent;
6031 if ((node != tree) && (node->next != NULL)) {
6032 node = node->next;
6033 break;
6034 }
6035 if (node->parent == NULL) {
6036 node = NULL;
6037 break;
6038 }
6039 }
6040 /* exit condition */
6041 if (node == tree)
6042 node = NULL;
6043 } else
6044 break;
6045 }
6046 if (oldNs != NULL)
6047 xmlFree(oldNs);
6048 if (newNs != NULL)
6049 xmlFree(newNs);
6050 return(ret);
6051}
6052#endif /* LIBXML_TREE_ENABLED */
6053
6054static xmlAttrPtr
6055xmlGetPropNodeInternal(xmlNodePtr node, const xmlChar *name,
6056 const xmlChar *nsName, int useDTD)
6057{
6058 xmlAttrPtr prop;
6059
6060 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
6061 return(NULL);
6062
6063 if (node->properties != NULL) {
6064 prop = node->properties;
6065 if (nsName == NULL) {
6066 /*
6067 * We want the attr to be in no namespace.
6068 */
6069 do {
6070 if ((prop->ns == NULL) && xmlStrEqual(prop->name, name)) {
6071 return(prop);
6072 }
6073 prop = prop->next;
6074 } while (prop != NULL);
6075 } else {
6076 /*
6077 * We want the attr to be in the specified namespace.
6078 */
6079 do {
6080 if ((prop->ns != NULL) && xmlStrEqual(prop->name, name) &&
6081 ((prop->ns->href == nsName) ||
6082 xmlStrEqual(prop->ns->href, nsName)))
6083 {
6084 return(prop);
6085 }
6086 prop = prop->next;
6087 } while (prop != NULL);
6088 }
6089 }
6090
6091#ifdef LIBXML_TREE_ENABLED
6092 if (! useDTD)
6093 return(NULL);
6094 /*
6095 * Check if there is a default/fixed attribute declaration in
6096 * the internal or external subset.
6097 */
6098 if ((node->doc != NULL) && (node->doc->intSubset != NULL)) {
6099 xmlDocPtr doc = node->doc;
6100 xmlAttributePtr attrDecl = NULL;
6101 xmlChar *elemQName, *tmpstr = NULL;
6102
6103 /*
6104 * We need the QName of the element for the DTD-lookup.
6105 */
6106 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
6107 tmpstr = xmlStrdup(node->ns->prefix);
6108 tmpstr = xmlStrcat(tmpstr, BAD_CAST ":");
6109 tmpstr = xmlStrcat(tmpstr, node->name);
6110 if (tmpstr == NULL)
6111 return(NULL);
6112 elemQName = tmpstr;
6113 } else
6114 elemQName = (xmlChar *) node->name;
6115 if (nsName == NULL) {
6116 /*
6117 * The common and nice case: Attr in no namespace.
6118 */
6119 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset,
6120 elemQName, name, NULL);
6121 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
6122 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset,
6123 elemQName, name, NULL);
6124 }
6125 } else {
6126 xmlNsPtr *nsList, *cur;
6127
6128 /*
6129 * The ugly case: Search using the prefixes of in-scope
6130 * ns-decls corresponding to @nsName.
6131 */
6132 nsList = xmlGetNsList(node->doc, node);
6133 if (nsList == NULL) {
6134 if (tmpstr != NULL)
6135 xmlFree(tmpstr);
6136 return(NULL);
6137 }
6138 cur = nsList;
6139 while (*cur != NULL) {
6140 if (xmlStrEqual((*cur)->href, nsName)) {
6141 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elemQName,
6142 name, (*cur)->prefix);
6143 if (attrDecl)
6144 break;
6145 if (doc->extSubset != NULL) {
6146 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elemQName,
6147 name, (*cur)->prefix);
6148 if (attrDecl)
6149 break;
6150 }
6151 }
6152 cur++;
6153 }
6154 xmlFree(nsList);
6155 }
6156 if (tmpstr != NULL)
6157 xmlFree(tmpstr);
6158 /*
6159 * Only default/fixed attrs are relevant.
6160 */
6161 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6162 return((xmlAttrPtr) attrDecl);
6163 }
6164#endif /* LIBXML_TREE_ENABLED */
6165 return(NULL);
6166}
6167
6168static xmlChar*
6169xmlGetPropNodeValueInternal(xmlAttrPtr prop)
6170{
6171 if (prop == NULL)
6172 return(NULL);
6173 if (prop->type == XML_ATTRIBUTE_NODE) {
6174 /*
6175 * Note that we return at least the empty string.
6176 * TODO: Do we really always want that?
6177 */
6178 if (prop->children != NULL) {
6179 if ((prop->children->next == NULL) &&
6180 ((prop->children->type == XML_TEXT_NODE) ||
6181 (prop->children->type == XML_CDATA_SECTION_NODE)))
6182 {
6183 /*
6184 * Optimization for the common case: only 1 text node.
6185 */
6186 return(xmlStrdup(prop->children->content));
6187 } else {
6188 xmlChar *ret;
6189
6190 ret = xmlNodeListGetString(prop->doc, prop->children, 1);
6191 if (ret != NULL)
6192 return(ret);
6193 }
6194 }
6195 return(xmlStrdup((xmlChar *)""));
6196 } else if (prop->type == XML_ATTRIBUTE_DECL) {
6197 return(xmlStrdup(((xmlAttributePtr)prop)->defaultValue));
6198 }
6199 return(NULL);
6200}
6201
6202/**
6203 * xmlHasProp:
6204 * @node: the node
6205 * @name: the attribute name
6206 *
6207 * Search an attribute associated to a node
6208 * This function also looks in DTD attribute declaration for #FIXED or
6209 * default declaration values unless DTD use has been turned off.
6210 *
6211 * Returns the attribute or the attribute declaration or NULL if
6212 * neither was found.
6213 */
6214xmlAttrPtr
6215xmlHasProp(xmlNodePtr node, const xmlChar *name) {
6216 xmlAttrPtr prop;
6217 xmlDocPtr doc;
6218
6219 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
6220 return(NULL);
6221 /*
6222 * Check on the properties attached to the node
6223 */
6224 prop = node->properties;
6225 while (prop != NULL) {
6226 if (xmlStrEqual(prop->name, name)) {
6227 return(prop);
6228 }
6229 prop = prop->next;
6230 }
6231 if (!xmlCheckDTD) return(NULL);
6232
6233 /*
6234 * Check if there is a default declaration in the internal
6235 * or external subsets
6236 */
6237 doc = node->doc;
6238 if (doc != NULL) {
6239 xmlAttributePtr attrDecl;
6240 if (doc->intSubset != NULL) {
6241 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6242 if ((attrDecl == NULL) && (doc->extSubset != NULL))
6243 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
6244 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6245 /* return attribute declaration only if a default value is given
6246 (that includes #FIXED declarations) */
6247 return((xmlAttrPtr) attrDecl);
6248 }
6249 }
6250 return(NULL);
6251}
6252
6253/**
6254 * xmlHasNsProp:
6255 * @node: the node
6256 * @name: the attribute name
6257 * @nameSpace: the URI of the namespace
6258 *
6259 * Search for an attribute associated to a node
6260 * This attribute has to be anchored in the namespace specified.
6261 * This does the entity substitution.
6262 * This function looks in DTD attribute declaration for #FIXED or
6263 * default declaration values unless DTD use has been turned off.
6264 * Note that a namespace of NULL indicates to use the default namespace.
6265 *
6266 * Returns the attribute or the attribute declaration or NULL
6267 * if neither was found.
6268 */
6269xmlAttrPtr
6270xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
6271
6272 return(xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD));
6273}
6274
6275/**
6276 * xmlGetProp:
6277 * @node: the node
6278 * @name: the attribute name
6279 *
6280 * Search and get the value of an attribute associated to a node
6281 * This does the entity substitution.
6282 * This function looks in DTD attribute declaration for #FIXED or
6283 * default declaration values unless DTD use has been turned off.
6284 * NOTE: this function acts independently of namespaces associated
6285 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
6286 * for namespace aware processing.
6287 *
6288 * Returns the attribute value or NULL if not found.
6289 * It's up to the caller to free the memory with xmlFree().
6290 */
6291xmlChar *
6292xmlGetProp(xmlNodePtr node, const xmlChar *name) {
6293 xmlAttrPtr prop;
6294
6295 prop = xmlHasProp(node, name);
6296 if (prop == NULL)
6297 return(NULL);
6298 return(xmlGetPropNodeValueInternal(prop));
6299}
6300
6301/**
6302 * xmlGetNoNsProp:
6303 * @node: the node
6304 * @name: the attribute name
6305 *
6306 * Search and get the value of an attribute associated to a node
6307 * This does the entity substitution.
6308 * This function looks in DTD attribute declaration for #FIXED or
6309 * default declaration values unless DTD use has been turned off.
6310 * This function is similar to xmlGetProp except it will accept only
6311 * an attribute in no namespace.
6312 *
6313 * Returns the attribute value or NULL if not found.
6314 * It's up to the caller to free the memory with xmlFree().
6315 */
6316xmlChar *
6317xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) {
6318 xmlAttrPtr prop;
6319
6320 prop = xmlGetPropNodeInternal(node, name, NULL, xmlCheckDTD);
6321 if (prop == NULL)
6322 return(NULL);
6323 return(xmlGetPropNodeValueInternal(prop));
6324}
6325
6326/**
6327 * xmlGetNsProp:
6328 * @node: the node
6329 * @name: the attribute name
6330 * @nameSpace: the URI of the namespace
6331 *
6332 * Search and get the value of an attribute associated to a node
6333 * This attribute has to be anchored in the namespace specified.
6334 * This does the entity substitution.
6335 * This function looks in DTD attribute declaration for #FIXED or
6336 * default declaration values unless DTD use has been turned off.
6337 *
6338 * Returns the attribute value or NULL if not found.
6339 * It's up to the caller to free the memory with xmlFree().
6340 */
6341xmlChar *
6342xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
6343 xmlAttrPtr prop;
6344
6345 prop = xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD);
6346 if (prop == NULL)
6347 return(NULL);
6348 return(xmlGetPropNodeValueInternal(prop));
6349}
6350
6351#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
6352/**
6353 * xmlUnsetProp:
6354 * @node: the node
6355 * @name: the attribute name
6356 *
6357 * Remove an attribute carried by a node.
6358 * This handles only attributes in no namespace.
6359 * Returns 0 if successful, -1 if not found
6360 */
6361int
6362xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
6363 xmlAttrPtr prop;
6364
6365 prop = xmlGetPropNodeInternal(node, name, NULL, 0);
6366 if (prop == NULL)
6367 return(-1);
6368 xmlUnlinkNode((xmlNodePtr) prop);
6369 xmlFreeProp(prop);
6370 return(0);
6371}
6372
6373/**
6374 * xmlUnsetNsProp:
6375 * @node: the node
6376 * @ns: the namespace definition
6377 * @name: the attribute name
6378 *
6379 * Remove an attribute carried by a node.
6380 * Returns 0 if successful, -1 if not found
6381 */
6382int
6383xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
6384 xmlAttrPtr prop;
6385
6386 prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0);
6387 if (prop == NULL)
6388 return(-1);
6389 xmlUnlinkNode((xmlNodePtr) prop);
6390 xmlFreeProp(prop);
6391 return(0);
6392}
6393#endif
6394
6395#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)
6396/**
6397 * xmlSetProp:
6398 * @node: the node
6399 * @name: the attribute name (a QName)
6400 * @value: the attribute value
6401 *
6402 * Set (or reset) an attribute carried by a node.
6403 * If @name has a prefix, then the corresponding
6404 * namespace-binding will be used, if in scope; it is an
6405 * error it there's no such ns-binding for the prefix in
6406 * scope.
6407 * Returns the attribute pointer.
6408 *
6409 */
6410xmlAttrPtr
6411xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
6412 int len;
6413 const xmlChar *nqname;
6414
6415 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
6416 return(NULL);
6417
6418 /*
6419 * handle QNames
6420 */
6421 nqname = xmlSplitQName3(name, &len);
6422 if (nqname != NULL) {
6423 xmlNsPtr ns;
6424 xmlChar *prefix = xmlStrndup(name, len);
6425 ns = xmlSearchNs(node->doc, node, prefix);
6426 if (prefix != NULL)
6427 xmlFree(prefix);
6428 if (ns != NULL)
6429 return(xmlSetNsProp(node, ns, nqname, value));
6430 }
6431 return(xmlSetNsProp(node, NULL, name, value));
6432}
6433
6434/**
6435 * xmlSetNsProp:
6436 * @node: the node
6437 * @ns: the namespace definition
6438 * @name: the attribute name
6439 * @value: the attribute value
6440 *
6441 * Set (or reset) an attribute carried by a node.
6442 * The ns structure must be in scope, this is not checked
6443 *
6444 * Returns the attribute pointer.
6445 */
6446xmlAttrPtr
6447xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
6448 const xmlChar *value)
6449{
6450 xmlAttrPtr prop;
6451
6452 if (ns && (ns->href == NULL))
6453 return(NULL);
6454 prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0);
6455 if (prop != NULL) {
6456 /*
6457 * Modify the attribute's value.
6458 */
6459 if (prop->atype == XML_ATTRIBUTE_ID) {
6460 xmlRemoveID(node->doc, prop);
6461 prop->atype = XML_ATTRIBUTE_ID;
6462 }
6463 if (prop->children != NULL)
6464 xmlFreeNodeList(prop->children);
6465 prop->children = NULL;
6466 prop->last = NULL;
6467 prop->ns = ns;
6468 if (value != NULL) {
6469 xmlChar *buffer;
6470 xmlNodePtr tmp;
6471
6472 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
6473 prop->children = xmlStringGetNodeList(node->doc, buffer);
6474 prop->last = NULL;
6475 tmp = prop->children;
6476 while (tmp != NULL) {
6477 tmp->parent = (xmlNodePtr) prop;
6478 if (tmp->next == NULL)
6479 prop->last = tmp;
6480 tmp = tmp->next;
6481 }
6482 xmlFree(buffer);
6483 }
6484 if (prop->atype == XML_ATTRIBUTE_ID)
6485 xmlAddID(NULL, node->doc, value, prop);
6486 return(prop);
6487 }
6488 /*
6489 * No equal attr found; create a new one.
6490 */
6491 return(xmlNewPropInternal(node, ns, name, value, 0));
6492}
6493
6494#endif /* LIBXML_TREE_ENABLED */
6495
6496/**
6497 * xmlNodeIsText:
6498 * @node: the node
6499 *
6500 * Is this node a Text node ?
6501 * Returns 1 yes, 0 no
6502 */
6503int
6504xmlNodeIsText(xmlNodePtr node) {
6505 if (node == NULL) return(0);
6506
6507 if (node->type == XML_TEXT_NODE) return(1);
6508 return(0);
6509}
6510
6511/**
6512 * xmlIsBlankNode:
6513 * @node: the node
6514 *
6515 * Checks whether this node is an empty or whitespace only
6516 * (and possibly ignorable) text-node.
6517 *
6518 * Returns 1 yes, 0 no
6519 */
6520int
6521xmlIsBlankNode(xmlNodePtr node) {
6522 const xmlChar *cur;
6523 if (node == NULL) return(0);
6524
6525 if ((node->type != XML_TEXT_NODE) &&
6526 (node->type != XML_CDATA_SECTION_NODE))
6527 return(0);
6528 if (node->content == NULL) return(1);
6529 cur = node->content;
6530 while (*cur != 0) {
6531 if (!IS_BLANK_CH(*cur)) return(0);
6532 cur++;
6533 }
6534
6535 return(1);
6536}
6537
6538/**
6539 * xmlTextConcat:
6540 * @node: the node
6541 * @content: the content
6542 * @len: @content length
6543 *
6544 * Concat the given string at the end of the existing node content
6545 *
6546 * Returns -1 in case of error, 0 otherwise
6547 */
6548
6549int
6550xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
6551 if (node == NULL) return(-1);
6552
6553 if ((node->type != XML_TEXT_NODE) &&
6554 (node->type != XML_CDATA_SECTION_NODE) &&
6555 (node->type != XML_COMMENT_NODE) &&
6556 (node->type != XML_PI_NODE)) {
6557#ifdef DEBUG_TREE
6558 xmlGenericError(xmlGenericErrorContext,
6559 "xmlTextConcat: node is not text nor CDATA\n");
6560#endif
6561 return(-1);
6562 }
6563 /* need to check if content is currently in the dictionary */
6564 if ((node->content == (xmlChar *) &(node->properties)) ||
6565 ((node->doc != NULL) && (node->doc->dict != NULL) &&
6566 xmlDictOwns(node->doc->dict, node->content))) {
6567 node->content = xmlStrncatNew(node->content, content, len);
6568 } else {
6569 node->content = xmlStrncat(node->content, content, len);
6570 }
6571 node->properties = NULL;
6572 if (node->content == NULL)
6573 return(-1);
6574 return(0);
6575}
6576
6577/************************************************************************
6578 * *
6579 * Output : to a FILE or in memory *
6580 * *
6581 ************************************************************************/
6582
6583/**
6584 * xmlBufferCreate:
6585 *
6586 * routine to create an XML buffer.
6587 * returns the new structure.
6588 */
6589xmlBufferPtr
6590xmlBufferCreate(void) {
6591 xmlBufferPtr ret;
6592
6593 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6594 if (ret == NULL) {
6595 xmlTreeErrMemory("creating buffer");
6596 return(NULL);
6597 }
6598 ret->use = 0;
6599 ret->size = xmlDefaultBufferSize;
6600 ret->alloc = xmlBufferAllocScheme;
6601 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
6602 if (ret->content == NULL) {
6603 xmlTreeErrMemory("creating buffer");
6604 xmlFree(ret);
6605 return(NULL);
6606 }
6607 ret->content[0] = 0;
6608 return(ret);
6609}
6610
6611/**
6612 * xmlBufferCreateSize:
6613 * @size: initial size of buffer
6614 *
6615 * routine to create an XML buffer.
6616 * returns the new structure.
6617 */
6618xmlBufferPtr
6619xmlBufferCreateSize(size_t size) {
6620 xmlBufferPtr ret;
6621
6622 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6623 if (ret == NULL) {
6624 xmlTreeErrMemory("creating buffer");
6625 return(NULL);
6626 }
6627 ret->use = 0;
6628 ret->alloc = xmlBufferAllocScheme;
6629 ret->size = (size ? size+2 : 0); /* +1 for ending null */
6630 if (ret->size){
6631 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
6632 if (ret->content == NULL) {
6633 xmlTreeErrMemory("creating buffer");
6634 xmlFree(ret);
6635 return(NULL);
6636 }
6637 ret->content[0] = 0;
6638 } else
6639 ret->content = NULL;
6640 return(ret);
6641}
6642
6643/**
6644 * xmlBufferCreateStatic:
6645 * @mem: the memory area
6646 * @size: the size in byte
6647 *
6648 * routine to create an XML buffer from an immutable memory area.
6649 * The area won't be modified nor copied, and is expected to be
6650 * present until the end of the buffer lifetime.
6651 *
6652 * returns the new structure.
6653 */
6654xmlBufferPtr
6655xmlBufferCreateStatic(void *mem, size_t size) {
6656 xmlBufferPtr ret;
6657
6658 if ((mem == NULL) || (size == 0))
6659 return(NULL);
6660
6661 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
6662 if (ret == NULL) {
6663 xmlTreeErrMemory("creating buffer");
6664 return(NULL);
6665 }
6666 ret->use = size;
6667 ret->size = size;
6668 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
6669 ret->content = (xmlChar *) mem;
6670 return(ret);
6671}
6672
6673/**
6674 * xmlBufferSetAllocationScheme:
6675 * @buf: the buffer to tune
6676 * @scheme: allocation scheme to use
6677 *
6678 * Sets the allocation scheme for this buffer
6679 */
6680void
6681xmlBufferSetAllocationScheme(xmlBufferPtr buf,
6682 xmlBufferAllocationScheme scheme) {
6683 if (buf == NULL) {
6684#ifdef DEBUG_BUFFER
6685 xmlGenericError(xmlGenericErrorContext,
6686 "xmlBufferSetAllocationScheme: buf == NULL\n");
6687#endif
6688 return;
6689 }
6690 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
6691
6692 buf->alloc = scheme;
6693}
6694
6695/**
6696 * xmlBufferFree:
6697 * @buf: the buffer to free
6698 *
6699 * Frees an XML buffer. It frees both the content and the structure which
6700 * encapsulate it.
6701 */
6702void
6703xmlBufferFree(xmlBufferPtr buf) {
6704 if (buf == NULL) {
6705#ifdef DEBUG_BUFFER
6706 xmlGenericError(xmlGenericErrorContext,
6707 "xmlBufferFree: buf == NULL\n");
6708#endif
6709 return;
6710 }
6711
6712 if ((buf->content != NULL) &&
6713 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
6714 xmlFree(buf->content);
6715 }
6716 xmlFree(buf);
6717}
6718
6719/**
6720 * xmlBufferEmpty:
6721 * @buf: the buffer
6722 *
6723 * empty a buffer.
6724 */
6725void
6726xmlBufferEmpty(xmlBufferPtr buf) {
6727 if (buf == NULL) return;
6728 if (buf->content == NULL) return;
6729 buf->use = 0;
6730 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6731 buf->content = BAD_CAST "";
6732 } else {
6733 memset(buf->content, 0, buf->size);
6734 }
6735}
6736
6737/**
6738 * xmlBufferShrink:
6739 * @buf: the buffer to dump
6740 * @len: the number of xmlChar to remove
6741 *
6742 * Remove the beginning of an XML buffer.
6743 *
6744 * Returns the number of #xmlChar removed, or -1 in case of failure.
6745 */
6746int
6747xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
6748 if (buf == NULL) return(-1);
6749 if (len == 0) return(0);
6750 if (len > buf->use) return(-1);
6751
6752 buf->use -= len;
6753 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
6754 buf->content += len;
6755 } else {
6756 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
6757 buf->content[buf->use] = 0;
6758 }
6759 return(len);
6760}
6761
6762/**
6763 * xmlBufferGrow:
6764 * @buf: the buffer
6765 * @len: the minimum free size to allocate
6766 *
6767 * Grow the available space of an XML buffer.
6768 *
6769 * Returns the new available space or -1 in case of error
6770 */
6771int
6772xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
6773 int size;
6774 xmlChar *newbuf;
6775
6776 if (buf == NULL) return(-1);
6777
6778 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6779 if (len + buf->use < buf->size) return(0);
6780
6781/*
6782 * Windows has a BIG problem on realloc timing, so we try to double
6783 * the buffer size (if that's enough) (bug 146697)
6784 */
6785#ifdef WIN32
6786 if (buf->size > len)
6787 size = buf->size * 2;
6788 else
6789 size = buf->use + len + 100;
6790#else
6791 size = buf->use + len + 100;
6792#endif
6793
6794 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
6795 if (newbuf == NULL) {
6796 xmlTreeErrMemory("growing buffer");
6797 return(-1);
6798 }
6799 buf->content = newbuf;
6800 buf->size = size;
6801 return(buf->size - buf->use);
6802}
6803
6804/**
6805 * xmlBufferDump:
6806 * @file: the file output
6807 * @buf: the buffer to dump
6808 *
6809 * Dumps an XML buffer to a FILE *.
6810 * Returns the number of #xmlChar written
6811 */
6812int
6813xmlBufferDump(FILE *file, xmlBufferPtr buf) {
6814 int ret;
6815
6816 if (buf == NULL) {
6817#ifdef DEBUG_BUFFER
6818 xmlGenericError(xmlGenericErrorContext,
6819 "xmlBufferDump: buf == NULL\n");
6820#endif
6821 return(0);
6822 }
6823 if (buf->content == NULL) {
6824#ifdef DEBUG_BUFFER
6825 xmlGenericError(xmlGenericErrorContext,
6826 "xmlBufferDump: buf->content == NULL\n");
6827#endif
6828 return(0);
6829 }
6830 if (file == NULL)
6831 file = stdout;
6832 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
6833 return(ret);
6834}
6835
6836/**
6837 * xmlBufferContent:
6838 * @buf: the buffer
6839 *
6840 * Function to extract the content of a buffer
6841 *
6842 * Returns the internal content
6843 */
6844
6845const xmlChar *
6846xmlBufferContent(const xmlBufferPtr buf)
6847{
6848 if(!buf)
6849 return NULL;
6850
6851 return buf->content;
6852}
6853
6854/**
6855 * xmlBufferLength:
6856 * @buf: the buffer
6857 *
6858 * Function to get the length of a buffer
6859 *
6860 * Returns the length of data in the internal content
6861 */
6862
6863int
6864xmlBufferLength(const xmlBufferPtr buf)
6865{
6866 if(!buf)
6867 return 0;
6868
6869 return buf->use;
6870}
6871
6872/**
6873 * xmlBufferResize:
6874 * @buf: the buffer to resize
6875 * @size: the desired size
6876 *
6877 * Resize a buffer to accommodate minimum size of @size.
6878 *
6879 * Returns 0 in case of problems, 1 otherwise
6880 */
6881int
6882xmlBufferResize(xmlBufferPtr buf, unsigned int size)
6883{
6884 unsigned int newSize;
6885 xmlChar* rebuf = NULL;
6886
6887 if (buf == NULL)
6888 return(0);
6889
6890 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
6891
6892 /* Don't resize if we don't have to */
6893 if (size < buf->size)
6894 return 1;
6895
6896 /* figure out new size */
6897 switch (buf->alloc){
6898 case XML_BUFFER_ALLOC_DOUBLEIT:
6899 /*take care of empty case*/
6900 newSize = (buf->size ? buf->size*2 : size + 10);
6901 while (size > newSize) {
6902 if (newSize > UINT_MAX / 2) {
6903 xmlTreeErrMemory("growing buffer");
6904 return 0;
6905 }
6906 newSize *= 2;
6907 }
6908 break;
6909 case XML_BUFFER_ALLOC_EXACT:
6910 newSize = size+10;
6911 break;
6912 default:
6913 newSize = size+10;
6914 break;
6915 }
6916
6917 if (buf->content == NULL)
6918 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6919 else if (buf->size - buf->use < 100) {
6920 rebuf = (xmlChar *) xmlRealloc(buf->content,
6921 newSize * sizeof(xmlChar));
6922 } else {
6923 /*
6924 * if we are reallocating a buffer far from being full, it's
6925 * better to make a new allocation and copy only the used range
6926 * and free the old one.
6927 */
6928 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar));
6929 if (rebuf != NULL) {
6930 memcpy(rebuf, buf->content, buf->use);
6931 xmlFree(buf->content);
6932 rebuf[buf->use] = 0;
6933 }
6934 }
6935 if (rebuf == NULL) {
6936 xmlTreeErrMemory("growing buffer");
6937 return 0;
6938 }
6939 buf->content = rebuf;
6940 buf->size = newSize;
6941
6942 return 1;
6943}
6944
6945/**
6946 * xmlBufferAdd:
6947 * @buf: the buffer to dump
6948 * @str: the #xmlChar string
6949 * @len: the number of #xmlChar to add
6950 *
6951 * Add a string range to an XML buffer. if len == -1, the length of
6952 * str is recomputed.
6953 *
6954 * Returns 0 successful, a positive error code number otherwise
6955 * and -1 in case of internal or API error.
6956 */
6957int
6958xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
6959 unsigned int needSize;
6960
6961 if ((str == NULL) || (buf == NULL)) {
6962 return -1;
6963 }
6964 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
6965 if (len < -1) {
6966#ifdef DEBUG_BUFFER
6967 xmlGenericError(xmlGenericErrorContext,
6968 "xmlBufferAdd: len < 0\n");
6969#endif
6970 return -1;
6971 }
6972 if (len == 0) return 0;
6973
6974 if (len < 0)
6975 len = xmlStrlen(str);
6976
6977 if (len < 0) return -1;
6978 if (len == 0) return 0;
6979
6980 needSize = buf->use + len + 2;
6981 if (needSize > buf->size){
6982 if (!xmlBufferResize(buf, needSize)){
6983 xmlTreeErrMemory("growing buffer");
6984 return XML_ERR_NO_MEMORY;
6985 }
6986 }
6987
6988 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
6989 buf->use += len;
6990 buf->content[buf->use] = 0;
6991 return 0;
6992}
6993
6994/**
6995 * xmlBufferAddHead:
6996 * @buf: the buffer
6997 * @str: the #xmlChar string
6998 * @len: the number of #xmlChar to add
6999 *
7000 * Add a string range to the beginning of an XML buffer.
7001 * if len == -1, the length of @str is recomputed.
7002 *
7003 * Returns 0 successful, a positive error code number otherwise
7004 * and -1 in case of internal or API error.
7005 */
7006int
7007xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
7008 unsigned int needSize;
7009
7010 if (buf == NULL)
7011 return(-1);
7012 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
7013 if (str == NULL) {
7014#ifdef DEBUG_BUFFER
7015 xmlGenericError(xmlGenericErrorContext,
7016 "xmlBufferAddHead: str == NULL\n");
7017#endif
7018 return -1;
7019 }
7020 if (len < -1) {
7021#ifdef DEBUG_BUFFER
7022 xmlGenericError(xmlGenericErrorContext,
7023 "xmlBufferAddHead: len < 0\n");
7024#endif
7025 return -1;
7026 }
7027 if (len == 0) return 0;
7028
7029 if (len < 0)
7030 len = xmlStrlen(str);
7031
7032 if (len <= 0) return -1;
7033
7034 needSize = buf->use + len + 2;
7035 if (needSize > buf->size){
7036 if (!xmlBufferResize(buf, needSize)){
7037 xmlTreeErrMemory("growing buffer");
7038 return XML_ERR_NO_MEMORY;
7039 }
7040 }
7041
7042 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
7043 memmove(&buf->content[0], str, len * sizeof(xmlChar));
7044 buf->use += len;
7045 buf->content[buf->use] = 0;
7046 return 0;
7047}
7048
7049/**
7050 * xmlBufferCat:
7051 * @buf: the buffer to add to
7052 * @str: the #xmlChar string
7053 *
7054 * Append a zero terminated string to an XML buffer.
7055 *
7056 * Returns 0 successful, a positive error code number otherwise
7057 * and -1 in case of internal or API error.
7058 */
7059int
7060xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
7061 if (buf == NULL)
7062 return(-1);
7063 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
7064 if (str == NULL) return -1;
7065 return xmlBufferAdd(buf, str, -1);
7066}
7067
7068/**
7069 * xmlBufferCCat:
7070 * @buf: the buffer to dump
7071 * @str: the C char string
7072 *
7073 * Append a zero terminated C string to an XML buffer.
7074 *
7075 * Returns 0 successful, a positive error code number otherwise
7076 * and -1 in case of internal or API error.
7077 */
7078int
7079xmlBufferCCat(xmlBufferPtr buf, const char *str) {
7080 const char *cur;
7081
7082 if (buf == NULL)
7083 return(-1);
7084 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
7085 if (str == NULL) {
7086#ifdef DEBUG_BUFFER
7087 xmlGenericError(xmlGenericErrorContext,
7088 "xmlBufferCCat: str == NULL\n");
7089#endif
7090 return -1;
7091 }
7092 for (cur = str;*cur != 0;cur++) {
7093 if (buf->use + 10 >= buf->size) {
7094 if (!xmlBufferResize(buf, buf->use+10)){
7095 xmlTreeErrMemory("growing buffer");
7096 return XML_ERR_NO_MEMORY;
7097 }
7098 }
7099 buf->content[buf->use++] = *cur;
7100 }
7101 buf->content[buf->use] = 0;
7102 return 0;
7103}
7104
7105/**
7106 * xmlBufferWriteCHAR:
7107 * @buf: the XML buffer
7108 * @string: the string to add
7109 *
7110 * routine which manages and grows an output buffer. This one adds
7111 * xmlChars at the end of the buffer.
7112 */
7113void
7114xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
7115 if (buf == NULL)
7116 return;
7117 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
7118 xmlBufferCat(buf, string);
7119}
7120
7121/**
7122 * xmlBufferWriteChar:
7123 * @buf: the XML buffer output
7124 * @string: the string to add
7125 *
7126 * routine which manage and grows an output buffer. This one add
7127 * C chars at the end of the array.
7128 */
7129void
7130xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
7131 if (buf == NULL)
7132 return;
7133 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
7134 xmlBufferCCat(buf, string);
7135}
7136
7137
7138/**
7139 * xmlBufferWriteQuotedString:
7140 * @buf: the XML buffer output
7141 * @string: the string to add
7142 *
7143 * routine which manage and grows an output buffer. This one writes
7144 * a quoted or double quoted #xmlChar string, checking first if it holds
7145 * quote or double-quotes internally
7146 */
7147void
7148xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
7149 const xmlChar *cur, *base;
7150 if (buf == NULL)
7151 return;
7152 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
7153 if (xmlStrchr(string, '\"')) {
7154 if (xmlStrchr(string, '\'')) {
7155#ifdef DEBUG_BUFFER
7156 xmlGenericError(xmlGenericErrorContext,
7157 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
7158#endif
7159 xmlBufferCCat(buf, "\"");
7160 base = cur = string;
7161 while(*cur != 0){
7162 if(*cur == '"'){
7163 if (base != cur)
7164 xmlBufferAdd(buf, base, cur - base);
7165 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7166 cur++;
7167 base = cur;
7168 }
7169 else {
7170 cur++;
7171 }
7172 }
7173 if (base != cur)
7174 xmlBufferAdd(buf, base, cur - base);
7175 xmlBufferCCat(buf, "\"");
7176 }
7177 else{
7178 xmlBufferCCat(buf, "\'");
7179 xmlBufferCat(buf, string);
7180 xmlBufferCCat(buf, "\'");
7181 }
7182 } else {
7183 xmlBufferCCat(buf, "\"");
7184 xmlBufferCat(buf, string);
7185 xmlBufferCCat(buf, "\"");
7186 }
7187}
7188
7189
7190/**
7191 * xmlGetDocCompressMode:
7192 * @doc: the document
7193 *
7194 * get the compression ratio for a document, ZLIB based
7195 * Returns 0 (uncompressed) to 9 (max compression)
7196 */
7197int
7198xmlGetDocCompressMode (xmlDocPtr doc) {
7199 if (doc == NULL) return(-1);
7200 return(doc->compression);
7201}
7202
7203/**
7204 * xmlSetDocCompressMode:
7205 * @doc: the document
7206 * @mode: the compression ratio
7207 *
7208 * set the compression ratio for a document, ZLIB based
7209 * Correct values: 0 (uncompressed) to 9 (max compression)
7210 */
7211void
7212xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7213 if (doc == NULL) return;
7214 if (mode < 0) doc->compression = 0;
7215 else if (mode > 9) doc->compression = 9;
7216 else doc->compression = mode;
7217}
7218
7219/**
7220 * xmlGetCompressMode:
7221 *
7222 * get the default compression mode used, ZLIB based.
7223 * Returns 0 (uncompressed) to 9 (max compression)
7224 */
7225int
7226xmlGetCompressMode(void)
7227{
7228 return (xmlCompressMode);
7229}
7230
7231/**
7232 * xmlSetCompressMode:
7233 * @mode: the compression ratio
7234 *
7235 * set the default compression mode used, ZLIB based
7236 * Correct values: 0 (uncompressed) to 9 (max compression)
7237 */
7238void
7239xmlSetCompressMode(int mode) {
7240 if (mode < 0) xmlCompressMode = 0;
7241 else if (mode > 9) xmlCompressMode = 9;
7242 else xmlCompressMode = mode;
7243}
7244
7245#define XML_TREE_NSMAP_PARENT -1
7246#define XML_TREE_NSMAP_XML -2
7247#define XML_TREE_NSMAP_DOC -3
7248#define XML_TREE_NSMAP_CUSTOM -4
7249
7250typedef struct xmlNsMapItem *xmlNsMapItemPtr;
7251struct xmlNsMapItem {
7252 xmlNsMapItemPtr next;
7253 xmlNsMapItemPtr prev;
7254 xmlNsPtr oldNs; /* old ns decl reference */
7255 xmlNsPtr newNs; /* new ns decl reference */
7256 int shadowDepth; /* Shadowed at this depth */
7257 /*
7258 * depth:
7259 * >= 0 == @node's ns-decls
7260 * -1 == @parent's ns-decls
7261 * -2 == the doc->oldNs XML ns-decl
7262 * -3 == the doc->oldNs storage ns-decls
7263 * -4 == ns-decls provided via custom ns-handling
7264 */
7265 int depth;
7266};
7267
7268typedef struct xmlNsMap *xmlNsMapPtr;
7269struct xmlNsMap {
7270 xmlNsMapItemPtr first;
7271 xmlNsMapItemPtr last;
7272 xmlNsMapItemPtr pool;
7273};
7274
7275#define XML_NSMAP_NOTEMPTY(m) (((m) != NULL) && ((m)->first != NULL))
7276#define XML_NSMAP_FOREACH(m, i) for (i = (m)->first; i != NULL; i = (i)->next)
7277#define XML_NSMAP_POP(m, i) \
7278 i = (m)->last; \
7279 (m)->last = (i)->prev; \
7280 if ((m)->last == NULL) \
7281 (m)->first = NULL; \
7282 else \
7283 (m)->last->next = NULL; \
7284 (i)->next = (m)->pool; \
7285 (m)->pool = i;
7286
7287/*
7288* xmlDOMWrapNsMapFree:
7289* @map: the ns-map
7290*
7291* Frees the ns-map
7292*/
7293static void
7294xmlDOMWrapNsMapFree(xmlNsMapPtr nsmap)
7295{
7296 xmlNsMapItemPtr cur, tmp;
7297
7298 if (nsmap == NULL)
7299 return;
7300 cur = nsmap->pool;
7301 while (cur != NULL) {
7302 tmp = cur;
7303 cur = cur->next;
7304 xmlFree(tmp);
7305 }
7306 cur = nsmap->first;
7307 while (cur != NULL) {
7308 tmp = cur;
7309 cur = cur->next;
7310 xmlFree(tmp);
7311 }
7312 xmlFree(nsmap);
7313}
7314
7315/*
7316* xmlDOMWrapNsMapAddItem:
7317* @map: the ns-map
7318* @oldNs: the old ns-struct
7319* @newNs: the new ns-struct
7320* @depth: depth and ns-kind information
7321*
7322* Adds an ns-mapping item.
7323*/
7324static xmlNsMapItemPtr
7325xmlDOMWrapNsMapAddItem(xmlNsMapPtr *nsmap, int position,
7326 xmlNsPtr oldNs, xmlNsPtr newNs, int depth)
7327{
7328 xmlNsMapItemPtr ret;
7329 xmlNsMapPtr map;
7330
7331 if (nsmap == NULL)
7332 return(NULL);
7333 if ((position != -1) && (position != 0))
7334 return(NULL);
7335 map = *nsmap;
7336
7337 if (map == NULL) {
7338 /*
7339 * Create the ns-map.
7340 */
7341 map = (xmlNsMapPtr) xmlMalloc(sizeof(struct xmlNsMap));
7342 if (map == NULL) {
7343 xmlTreeErrMemory("allocating namespace map");
7344 return (NULL);
7345 }
7346 memset(map, 0, sizeof(struct xmlNsMap));
7347 *nsmap = map;
7348 }
7349
7350 if (map->pool != NULL) {
7351 /*
7352 * Reuse an item from the pool.
7353 */
7354 ret = map->pool;
7355 map->pool = ret->next;
7356 memset(ret, 0, sizeof(struct xmlNsMapItem));
7357 } else {
7358 /*
7359 * Create a new item.
7360 */
7361 ret = (xmlNsMapItemPtr) xmlMalloc(sizeof(struct xmlNsMapItem));
7362 if (ret == NULL) {
7363 xmlTreeErrMemory("allocating namespace map item");
7364 return (NULL);
7365 }
7366 memset(ret, 0, sizeof(struct xmlNsMapItem));
7367 }
7368
7369 if (map->first == NULL) {
7370 /*
7371 * First ever.
7372 */
7373 map->first = ret;
7374 map->last = ret;
7375 } else if (position == -1) {
7376 /*
7377 * Append.
7378 */
7379 ret->prev = map->last;
7380 map->last->next = ret;
7381 map->last = ret;
7382 } else if (position == 0) {
7383 /*
7384 * Set on first position.
7385 */
7386 map->first->prev = ret;
7387 ret->next = map->first;
7388 map->first = ret;
7389 } else
7390 return(NULL);
7391
7392 ret->oldNs = oldNs;
7393 ret->newNs = newNs;
7394 ret->shadowDepth = -1;
7395 ret->depth = depth;
7396 return (ret);
7397}
7398
7399/*
7400* xmlDOMWrapStoreNs:
7401* @doc: the doc
7402* @nsName: the namespace name
7403* @prefix: the prefix
7404*
7405* Creates or reuses an xmlNs struct on doc->oldNs with
7406* the given prefix and namespace name.
7407*
7408* Returns the aquired ns struct or NULL in case of an API
7409* or internal error.
7410*/
7411static xmlNsPtr
7412xmlDOMWrapStoreNs(xmlDocPtr doc,
7413 const xmlChar *nsName,
7414 const xmlChar *prefix)
7415{
7416 xmlNsPtr ns;
7417
7418 if (doc == NULL)
7419 return (NULL);
7420 ns = xmlTreeEnsureXMLDecl(doc);
7421 if (ns == NULL)
7422 return (NULL);
7423 if (ns->next != NULL) {
7424 /* Reuse. */
7425 ns = ns->next;
7426 while (ns != NULL) {
7427 if (((ns->prefix == prefix) ||
7428 xmlStrEqual(ns->prefix, prefix)) &&
7429 xmlStrEqual(ns->href, nsName)) {
7430 return (ns);
7431 }
7432 if (ns->next == NULL)
7433 break;
7434 ns = ns->next;
7435 }
7436 }
7437 /* Create. */
7438 ns->next = xmlNewNs(NULL, nsName, prefix);
7439 return (ns->next);
7440}
7441
7442/*
7443* xmlDOMWrapNewCtxt:
7444*
7445* Allocates and initializes a new DOM-wrapper context.
7446*
7447* Returns the xmlDOMWrapCtxtPtr or NULL in case of an internal errror.
7448*/
7449xmlDOMWrapCtxtPtr
7450xmlDOMWrapNewCtxt(void)
7451{
7452 xmlDOMWrapCtxtPtr ret;
7453
7454 ret = xmlMalloc(sizeof(xmlDOMWrapCtxt));
7455 if (ret == NULL) {
7456 xmlTreeErrMemory("allocating DOM-wrapper context");
7457 return (NULL);
7458 }
7459 memset(ret, 0, sizeof(xmlDOMWrapCtxt));
7460 return (ret);
7461}
7462
7463/*
7464* xmlDOMWrapFreeCtxt:
7465* @ctxt: the DOM-wrapper context
7466*
7467* Frees the DOM-wrapper context.
7468*/
7469void
7470xmlDOMWrapFreeCtxt(xmlDOMWrapCtxtPtr ctxt)
7471{
7472 if (ctxt == NULL)
7473 return;
7474 if (ctxt->namespaceMap != NULL)
7475 xmlDOMWrapNsMapFree((xmlNsMapPtr) ctxt->namespaceMap);
7476 /*
7477 * TODO: Store the namespace map in the context.
7478 */
7479 xmlFree(ctxt);
7480}
7481
7482/*
7483* xmlTreeLookupNsListByPrefix:
7484* @nsList: a list of ns-structs
7485* @prefix: the searched prefix
7486*
7487* Searches for a ns-decl with the given prefix in @nsList.
7488*
7489* Returns the ns-decl if found, NULL if not found and on
7490* API errors.
7491*/
7492static xmlNsPtr
7493xmlTreeNSListLookupByPrefix(xmlNsPtr nsList, const xmlChar *prefix)
7494{
7495 if (nsList == NULL)
7496 return (NULL);
7497 {
7498 xmlNsPtr ns;
7499 ns = nsList;
7500 do {
7501 if ((prefix == ns->prefix) ||
7502 xmlStrEqual(prefix, ns->prefix)) {
7503 return (ns);
7504 }
7505 ns = ns->next;
7506 } while (ns != NULL);
7507 }
7508 return (NULL);
7509}
7510
7511/*
7512*
7513* xmlDOMWrapNSNormGatherInScopeNs:
7514* @map: the namespace map
7515* @node: the node to start with
7516*
7517* Puts in-scope namespaces into the ns-map.
7518*
7519* Returns 0 on success, -1 on API or internal errors.
7520*/
7521static int
7522xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapPtr *map,
7523 xmlNodePtr node)
7524{
7525 xmlNodePtr cur;
7526 xmlNsPtr ns;
7527 xmlNsMapItemPtr mi;
7528 int shadowed;
7529
7530 if ((map == NULL) || (*map != NULL))
7531 return (-1);
7532 /*
7533 * Get in-scope ns-decls of @parent.
7534 */
7535 cur = node;
7536 while ((cur != NULL) && (cur != (xmlNodePtr) cur->doc)) {
7537 if (cur->type == XML_ELEMENT_NODE) {
7538 if (cur->nsDef != NULL) {
7539 ns = cur->nsDef;
7540 do {
7541 shadowed = 0;
7542 if (XML_NSMAP_NOTEMPTY(*map)) {
7543 /*
7544 * Skip shadowed prefixes.
7545 */
7546 XML_NSMAP_FOREACH(*map, mi) {
7547 if ((ns->prefix == mi->newNs->prefix) ||
7548 xmlStrEqual(ns->prefix, mi->newNs->prefix)) {
7549 shadowed = 1;
7550 break;
7551 }
7552 }
7553 }
7554 /*
7555 * Insert mapping.
7556 */
7557 mi = xmlDOMWrapNsMapAddItem(map, 0, NULL,
7558 ns, XML_TREE_NSMAP_PARENT);
7559 if (mi == NULL)
7560 return (-1);
7561 if (shadowed)
7562 mi->shadowDepth = 0;
7563 ns = ns->next;
7564 } while (ns != NULL);
7565 }
7566 }
7567 cur = cur->parent;
7568 }
7569 return (0);
7570}
7571
7572/*
7573* XML_TREE_ADOPT_STR: If we have a dest-dict, put @str in the dict;
7574* otherwise copy it, when it was in the source-dict.
7575*/
7576#define XML_TREE_ADOPT_STR(str) \
7577 if (adoptStr && (str != NULL)) { \
7578 if (destDoc->dict) { \
7579 const xmlChar *old = str; \
7580 str = xmlDictLookup(destDoc->dict, str, -1); \
7581 if ((sourceDoc == NULL) || (sourceDoc->dict == NULL) || \
7582 (!xmlDictOwns(sourceDoc->dict, old))) \
7583 xmlFree((char *)old); \
7584 } else if ((sourceDoc) && (sourceDoc->dict) && \
7585 xmlDictOwns(sourceDoc->dict, str)) { \
7586 str = BAD_CAST xmlStrdup(str); \
7587 } \
7588 }
7589
7590/*
7591* XML_TREE_ADOPT_STR_2: If @str was in the source-dict, then
7592* put it in dest-dict or copy it.
7593*/
7594#define XML_TREE_ADOPT_STR_2(str) \
7595 if (adoptStr && (str != NULL) && (sourceDoc != NULL) && \
7596 (sourceDoc->dict != NULL) && \
7597 xmlDictOwns(sourceDoc->dict, cur->content)) { \
7598 if (destDoc->dict) \
7599 cur->content = (xmlChar *) \
7600 xmlDictLookup(destDoc->dict, cur->content, -1); \
7601 else \
7602 cur->content = xmlStrdup(BAD_CAST cur->content); \
7603 }
7604
7605/*
7606* xmlDOMWrapNSNormAddNsMapItem2:
7607*
7608* For internal use. Adds a ns-decl mapping.
7609*
7610* Returns 0 on success, -1 on internal errors.
7611*/
7612static int
7613xmlDOMWrapNSNormAddNsMapItem2(xmlNsPtr **list, int *size, int *number,
7614 xmlNsPtr oldNs, xmlNsPtr newNs)
7615{
7616 if (*list == NULL) {
7617 *list = (xmlNsPtr *) xmlMalloc(6 * sizeof(xmlNsPtr));
7618 if (*list == NULL) {
7619 xmlTreeErrMemory("alloc ns map item");
7620 return(-1);
7621 }
7622 *size = 3;
7623 *number = 0;
7624 } else if ((*number) >= (*size)) {
7625 *size *= 2;
7626 *list = (xmlNsPtr *) xmlRealloc(*list,
7627 (*size) * 2 * sizeof(xmlNsPtr));
7628 if (*list == NULL) {
7629 xmlTreeErrMemory("realloc ns map item");
7630 return(-1);
7631 }
7632 }
7633 (*list)[2 * (*number)] = oldNs;
7634 (*list)[2 * (*number) +1] = newNs;
7635 (*number)++;
7636 return (0);
7637}
7638
7639/*
7640* xmlDOMWrapRemoveNode:
7641* @ctxt: a DOM wrapper context
7642* @doc: the doc
7643* @node: the node to be removed.
7644* @options: set of options, unused at the moment
7645*
7646* Unlinks the given node from its owner.
7647* This will substitute ns-references to node->nsDef for
7648* ns-references to doc->oldNs, thus ensuring the removed
7649* branch to be autark wrt ns-references.
7650*
7651* NOTE: This function was not intensively tested.
7652*
7653* Returns 0 on success, 1 if the node is not supported,
7654* -1 on API and internal errors.
7655*/
7656int
7657xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc,
7658 xmlNodePtr node, int options ATTRIBUTE_UNUSED)
7659{
7660 xmlNsPtr *list = NULL;
7661 int sizeList, nbList, i, j;
7662 xmlNsPtr ns;
7663
7664 if ((node == NULL) || (doc == NULL) || (node->doc != doc))
7665 return (-1);
7666
7667 /* TODO: 0 or -1 ? */
7668 if (node->parent == NULL)
7669 return (0);
7670
7671 switch (node->type) {
7672 case XML_TEXT_NODE:
7673 case XML_CDATA_SECTION_NODE:
7674 case XML_ENTITY_REF_NODE:
7675 case XML_PI_NODE:
7676 case XML_COMMENT_NODE:
7677 xmlUnlinkNode(node);
7678 return (0);
7679 case XML_ELEMENT_NODE:
7680 case XML_ATTRIBUTE_NODE:
7681 break;
7682 default:
7683 return (1);
7684 }
7685 xmlUnlinkNode(node);
7686 /*
7687 * Save out-of-scope ns-references in doc->oldNs.
7688 */
7689 do {
7690 switch (node->type) {
7691 case XML_ELEMENT_NODE:
7692 if ((ctxt == NULL) && (node->nsDef != NULL)) {
7693 ns = node->nsDef;
7694 do {
7695 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
7696 &nbList, ns, ns) == -1)
7697 goto internal_error;
7698 ns = ns->next;
7699 } while (ns != NULL);
7700 }
7701 /* No break on purpose. */
7702 case XML_ATTRIBUTE_NODE:
7703 if (node->ns != NULL) {
7704 /*
7705 * Find a mapping.
7706 */
7707 if (list != NULL) {
7708 for (i = 0, j = 0; i < nbList; i++, j += 2) {
7709 if (node->ns == list[j]) {
7710 node->ns = list[++j];
7711 goto next_node;
7712 }
7713 }
7714 }
7715 ns = NULL;
7716 if (ctxt != NULL) {
7717 /*
7718 * User defined.
7719 */
7720 } else {
7721 /*
7722 * Add to doc's oldNs.
7723 */
7724 ns = xmlDOMWrapStoreNs(doc, node->ns->href,
7725 node->ns->prefix);
7726 if (ns == NULL)
7727 goto internal_error;
7728 }
7729 if (ns != NULL) {
7730 /*
7731 * Add mapping.
7732 */
7733 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
7734 &nbList, node->ns, ns) == -1)
7735 goto internal_error;
7736 }
7737 node->ns = ns;
7738 }
7739 if ((node->type == XML_ELEMENT_NODE) &&
7740 (node->properties != NULL)) {
7741 node = (xmlNodePtr) node->properties;
7742 continue;
7743 }
7744 break;
7745 default:
7746 goto next_sibling;
7747 }
7748next_node:
7749 if ((node->type == XML_ELEMENT_NODE) &&
7750 (node->children != NULL)) {
7751 node = node->children;
7752 continue;
7753 }
7754next_sibling:
7755 if (node == NULL)
7756 break;
7757 if (node->next != NULL)
7758 node = node->next;
7759 else {
7760 node = node->parent;
7761 goto next_sibling;
7762 }
7763 } while (node != NULL);
7764
7765 if (list != NULL)
7766 xmlFree(list);
7767 return (0);
7768
7769internal_error:
7770 if (list != NULL)
7771 xmlFree(list);
7772 return (-1);
7773}
7774
7775/*
7776* xmlSearchNsByNamespaceStrict:
7777* @doc: the document
7778* @node: the start node
7779* @nsName: the searched namespace name
7780* @retNs: the resulting ns-decl
7781* @prefixed: if the found ns-decl must have a prefix (for attributes)
7782*
7783* Dynamically searches for a ns-declaration which matches
7784* the given @nsName in the ancestor-or-self axis of @node.
7785*
7786* Returns 1 if a ns-decl was found, 0 if not and -1 on API
7787* and internal errors.
7788*/
7789static int
7790xmlSearchNsByNamespaceStrict(xmlDocPtr doc, xmlNodePtr node,
7791 const xmlChar* nsName,
7792 xmlNsPtr *retNs, int prefixed)
7793{
7794 xmlNodePtr cur, prev = NULL, out = NULL;
7795 xmlNsPtr ns, prevns;
7796
7797 if ((doc == NULL) || (nsName == NULL) || (retNs == NULL))
7798 return (-1);
7799
7800 *retNs = NULL;
7801 if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) {
7802 *retNs = xmlTreeEnsureXMLDecl(doc);
7803 if (*retNs == NULL)
7804 return (-1);
7805 return (1);
7806 }
7807 cur = node;
7808 do {
7809 if (cur->type == XML_ELEMENT_NODE) {
7810 if (cur->nsDef != NULL) {
7811 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
7812 if (prefixed && (ns->prefix == NULL))
7813 continue;
7814 if (prev != NULL) {
7815 /*
7816 * Check the last level of ns-decls for a
7817 * shadowing prefix.
7818 */
7819 prevns = prev->nsDef;
7820 do {
7821 if ((prevns->prefix == ns->prefix) ||
7822 ((prevns->prefix != NULL) &&
7823 (ns->prefix != NULL) &&
7824 xmlStrEqual(prevns->prefix, ns->prefix))) {
7825 /*
7826 * Shadowed.
7827 */
7828 break;
7829 }
7830 prevns = prevns->next;
7831 } while (prevns != NULL);
7832 if (prevns != NULL)
7833 continue;
7834 }
7835 /*
7836 * Ns-name comparison.
7837 */
7838 if ((nsName == ns->href) ||
7839 xmlStrEqual(nsName, ns->href)) {
7840 /*
7841 * At this point the prefix can only be shadowed,
7842 * if we are the the (at least) 3rd level of
7843 * ns-decls.
7844 */
7845 if (out) {
7846 int ret;
7847
7848 ret = xmlNsInScope(doc, node, prev, ns->prefix);
7849 if (ret < 0)
7850 return (-1);
7851 /*
7852 * TODO: Should we try to find a matching ns-name
7853 * only once? This here keeps on searching.
7854 * I think we should try further since, there might
7855 * be an other matching ns-decl with an unshadowed
7856 * prefix.
7857 */
7858 if (! ret)
7859 continue;
7860 }
7861 *retNs = ns;
7862 return (1);
7863 }
7864 }
7865 out = prev;
7866 prev = cur;
7867 }
7868 } else if ((cur->type == XML_ENTITY_NODE) ||
7869 (cur->type == XML_ENTITY_DECL))
7870 return (0);
7871 cur = cur->parent;
7872 } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
7873 return (0);
7874}
7875
7876/*
7877* xmlSearchNsByPrefixStrict:
7878* @doc: the document
7879* @node: the start node
7880* @prefix: the searched namespace prefix
7881* @retNs: the resulting ns-decl
7882*
7883* Dynamically searches for a ns-declaration which matches
7884* the given @nsName in the ancestor-or-self axis of @node.
7885*
7886* Returns 1 if a ns-decl was found, 0 if not and -1 on API
7887* and internal errors.
7888*/
7889static int
7890xmlSearchNsByPrefixStrict(xmlDocPtr doc, xmlNodePtr node,
7891 const xmlChar* prefix,
7892 xmlNsPtr *retNs)
7893{
7894 xmlNodePtr cur;
7895 xmlNsPtr ns;
7896
7897 if ((doc == NULL) || (node == NULL))
7898 return (-1);
7899
7900 if (retNs)
7901 *retNs = NULL;
7902 if (IS_STR_XML(prefix)) {
7903 if (retNs) {
7904 *retNs = xmlTreeEnsureXMLDecl(doc);
7905 if (*retNs == NULL)
7906 return (-1);
7907 }
7908 return (1);
7909 }
7910 cur = node;
7911 do {
7912 if (cur->type == XML_ELEMENT_NODE) {
7913 if (cur->nsDef != NULL) {
7914 ns = cur->nsDef;
7915 do {
7916 if ((prefix == ns->prefix) ||
7917 xmlStrEqual(prefix, ns->prefix))
7918 {
7919 /*
7920 * Disabled namespaces, e.g. xmlns:abc="".
7921 */
7922 if (ns->href == NULL)
7923 return(0);
7924 if (retNs)
7925 *retNs = ns;
7926 return (1);
7927 }
7928 ns = ns->next;
7929 } while (ns != NULL);
7930 }
7931 } else if ((cur->type == XML_ENTITY_NODE) ||
7932 (cur->type == XML_ENTITY_DECL))
7933 return (0);
7934 cur = cur->parent;
7935 } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
7936 return (0);
7937}
7938
7939/*
7940* xmlDOMWrapNSNormDeclareNsForced:
7941* @doc: the doc
7942* @elem: the element-node to declare on
7943* @nsName: the namespace-name of the ns-decl
7944* @prefix: the preferred prefix of the ns-decl
7945* @checkShadow: ensure that the new ns-decl doesn't shadow ancestor ns-decls
7946*
7947* Declares a new namespace on @elem. It tries to use the
7948* given @prefix; if a ns-decl with the given prefix is already existent
7949* on @elem, it will generate an other prefix.
7950*
7951* Returns 1 if a ns-decl was found, 0 if not and -1 on API
7952* and internal errors.
7953*/
7954static xmlNsPtr
7955xmlDOMWrapNSNormDeclareNsForced(xmlDocPtr doc,
7956 xmlNodePtr elem,
7957 const xmlChar *nsName,
7958 const xmlChar *prefix,
7959 int checkShadow)
7960{
7961
7962 xmlNsPtr ret;
7963 char buf[50];
7964 const xmlChar *pref;
7965 int counter = 0;
7966 /*
7967 * Create a ns-decl on @anchor.
7968 */
7969 pref = prefix;
7970 while (1) {
7971 /*
7972 * Lookup whether the prefix is unused in elem's ns-decls.
7973 */
7974 if ((elem->nsDef != NULL) &&
7975 (xmlTreeNSListLookupByPrefix(elem->nsDef, pref) != NULL))
7976 goto ns_next_prefix;
7977 if (checkShadow && elem->parent &&
7978 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
7979 /*
7980 * Does it shadow ancestor ns-decls?
7981 */
7982 if (xmlSearchNsByPrefixStrict(doc, elem->parent, pref, NULL) == 1)
7983 goto ns_next_prefix;
7984 }
7985 ret = xmlNewNs(NULL, nsName, pref);
7986 if (ret == NULL)
7987 return (NULL);
7988 if (elem->nsDef == NULL)
7989 elem->nsDef = ret;
7990 else {
7991 xmlNsPtr ns2 = elem->nsDef;
7992 while (ns2->next != NULL)
7993 ns2 = ns2->next;
7994 ns2->next = ret;
7995 }
7996 return (ret);
7997ns_next_prefix:
7998 counter++;
7999 if (counter > 1000)
8000 return (NULL);
8001 if (prefix == NULL) {
8002 snprintf((char *) buf, sizeof(buf),
8003 "ns_%d", counter);
8004 } else
8005 snprintf((char *) buf, sizeof(buf),
8006 "%.30s_%d", (char *)prefix, counter);
8007 pref = BAD_CAST buf;
8008 }
8009}
8010
8011/*
8012* xmlDOMWrapNSNormAquireNormalizedNs:
8013* @doc: the doc
8014* @elem: the element-node to declare namespaces on
8015* @ns: the ns-struct to use for the search
8016* @retNs: the found/created ns-struct
8017* @nsMap: the ns-map
8018* @depth: the current tree depth
8019* @ancestorsOnly: search in ancestor ns-decls only
8020* @prefixed: if the searched ns-decl must have a prefix (for attributes)
8021*
8022* Searches for a matching ns-name in the ns-decls of @nsMap, if not
8023* found it will either declare it on @elem, or store it in doc->oldNs.
8024* If a new ns-decl needs to be declared on @elem, it tries to use the
8025* @ns->prefix for it, if this prefix is already in use on @elem, it will
8026* change the prefix or the new ns-decl.
8027*
8028* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8029*/
8030static int
8031xmlDOMWrapNSNormAquireNormalizedNs(xmlDocPtr doc,
8032 xmlNodePtr elem,
8033 xmlNsPtr ns,
8034 xmlNsPtr *retNs,
8035 xmlNsMapPtr *nsMap,
8036
8037 int depth,
8038 int ancestorsOnly,
8039 int prefixed)
8040{
8041 xmlNsMapItemPtr mi;
8042
8043 if ((doc == NULL) || (ns == NULL) || (retNs == NULL) ||
8044 (nsMap == NULL))
8045 return (-1);
8046
8047 *retNs = NULL;
8048 /*
8049 * Handle XML namespace.
8050 */
8051 if (IS_STR_XML(ns->prefix)) {
8052 /*
8053 * Insert XML namespace mapping.
8054 */
8055 *retNs = xmlTreeEnsureXMLDecl(doc);
8056 if (*retNs == NULL)
8057 return (-1);
8058 return (0);
8059 }
8060 /*
8061 * If the search should be done in ancestors only and no
8062 * @elem (the first ancestor) was specified, then skip the search.
8063 */
8064 if ((XML_NSMAP_NOTEMPTY(*nsMap)) &&
8065 (! (ancestorsOnly && (elem == NULL))))
8066 {
8067 /*
8068 * Try to find an equal ns-name in in-scope ns-decls.
8069 */
8070 XML_NSMAP_FOREACH(*nsMap, mi) {
8071 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8072 /*
8073 * ancestorsOnly: This should be turned on to gain speed,
8074 * if one knows that the branch itself was already
8075 * ns-wellformed and no stale references existed.
8076 * I.e. it searches in the ancestor axis only.
8077 */
8078 ((! ancestorsOnly) || (mi->depth == XML_TREE_NSMAP_PARENT)) &&
8079 /* Skip shadowed prefixes. */
8080 (mi->shadowDepth == -1) &&
8081 /* Skip xmlns="" or xmlns:foo="". */
8082 ((mi->newNs->href != NULL) &&
8083 (mi->newNs->href[0] != 0)) &&
8084 /* Ensure a prefix if wanted. */
8085 ((! prefixed) || (mi->newNs->prefix != NULL)) &&
8086 /* Equal ns name */
8087 ((mi->newNs->href == ns->href) ||
8088 xmlStrEqual(mi->newNs->href, ns->href))) {
8089 /* Set the mapping. */
8090 mi->oldNs = ns;
8091 *retNs = mi->newNs;
8092 return (0);
8093 }
8094 }
8095 }
8096 /*
8097 * No luck, the namespace is out of scope or shadowed.
8098 */
8099 if (elem == NULL) {
8100 xmlNsPtr tmpns;
8101
8102 /*
8103 * Store ns-decls in "oldNs" of the document-node.
8104 */
8105 tmpns = xmlDOMWrapStoreNs(doc, ns->href, ns->prefix);
8106 if (tmpns == NULL)
8107 return (-1);
8108 /*
8109 * Insert mapping.
8110 */
8111 if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns,
8112 tmpns, XML_TREE_NSMAP_DOC) == NULL) {
8113 xmlFreeNs(tmpns);
8114 return (-1);
8115 }
8116 *retNs = tmpns;
8117 } else {
8118 xmlNsPtr tmpns;
8119
8120 tmpns = xmlDOMWrapNSNormDeclareNsForced(doc, elem, ns->href,
8121 ns->prefix, 0);
8122 if (tmpns == NULL)
8123 return (-1);
8124
8125 if (*nsMap != NULL) {
8126 /*
8127 * Does it shadow ancestor ns-decls?
8128 */
8129 XML_NSMAP_FOREACH(*nsMap, mi) {
8130 if ((mi->depth < depth) &&
8131 (mi->shadowDepth == -1) &&
8132 ((ns->prefix == mi->newNs->prefix) ||
8133 xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
8134 /*
8135 * Shadows.
8136 */
8137 mi->shadowDepth = depth;
8138 break;
8139 }
8140 }
8141 }
8142 if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns, tmpns, depth) == NULL) {
8143 xmlFreeNs(tmpns);
8144 return (-1);
8145 }
8146 *retNs = tmpns;
8147 }
8148 return (0);
8149}
8150
8151typedef enum {
8152 XML_DOM_RECONNS_REMOVEREDUND = 1<<0
8153} xmlDOMReconcileNSOptions;
8154
8155/*
8156* xmlDOMWrapReconcileNamespaces:
8157* @ctxt: DOM wrapper context, unused at the moment
8158* @elem: the element-node
8159* @options: option flags
8160*
8161* Ensures that ns-references point to ns-decls hold on element-nodes.
8162* Ensures that the tree is namespace wellformed by creating additional
8163* ns-decls where needed. Note that, since prefixes of already existent
8164* ns-decls can be shadowed by this process, it could break QNames in
8165* attribute values or element content.
8166*
8167* NOTE: This function was not intensively tested.
8168*
8169* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8170*/
8171
8172int
8173xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED,
8174 xmlNodePtr elem,
8175 int options)
8176{
8177 int depth = -1, adoptns = 0, parnsdone = 0;
8178 xmlNsPtr ns, prevns;
8179 xmlDocPtr doc;
8180 xmlNodePtr cur, curElem = NULL;
8181 xmlNsMapPtr nsMap = NULL;
8182 xmlNsMapItemPtr /* topmi = NULL, */ mi;
8183 /* @ancestorsOnly should be set by an option flag. */
8184 int ancestorsOnly = 0;
8185 int optRemoveRedundantNS =
8186 ((xmlDOMReconcileNSOptions) options & XML_DOM_RECONNS_REMOVEREDUND) ? 1 : 0;
8187 xmlNsPtr *listRedund = NULL;
8188 int sizeRedund = 0, nbRedund = 0, ret, i, j;
8189
8190 if ((elem == NULL) || (elem->doc == NULL) ||
8191 (elem->type != XML_ELEMENT_NODE))
8192 return (-1);
8193
8194 doc = elem->doc;
8195 cur = elem;
8196 do {
8197 switch (cur->type) {
8198 case XML_ELEMENT_NODE:
8199 adoptns = 1;
8200 curElem = cur;
8201 depth++;
8202 /*
8203 * Namespace declarations.
8204 */
8205 if (cur->nsDef != NULL) {
8206 prevns = NULL;
8207 ns = cur->nsDef;
8208 while (ns != NULL) {
8209 if (! parnsdone) {
8210 if ((elem->parent) &&
8211 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8212 /*
8213 * Gather ancestor in-scope ns-decls.
8214 */
8215 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8216 elem->parent) == -1)
8217 goto internal_error;
8218 }
8219 parnsdone = 1;
8220 }
8221
8222 /*
8223 * Lookup the ns ancestor-axis for equal ns-decls in scope.
8224 */
8225 if (optRemoveRedundantNS && XML_NSMAP_NOTEMPTY(nsMap)) {
8226 XML_NSMAP_FOREACH(nsMap, mi) {
8227 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8228 (mi->shadowDepth == -1) &&
8229 ((ns->prefix == mi->newNs->prefix) ||
8230 xmlStrEqual(ns->prefix, mi->newNs->prefix)) &&
8231 ((ns->href == mi->newNs->href) ||
8232 xmlStrEqual(ns->href, mi->newNs->href)))
8233 {
8234 /*
8235 * A redundant ns-decl was found.
8236 * Add it to the list of redundant ns-decls.
8237 */
8238 if (xmlDOMWrapNSNormAddNsMapItem2(&listRedund,
8239 &sizeRedund, &nbRedund, ns, mi->newNs) == -1)
8240 goto internal_error;
8241 /*
8242 * Remove the ns-decl from the element-node.
8243 */
8244 if (prevns)
8245 prevns->next = ns->next;
8246 else
8247 cur->nsDef = ns->next;
8248 goto next_ns_decl;
8249 }
8250 }
8251 }
8252
8253 /*
8254 * Skip ns-references handling if the referenced
8255 * ns-decl is declared on the same element.
8256 */
8257 if ((cur->ns != NULL) && adoptns && (cur->ns == ns))
8258 adoptns = 0;
8259 /*
8260 * Does it shadow any ns-decl?
8261 */
8262 if (XML_NSMAP_NOTEMPTY(nsMap)) {
8263 XML_NSMAP_FOREACH(nsMap, mi) {
8264 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8265 (mi->shadowDepth == -1) &&
8266 ((ns->prefix == mi->newNs->prefix) ||
8267 xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
8268
8269 mi->shadowDepth = depth;
8270 }
8271 }
8272 }
8273 /*
8274 * Push mapping.
8275 */
8276 if (xmlDOMWrapNsMapAddItem(&nsMap, -1, ns, ns,
8277 depth) == NULL)
8278 goto internal_error;
8279
8280 prevns = ns;
8281next_ns_decl:
8282 ns = ns->next;
8283 }
8284 }
8285 if (! adoptns)
8286 goto ns_end;
8287 /* No break on purpose. */
8288 case XML_ATTRIBUTE_NODE:
8289 /* No ns, no fun. */
8290 if (cur->ns == NULL)
8291 goto ns_end;
8292
8293 if (! parnsdone) {
8294 if ((elem->parent) &&
8295 ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8296 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8297 elem->parent) == -1)
8298 goto internal_error;
8299 }
8300 parnsdone = 1;
8301 }
8302 /*
8303 * Adjust the reference if this was a redundant ns-decl.
8304 */
8305 if (listRedund) {
8306 for (i = 0, j = 0; i < nbRedund; i++, j += 2) {
8307 if (cur->ns == listRedund[j]) {
8308 cur->ns = listRedund[++j];
8309 break;
8310 }
8311 }
8312 }
8313 /*
8314 * Adopt ns-references.
8315 */
8316 if (XML_NSMAP_NOTEMPTY(nsMap)) {
8317 /*
8318 * Search for a mapping.
8319 */
8320 XML_NSMAP_FOREACH(nsMap, mi) {
8321 if ((mi->shadowDepth == -1) &&
8322 (cur->ns == mi->oldNs)) {
8323
8324 cur->ns = mi->newNs;
8325 goto ns_end;
8326 }
8327 }
8328 }
8329 /*
8330 * Aquire a normalized ns-decl and add it to the map.
8331 */
8332 if (xmlDOMWrapNSNormAquireNormalizedNs(doc, curElem,
8333 cur->ns, &ns,
8334 &nsMap, depth,
8335 ancestorsOnly,
8336 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
8337 goto internal_error;
8338 cur->ns = ns;
8339
8340ns_end:
8341 if ((cur->type == XML_ELEMENT_NODE) &&
8342 (cur->properties != NULL)) {
8343 /*
8344 * Process attributes.
8345 */
8346 cur = (xmlNodePtr) cur->properties;
8347 continue;
8348 }
8349 break;
8350 default:
8351 goto next_sibling;
8352 }
8353into_content:
8354 if ((cur->type == XML_ELEMENT_NODE) &&
8355 (cur->children != NULL)) {
8356 /*
8357 * Process content of element-nodes only.
8358 */
8359 cur = cur->children;
8360 continue;
8361 }
8362next_sibling:
8363 if (cur == elem)
8364 break;
8365 if (cur->type == XML_ELEMENT_NODE) {
8366 if (XML_NSMAP_NOTEMPTY(nsMap)) {
8367 /*
8368 * Pop mappings.
8369 */
8370 while ((nsMap->last != NULL) &&
8371 (nsMap->last->depth >= depth))
8372 {
8373 XML_NSMAP_POP(nsMap, mi)
8374 }
8375 /*
8376 * Unshadow.
8377 */
8378 XML_NSMAP_FOREACH(nsMap, mi) {
8379 if (mi->shadowDepth >= depth)
8380 mi->shadowDepth = -1;
8381 }
8382 }
8383 depth--;
8384 }
8385 if (cur->next != NULL)
8386 cur = cur->next;
8387 else {
8388 if (cur->type == XML_ATTRIBUTE_NODE) {
8389 cur = cur->parent;
8390 goto into_content;
8391 }
8392 cur = cur->parent;
8393 goto next_sibling;
8394 }
8395 } while (cur != NULL);
8396
8397 ret = 0;
8398 goto exit;
8399internal_error:
8400 ret = -1;
8401exit:
8402 if (listRedund) {
8403 for (i = 0, j = 0; i < nbRedund; i++, j += 2) {
8404 xmlFreeNs(listRedund[j]);
8405 }
8406 xmlFree(listRedund);
8407 }
8408 if (nsMap != NULL)
8409 xmlDOMWrapNsMapFree(nsMap);
8410 return (ret);
8411}
8412
8413/*
8414* xmlDOMWrapAdoptBranch:
8415* @ctxt: the optional context for custom processing
8416* @sourceDoc: the optional sourceDoc
8417* @node: the element-node to start with
8418* @destDoc: the destination doc for adoption
8419* @destParent: the optional new parent of @node in @destDoc
8420* @options: option flags
8421*
8422* Ensures that ns-references point to @destDoc: either to
8423* elements->nsDef entries if @destParent is given, or to
8424* @destDoc->oldNs otherwise.
8425* If @destParent is given, it ensures that the tree is namespace
8426* wellformed by creating additional ns-decls where needed.
8427* Note that, since prefixes of already existent ns-decls can be
8428* shadowed by this process, it could break QNames in attribute
8429* values or element content.
8430*
8431* NOTE: This function was not intensively tested.
8432*
8433* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8434*/
8435static int
8436xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt,
8437 xmlDocPtr sourceDoc,
8438 xmlNodePtr node,
8439 xmlDocPtr destDoc,
8440 xmlNodePtr destParent,
8441 int options ATTRIBUTE_UNUSED)
8442{
8443 int ret = 0;
8444 xmlNodePtr cur, curElem = NULL;
8445 xmlNsMapPtr nsMap = NULL;
8446 xmlNsMapItemPtr mi;
8447 xmlNsPtr ns = NULL;
8448 int depth = -1, adoptStr = 1;
8449 /* gather @parent's ns-decls. */
8450 int parnsdone;
8451 /* @ancestorsOnly should be set per option. */
8452 int ancestorsOnly = 0;
8453
8454 /*
8455 * Optimize string adoption for equal or none dicts.
8456 */
8457 if ((sourceDoc != NULL) &&
8458 (sourceDoc->dict == destDoc->dict))
8459 adoptStr = 0;
8460 else
8461 adoptStr = 1;
8462
8463 /*
8464 * Get the ns-map from the context if available.
8465 */
8466 if (ctxt)
8467 nsMap = (xmlNsMapPtr) ctxt->namespaceMap;
8468 /*
8469 * Disable search for ns-decls in the parent-axis of the
8470 * desination element, if:
8471 * 1) there's no destination parent
8472 * 2) custom ns-reference handling is used
8473 */
8474 if ((destParent == NULL) ||
8475 (ctxt && ctxt->getNsForNodeFunc))
8476 {
8477 parnsdone = 1;
8478 } else
8479 parnsdone = 0;
8480
8481 cur = node;
8482 while (cur != NULL) {
8483 /*
8484 * Paranoid source-doc sanity check.
8485 */
8486 if (cur->doc != sourceDoc) {
8487 /*
8488 * We'll assume XIncluded nodes if the doc differs.
8489 * TODO: Do we need to reconciliate XIncluded nodes?
8490 * This here skips XIncluded nodes and tries to handle
8491 * broken sequences.
8492 */
8493 if (cur->next == NULL)
8494 goto leave_node;
8495 do {
8496 cur = cur->next;
8497 if ((cur->type == XML_XINCLUDE_END) ||
8498 (cur->doc == node->doc))
8499 break;
8500 } while (cur->next != NULL);
8501
8502 if (cur->doc != node->doc)
8503 goto leave_node;
8504 }
8505 cur->doc = destDoc;
8506 switch (cur->type) {
8507 case XML_XINCLUDE_START:
8508 case XML_XINCLUDE_END:
8509 /*
8510 * TODO
8511 */
8512 return (-1);
8513 case XML_ELEMENT_NODE:
8514 curElem = cur;
8515 depth++;
8516 /*
8517 * Namespace declarations.
8518 * - ns->href and ns->prefix are never in the dict, so
8519 * we need not move the values over to the destination dict.
8520 * - Note that for custom handling of ns-references,
8521 * the ns-decls need not be stored in the ns-map,
8522 * since they won't be referenced by node->ns.
8523 */
8524 if ((cur->nsDef) &&
8525 ((ctxt == NULL) || (ctxt->getNsForNodeFunc == NULL)))
8526 {
8527 if (! parnsdone) {
8528 /*
8529 * Gather @parent's in-scope ns-decls.
8530 */
8531 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8532 destParent) == -1)
8533 goto internal_error;
8534 parnsdone = 1;
8535 }
8536 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
8537 /*
8538 * NOTE: ns->prefix and ns->href are never in the dict.
8539 * XML_TREE_ADOPT_STR(ns->prefix)
8540 * XML_TREE_ADOPT_STR(ns->href)
8541 */
8542 /*
8543 * Does it shadow any ns-decl?
8544 */
8545 if (XML_NSMAP_NOTEMPTY(nsMap)) {
8546 XML_NSMAP_FOREACH(nsMap, mi) {
8547 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8548 (mi->shadowDepth == -1) &&
8549 ((ns->prefix == mi->newNs->prefix) ||
8550 xmlStrEqual(ns->prefix,
8551 mi->newNs->prefix))) {
8552
8553 mi->shadowDepth = depth;
8554 }
8555 }
8556 }
8557 /*
8558 * Push mapping.
8559 */
8560 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
8561 ns, ns, depth) == NULL)
8562 goto internal_error;
8563 }
8564 }
8565 /* No break on purpose. */
8566 case XML_ATTRIBUTE_NODE:
8567 /* No namespace, no fun. */
8568 if (cur->ns == NULL)
8569 goto ns_end;
8570
8571 if (! parnsdone) {
8572 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8573 destParent) == -1)
8574 goto internal_error;
8575 parnsdone = 1;
8576 }
8577 /*
8578 * Adopt ns-references.
8579 */
8580 if (XML_NSMAP_NOTEMPTY(nsMap)) {
8581 /*
8582 * Search for a mapping.
8583 */
8584 XML_NSMAP_FOREACH(nsMap, mi) {
8585 if ((mi->shadowDepth == -1) &&
8586 (cur->ns == mi->oldNs)) {
8587
8588 cur->ns = mi->newNs;
8589 goto ns_end;
8590 }
8591 }
8592 }
8593 /*
8594 * No matching namespace in scope. We need a new one.
8595 */
8596 if ((ctxt) && (ctxt->getNsForNodeFunc)) {
8597 /*
8598 * User-defined behaviour.
8599 */
8600 ns = ctxt->getNsForNodeFunc(ctxt, cur,
8601 cur->ns->href, cur->ns->prefix);
8602 /*
8603 * Insert mapping if ns is available; it's the users fault
8604 * if not.
8605 */
8606 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
8607 cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
8608 goto internal_error;
8609 cur->ns = ns;
8610 } else {
8611 /*
8612 * Aquire a normalized ns-decl and add it to the map.
8613 */
8614 if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc,
8615 /* ns-decls on curElem or on destDoc->oldNs */
8616 destParent ? curElem : NULL,
8617 cur->ns, &ns,
8618 &nsMap, depth,
8619 ancestorsOnly,
8620 /* ns-decls must be prefixed for attributes. */
8621 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
8622 goto internal_error;
8623 cur->ns = ns;
8624 }
8625ns_end:
8626 /*
8627 * Further node properties.
8628 * TODO: Is this all?
8629 */
8630 XML_TREE_ADOPT_STR(cur->name)
8631 if (cur->type == XML_ELEMENT_NODE) {
8632 cur->psvi = NULL;
8633 cur->line = 0;
8634 cur->extra = 0;
8635 /*
8636 * Walk attributes.
8637 */
8638 if (cur->properties != NULL) {
8639 /*
8640 * Process first attribute node.
8641 */
8642 cur = (xmlNodePtr) cur->properties;
8643 continue;
8644 }
8645 } else {
8646 /*
8647 * Attributes.
8648 */
8649 if ((sourceDoc != NULL) &&
8650 (((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID))
8651 {
8652 xmlRemoveID(sourceDoc, (xmlAttrPtr) cur);
8653 }
8654 ((xmlAttrPtr) cur)->atype = 0;
8655 ((xmlAttrPtr) cur)->psvi = NULL;
8656 }
8657 break;
8658 case XML_TEXT_NODE:
8659 case XML_CDATA_SECTION_NODE:
8660 /*
8661 * This puts the content in the dest dict, only if
8662 * it was previously in the source dict.
8663 */
8664 XML_TREE_ADOPT_STR_2(cur->content)
8665 goto leave_node;
8666 case XML_ENTITY_REF_NODE:
8667 /*
8668 * Remove reference to the entitity-node.
8669 */
8670 cur->content = NULL;
8671 cur->children = NULL;
8672 cur->last = NULL;
8673 if ((destDoc->intSubset) || (destDoc->extSubset)) {
8674 xmlEntityPtr ent;
8675 /*
8676 * Assign new entity-node if available.
8677 */
8678 ent = xmlGetDocEntity(destDoc, cur->name);
8679 if (ent != NULL) {
8680 cur->content = ent->content;
8681 cur->children = (xmlNodePtr) ent;
8682 cur->last = (xmlNodePtr) ent;
8683 }
8684 }
8685 goto leave_node;
8686 case XML_PI_NODE:
8687 XML_TREE_ADOPT_STR(cur->name)
8688 XML_TREE_ADOPT_STR_2(cur->content)
8689 break;
8690 case XML_COMMENT_NODE:
8691 break;
8692 default:
8693 goto internal_error;
8694 }
8695 /*
8696 * Walk the tree.
8697 */
8698 if (cur->children != NULL) {
8699 cur = cur->children;
8700 continue;
8701 }
8702
8703leave_node:
8704 if (cur == node)
8705 break;
8706 if ((cur->type == XML_ELEMENT_NODE) ||
8707 (cur->type == XML_XINCLUDE_START) ||
8708 (cur->type == XML_XINCLUDE_END))
8709 {
8710 /*
8711 * TODO: Do we expect nsDefs on XML_XINCLUDE_START?
8712 */
8713 if (XML_NSMAP_NOTEMPTY(nsMap)) {
8714 /*
8715 * Pop mappings.
8716 */
8717 while ((nsMap->last != NULL) &&
8718 (nsMap->last->depth >= depth))
8719 {
8720 XML_NSMAP_POP(nsMap, mi)
8721 }
8722 /*
8723 * Unshadow.
8724 */
8725 XML_NSMAP_FOREACH(nsMap, mi) {
8726 if (mi->shadowDepth >= depth)
8727 mi->shadowDepth = -1;
8728 }
8729 }
8730 depth--;
8731 }
8732 if (cur->next != NULL)
8733 cur = cur->next;
8734 else if ((cur->type == XML_ATTRIBUTE_NODE) &&
8735 (cur->parent->children != NULL))
8736 {
8737 cur = cur->parent->children;
8738 } else {
8739 cur = cur->parent;
8740 goto leave_node;
8741 }
8742 }
8743
8744 goto exit;
8745
8746internal_error:
8747 ret = -1;
8748
8749exit:
8750 /*
8751 * Cleanup.
8752 */
8753 if (nsMap != NULL) {
8754 if ((ctxt) && (ctxt->namespaceMap == nsMap)) {
8755 /*
8756 * Just cleanup the map but don't free.
8757 */
8758 if (nsMap->first) {
8759 if (nsMap->pool)
8760 nsMap->last->next = nsMap->pool;
8761 nsMap->pool = nsMap->first;
8762 nsMap->first = NULL;
8763 }
8764 } else
8765 xmlDOMWrapNsMapFree(nsMap);
8766 }
8767 return(ret);
8768}
8769
8770/*
8771* xmlDOMWrapCloneNode:
8772* @ctxt: the optional context for custom processing
8773* @sourceDoc: the optional sourceDoc
8774* @node: the node to start with
8775* @resNode: the clone of the given @node
8776* @destDoc: the destination doc
8777* @destParent: the optional new parent of @node in @destDoc
8778* @deep: descend into child if set
8779* @options: option flags
8780*
8781* References of out-of scope ns-decls are remapped to point to @destDoc:
8782* 1) If @destParent is given, then nsDef entries on element-nodes are used
8783* 2) If *no* @destParent is given, then @destDoc->oldNs entries are used.
8784* This is the case when you don't know already where the cloned branch
8785* will be added to.
8786*
8787* If @destParent is given, it ensures that the tree is namespace
8788* wellformed by creating additional ns-decls where needed.
8789* Note that, since prefixes of already existent ns-decls can be
8790* shadowed by this process, it could break QNames in attribute
8791* values or element content.
8792* TODO:
8793* 1) What to do with XInclude? Currently this returns an error for XInclude.
8794*
8795* Returns 0 if the operation succeeded,
8796* 1 if a node of unsupported (or not yet supported) type was given,
8797* -1 on API/internal errors.
8798*/
8799
8800int
8801xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt,
8802 xmlDocPtr sourceDoc,
8803 xmlNodePtr node,
8804 xmlNodePtr *resNode,
8805 xmlDocPtr destDoc,
8806 xmlNodePtr destParent,
8807 int deep,
8808 int options ATTRIBUTE_UNUSED)
8809{
8810 int ret = 0;
8811 xmlNodePtr cur, curElem = NULL;
8812 xmlNsMapPtr nsMap = NULL;
8813 xmlNsMapItemPtr mi;
8814 xmlNsPtr ns;
8815 int depth = -1;
8816 /* int adoptStr = 1; */
8817 /* gather @parent's ns-decls. */
8818 int parnsdone = 0;
8819 /*
8820 * @ancestorsOnly:
8821 * TODO: @ancestorsOnly should be set per option.
8822 *
8823 */
8824 int ancestorsOnly = 0;
8825 xmlNodePtr resultClone = NULL, clone = NULL, parentClone = NULL, prevClone = NULL;
8826 xmlNsPtr cloneNs = NULL, *cloneNsDefSlot = NULL;
8827 xmlDictPtr dict; /* The destination dict */
8828
8829 if ((node == NULL) || (resNode == NULL) || (destDoc == NULL))
8830 return(-1);
8831 /*
8832 * TODO: Initially we support only element-nodes.
8833 */
8834 if (node->type != XML_ELEMENT_NODE)
8835 return(1);
8836 /*
8837 * Check node->doc sanity.
8838 */
8839 if ((node->doc != NULL) && (sourceDoc != NULL) &&
8840 (node->doc != sourceDoc)) {
8841 /*
8842 * Might be an XIncluded node.
8843 */
8844 return (-1);
8845 }
8846 if (sourceDoc == NULL)
8847 sourceDoc = node->doc;
8848 if (sourceDoc == NULL)
8849 return (-1);
8850
8851 dict = destDoc->dict;
8852 /*
8853 * Reuse the namespace map of the context.
8854 */
8855 if (ctxt)
8856 nsMap = (xmlNsMapPtr) ctxt->namespaceMap;
8857
8858 *resNode = NULL;
8859
8860 cur = node;
8861 while (cur != NULL) {
8862 if (cur->doc != sourceDoc) {
8863 /*
8864 * We'll assume XIncluded nodes if the doc differs.
8865 * TODO: Do we need to reconciliate XIncluded nodes?
8866 * TODO: This here returns -1 in this case.
8867 */
8868 goto internal_error;
8869 }
8870 /*
8871 * Create a new node.
8872 */
8873 switch (cur->type) {
8874 case XML_XINCLUDE_START:
8875 case XML_XINCLUDE_END:
8876 /*
8877 * TODO: What to do with XInclude?
8878 */
8879 goto internal_error;
8880 break;
8881 case XML_ELEMENT_NODE:
8882 case XML_TEXT_NODE:
8883 case XML_CDATA_SECTION_NODE:
8884 case XML_COMMENT_NODE:
8885 case XML_PI_NODE:
8886 case XML_DOCUMENT_FRAG_NODE:
8887 case XML_ENTITY_REF_NODE:
8888 case XML_ENTITY_NODE:
8889 /*
8890 * Nodes of xmlNode structure.
8891 */
8892 clone = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
8893 if (clone == NULL) {
8894 xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating a node");
8895 goto internal_error;
8896 }
8897 memset(clone, 0, sizeof(xmlNode));
8898 /*
8899 * Set hierachical links.
8900 */
8901 if (resultClone != NULL) {
8902 clone->parent = parentClone;
8903 if (prevClone) {
8904 prevClone->next = clone;
8905 clone->prev = prevClone;
8906 } else
8907 parentClone->children = clone;
8908 } else
8909 resultClone = clone;
8910
8911 break;
8912 case XML_ATTRIBUTE_NODE:
8913 /*
8914 * Attributes (xmlAttr).
8915 */
8916 clone = (xmlNodePtr) xmlMalloc(sizeof(xmlAttr));
8917 if (clone == NULL) {
8918 xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating an attr-node");
8919 goto internal_error;
8920 }
8921 memset(clone, 0, sizeof(xmlAttr));
8922 /*
8923 * Set hierachical links.
8924 * TODO: Change this to add to the end of attributes.
8925 */
8926 if (resultClone != NULL) {
8927 clone->parent = parentClone;
8928 if (prevClone) {
8929 prevClone->next = clone;
8930 clone->prev = prevClone;
8931 } else
8932 parentClone->properties = (xmlAttrPtr) clone;
8933 } else
8934 resultClone = clone;
8935 break;
8936 default:
8937 /*
8938 * TODO QUESTION: Any other nodes expected?
8939 */
8940 goto internal_error;
8941 }
8942
8943 clone->type = cur->type;
8944 clone->doc = destDoc;
8945
8946 /*
8947 * Clone the name of the node if any.
8948 */
8949 if (cur->name == xmlStringText)
8950 clone->name = xmlStringText;
8951 else if (cur->name == xmlStringTextNoenc)
8952 /*
8953 * NOTE: Although xmlStringTextNoenc is never assigned to a node
8954 * in tree.c, it might be set in Libxslt via
8955 * "xsl:disable-output-escaping".
8956 */
8957 clone->name = xmlStringTextNoenc;
8958 else if (cur->name == xmlStringComment)
8959 clone->name = xmlStringComment;
8960 else if (cur->name != NULL) {
8961 DICT_CONST_COPY(cur->name, clone->name);
8962 }
8963
8964 switch (cur->type) {
8965 case XML_XINCLUDE_START:
8966 case XML_XINCLUDE_END:
8967 /*
8968 * TODO
8969 */
8970 return (-1);
8971 case XML_ELEMENT_NODE:
8972 curElem = cur;
8973 depth++;
8974 /*
8975 * Namespace declarations.
8976 */
8977 if (cur->nsDef != NULL) {
8978 if (! parnsdone) {
8979 if (destParent && (ctxt == NULL)) {
8980 /*
8981 * Gather @parent's in-scope ns-decls.
8982 */
8983 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8984 destParent) == -1)
8985 goto internal_error;
8986 }
8987 parnsdone = 1;
8988 }
8989 /*
8990 * Clone namespace declarations.
8991 */
8992 cloneNsDefSlot = &(clone->nsDef);
8993 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
8994 /*
8995 * Create a new xmlNs.
8996 */
8997 cloneNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
8998 if (cloneNs == NULL) {
8999 xmlTreeErrMemory("xmlDOMWrapCloneNode(): "
9000 "allocating namespace");
9001 return(-1);
9002 }
9003 memset(cloneNs, 0, sizeof(xmlNs));
9004 cloneNs->type = XML_LOCAL_NAMESPACE;
9005
9006 if (ns->href != NULL)
9007 cloneNs->href = xmlStrdup(ns->href);
9008 if (ns->prefix != NULL)
9009 cloneNs->prefix = xmlStrdup(ns->prefix);
9010
9011 *cloneNsDefSlot = cloneNs;
9012 cloneNsDefSlot = &(cloneNs->next);
9013
9014 /*
9015 * Note that for custom handling of ns-references,
9016 * the ns-decls need not be stored in the ns-map,
9017 * since they won't be referenced by node->ns.
9018 */
9019 if ((ctxt == NULL) ||
9020 (ctxt->getNsForNodeFunc == NULL))
9021 {
9022 /*
9023 * Does it shadow any ns-decl?
9024 */
9025 if (XML_NSMAP_NOTEMPTY(nsMap)) {
9026 XML_NSMAP_FOREACH(nsMap, mi) {
9027 if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
9028 (mi->shadowDepth == -1) &&
9029 ((ns->prefix == mi->newNs->prefix) ||
9030 xmlStrEqual(ns->prefix,
9031 mi->newNs->prefix))) {
9032 /*
9033 * Mark as shadowed at the current
9034 * depth.
9035 */
9036 mi->shadowDepth = depth;
9037 }
9038 }
9039 }
9040 /*
9041 * Push mapping.
9042 */
9043 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
9044 ns, cloneNs, depth) == NULL)
9045 goto internal_error;
9046 }
9047 }
9048 }
9049 /* cur->ns will be processed further down. */
9050 break;
9051 case XML_ATTRIBUTE_NODE:
9052 /* IDs will be processed further down. */
9053 /* cur->ns will be processed further down. */
9054 break;
9055 case XML_TEXT_NODE:
9056 case XML_CDATA_SECTION_NODE:
9057 /*
9058 * Note that this will also cover the values of attributes.
9059 */
9060 DICT_COPY(cur->content, clone->content);
9061 goto leave_node;
9062 case XML_ENTITY_NODE:
9063 /* TODO: What to do here? */
9064 goto leave_node;
9065 case XML_ENTITY_REF_NODE:
9066 if (sourceDoc != destDoc) {
9067 if ((destDoc->intSubset) || (destDoc->extSubset)) {
9068 xmlEntityPtr ent;
9069 /*
9070 * Different doc: Assign new entity-node if available.
9071 */
9072 ent = xmlGetDocEntity(destDoc, cur->name);
9073 if (ent != NULL) {
9074 clone->content = ent->content;
9075 clone->children = (xmlNodePtr) ent;
9076 clone->last = (xmlNodePtr) ent;
9077 }
9078 }
9079 } else {
9080 /*
9081 * Same doc: Use the current node's entity declaration
9082 * and value.
9083 */
9084 clone->content = cur->content;
9085 clone->children = cur->children;
9086 clone->last = cur->last;
9087 }
9088 goto leave_node;
9089 case XML_PI_NODE:
9090 DICT_COPY(cur->content, clone->content);
9091 goto leave_node;
9092 case XML_COMMENT_NODE:
9093 DICT_COPY(cur->content, clone->content);
9094 goto leave_node;
9095 default:
9096 goto internal_error;
9097 }
9098
9099 if (cur->ns == NULL)
9100 goto end_ns_reference;
9101
9102/* handle_ns_reference: */
9103 /*
9104 ** The following will take care of references to ns-decls ********
9105 ** and is intended only for element- and attribute-nodes.
9106 **
9107 */
9108 if (! parnsdone) {
9109 if (destParent && (ctxt == NULL)) {
9110 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, destParent) == -1)
9111 goto internal_error;
9112 }
9113 parnsdone = 1;
9114 }
9115 /*
9116 * Adopt ns-references.
9117 */
9118 if (XML_NSMAP_NOTEMPTY(nsMap)) {
9119 /*
9120 * Search for a mapping.
9121 */
9122 XML_NSMAP_FOREACH(nsMap, mi) {
9123 if ((mi->shadowDepth == -1) &&
9124 (cur->ns == mi->oldNs)) {
9125 /*
9126 * This is the nice case: a mapping was found.
9127 */
9128 clone->ns = mi->newNs;
9129 goto end_ns_reference;
9130 }
9131 }
9132 }
9133 /*
9134 * No matching namespace in scope. We need a new one.
9135 */
9136 if ((ctxt != NULL) && (ctxt->getNsForNodeFunc != NULL)) {
9137 /*
9138 * User-defined behaviour.
9139 */
9140 ns = ctxt->getNsForNodeFunc(ctxt, cur,
9141 cur->ns->href, cur->ns->prefix);
9142 /*
9143 * Add user's mapping.
9144 */
9145 if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
9146 cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
9147 goto internal_error;
9148 clone->ns = ns;
9149 } else {
9150 /*
9151 * Aquire a normalized ns-decl and add it to the map.
9152 */
9153 if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc,
9154 /* ns-decls on curElem or on destDoc->oldNs */
9155 destParent ? curElem : NULL,
9156 cur->ns, &ns,
9157 &nsMap, depth,
9158 /* if we need to search only in the ancestor-axis */
9159 ancestorsOnly,
9160 /* ns-decls must be prefixed for attributes. */
9161 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
9162 goto internal_error;
9163 clone->ns = ns;
9164 }
9165
9166end_ns_reference:
9167
9168 /*
9169 * Some post-processing.
9170 *
9171 * Handle ID attributes.
9172 */
9173 if ((clone->type == XML_ATTRIBUTE_NODE) &&
9174 (clone->parent != NULL))
9175 {
9176 if (xmlIsID(destDoc, clone->parent, (xmlAttrPtr) clone)) {
9177
9178 xmlChar *idVal;
9179
9180 idVal = xmlNodeListGetString(cur->doc, cur->children, 1);
9181 if (idVal != NULL) {
9182 if (xmlAddID(NULL, destDoc, idVal, (xmlAttrPtr) cur) == NULL) {
9183 /* TODO: error message. */
9184 xmlFree(idVal);
9185 goto internal_error;
9186 }
9187 xmlFree(idVal);
9188 }
9189 }
9190 }
9191 /*
9192 **
9193 ** The following will traverse the tree **************************
9194 **
9195 *
9196 * Walk the element's attributes before descending into child-nodes.
9197 */
9198 if ((cur->type == XML_ELEMENT_NODE) && (cur->properties != NULL)) {
9199 prevClone = NULL;
9200 parentClone = clone;
9201 cur = (xmlNodePtr) cur->properties;
9202 continue;
9203 }
9204into_content:
9205 /*
9206 * Descend into child-nodes.
9207 */
9208 if (cur->children != NULL) {
9209 if (deep || (cur->type == XML_ATTRIBUTE_NODE)) {
9210 prevClone = NULL;
9211 parentClone = clone;
9212 cur = cur->children;
9213 continue;
9214 }
9215 }
9216
9217leave_node:
9218 /*
9219 * At this point we are done with the node, its content
9220 * and an element-nodes's attribute-nodes.
9221 */
9222 if (cur == node)
9223 break;
9224 if ((cur->type == XML_ELEMENT_NODE) ||
9225 (cur->type == XML_XINCLUDE_START) ||
9226 (cur->type == XML_XINCLUDE_END)) {
9227 /*
9228 * TODO: Do we expect nsDefs on XML_XINCLUDE_START?
9229 */
9230 if (XML_NSMAP_NOTEMPTY(nsMap)) {
9231 /*
9232 * Pop mappings.
9233 */
9234 while ((nsMap->last != NULL) &&
9235 (nsMap->last->depth >= depth))
9236 {
9237 XML_NSMAP_POP(nsMap, mi)
9238 }
9239 /*
9240 * Unshadow.
9241 */
9242 XML_NSMAP_FOREACH(nsMap, mi) {
9243 if (mi->shadowDepth >= depth)
9244 mi->shadowDepth = -1;
9245 }
9246 }
9247 depth--;
9248 }
9249 if (cur->next != NULL) {
9250 prevClone = clone;
9251 cur = cur->next;
9252 } else if (cur->type != XML_ATTRIBUTE_NODE) {
9253 /*
9254 * Set clone->last.
9255 */
9256 if (clone->parent != NULL)
9257 clone->parent->last = clone;
9258 clone = clone->parent;
9259 parentClone = clone->parent;
9260 /*
9261 * Process parent --> next;
9262 */
9263 cur = cur->parent;
9264 goto leave_node;
9265 } else {
9266 /* This is for attributes only. */
9267 clone = clone->parent;
9268 parentClone = clone->parent;
9269 /*
9270 * Process parent-element --> children.
9271 */
9272 cur = cur->parent;
9273 goto into_content;
9274 }
9275 }
9276 goto exit;
9277
9278internal_error:
9279 ret = -1;
9280
9281exit:
9282 /*
9283 * Cleanup.
9284 */
9285 if (nsMap != NULL) {
9286 if ((ctxt) && (ctxt->namespaceMap == nsMap)) {
9287 /*
9288 * Just cleanup the map but don't free.
9289 */
9290 if (nsMap->first) {
9291 if (nsMap->pool)
9292 nsMap->last->next = nsMap->pool;
9293 nsMap->pool = nsMap->first;
9294 nsMap->first = NULL;
9295 }
9296 } else
9297 xmlDOMWrapNsMapFree(nsMap);
9298 }
9299 /*
9300 * TODO: Should we try a cleanup of the cloned node in case of a
9301 * fatal error?
9302 */
9303 *resNode = resultClone;
9304 return (ret);
9305}
9306
9307/*
9308* xmlDOMWrapAdoptAttr:
9309* @ctxt: the optional context for custom processing
9310* @sourceDoc: the optional source document of attr
9311* @attr: the attribute-node to be adopted
9312* @destDoc: the destination doc for adoption
9313* @destParent: the optional new parent of @attr in @destDoc
9314* @options: option flags
9315*
9316* @attr is adopted by @destDoc.
9317* Ensures that ns-references point to @destDoc: either to
9318* elements->nsDef entries if @destParent is given, or to
9319* @destDoc->oldNs otherwise.
9320*
9321* Returns 0 if succeeded, -1 otherwise and on API/internal errors.
9322*/
9323static int
9324xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt,
9325 xmlDocPtr sourceDoc,
9326 xmlAttrPtr attr,
9327 xmlDocPtr destDoc,
9328 xmlNodePtr destParent,
9329 int options ATTRIBUTE_UNUSED)
9330{
9331 xmlNodePtr cur;
9332 int adoptStr = 1;
9333
9334 if ((attr == NULL) || (destDoc == NULL))
9335 return (-1);
9336
9337 attr->doc = destDoc;
9338 if (attr->ns != NULL) {
9339 xmlNsPtr ns = NULL;
9340
9341 if (ctxt != NULL) {
9342 /* TODO: User defined. */
9343 }
9344 /* XML Namespace. */
9345 if (IS_STR_XML(attr->ns->prefix)) {
9346 ns = xmlTreeEnsureXMLDecl(destDoc);
9347 } else if (destParent == NULL) {
9348 /*
9349 * Store in @destDoc->oldNs.
9350 */
9351 ns = xmlDOMWrapStoreNs(destDoc, attr->ns->href, attr->ns->prefix);
9352 } else {
9353 /*
9354 * Declare on @destParent.
9355 */
9356 if (xmlSearchNsByNamespaceStrict(destDoc, destParent, attr->ns->href,
9357 &ns, 1) == -1)
9358 goto internal_error;
9359 if (ns == NULL) {
9360 ns = xmlDOMWrapNSNormDeclareNsForced(destDoc, destParent,
9361 attr->ns->href, attr->ns->prefix, 1);
9362 }
9363 }
9364 if (ns == NULL)
9365 goto internal_error;
9366 attr->ns = ns;
9367 }
9368
9369 XML_TREE_ADOPT_STR(attr->name);
9370 attr->atype = 0;
9371 attr->psvi = NULL;
9372 /*
9373 * Walk content.
9374 */
9375 if (attr->children == NULL)
9376 return (0);
9377 cur = attr->children;
9378 while (cur != NULL) {
9379 cur->doc = destDoc;
9380 switch (cur->type) {
9381 case XML_TEXT_NODE:
9382 case XML_CDATA_SECTION_NODE:
9383 XML_TREE_ADOPT_STR_2(cur->content)
9384 break;
9385 case XML_ENTITY_REF_NODE:
9386 /*
9387 * Remove reference to the entitity-node.
9388 */
9389 cur->content = NULL;
9390 cur->children = NULL;
9391 cur->last = NULL;
9392 if ((destDoc->intSubset) || (destDoc->extSubset)) {
9393 xmlEntityPtr ent;
9394 /*
9395 * Assign new entity-node if available.
9396 */
9397 ent = xmlGetDocEntity(destDoc, cur->name);
9398 if (ent != NULL) {
9399 cur->content = ent->content;
9400 cur->children = (xmlNodePtr) ent;
9401 cur->last = (xmlNodePtr) ent;
9402 }
9403 }
9404 break;
9405 default:
9406 break;
9407 }
9408 if (cur->children != NULL) {
9409 cur = cur->children;
9410 continue;
9411 }
9412next_sibling:
9413 if (cur == (xmlNodePtr) attr)
9414 break;
9415 if (cur->next != NULL)
9416 cur = cur->next;
9417 else {
9418 cur = cur->parent;
9419 goto next_sibling;
9420 }
9421 }
9422 return (0);
9423internal_error:
9424 return (-1);
9425}
9426
9427/*
9428* xmlDOMWrapAdoptNode:
9429* @ctxt: the optional context for custom processing
9430* @sourceDoc: the optional sourceDoc
9431* @node: the node to start with
9432* @destDoc: the destination doc
9433* @destParent: the optional new parent of @node in @destDoc
9434* @options: option flags
9435*
9436* References of out-of scope ns-decls are remapped to point to @destDoc:
9437* 1) If @destParent is given, then nsDef entries on element-nodes are used
9438* 2) If *no* @destParent is given, then @destDoc->oldNs entries are used
9439* This is the case when you have an unliked node and just want to move it
9440* to the context of
9441*
9442* If @destParent is given, it ensures that the tree is namespace
9443* wellformed by creating additional ns-decls where needed.
9444* Note that, since prefixes of already existent ns-decls can be
9445* shadowed by this process, it could break QNames in attribute
9446* values or element content.
9447* NOTE: This function was not intensively tested.
9448*
9449* Returns 0 if the operation succeeded,
9450* 1 if a node of unsupported type was given,
9451* 2 if a node of not yet supported type was given and
9452* -1 on API/internal errors.
9453*/
9454int
9455xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt,
9456 xmlDocPtr sourceDoc,
9457 xmlNodePtr node,
9458 xmlDocPtr destDoc,
9459 xmlNodePtr destParent,
9460 int options)
9461{
9462 if ((node == NULL) || (destDoc == NULL) ||
9463 ((destParent != NULL) && (destParent->doc != destDoc)))
9464 return(-1);
9465 /*
9466 * Check node->doc sanity.
9467 */
9468 if ((node->doc != NULL) && (sourceDoc != NULL) &&
9469 (node->doc != sourceDoc)) {
9470 /*
9471 * Might be an XIncluded node.
9472 */
9473 return (-1);
9474 }
9475 if (sourceDoc == NULL)
9476 sourceDoc = node->doc;
9477 if (sourceDoc == destDoc)
9478 return (-1);
9479 switch (node->type) {
9480 case XML_ELEMENT_NODE:
9481 case XML_ATTRIBUTE_NODE:
9482 case XML_TEXT_NODE:
9483 case XML_CDATA_SECTION_NODE:
9484 case XML_ENTITY_REF_NODE:
9485 case XML_PI_NODE:
9486 case XML_COMMENT_NODE:
9487 break;
9488 case XML_DOCUMENT_FRAG_NODE:
9489 /* TODO: Support document-fragment-nodes. */
9490 return (2);
9491 default:
9492 return (1);
9493 }
9494 /*
9495 * Unlink only if @node was not already added to @destParent.
9496 */
9497 if ((node->parent != NULL) && (destParent != node->parent))
9498 xmlUnlinkNode(node);
9499
9500 if (node->type == XML_ELEMENT_NODE) {
9501 return (xmlDOMWrapAdoptBranch(ctxt, sourceDoc, node,
9502 destDoc, destParent, options));
9503 } else if (node->type == XML_ATTRIBUTE_NODE) {
9504 return (xmlDOMWrapAdoptAttr(ctxt, sourceDoc,
9505 (xmlAttrPtr) node, destDoc, destParent, options));
9506 } else {
9507 xmlNodePtr cur = node;
9508 int adoptStr = 1;
9509
9510 cur->doc = destDoc;
9511 /*
9512 * Optimize string adoption.
9513 */
9514 if ((sourceDoc != NULL) &&
9515 (sourceDoc->dict == destDoc->dict))
9516 adoptStr = 0;
9517 switch (node->type) {
9518 case XML_TEXT_NODE:
9519 case XML_CDATA_SECTION_NODE:
9520 XML_TREE_ADOPT_STR_2(node->content)
9521 break;
9522 case XML_ENTITY_REF_NODE:
9523 /*
9524 * Remove reference to the entitity-node.
9525 */
9526 node->content = NULL;
9527 node->children = NULL;
9528 node->last = NULL;
9529 if ((destDoc->intSubset) || (destDoc->extSubset)) {
9530 xmlEntityPtr ent;
9531 /*
9532 * Assign new entity-node if available.
9533 */
9534 ent = xmlGetDocEntity(destDoc, node->name);
9535 if (ent != NULL) {
9536 node->content = ent->content;
9537 node->children = (xmlNodePtr) ent;
9538 node->last = (xmlNodePtr) ent;
9539 }
9540 }
9541 XML_TREE_ADOPT_STR(node->name)
9542 break;
9543 case XML_PI_NODE: {
9544 XML_TREE_ADOPT_STR(node->name)
9545 XML_TREE_ADOPT_STR_2(node->content)
9546 break;
9547 }
9548 default:
9549 break;
9550 }
9551 }
9552 return (0);
9553}
9554
9555#define bottom_tree
9556#include "elfgcchack.h"
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette