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