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