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