Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygentree.c
Go to the documentation of this file.
00001 /* 00002 * tree.c : implementation of access function for an XML tree. 00003 * 00004 * References: 00005 * XHTML 1.0 W3C REC: http://www.w3.org/TR/2002/REC-xhtml1-20020801/ 00006 * 00007 * See Copyright for the status of this software. 00008 * 00009 * daniel@veillard.com 00010 * 00011 */ 00012 00013 #define IN_LIBXML 00014 #include "libxml.h" 00015 00016 #include <string.h> /* for memset() only ! */ 00017 #include <limits.h> 00018 #ifdef HAVE_CTYPE_H 00019 #include <ctype.h> 00020 #endif 00021 #ifdef HAVE_STDLIB_H 00022 #include <stdlib.h> 00023 #endif 00024 #ifdef HAVE_ZLIB_H 00025 #include <zlib.h> 00026 #endif 00027 00028 #include <libxml/xmlmemory.h> 00029 #include <libxml/tree.h> 00030 #include <libxml/parser.h> 00031 #include <libxml/uri.h> 00032 #include <libxml/entities.h> 00033 #include <libxml/valid.h> 00034 #include <libxml/xmlerror.h> 00035 #include <libxml/parserInternals.h> 00036 #include <libxml/globals.h> 00037 #ifdef LIBXML_HTML_ENABLED 00038 #include <libxml/HTMLtree.h> 00039 #endif 00040 #ifdef LIBXML_DEBUG_ENABLED 00041 #include <libxml/debugXML.h> 00042 #endif 00043 00044 int __xmlRegisterCallbacks = 0; 00045 00046 /************************************************************************ 00047 * * 00048 * Forward declarations * 00049 * * 00050 ************************************************************************/ 00051 00052 static xmlNsPtr 00053 xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns); 00054 00055 static xmlChar* xmlGetPropNodeValueInternal(xmlAttrPtr prop); 00056 00057 /************************************************************************ 00058 * * 00059 * Tree memory error handler * 00060 * * 00061 ************************************************************************/ 00068 static void 00069 xmlTreeErrMemory(const char *extra) 00070 { 00071 __xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra); 00072 } 00073 00081 static void 00082 xmlTreeErr(int code, xmlNodePtr node, const char *extra) 00083 { 00084 const char *msg = NULL; 00085 00086 switch(code) { 00087 case XML_TREE_INVALID_HEX: 00088 msg = "invalid hexadecimal character value\n"; 00089 break; 00090 case XML_TREE_INVALID_DEC: 00091 msg = "invalid decimal character value\n"; 00092 break; 00093 case XML_TREE_UNTERMINATED_ENTITY: 00094 msg = "unterminated entity reference %15s\n"; 00095 break; 00096 case XML_TREE_NOT_UTF8: 00097 msg = "string is not in UTF-8\n"; 00098 break; 00099 default: 00100 msg = "unexpected error number\n"; 00101 } 00102 __xmlSimpleError(XML_FROM_TREE, code, node, msg, extra); 00103 } 00104 00105 /************************************************************************ 00106 * * 00107 * A few static variables and macros * 00108 * * 00109 ************************************************************************/ 00110 /* #undef xmlStringText */ 00111 const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 }; 00112 /* #undef xmlStringTextNoenc */ 00113 const xmlChar xmlStringTextNoenc[] = 00114 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 }; 00115 /* #undef xmlStringComment */ 00116 const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 }; 00117 00118 static int xmlCompressMode = 0; 00119 static int xmlCheckDTD = 1; 00120 00121 #define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \ 00122 xmlNodePtr ulccur = (n)->children; \ 00123 if (ulccur == NULL) { \ 00124 (n)->last = NULL; \ 00125 } else { \ 00126 while (ulccur->next != NULL) { \ 00127 ulccur->parent = (n); \ 00128 ulccur = ulccur->next; \ 00129 } \ 00130 ulccur->parent = (n); \ 00131 (n)->last = ulccur; \ 00132 }} 00133 00134 #define IS_STR_XML(str) ((str != NULL) && (str[0] == 'x') && \ 00135 (str[1] == 'm') && (str[2] == 'l') && (str[3] == 0)) 00136 00137 /* #define DEBUG_BUFFER */ 00138 /* #define DEBUG_TREE */ 00139 00140 /************************************************************************ 00141 * * 00142 * Functions to move to entities.c once the * 00143 * API freeze is smoothen and they can be made public. * 00144 * * 00145 ************************************************************************/ 00146 #include <libxml/hash.h> 00147 00148 #ifdef LIBXML_TREE_ENABLED 00149 00159 static xmlEntityPtr 00160 xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) { 00161 xmlEntitiesTablePtr table; 00162 00163 if((dtd != NULL) && (dtd->entities != NULL)) { 00164 table = (xmlEntitiesTablePtr) dtd->entities; 00165 return((xmlEntityPtr) xmlHashLookup(table, name)); 00166 /* return(xmlGetEntityFromTable(table, name)); */ 00167 } 00168 return(NULL); 00169 } 00180 static xmlEntityPtr 00181 xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) { 00182 xmlEntitiesTablePtr table; 00183 00184 if ((dtd != NULL) && (dtd->pentities != NULL)) { 00185 table = (xmlEntitiesTablePtr) dtd->pentities; 00186 return((xmlEntityPtr) xmlHashLookup(table, name)); 00187 /* return(xmlGetEntityFromTable(table, name)); */ 00188 } 00189 return(NULL); 00190 } 00191 #endif /* LIBXML_TREE_ENABLED */ 00192 00193 /************************************************************************ 00194 * * 00195 * QName handling helper * 00196 * * 00197 ************************************************************************/ 00198 00213 xmlChar * 00214 xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix, 00215 xmlChar *memory, int len) { 00216 int lenn, lenp; 00217 xmlChar *ret; 00218 00219 if (ncname == NULL) return(NULL); 00220 if (prefix == NULL) return((xmlChar *) ncname); 00221 00222 lenn = strlen((char *) ncname); 00223 lenp = strlen((char *) prefix); 00224 00225 if ((memory == NULL) || (len < lenn + lenp + 2)) { 00226 ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2); 00227 if (ret == NULL) { 00228 xmlTreeErrMemory("building QName"); 00229 return(NULL); 00230 } 00231 } else { 00232 ret = memory; 00233 } 00234 memcpy(&ret[0], prefix, lenp); 00235 ret[lenp] = ':'; 00236 memcpy(&ret[lenp + 1], ncname, lenn); 00237 ret[lenn + lenp + 1] = 0; 00238 return(ret); 00239 } 00240 00258 xmlChar * 00259 xmlSplitQName2(const xmlChar *name, xmlChar **prefix) { 00260 int len = 0; 00261 xmlChar *ret = NULL; 00262 00263 if (prefix == NULL) return(NULL); 00264 *prefix = NULL; 00265 if (name == NULL) return(NULL); 00266 00267 #ifndef XML_XML_NAMESPACE 00268 /* xml: prefix is not really a namespace */ 00269 if ((name[0] == 'x') && (name[1] == 'm') && 00270 (name[2] == 'l') && (name[3] == ':')) 00271 return(NULL); 00272 #endif 00273 00274 /* nasty but valid */ 00275 if (name[0] == ':') 00276 return(NULL); 00277 00278 /* 00279 * we are not trying to validate but just to cut, and yes it will 00280 * work even if this is as set of UTF-8 encoded chars 00281 */ 00282 while ((name[len] != 0) && (name[len] != ':')) 00283 len++; 00284 00285 if (name[len] == 0) 00286 return(NULL); 00287 00288 *prefix = xmlStrndup(name, len); 00289 if (*prefix == NULL) { 00290 xmlTreeErrMemory("QName split"); 00291 return(NULL); 00292 } 00293 ret = xmlStrdup(&name[len + 1]); 00294 if (ret == NULL) { 00295 xmlTreeErrMemory("QName split"); 00296 if (*prefix != NULL) { 00297 xmlFree(*prefix); 00298 *prefix = NULL; 00299 } 00300 return(NULL); 00301 } 00302 00303 return(ret); 00304 } 00305 00318 const xmlChar * 00319 xmlSplitQName3(const xmlChar *name, int *len) { 00320 int l = 0; 00321 00322 if (name == NULL) return(NULL); 00323 if (len == NULL) return(NULL); 00324 00325 /* nasty but valid */ 00326 if (name[0] == ':') 00327 return(NULL); 00328 00329 /* 00330 * we are not trying to validate but just to cut, and yes it will 00331 * work even if this is as set of UTF-8 encoded chars 00332 */ 00333 while ((name[l] != 0) && (name[l] != ':')) 00334 l++; 00335 00336 if (name[l] == 0) 00337 return(NULL); 00338 00339 *len = l; 00340 00341 return(&name[l+1]); 00342 } 00343 00344 /************************************************************************ 00345 * * 00346 * Check Name, NCName and QName strings * 00347 * * 00348 ************************************************************************/ 00349 00350 #define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l) 00351 00352 #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) 00353 00363 int 00364 xmlValidateNCName(const xmlChar *value, int space) { 00365 const xmlChar *cur = value; 00366 int c,l; 00367 00368 if (value == NULL) 00369 return(-1); 00370 00371 /* 00372 * First quick algorithm for ASCII range 00373 */ 00374 if (space) 00375 while (IS_BLANK_CH(*cur)) cur++; 00376 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) || 00377 (*cur == '_')) 00378 cur++; 00379 else 00380 goto try_complex; 00381 while (((*cur >= 'a') && (*cur <= 'z')) || 00382 ((*cur >= 'A') && (*cur <= 'Z')) || 00383 ((*cur >= '0') && (*cur <= '9')) || 00384 (*cur == '_') || (*cur == '-') || (*cur == '.')) 00385 cur++; 00386 if (space) 00387 while (IS_BLANK_CH(*cur)) cur++; 00388 if (*cur == 0) 00389 return(0); 00390 00391 try_complex: 00392 /* 00393 * Second check for chars outside the ASCII range 00394 */ 00395 cur = value; 00396 c = CUR_SCHAR(cur, l); 00397 if (space) { 00398 while (IS_BLANK(c)) { 00399 cur += l; 00400 c = CUR_SCHAR(cur, l); 00401 } 00402 } 00403 if ((!IS_LETTER(c)) && (c != '_')) 00404 return(1); 00405 cur += l; 00406 c = CUR_SCHAR(cur, l); 00407 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || 00408 (c == '-') || (c == '_') || IS_COMBINING(c) || 00409 IS_EXTENDER(c)) { 00410 cur += l; 00411 c = CUR_SCHAR(cur, l); 00412 } 00413 if (space) { 00414 while (IS_BLANK(c)) { 00415 cur += l; 00416 c = CUR_SCHAR(cur, l); 00417 } 00418 } 00419 if (c != 0) 00420 return(1); 00421 00422 return(0); 00423 } 00424 #endif 00425 00426 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) 00427 00437 int 00438 xmlValidateQName(const xmlChar *value, int space) { 00439 const xmlChar *cur = value; 00440 int c,l; 00441 00442 if (value == NULL) 00443 return(-1); 00444 /* 00445 * First quick algorithm for ASCII range 00446 */ 00447 if (space) 00448 while (IS_BLANK_CH(*cur)) cur++; 00449 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) || 00450 (*cur == '_')) 00451 cur++; 00452 else 00453 goto try_complex; 00454 while (((*cur >= 'a') && (*cur <= 'z')) || 00455 ((*cur >= 'A') && (*cur <= 'Z')) || 00456 ((*cur >= '0') && (*cur <= '9')) || 00457 (*cur == '_') || (*cur == '-') || (*cur == '.')) 00458 cur++; 00459 if (*cur == ':') { 00460 cur++; 00461 if (((*cur >= 'a') && (*cur <= 'z')) || 00462 ((*cur >= 'A') && (*cur <= 'Z')) || 00463 (*cur == '_')) 00464 cur++; 00465 else 00466 goto try_complex; 00467 while (((*cur >= 'a') && (*cur <= 'z')) || 00468 ((*cur >= 'A') && (*cur <= 'Z')) || 00469 ((*cur >= '0') && (*cur <= '9')) || 00470 (*cur == '_') || (*cur == '-') || (*cur == '.')) 00471 cur++; 00472 } 00473 if (space) 00474 while (IS_BLANK_CH(*cur)) cur++; 00475 if (*cur == 0) 00476 return(0); 00477 00478 try_complex: 00479 /* 00480 * Second check for chars outside the ASCII range 00481 */ 00482 cur = value; 00483 c = CUR_SCHAR(cur, l); 00484 if (space) { 00485 while (IS_BLANK(c)) { 00486 cur += l; 00487 c = CUR_SCHAR(cur, l); 00488 } 00489 } 00490 if ((!IS_LETTER(c)) && (c != '_')) 00491 return(1); 00492 cur += l; 00493 c = CUR_SCHAR(cur, l); 00494 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || 00495 (c == '-') || (c == '_') || IS_COMBINING(c) || 00496 IS_EXTENDER(c)) { 00497 cur += l; 00498 c = CUR_SCHAR(cur, l); 00499 } 00500 if (c == ':') { 00501 cur += l; 00502 c = CUR_SCHAR(cur, l); 00503 if ((!IS_LETTER(c)) && (c != '_')) 00504 return(1); 00505 cur += l; 00506 c = CUR_SCHAR(cur, l); 00507 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || 00508 (c == '-') || (c == '_') || IS_COMBINING(c) || 00509 IS_EXTENDER(c)) { 00510 cur += l; 00511 c = CUR_SCHAR(cur, l); 00512 } 00513 } 00514 if (space) { 00515 while (IS_BLANK(c)) { 00516 cur += l; 00517 c = CUR_SCHAR(cur, l); 00518 } 00519 } 00520 if (c != 0) 00521 return(1); 00522 return(0); 00523 } 00524 00535 int 00536 xmlValidateName(const xmlChar *value, int space) { 00537 const xmlChar *cur = value; 00538 int c,l; 00539 00540 if (value == NULL) 00541 return(-1); 00542 /* 00543 * First quick algorithm for ASCII range 00544 */ 00545 if (space) 00546 while (IS_BLANK_CH(*cur)) cur++; 00547 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) || 00548 (*cur == '_') || (*cur == ':')) 00549 cur++; 00550 else 00551 goto try_complex; 00552 while (((*cur >= 'a') && (*cur <= 'z')) || 00553 ((*cur >= 'A') && (*cur <= 'Z')) || 00554 ((*cur >= '0') && (*cur <= '9')) || 00555 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':')) 00556 cur++; 00557 if (space) 00558 while (IS_BLANK_CH(*cur)) cur++; 00559 if (*cur == 0) 00560 return(0); 00561 00562 try_complex: 00563 /* 00564 * Second check for chars outside the ASCII range 00565 */ 00566 cur = value; 00567 c = CUR_SCHAR(cur, l); 00568 if (space) { 00569 while (IS_BLANK(c)) { 00570 cur += l; 00571 c = CUR_SCHAR(cur, l); 00572 } 00573 } 00574 if ((!IS_LETTER(c)) && (c != '_') && (c != ':')) 00575 return(1); 00576 cur += l; 00577 c = CUR_SCHAR(cur, l); 00578 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') || 00579 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) { 00580 cur += l; 00581 c = CUR_SCHAR(cur, l); 00582 } 00583 if (space) { 00584 while (IS_BLANK(c)) { 00585 cur += l; 00586 c = CUR_SCHAR(cur, l); 00587 } 00588 } 00589 if (c != 0) 00590 return(1); 00591 return(0); 00592 } 00593 00604 int 00605 xmlValidateNMToken(const xmlChar *value, int space) { 00606 const xmlChar *cur = value; 00607 int c,l; 00608 00609 if (value == NULL) 00610 return(-1); 00611 /* 00612 * First quick algorithm for ASCII range 00613 */ 00614 if (space) 00615 while (IS_BLANK_CH(*cur)) cur++; 00616 if (((*cur >= 'a') && (*cur <= 'z')) || 00617 ((*cur >= 'A') && (*cur <= 'Z')) || 00618 ((*cur >= '0') && (*cur <= '9')) || 00619 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':')) 00620 cur++; 00621 else 00622 goto try_complex; 00623 while (((*cur >= 'a') && (*cur <= 'z')) || 00624 ((*cur >= 'A') && (*cur <= 'Z')) || 00625 ((*cur >= '0') && (*cur <= '9')) || 00626 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':')) 00627 cur++; 00628 if (space) 00629 while (IS_BLANK_CH(*cur)) cur++; 00630 if (*cur == 0) 00631 return(0); 00632 00633 try_complex: 00634 /* 00635 * Second check for chars outside the ASCII range 00636 */ 00637 cur = value; 00638 c = CUR_SCHAR(cur, l); 00639 if (space) { 00640 while (IS_BLANK(c)) { 00641 cur += l; 00642 c = CUR_SCHAR(cur, l); 00643 } 00644 } 00645 if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') || 00646 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c))) 00647 return(1); 00648 cur += l; 00649 c = CUR_SCHAR(cur, l); 00650 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') || 00651 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) { 00652 cur += l; 00653 c = CUR_SCHAR(cur, l); 00654 } 00655 if (space) { 00656 while (IS_BLANK(c)) { 00657 cur += l; 00658 c = CUR_SCHAR(cur, l); 00659 } 00660 } 00661 if (c != 0) 00662 return(1); 00663 return(0); 00664 } 00665 #endif /* LIBXML_TREE_ENABLED */ 00666 00667 /************************************************************************ 00668 * * 00669 * Allocation and deallocation of basic structures * 00670 * * 00671 ************************************************************************/ 00672 00682 void 00683 xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) { 00684 if ((scheme == XML_BUFFER_ALLOC_EXACT) || 00685 (scheme == XML_BUFFER_ALLOC_DOUBLEIT)) 00686 xmlBufferAllocScheme = scheme; 00687 } 00688 00699 xmlBufferAllocationScheme 00700 xmlGetBufferAllocationScheme(void) { 00701 return(xmlBufferAllocScheme); 00702 } 00703 00717 xmlNsPtr 00718 xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) { 00719 xmlNsPtr cur; 00720 00721 if ((node != NULL) && (node->type != XML_ELEMENT_NODE)) 00722 return(NULL); 00723 00724 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml"))) { 00725 /* xml namespace is predefined, no need to add it */ 00726 if (xmlStrEqual(href, XML_XML_NAMESPACE)) 00727 return(NULL); 00728 00729 /* 00730 * Problem, this is an attempt to bind xml prefix to a wrong 00731 * namespace, which breaks 00732 * Namespace constraint: Reserved Prefixes and Namespace Names 00733 * from XML namespace. But documents authors may not care in 00734 * their context so let's proceed. 00735 */ 00736 } 00737 00738 /* 00739 * Allocate a new Namespace and fill the fields. 00740 */ 00741 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 00742 if (cur == NULL) { 00743 xmlTreeErrMemory("building namespace"); 00744 return(NULL); 00745 } 00746 memset(cur, 0, sizeof(xmlNs)); 00747 cur->type = XML_LOCAL_NAMESPACE; 00748 00749 if (href != NULL) 00750 cur->href = xmlStrdup(href); 00751 if (prefix != NULL) 00752 cur->prefix = xmlStrdup(prefix); 00753 00754 /* 00755 * Add it at the end to preserve parsing order ... 00756 * and checks for existing use of the prefix 00757 */ 00758 if (node != NULL) { 00759 if (node->nsDef == NULL) { 00760 node->nsDef = cur; 00761 } else { 00762 xmlNsPtr prev = node->nsDef; 00763 00764 if (((prev->prefix == NULL) && (cur->prefix == NULL)) || 00765 (xmlStrEqual(prev->prefix, cur->prefix))) { 00766 xmlFreeNs(cur); 00767 return(NULL); 00768 } 00769 while (prev->next != NULL) { 00770 prev = prev->next; 00771 if (((prev->prefix == NULL) && (cur->prefix == NULL)) || 00772 (xmlStrEqual(prev->prefix, cur->prefix))) { 00773 xmlFreeNs(cur); 00774 return(NULL); 00775 } 00776 } 00777 prev->next = cur; 00778 } 00779 } 00780 return(cur); 00781 } 00782 00790 void 00791 xmlSetNs(xmlNodePtr node, xmlNsPtr ns) { 00792 if (node == NULL) { 00793 #ifdef DEBUG_TREE 00794 xmlGenericError(xmlGenericErrorContext, 00795 "xmlSetNs: node == NULL\n"); 00796 #endif 00797 return; 00798 } 00799 node->ns = ns; 00800 } 00801 00808 void 00809 xmlFreeNs(xmlNsPtr cur) { 00810 if (cur == NULL) { 00811 #ifdef DEBUG_TREE 00812 xmlGenericError(xmlGenericErrorContext, 00813 "xmlFreeNs : ns == NULL\n"); 00814 #endif 00815 return; 00816 } 00817 if (cur->href != NULL) xmlFree((char *) cur->href); 00818 if (cur->prefix != NULL) xmlFree((char *) cur->prefix); 00819 xmlFree(cur); 00820 } 00821 00828 void 00829 xmlFreeNsList(xmlNsPtr cur) { 00830 xmlNsPtr next; 00831 if (cur == NULL) { 00832 #ifdef DEBUG_TREE 00833 xmlGenericError(xmlGenericErrorContext, 00834 "xmlFreeNsList : ns == NULL\n"); 00835 #endif 00836 return; 00837 } 00838 while (cur != NULL) { 00839 next = cur->next; 00840 xmlFreeNs(cur); 00841 cur = next; 00842 } 00843 } 00844 00857 xmlDtdPtr 00858 xmlNewDtd(xmlDocPtr doc, const xmlChar *name, 00859 const xmlChar *ExternalID, const xmlChar *SystemID) { 00860 xmlDtdPtr cur; 00861 00862 if ((doc != NULL) && (doc->extSubset != NULL)) { 00863 #ifdef DEBUG_TREE 00864 xmlGenericError(xmlGenericErrorContext, 00865 "xmlNewDtd(%s): document %s already have a DTD %s\n", 00866 /* !!! */ (char *) name, doc->name, 00867 /* !!! */ (char *)doc->extSubset->name); 00868 #endif 00869 return(NULL); 00870 } 00871 00872 /* 00873 * Allocate a new DTD and fill the fields. 00874 */ 00875 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd)); 00876 if (cur == NULL) { 00877 xmlTreeErrMemory("building DTD"); 00878 return(NULL); 00879 } 00880 memset(cur, 0 , sizeof(xmlDtd)); 00881 cur->type = XML_DTD_NODE; 00882 00883 if (name != NULL) 00884 cur->name = xmlStrdup(name); 00885 if (ExternalID != NULL) 00886 cur->ExternalID = xmlStrdup(ExternalID); 00887 if (SystemID != NULL) 00888 cur->SystemID = xmlStrdup(SystemID); 00889 if (doc != NULL) 00890 doc->extSubset = cur; 00891 cur->doc = doc; 00892 00893 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 00894 xmlRegisterNodeDefaultValue((xmlNodePtr)cur); 00895 return(cur); 00896 } 00897 00906 xmlDtdPtr 00907 xmlGetIntSubset(xmlDocPtr doc) { 00908 xmlNodePtr cur; 00909 00910 if (doc == NULL) 00911 return(NULL); 00912 cur = doc->children; 00913 while (cur != NULL) { 00914 if (cur->type == XML_DTD_NODE) 00915 return((xmlDtdPtr) cur); 00916 cur = cur->next; 00917 } 00918 return((xmlDtdPtr) doc->intSubset); 00919 } 00920 00931 xmlDtdPtr 00932 xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name, 00933 const xmlChar *ExternalID, const xmlChar *SystemID) { 00934 xmlDtdPtr cur; 00935 00936 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) { 00937 #ifdef DEBUG_TREE 00938 xmlGenericError(xmlGenericErrorContext, 00939 00940 "xmlCreateIntSubset(): document %s already have an internal subset\n", 00941 doc->name); 00942 #endif 00943 return(NULL); 00944 } 00945 00946 /* 00947 * Allocate a new DTD and fill the fields. 00948 */ 00949 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd)); 00950 if (cur == NULL) { 00951 xmlTreeErrMemory("building internal subset"); 00952 return(NULL); 00953 } 00954 memset(cur, 0, sizeof(xmlDtd)); 00955 cur->type = XML_DTD_NODE; 00956 00957 if (name != NULL) { 00958 cur->name = xmlStrdup(name); 00959 if (cur->name == NULL) { 00960 xmlTreeErrMemory("building internal subset"); 00961 xmlFree(cur); 00962 return(NULL); 00963 } 00964 } 00965 if (ExternalID != NULL) { 00966 cur->ExternalID = xmlStrdup(ExternalID); 00967 if (cur->ExternalID == NULL) { 00968 xmlTreeErrMemory("building internal subset"); 00969 if (cur->name != NULL) 00970 xmlFree((char *)cur->name); 00971 xmlFree(cur); 00972 return(NULL); 00973 } 00974 } 00975 if (SystemID != NULL) { 00976 cur->SystemID = xmlStrdup(SystemID); 00977 if (cur->SystemID == NULL) { 00978 xmlTreeErrMemory("building internal subset"); 00979 if (cur->name != NULL) 00980 xmlFree((char *)cur->name); 00981 if (cur->ExternalID != NULL) 00982 xmlFree((char *)cur->ExternalID); 00983 xmlFree(cur); 00984 return(NULL); 00985 } 00986 } 00987 if (doc != NULL) { 00988 doc->intSubset = cur; 00989 cur->parent = doc; 00990 cur->doc = doc; 00991 if (doc->children == NULL) { 00992 doc->children = (xmlNodePtr) cur; 00993 doc->last = (xmlNodePtr) cur; 00994 } else { 00995 if (doc->type == XML_HTML_DOCUMENT_NODE) { 00996 xmlNodePtr prev; 00997 00998 prev = doc->children; 00999 prev->prev = (xmlNodePtr) cur; 01000 cur->next = prev; 01001 doc->children = (xmlNodePtr) cur; 01002 } else { 01003 xmlNodePtr next; 01004 01005 next = doc->children; 01006 while ((next != NULL) && (next->type != XML_ELEMENT_NODE)) 01007 next = next->next; 01008 if (next == NULL) { 01009 cur->prev = doc->last; 01010 cur->prev->next = (xmlNodePtr) cur; 01011 cur->next = NULL; 01012 doc->last = (xmlNodePtr) cur; 01013 } else { 01014 cur->next = next; 01015 cur->prev = next->prev; 01016 if (cur->prev == NULL) 01017 doc->children = (xmlNodePtr) cur; 01018 else 01019 cur->prev->next = (xmlNodePtr) cur; 01020 next->prev = (xmlNodePtr) cur; 01021 } 01022 } 01023 } 01024 } 01025 01026 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 01027 xmlRegisterNodeDefaultValue((xmlNodePtr)cur); 01028 return(cur); 01029 } 01030 01038 #define DICT_FREE(str) \ 01039 if ((str) && ((!dict) || \ 01040 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \ 01041 xmlFree((char *)(str)); 01042 01043 01051 #define DICT_COPY(str, cpy) \ 01052 if (str) { \ 01053 if (dict) { \ 01054 if (xmlDictOwns(dict, (const xmlChar *)(str))) \ 01055 cpy = (xmlChar *) (str); \ 01056 else \ 01057 cpy = (xmlChar *) xmlDictLookup((dict), (const xmlChar *)(str), -1); \ 01058 } else \ 01059 cpy = xmlStrdup((const xmlChar *)(str)); } 01060 01068 #define DICT_CONST_COPY(str, cpy) \ 01069 if (str) { \ 01070 if (dict) { \ 01071 if (xmlDictOwns(dict, (const xmlChar *)(str))) \ 01072 cpy = (const xmlChar *) (str); \ 01073 else \ 01074 cpy = xmlDictLookup((dict), (const xmlChar *)(str), -1); \ 01075 } else \ 01076 cpy = (const xmlChar *) xmlStrdup((const xmlChar *)(str)); } 01077 01078 01085 void 01086 xmlFreeDtd(xmlDtdPtr cur) { 01087 xmlDictPtr dict = NULL; 01088 01089 if (cur == NULL) { 01090 return; 01091 } 01092 if (cur->doc != NULL) dict = cur->doc->dict; 01093 01094 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue)) 01095 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur); 01096 01097 if (cur->children != NULL) { 01098 xmlNodePtr next, c = cur->children; 01099 01100 /* 01101 * Cleanup all nodes which are not part of the specific lists 01102 * of notations, elements, attributes and entities. 01103 */ 01104 while (c != NULL) { 01105 next = c->next; 01106 if ((c->type != XML_NOTATION_NODE) && 01107 (c->type != XML_ELEMENT_DECL) && 01108 (c->type != XML_ATTRIBUTE_DECL) && 01109 (c->type != XML_ENTITY_DECL)) { 01110 xmlUnlinkNode(c); 01111 xmlFreeNode(c); 01112 } 01113 c = next; 01114 } 01115 } 01116 DICT_FREE(cur->name) 01117 DICT_FREE(cur->SystemID) 01118 DICT_FREE(cur->ExternalID) 01119 /* TODO !!! */ 01120 if (cur->notations != NULL) 01121 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations); 01122 01123 if (cur->elements != NULL) 01124 xmlFreeElementTable((xmlElementTablePtr) cur->elements); 01125 if (cur->attributes != NULL) 01126 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes); 01127 if (cur->entities != NULL) 01128 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities); 01129 if (cur->pentities != NULL) 01130 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities); 01131 01132 xmlFree(cur); 01133 } 01134 01143 xmlDocPtr 01144 xmlNewDoc(const xmlChar *version) { 01145 xmlDocPtr cur; 01146 01147 if (version == NULL) 01148 version = (const xmlChar *) "1.0"; 01149 01150 /* 01151 * Allocate a new document and fill the fields. 01152 */ 01153 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc)); 01154 if (cur == NULL) { 01155 xmlTreeErrMemory("building doc"); 01156 return(NULL); 01157 } 01158 memset(cur, 0, sizeof(xmlDoc)); 01159 cur->type = XML_DOCUMENT_NODE; 01160 01161 cur->version = xmlStrdup(version); 01162 if (cur->version == NULL) { 01163 xmlTreeErrMemory("building doc"); 01164 xmlFree(cur); 01165 return(NULL); 01166 } 01167 cur->standalone = -1; 01168 cur->compression = -1; /* not initialized */ 01169 cur->doc = cur; 01170 cur->parseFlags = 0; 01171 cur->properties = XML_DOC_USERBUILT; 01172 /* 01173 * The in memory encoding is always UTF8 01174 * This field will never change and would 01175 * be obsolete if not for binary compatibility. 01176 */ 01177 cur->charset = XML_CHAR_ENCODING_UTF8; 01178 01179 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 01180 xmlRegisterNodeDefaultValue((xmlNodePtr)cur); 01181 return(cur); 01182 } 01183 01190 void 01191 xmlFreeDoc(xmlDocPtr cur) { 01192 xmlDtdPtr extSubset, intSubset; 01193 xmlDictPtr dict = NULL; 01194 01195 if (cur == NULL) { 01196 #ifdef DEBUG_TREE 01197 xmlGenericError(xmlGenericErrorContext, 01198 "xmlFreeDoc : document == NULL\n"); 01199 #endif 01200 return; 01201 } 01202 #ifdef LIBXML_DEBUG_RUNTIME 01203 #ifdef LIBXML_DEBUG_ENABLED 01204 xmlDebugCheckDocument(stderr, cur); 01205 #endif 01206 #endif 01207 01208 if (cur != NULL) dict = cur->dict; 01209 01210 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue)) 01211 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur); 01212 01213 /* 01214 * Do this before freeing the children list to avoid ID lookups 01215 */ 01216 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids); 01217 cur->ids = NULL; 01218 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs); 01219 cur->refs = NULL; 01220 extSubset = cur->extSubset; 01221 intSubset = cur->intSubset; 01222 if (intSubset == extSubset) 01223 extSubset = NULL; 01224 if (extSubset != NULL) { 01225 xmlUnlinkNode((xmlNodePtr) cur->extSubset); 01226 cur->extSubset = NULL; 01227 xmlFreeDtd(extSubset); 01228 } 01229 if (intSubset != NULL) { 01230 xmlUnlinkNode((xmlNodePtr) cur->intSubset); 01231 cur->intSubset = NULL; 01232 xmlFreeDtd(intSubset); 01233 } 01234 01235 if (cur->children != NULL) xmlFreeNodeList(cur->children); 01236 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs); 01237 01238 DICT_FREE(cur->version) 01239 DICT_FREE(cur->name) 01240 DICT_FREE(cur->encoding) 01241 DICT_FREE(cur->URL) 01242 xmlFree(cur); 01243 if (dict) xmlDictFree(dict); 01244 } 01245 01256 xmlNodePtr 01257 xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) { 01258 xmlNodePtr ret = NULL, last = NULL; 01259 xmlNodePtr node; 01260 xmlChar *val; 01261 const xmlChar *cur = value, *end = cur + len; 01262 const xmlChar *q; 01263 xmlEntityPtr ent; 01264 01265 if (value == NULL) return(NULL); 01266 01267 q = cur; 01268 while ((cur < end) && (*cur != 0)) { 01269 if (cur[0] == '&') { 01270 int charval = 0; 01271 xmlChar tmp; 01272 01273 /* 01274 * Save the current text. 01275 */ 01276 if (cur != q) { 01277 if ((last != NULL) && (last->type == XML_TEXT_NODE)) { 01278 xmlNodeAddContentLen(last, q, cur - q); 01279 } else { 01280 node = xmlNewDocTextLen(doc, q, cur - q); 01281 if (node == NULL) return(ret); 01282 if (last == NULL) 01283 last = ret = node; 01284 else { 01285 last->next = node; 01286 node->prev = last; 01287 last = node; 01288 } 01289 } 01290 } 01291 q = cur; 01292 if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) { 01293 cur += 3; 01294 if (cur < end) 01295 tmp = *cur; 01296 else 01297 tmp = 0; 01298 while (tmp != ';') { /* Non input consuming loop */ 01299 if ((tmp >= '0') && (tmp <= '9')) 01300 charval = charval * 16 + (tmp - '0'); 01301 else if ((tmp >= 'a') && (tmp <= 'f')) 01302 charval = charval * 16 + (tmp - 'a') + 10; 01303 else if ((tmp >= 'A') && (tmp <= 'F')) 01304 charval = charval * 16 + (tmp - 'A') + 10; 01305 else { 01306 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc, 01307 NULL); 01308 charval = 0; 01309 break; 01310 } 01311 cur++; 01312 if (cur < end) 01313 tmp = *cur; 01314 else 01315 tmp = 0; 01316 } 01317 if (tmp == ';') 01318 cur++; 01319 q = cur; 01320 } else if ((cur + 1 < end) && (cur[1] == '#')) { 01321 cur += 2; 01322 if (cur < end) 01323 tmp = *cur; 01324 else 01325 tmp = 0; 01326 while (tmp != ';') { /* Non input consuming loops */ 01327 if ((tmp >= '0') && (tmp <= '9')) 01328 charval = charval * 10 + (tmp - '0'); 01329 else { 01330 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc, 01331 NULL); 01332 charval = 0; 01333 break; 01334 } 01335 cur++; 01336 if (cur < end) 01337 tmp = *cur; 01338 else 01339 tmp = 0; 01340 } 01341 if (tmp == ';') 01342 cur++; 01343 q = cur; 01344 } else { 01345 /* 01346 * Read the entity string 01347 */ 01348 cur++; 01349 q = cur; 01350 while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++; 01351 if ((cur >= end) || (*cur == 0)) { 01352 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc, 01353 (const char *) q); 01354 return(ret); 01355 } 01356 if (cur != q) { 01357 /* 01358 * Predefined entities don't generate nodes 01359 */ 01360 val = xmlStrndup(q, cur - q); 01361 ent = xmlGetDocEntity(doc, val); 01362 if ((ent != NULL) && 01363 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) { 01364 if (last == NULL) { 01365 node = xmlNewDocText(doc, ent->content); 01366 last = ret = node; 01367 } else if (last->type != XML_TEXT_NODE) { 01368 node = xmlNewDocText(doc, ent->content); 01369 last = xmlAddNextSibling(last, node); 01370 } else 01371 xmlNodeAddContent(last, ent->content); 01372 01373 } else { 01374 /* 01375 * Create a new REFERENCE_REF node 01376 */ 01377 node = xmlNewReference(doc, val); 01378 if (node == NULL) { 01379 if (val != NULL) xmlFree(val); 01380 return(ret); 01381 } 01382 else if ((ent != NULL) && (ent->children == NULL)) { 01383 xmlNodePtr temp; 01384 01385 ent->children = xmlStringGetNodeList(doc, 01386 (const xmlChar*)node->content); 01387 ent->owner = 1; 01388 temp = ent->children; 01389 while (temp) { 01390 temp->parent = (xmlNodePtr)ent; 01391 ent->last = temp; 01392 temp = temp->next; 01393 } 01394 } 01395 if (last == NULL) { 01396 last = ret = node; 01397 } else { 01398 last = xmlAddNextSibling(last, node); 01399 } 01400 } 01401 xmlFree(val); 01402 } 01403 cur++; 01404 q = cur; 01405 } 01406 if (charval != 0) { 01407 xmlChar buf[10]; 01408 int l; 01409 01410 l = xmlCopyCharMultiByte(buf, charval); 01411 buf[l] = 0; 01412 node = xmlNewDocText(doc, buf); 01413 if (node != NULL) { 01414 if (last == NULL) { 01415 last = ret = node; 01416 } else { 01417 last = xmlAddNextSibling(last, node); 01418 } 01419 } 01420 charval = 0; 01421 } 01422 } else 01423 cur++; 01424 } 01425 if ((cur != q) || (ret == NULL)) { 01426 /* 01427 * Handle the last piece of text. 01428 */ 01429 if ((last != NULL) && (last->type == XML_TEXT_NODE)) { 01430 xmlNodeAddContentLen(last, q, cur - q); 01431 } else { 01432 node = xmlNewDocTextLen(doc, q, cur - q); 01433 if (node == NULL) return(ret); 01434 if (last == NULL) { 01435 ret = node; 01436 } else { 01437 xmlAddNextSibling(last, node); 01438 } 01439 } 01440 } 01441 return(ret); 01442 } 01443 01453 xmlNodePtr 01454 xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) { 01455 xmlNodePtr ret = NULL, last = NULL; 01456 xmlNodePtr node; 01457 xmlChar *val; 01458 const xmlChar *cur = value; 01459 const xmlChar *q; 01460 xmlEntityPtr ent; 01461 01462 if (value == NULL) return(NULL); 01463 01464 q = cur; 01465 while (*cur != 0) { 01466 if (cur[0] == '&') { 01467 int charval = 0; 01468 xmlChar tmp; 01469 01470 /* 01471 * Save the current text. 01472 */ 01473 if (cur != q) { 01474 if ((last != NULL) && (last->type == XML_TEXT_NODE)) { 01475 xmlNodeAddContentLen(last, q, cur - q); 01476 } else { 01477 node = xmlNewDocTextLen(doc, q, cur - q); 01478 if (node == NULL) return(ret); 01479 if (last == NULL) 01480 last = ret = node; 01481 else { 01482 last->next = node; 01483 node->prev = last; 01484 last = node; 01485 } 01486 } 01487 } 01488 q = cur; 01489 if ((cur[1] == '#') && (cur[2] == 'x')) { 01490 cur += 3; 01491 tmp = *cur; 01492 while (tmp != ';') { /* Non input consuming loop */ 01493 if ((tmp >= '0') && (tmp <= '9')) 01494 charval = charval * 16 + (tmp - '0'); 01495 else if ((tmp >= 'a') && (tmp <= 'f')) 01496 charval = charval * 16 + (tmp - 'a') + 10; 01497 else if ((tmp >= 'A') && (tmp <= 'F')) 01498 charval = charval * 16 + (tmp - 'A') + 10; 01499 else { 01500 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc, 01501 NULL); 01502 charval = 0; 01503 break; 01504 } 01505 cur++; 01506 tmp = *cur; 01507 } 01508 if (tmp == ';') 01509 cur++; 01510 q = cur; 01511 } else if (cur[1] == '#') { 01512 cur += 2; 01513 tmp = *cur; 01514 while (tmp != ';') { /* Non input consuming loops */ 01515 if ((tmp >= '0') && (tmp <= '9')) 01516 charval = charval * 10 + (tmp - '0'); 01517 else { 01518 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc, 01519 NULL); 01520 charval = 0; 01521 break; 01522 } 01523 cur++; 01524 tmp = *cur; 01525 } 01526 if (tmp == ';') 01527 cur++; 01528 q = cur; 01529 } else { 01530 /* 01531 * Read the entity string 01532 */ 01533 cur++; 01534 q = cur; 01535 while ((*cur != 0) && (*cur != ';')) cur++; 01536 if (*cur == 0) { 01537 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, 01538 (xmlNodePtr) doc, (const char *) q); 01539 return(ret); 01540 } 01541 if (cur != q) { 01542 /* 01543 * Predefined entities don't generate nodes 01544 */ 01545 val = xmlStrndup(q, cur - q); 01546 ent = xmlGetDocEntity(doc, val); 01547 if ((ent != NULL) && 01548 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) { 01549 if (last == NULL) { 01550 node = xmlNewDocText(doc, ent->content); 01551 last = ret = node; 01552 } else if (last->type != XML_TEXT_NODE) { 01553 node = xmlNewDocText(doc, ent->content); 01554 last = xmlAddNextSibling(last, node); 01555 } else 01556 xmlNodeAddContent(last, ent->content); 01557 01558 } else { 01559 /* 01560 * Create a new REFERENCE_REF node 01561 */ 01562 node = xmlNewReference(doc, val); 01563 if (node == NULL) { 01564 if (val != NULL) xmlFree(val); 01565 return(ret); 01566 } 01567 else if ((ent != NULL) && (ent->children == NULL)) { 01568 xmlNodePtr temp; 01569 01570 ent->children = xmlStringGetNodeList(doc, 01571 (const xmlChar*)node->content); 01572 ent->owner = 1; 01573 temp = ent->children; 01574 while (temp) { 01575 temp->parent = (xmlNodePtr)ent; 01576 temp = temp->next; 01577 } 01578 } 01579 if (last == NULL) { 01580 last = ret = node; 01581 } else { 01582 last = xmlAddNextSibling(last, node); 01583 } 01584 } 01585 xmlFree(val); 01586 } 01587 cur++; 01588 q = cur; 01589 } 01590 if (charval != 0) { 01591 xmlChar buf[10]; 01592 int len; 01593 01594 len = xmlCopyCharMultiByte(buf, charval); 01595 buf[len] = 0; 01596 node = xmlNewDocText(doc, buf); 01597 if (node != NULL) { 01598 if (last == NULL) { 01599 last = ret = node; 01600 } else { 01601 last = xmlAddNextSibling(last, node); 01602 } 01603 } 01604 } 01605 } else 01606 cur++; 01607 } 01608 if ((cur != q) || (ret == NULL)) { 01609 /* 01610 * Handle the last piece of text. 01611 */ 01612 if ((last != NULL) && (last->type == XML_TEXT_NODE)) { 01613 xmlNodeAddContentLen(last, q, cur - q); 01614 } else { 01615 node = xmlNewDocTextLen(doc, q, cur - q); 01616 if (node == NULL) return(ret); 01617 if (last == NULL) { 01618 last = ret = node; 01619 } else { 01620 last = xmlAddNextSibling(last, node); 01621 } 01622 } 01623 } 01624 return(ret); 01625 } 01626 01638 xmlChar * 01639 xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) 01640 { 01641 xmlNodePtr node = list; 01642 xmlChar *ret = NULL; 01643 xmlEntityPtr ent; 01644 01645 if (list == NULL) 01646 return (NULL); 01647 01648 while (node != NULL) { 01649 if ((node->type == XML_TEXT_NODE) || 01650 (node->type == XML_CDATA_SECTION_NODE)) { 01651 if (inLine) { 01652 ret = xmlStrcat(ret, node->content); 01653 } else { 01654 xmlChar *buffer; 01655 01656 buffer = xmlEncodeEntitiesReentrant(doc, node->content); 01657 if (buffer != NULL) { 01658 ret = xmlStrcat(ret, buffer); 01659 xmlFree(buffer); 01660 } 01661 } 01662 } else if (node->type == XML_ENTITY_REF_NODE) { 01663 if (inLine) { 01664 ent = xmlGetDocEntity(doc, node->name); 01665 if (ent != NULL) { 01666 xmlChar *buffer; 01667 01668 /* an entity content can be any "well balanced chunk", 01669 * i.e. the result of the content [43] production: 01670 * http://www.w3.org/TR/REC-xml#NT-content. 01671 * So it can contain text, CDATA section or nested 01672 * entity reference nodes (among others). 01673 * -> we recursive call xmlNodeListGetString() 01674 * which handles these types */ 01675 buffer = xmlNodeListGetString(doc, ent->children, 1); 01676 if (buffer != NULL) { 01677 ret = xmlStrcat(ret, buffer); 01678 xmlFree(buffer); 01679 } 01680 } else { 01681 ret = xmlStrcat(ret, node->content); 01682 } 01683 } else { 01684 xmlChar buf[2]; 01685 01686 buf[0] = '&'; 01687 buf[1] = 0; 01688 ret = xmlStrncat(ret, buf, 1); 01689 ret = xmlStrcat(ret, node->name); 01690 buf[0] = ';'; 01691 buf[1] = 0; 01692 ret = xmlStrncat(ret, buf, 1); 01693 } 01694 } 01695 #if 0 01696 else { 01697 xmlGenericError(xmlGenericErrorContext, 01698 "xmlGetNodeListString : invalid node type %d\n", 01699 node->type); 01700 } 01701 #endif 01702 node = node->next; 01703 } 01704 return (ret); 01705 } 01706 01707 #ifdef LIBXML_TREE_ENABLED 01708 01720 xmlChar * 01721 xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine) 01722 { 01723 xmlNodePtr node = list; 01724 xmlChar *ret = NULL; 01725 xmlEntityPtr ent; 01726 01727 if (list == NULL) 01728 return (NULL); 01729 01730 while (node != NULL) { 01731 if ((node->type == XML_TEXT_NODE) || 01732 (node->type == XML_CDATA_SECTION_NODE)) { 01733 if (inLine) { 01734 ret = xmlStrcat(ret, node->content); 01735 } else { 01736 xmlChar *buffer; 01737 01738 buffer = xmlEncodeSpecialChars(doc, node->content); 01739 if (buffer != NULL) { 01740 ret = xmlStrcat(ret, buffer); 01741 xmlFree(buffer); 01742 } 01743 } 01744 } else if (node->type == XML_ENTITY_REF_NODE) { 01745 if (inLine) { 01746 ent = xmlGetDocEntity(doc, node->name); 01747 if (ent != NULL) { 01748 xmlChar *buffer; 01749 01750 /* an entity content can be any "well balanced chunk", 01751 * i.e. the result of the content [43] production: 01752 * http://www.w3.org/TR/REC-xml#NT-content. 01753 * So it can contain text, CDATA section or nested 01754 * entity reference nodes (among others). 01755 * -> we recursive call xmlNodeListGetRawString() 01756 * which handles these types */ 01757 buffer = 01758 xmlNodeListGetRawString(doc, ent->children, 1); 01759 if (buffer != NULL) { 01760 ret = xmlStrcat(ret, buffer); 01761 xmlFree(buffer); 01762 } 01763 } else { 01764 ret = xmlStrcat(ret, node->content); 01765 } 01766 } else { 01767 xmlChar buf[2]; 01768 01769 buf[0] = '&'; 01770 buf[1] = 0; 01771 ret = xmlStrncat(ret, buf, 1); 01772 ret = xmlStrcat(ret, node->name); 01773 buf[0] = ';'; 01774 buf[1] = 0; 01775 ret = xmlStrncat(ret, buf, 1); 01776 } 01777 } 01778 #if 0 01779 else { 01780 xmlGenericError(xmlGenericErrorContext, 01781 "xmlGetNodeListString : invalid node type %d\n", 01782 node->type); 01783 } 01784 #endif 01785 node = node->next; 01786 } 01787 return (ret); 01788 } 01789 #endif /* LIBXML_TREE_ENABLED */ 01790 01791 static xmlAttrPtr 01792 xmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns, 01793 const xmlChar * name, const xmlChar * value, 01794 int eatname) 01795 { 01796 xmlAttrPtr cur; 01797 xmlDocPtr doc = NULL; 01798 01799 if ((node != NULL) && (node->type != XML_ELEMENT_NODE)) { 01800 if ((eatname == 1) && 01801 ((node->doc == NULL) || 01802 (!(xmlDictOwns(node->doc->dict, name))))) 01803 xmlFree((xmlChar *) name); 01804 return (NULL); 01805 } 01806 01807 /* 01808 * Allocate a new property and fill the fields. 01809 */ 01810 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr)); 01811 if (cur == NULL) { 01812 if ((eatname == 1) && 01813 ((node == NULL) || (node->doc == NULL) || 01814 (!(xmlDictOwns(node->doc->dict, name))))) 01815 xmlFree((xmlChar *) name); 01816 xmlTreeErrMemory("building attribute"); 01817 return (NULL); 01818 } 01819 memset(cur, 0, sizeof(xmlAttr)); 01820 cur->type = XML_ATTRIBUTE_NODE; 01821 01822 cur->parent = node; 01823 if (node != NULL) { 01824 doc = node->doc; 01825 cur->doc = doc; 01826 } 01827 cur->ns = ns; 01828 01829 if (eatname == 0) { 01830 if ((doc != NULL) && (doc->dict != NULL)) 01831 cur->name = (xmlChar *) xmlDictLookup(doc->dict, name, -1); 01832 else 01833 cur->name = xmlStrdup(name); 01834 } else 01835 cur->name = name; 01836 01837 if (value != NULL) { 01838 xmlNodePtr tmp; 01839 01840 if(!xmlCheckUTF8(value)) { 01841 xmlTreeErr(XML_TREE_NOT_UTF8, (xmlNodePtr) doc, 01842 NULL); 01843 if (doc != NULL) 01844 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1"); 01845 } 01846 cur->children = xmlNewDocText(doc, value); 01847 cur->last = NULL; 01848 tmp = cur->children; 01849 while (tmp != NULL) { 01850 tmp->parent = (xmlNodePtr) cur; 01851 if (tmp->next == NULL) 01852 cur->last = tmp; 01853 tmp = tmp->next; 01854 } 01855 } 01856 01857 /* 01858 * Add it at the end to preserve parsing order ... 01859 */ 01860 if (node != NULL) { 01861 if (node->properties == NULL) { 01862 node->properties = cur; 01863 } else { 01864 xmlAttrPtr prev = node->properties; 01865 01866 while (prev->next != NULL) 01867 prev = prev->next; 01868 prev->next = cur; 01869 cur->prev = prev; 01870 } 01871 } 01872 01873 if ((value != NULL) && (node != NULL) && 01874 (xmlIsID(node->doc, node, cur) == 1)) 01875 xmlAddID(NULL, node->doc, value, cur); 01876 01877 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 01878 xmlRegisterNodeDefaultValue((xmlNodePtr) cur); 01879 return (cur); 01880 } 01881 01882 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \ 01883 defined(LIBXML_SCHEMAS_ENABLED) 01884 01893 xmlAttrPtr 01894 xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) { 01895 01896 if (name == NULL) { 01897 #ifdef DEBUG_TREE 01898 xmlGenericError(xmlGenericErrorContext, 01899 "xmlNewProp : name == NULL\n"); 01900 #endif 01901 return(NULL); 01902 } 01903 01904 return xmlNewPropInternal(node, NULL, name, value, 0); 01905 } 01906 #endif /* LIBXML_TREE_ENABLED */ 01907 01918 xmlAttrPtr 01919 xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name, 01920 const xmlChar *value) { 01921 01922 if (name == NULL) { 01923 #ifdef DEBUG_TREE 01924 xmlGenericError(xmlGenericErrorContext, 01925 "xmlNewNsProp : name == NULL\n"); 01926 #endif 01927 return(NULL); 01928 } 01929 01930 return xmlNewPropInternal(node, ns, name, value, 0); 01931 } 01932 01943 xmlAttrPtr 01944 xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name, 01945 const xmlChar *value) { 01946 01947 if (name == NULL) { 01948 #ifdef DEBUG_TREE 01949 xmlGenericError(xmlGenericErrorContext, 01950 "xmlNewNsPropEatName : name == NULL\n"); 01951 #endif 01952 return(NULL); 01953 } 01954 01955 return xmlNewPropInternal(node, ns, name, value, 1); 01956 } 01957 01967 xmlAttrPtr 01968 xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) { 01969 xmlAttrPtr cur; 01970 01971 if (name == NULL) { 01972 #ifdef DEBUG_TREE 01973 xmlGenericError(xmlGenericErrorContext, 01974 "xmlNewDocProp : name == NULL\n"); 01975 #endif 01976 return(NULL); 01977 } 01978 01979 /* 01980 * Allocate a new property and fill the fields. 01981 */ 01982 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr)); 01983 if (cur == NULL) { 01984 xmlTreeErrMemory("building attribute"); 01985 return(NULL); 01986 } 01987 memset(cur, 0, sizeof(xmlAttr)); 01988 cur->type = XML_ATTRIBUTE_NODE; 01989 01990 if ((doc != NULL) && (doc->dict != NULL)) 01991 cur->name = xmlDictLookup(doc->dict, name, -1); 01992 else 01993 cur->name = xmlStrdup(name); 01994 cur->doc = doc; 01995 if (value != NULL) { 01996 xmlNodePtr tmp; 01997 01998 cur->children = xmlStringGetNodeList(doc, value); 01999 cur->last = NULL; 02000 02001 tmp = cur->children; 02002 while (tmp != NULL) { 02003 tmp->parent = (xmlNodePtr) cur; 02004 if (tmp->next == NULL) 02005 cur->last = tmp; 02006 tmp = tmp->next; 02007 } 02008 } 02009 02010 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 02011 xmlRegisterNodeDefaultValue((xmlNodePtr)cur); 02012 return(cur); 02013 } 02014 02021 void 02022 xmlFreePropList(xmlAttrPtr cur) { 02023 xmlAttrPtr next; 02024 if (cur == NULL) return; 02025 while (cur != NULL) { 02026 next = cur->next; 02027 xmlFreeProp(cur); 02028 cur = next; 02029 } 02030 } 02031 02038 void 02039 xmlFreeProp(xmlAttrPtr cur) { 02040 xmlDictPtr dict = NULL; 02041 if (cur == NULL) return; 02042 02043 if (cur->doc != NULL) dict = cur->doc->dict; 02044 02045 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue)) 02046 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur); 02047 02048 /* Check for ID removal -> leading to invalid references ! */ 02049 if ((cur->doc != NULL) && (cur->atype == XML_ATTRIBUTE_ID)) { 02050 xmlRemoveID(cur->doc, cur); 02051 } 02052 if (cur->children != NULL) xmlFreeNodeList(cur->children); 02053 DICT_FREE(cur->name) 02054 xmlFree(cur); 02055 } 02056 02066 int 02067 xmlRemoveProp(xmlAttrPtr cur) { 02068 xmlAttrPtr tmp; 02069 if (cur == NULL) { 02070 #ifdef DEBUG_TREE 02071 xmlGenericError(xmlGenericErrorContext, 02072 "xmlRemoveProp : cur == NULL\n"); 02073 #endif 02074 return(-1); 02075 } 02076 if (cur->parent == NULL) { 02077 #ifdef DEBUG_TREE 02078 xmlGenericError(xmlGenericErrorContext, 02079 "xmlRemoveProp : cur->parent == NULL\n"); 02080 #endif 02081 return(-1); 02082 } 02083 tmp = cur->parent->properties; 02084 if (tmp == cur) { 02085 cur->parent->properties = cur->next; 02086 if (cur->next != NULL) 02087 cur->next->prev = NULL; 02088 xmlFreeProp(cur); 02089 return(0); 02090 } 02091 while (tmp != NULL) { 02092 if (tmp->next == cur) { 02093 tmp->next = cur->next; 02094 if (tmp->next != NULL) 02095 tmp->next->prev = tmp; 02096 xmlFreeProp(cur); 02097 return(0); 02098 } 02099 tmp = tmp->next; 02100 } 02101 #ifdef DEBUG_TREE 02102 xmlGenericError(xmlGenericErrorContext, 02103 "xmlRemoveProp : attribute not owned by its node\n"); 02104 #endif 02105 return(-1); 02106 } 02107 02117 xmlNodePtr 02118 xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) { 02119 xmlNodePtr cur; 02120 02121 if (name == NULL) { 02122 #ifdef DEBUG_TREE 02123 xmlGenericError(xmlGenericErrorContext, 02124 "xmlNewPI : name == NULL\n"); 02125 #endif 02126 return(NULL); 02127 } 02128 02129 /* 02130 * Allocate a new node and fill the fields. 02131 */ 02132 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); 02133 if (cur == NULL) { 02134 xmlTreeErrMemory("building PI"); 02135 return(NULL); 02136 } 02137 memset(cur, 0, sizeof(xmlNode)); 02138 cur->type = XML_PI_NODE; 02139 02140 if ((doc != NULL) && (doc->dict != NULL)) 02141 cur->name = xmlDictLookup(doc->dict, name, -1); 02142 else 02143 cur->name = xmlStrdup(name); 02144 if (content != NULL) { 02145 cur->content = xmlStrdup(content); 02146 } 02147 cur->doc = doc; 02148 02149 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 02150 xmlRegisterNodeDefaultValue((xmlNodePtr)cur); 02151 return(cur); 02152 } 02153 02164 xmlNodePtr 02165 xmlNewPI(const xmlChar *name, const xmlChar *content) { 02166 return(xmlNewDocPI(NULL, name, content)); 02167 } 02168 02179 xmlNodePtr 02180 xmlNewNode(xmlNsPtr ns, const xmlChar *name) { 02181 xmlNodePtr cur; 02182 02183 if (name == NULL) { 02184 #ifdef DEBUG_TREE 02185 xmlGenericError(xmlGenericErrorContext, 02186 "xmlNewNode : name == NULL\n"); 02187 #endif 02188 return(NULL); 02189 } 02190 02191 /* 02192 * Allocate a new node and fill the fields. 02193 */ 02194 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); 02195 if (cur == NULL) { 02196 xmlTreeErrMemory("building node"); 02197 return(NULL); 02198 } 02199 memset(cur, 0, sizeof(xmlNode)); 02200 cur->type = XML_ELEMENT_NODE; 02201 02202 cur->name = xmlStrdup(name); 02203 cur->ns = ns; 02204 02205 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 02206 xmlRegisterNodeDefaultValue(cur); 02207 return(cur); 02208 } 02209 02221 xmlNodePtr 02222 xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) { 02223 xmlNodePtr cur; 02224 02225 if (name == NULL) { 02226 #ifdef DEBUG_TREE 02227 xmlGenericError(xmlGenericErrorContext, 02228 "xmlNewNode : name == NULL\n"); 02229 #endif 02230 return(NULL); 02231 } 02232 02233 /* 02234 * Allocate a new node and fill the fields. 02235 */ 02236 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); 02237 if (cur == NULL) { 02238 xmlTreeErrMemory("building node"); 02239 /* we can't check here that name comes from the doc dictionnary */ 02240 return(NULL); 02241 } 02242 memset(cur, 0, sizeof(xmlNode)); 02243 cur->type = XML_ELEMENT_NODE; 02244 02245 cur->name = name; 02246 cur->ns = ns; 02247 02248 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 02249 xmlRegisterNodeDefaultValue((xmlNodePtr)cur); 02250 return(cur); 02251 } 02252 02269 xmlNodePtr 02270 xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns, 02271 const xmlChar *name, const xmlChar *content) { 02272 xmlNodePtr cur; 02273 02274 if ((doc != NULL) && (doc->dict != NULL)) 02275 cur = xmlNewNodeEatName(ns, (xmlChar *) 02276 xmlDictLookup(doc->dict, name, -1)); 02277 else 02278 cur = xmlNewNode(ns, name); 02279 if (cur != NULL) { 02280 cur->doc = doc; 02281 if (content != NULL) { 02282 cur->children = xmlStringGetNodeList(doc, content); 02283 UPDATE_LAST_CHILD_AND_PARENT(cur) 02284 } 02285 } 02286 02287 return(cur); 02288 } 02289 02306 xmlNodePtr 02307 xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns, 02308 xmlChar *name, const xmlChar *content) { 02309 xmlNodePtr cur; 02310 02311 cur = xmlNewNodeEatName(ns, name); 02312 if (cur != NULL) { 02313 cur->doc = doc; 02314 if (content != NULL) { 02315 cur->children = xmlStringGetNodeList(doc, content); 02316 UPDATE_LAST_CHILD_AND_PARENT(cur) 02317 } 02318 } else { 02319 /* if name don't come from the doc dictionnary free it here */ 02320 if ((name != NULL) && (doc != NULL) && 02321 (!(xmlDictOwns(doc->dict, name)))) 02322 xmlFree(name); 02323 } 02324 return(cur); 02325 } 02326 02327 #ifdef LIBXML_TREE_ENABLED 02328 02340 xmlNodePtr 02341 xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns, 02342 const xmlChar *name, const xmlChar *content) { 02343 xmlNodePtr cur; 02344 02345 cur = xmlNewDocNode(doc, ns, name, NULL); 02346 if (cur != NULL) { 02347 cur->doc = doc; 02348 if (content != NULL) { 02349 cur->children = xmlNewDocText(doc, content); 02350 UPDATE_LAST_CHILD_AND_PARENT(cur) 02351 } 02352 } 02353 return(cur); 02354 } 02355 02363 xmlNodePtr 02364 xmlNewDocFragment(xmlDocPtr doc) { 02365 xmlNodePtr cur; 02366 02367 /* 02368 * Allocate a new DocumentFragment node and fill the fields. 02369 */ 02370 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); 02371 if (cur == NULL) { 02372 xmlTreeErrMemory("building fragment"); 02373 return(NULL); 02374 } 02375 memset(cur, 0, sizeof(xmlNode)); 02376 cur->type = XML_DOCUMENT_FRAG_NODE; 02377 02378 cur->doc = doc; 02379 02380 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 02381 xmlRegisterNodeDefaultValue(cur); 02382 return(cur); 02383 } 02384 #endif /* LIBXML_TREE_ENABLED */ 02385 02393 xmlNodePtr 02394 xmlNewText(const xmlChar *content) { 02395 xmlNodePtr cur; 02396 02397 /* 02398 * Allocate a new node and fill the fields. 02399 */ 02400 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); 02401 if (cur == NULL) { 02402 xmlTreeErrMemory("building text"); 02403 return(NULL); 02404 } 02405 memset(cur, 0, sizeof(xmlNode)); 02406 cur->type = XML_TEXT_NODE; 02407 02408 cur->name = xmlStringText; 02409 if (content != NULL) { 02410 cur->content = xmlStrdup(content); 02411 } 02412 02413 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 02414 xmlRegisterNodeDefaultValue(cur); 02415 return(cur); 02416 } 02417 02418 #ifdef LIBXML_TREE_ENABLED 02419 02438 xmlNodePtr 02439 xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns, 02440 const xmlChar *name, const xmlChar *content) { 02441 xmlNodePtr cur, prev; 02442 02443 if (parent == NULL) { 02444 #ifdef DEBUG_TREE 02445 xmlGenericError(xmlGenericErrorContext, 02446 "xmlNewTextChild : parent == NULL\n"); 02447 #endif 02448 return(NULL); 02449 } 02450 02451 if (name == NULL) { 02452 #ifdef DEBUG_TREE 02453 xmlGenericError(xmlGenericErrorContext, 02454 "xmlNewTextChild : name == NULL\n"); 02455 #endif 02456 return(NULL); 02457 } 02458 02459 /* 02460 * Allocate a new node 02461 */ 02462 if (parent->type == XML_ELEMENT_NODE) { 02463 if (ns == NULL) 02464 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content); 02465 else 02466 cur = xmlNewDocRawNode(parent->doc, ns, name, content); 02467 } else if ((parent->type == XML_DOCUMENT_NODE) || 02468 (parent->type == XML_HTML_DOCUMENT_NODE)) { 02469 if (ns == NULL) 02470 cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content); 02471 else 02472 cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content); 02473 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) { 02474 cur = xmlNewDocRawNode( parent->doc, ns, name, content); 02475 } else { 02476 return(NULL); 02477 } 02478 if (cur == NULL) return(NULL); 02479 02480 /* 02481 * add the new element at the end of the children list. 02482 */ 02483 cur->type = XML_ELEMENT_NODE; 02484 cur->parent = parent; 02485 cur->doc = parent->doc; 02486 if (parent->children == NULL) { 02487 parent->children = cur; 02488 parent->last = cur; 02489 } else { 02490 prev = parent->last; 02491 prev->next = cur; 02492 cur->prev = prev; 02493 parent->last = cur; 02494 } 02495 02496 return(cur); 02497 } 02498 #endif /* LIBXML_TREE_ENABLED */ 02499 02508 xmlNodePtr 02509 xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) { 02510 xmlNodePtr cur; 02511 02512 if (name == NULL) 02513 return(NULL); 02514 02515 /* 02516 * Allocate a new node and fill the fields. 02517 */ 02518 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); 02519 if (cur == NULL) { 02520 xmlTreeErrMemory("building character reference"); 02521 return(NULL); 02522 } 02523 memset(cur, 0, sizeof(xmlNode)); 02524 cur->type = XML_ENTITY_REF_NODE; 02525 02526 cur->doc = doc; 02527 if (name[0] == '&') { 02528 int len; 02529 name++; 02530 len = xmlStrlen(name); 02531 if (name[len - 1] == ';') 02532 cur->name = xmlStrndup(name, len - 1); 02533 else 02534 cur->name = xmlStrndup(name, len); 02535 } else 02536 cur->name = xmlStrdup(name); 02537 02538 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 02539 xmlRegisterNodeDefaultValue(cur); 02540 return(cur); 02541 } 02542 02551 xmlNodePtr 02552 xmlNewReference(xmlDocPtr doc, const xmlChar *name) { 02553 xmlNodePtr cur; 02554 xmlEntityPtr ent; 02555 02556 if (name == NULL) 02557 return(NULL); 02558 02559 /* 02560 * Allocate a new node and fill the fields. 02561 */ 02562 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); 02563 if (cur == NULL) { 02564 xmlTreeErrMemory("building reference"); 02565 return(NULL); 02566 } 02567 memset(cur, 0, sizeof(xmlNode)); 02568 cur->type = XML_ENTITY_REF_NODE; 02569 02570 cur->doc = doc; 02571 if (name[0] == '&') { 02572 int len; 02573 name++; 02574 len = xmlStrlen(name); 02575 if (name[len - 1] == ';') 02576 cur->name = xmlStrndup(name, len - 1); 02577 else 02578 cur->name = xmlStrndup(name, len); 02579 } else 02580 cur->name = xmlStrdup(name); 02581 02582 ent = xmlGetDocEntity(doc, cur->name); 02583 if (ent != NULL) { 02584 cur->content = ent->content; 02585 /* 02586 * The parent pointer in entity is a DTD pointer and thus is NOT 02587 * updated. Not sure if this is 100% correct. 02588 * -George 02589 */ 02590 cur->children = (xmlNodePtr) ent; 02591 cur->last = (xmlNodePtr) ent; 02592 } 02593 02594 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 02595 xmlRegisterNodeDefaultValue(cur); 02596 return(cur); 02597 } 02598 02607 xmlNodePtr 02608 xmlNewDocText(xmlDocPtr doc, const xmlChar *content) { 02609 xmlNodePtr cur; 02610 02611 cur = xmlNewText(content); 02612 if (cur != NULL) cur->doc = doc; 02613 return(cur); 02614 } 02615 02624 xmlNodePtr 02625 xmlNewTextLen(const xmlChar *content, int len) { 02626 xmlNodePtr cur; 02627 02628 /* 02629 * Allocate a new node and fill the fields. 02630 */ 02631 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); 02632 if (cur == NULL) { 02633 xmlTreeErrMemory("building text"); 02634 return(NULL); 02635 } 02636 memset(cur, 0, sizeof(xmlNode)); 02637 cur->type = XML_TEXT_NODE; 02638 02639 cur->name = xmlStringText; 02640 if (content != NULL) { 02641 cur->content = xmlStrndup(content, len); 02642 } 02643 02644 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 02645 xmlRegisterNodeDefaultValue(cur); 02646 return(cur); 02647 } 02648 02659 xmlNodePtr 02660 xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) { 02661 xmlNodePtr cur; 02662 02663 cur = xmlNewTextLen(content, len); 02664 if (cur != NULL) cur->doc = doc; 02665 return(cur); 02666 } 02667 02675 xmlNodePtr 02676 xmlNewComment(const xmlChar *content) { 02677 xmlNodePtr cur; 02678 02679 /* 02680 * Allocate a new node and fill the fields. 02681 */ 02682 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); 02683 if (cur == NULL) { 02684 xmlTreeErrMemory("building comment"); 02685 return(NULL); 02686 } 02687 memset(cur, 0, sizeof(xmlNode)); 02688 cur->type = XML_COMMENT_NODE; 02689 02690 cur->name = xmlStringComment; 02691 if (content != NULL) { 02692 cur->content = xmlStrdup(content); 02693 } 02694 02695 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 02696 xmlRegisterNodeDefaultValue(cur); 02697 return(cur); 02698 } 02699 02709 xmlNodePtr 02710 xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) { 02711 xmlNodePtr cur; 02712 02713 /* 02714 * Allocate a new node and fill the fields. 02715 */ 02716 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); 02717 if (cur == NULL) { 02718 xmlTreeErrMemory("building CDATA"); 02719 return(NULL); 02720 } 02721 memset(cur, 0, sizeof(xmlNode)); 02722 cur->type = XML_CDATA_SECTION_NODE; 02723 cur->doc = doc; 02724 02725 if (content != NULL) { 02726 cur->content = xmlStrndup(content, len); 02727 } 02728 02729 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 02730 xmlRegisterNodeDefaultValue(cur); 02731 return(cur); 02732 } 02733 02742 xmlNodePtr 02743 xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) { 02744 xmlNodePtr cur; 02745 02746 cur = xmlNewComment(content); 02747 if (cur != NULL) cur->doc = doc; 02748 return(cur); 02749 } 02750 02758 void 02759 xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) { 02760 xmlAttrPtr prop; 02761 02762 if (tree == NULL) 02763 return; 02764 if (tree->doc != doc) { 02765 if(tree->type == XML_ELEMENT_NODE) { 02766 prop = tree->properties; 02767 while (prop != NULL) { 02768 prop->doc = doc; 02769 xmlSetListDoc(prop->children, doc); 02770 prop = prop->next; 02771 } 02772 } 02773 if (tree->children != NULL) 02774 xmlSetListDoc(tree->children, doc); 02775 tree->doc = doc; 02776 } 02777 } 02778 02786 void 02787 xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) { 02788 xmlNodePtr cur; 02789 02790 if (list == NULL) 02791 return; 02792 cur = list; 02793 while (cur != NULL) { 02794 if (cur->doc != doc) 02795 xmlSetTreeDoc(cur, doc); 02796 cur = cur->next; 02797 } 02798 } 02799 02800 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) 02801 02818 xmlNodePtr 02819 xmlNewChild(xmlNodePtr parent, xmlNsPtr ns, 02820 const xmlChar *name, const xmlChar *content) { 02821 xmlNodePtr cur, prev; 02822 02823 if (parent == NULL) { 02824 #ifdef DEBUG_TREE 02825 xmlGenericError(xmlGenericErrorContext, 02826 "xmlNewChild : parent == NULL\n"); 02827 #endif 02828 return(NULL); 02829 } 02830 02831 if (name == NULL) { 02832 #ifdef DEBUG_TREE 02833 xmlGenericError(xmlGenericErrorContext, 02834 "xmlNewChild : name == NULL\n"); 02835 #endif 02836 return(NULL); 02837 } 02838 02839 /* 02840 * Allocate a new node 02841 */ 02842 if (parent->type == XML_ELEMENT_NODE) { 02843 if (ns == NULL) 02844 cur = xmlNewDocNode(parent->doc, parent->ns, name, content); 02845 else 02846 cur = xmlNewDocNode(parent->doc, ns, name, content); 02847 } else if ((parent->type == XML_DOCUMENT_NODE) || 02848 (parent->type == XML_HTML_DOCUMENT_NODE)) { 02849 if (ns == NULL) 02850 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content); 02851 else 02852 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content); 02853 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) { 02854 cur = xmlNewDocNode( parent->doc, ns, name, content); 02855 } else { 02856 return(NULL); 02857 } 02858 if (cur == NULL) return(NULL); 02859 02860 /* 02861 * add the new element at the end of the children list. 02862 */ 02863 cur->type = XML_ELEMENT_NODE; 02864 cur->parent = parent; 02865 cur->doc = parent->doc; 02866 if (parent->children == NULL) { 02867 parent->children = cur; 02868 parent->last = cur; 02869 } else { 02870 prev = parent->last; 02871 prev->next = cur; 02872 cur->prev = prev; 02873 parent->last = cur; 02874 } 02875 02876 return(cur); 02877 } 02878 #endif /* LIBXML_TREE_ENABLED */ 02879 02893 static xmlNodePtr 02894 xmlAddPropSibling(xmlNodePtr prev, xmlNodePtr cur, xmlNodePtr prop) { 02895 xmlAttrPtr attr; 02896 02897 if (cur->type != XML_ATTRIBUTE_NODE) 02898 return(NULL); 02899 02900 /* check if an attribute with the same name exists */ 02901 if (prop->ns == NULL) 02902 attr = xmlHasNsProp(cur->parent, prop->name, NULL); 02903 else 02904 attr = xmlHasNsProp(cur->parent, prop->name, prop->ns->href); 02905 02906 if (prop->doc != cur->doc) { 02907 xmlSetTreeDoc(prop, cur->doc); 02908 } 02909 prop->parent = cur->parent; 02910 prop->prev = prev; 02911 if (prev != NULL) { 02912 prop->next = prev->next; 02913 prev->next = prop; 02914 if (prop->next) 02915 prop->next->prev = prop; 02916 } else { 02917 prop->next = cur; 02918 cur->prev = prop; 02919 } 02920 if (prop->prev == NULL && prop->parent != NULL) 02921 prop->parent->properties = (xmlAttrPtr) prop; 02922 if ((attr != NULL) && (attr->type != XML_ATTRIBUTE_DECL)) { 02923 /* different instance, destroy it (attributes must be unique) */ 02924 xmlRemoveProp((xmlAttrPtr) attr); 02925 } 02926 return prop; 02927 } 02928 02943 xmlNodePtr 02944 xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) { 02945 if (cur == NULL) { 02946 #ifdef DEBUG_TREE 02947 xmlGenericError(xmlGenericErrorContext, 02948 "xmlAddNextSibling : cur == NULL\n"); 02949 #endif 02950 return(NULL); 02951 } 02952 if (elem == NULL) { 02953 #ifdef DEBUG_TREE 02954 xmlGenericError(xmlGenericErrorContext, 02955 "xmlAddNextSibling : elem == NULL\n"); 02956 #endif 02957 return(NULL); 02958 } 02959 02960 if (cur == elem) { 02961 #ifdef DEBUG_TREE 02962 xmlGenericError(xmlGenericErrorContext, 02963 "xmlAddNextSibling : cur == elem\n"); 02964 #endif 02965 return(NULL); 02966 } 02967 02968 xmlUnlinkNode(elem); 02969 02970 if (elem->type == XML_TEXT_NODE) { 02971 if (cur->type == XML_TEXT_NODE) { 02972 xmlNodeAddContent(cur, elem->content); 02973 xmlFreeNode(elem); 02974 return(cur); 02975 } 02976 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) && 02977 (cur->name == cur->next->name)) { 02978 xmlChar *tmp; 02979 02980 tmp = xmlStrdup(elem->content); 02981 tmp = xmlStrcat(tmp, cur->next->content); 02982 xmlNodeSetContent(cur->next, tmp); 02983 xmlFree(tmp); 02984 xmlFreeNode(elem); 02985 return(cur->next); 02986 } 02987 } else if (elem->type == XML_ATTRIBUTE_NODE) { 02988 return xmlAddPropSibling(cur, cur, elem); 02989 } 02990 02991 if (elem->doc != cur->doc) { 02992 xmlSetTreeDoc(elem, cur->doc); 02993 } 02994 elem->parent = cur->parent; 02995 elem->prev = cur; 02996 elem->next = cur->next; 02997 cur->next = elem; 02998 if (elem->next != NULL) 02999 elem->next->prev = elem; 03000 if ((elem->parent != NULL) && (elem->parent->last == cur)) 03001 elem->parent->last = elem; 03002 return(elem); 03003 } 03004 03005 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \ 03006 defined(LIBXML_SCHEMAS_ENABLED) 03007 03021 xmlNodePtr 03022 xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) { 03023 if (cur == NULL) { 03024 #ifdef DEBUG_TREE 03025 xmlGenericError(xmlGenericErrorContext, 03026 "xmlAddPrevSibling : cur == NULL\n"); 03027 #endif 03028 return(NULL); 03029 } 03030 if (elem == NULL) { 03031 #ifdef DEBUG_TREE 03032 xmlGenericError(xmlGenericErrorContext, 03033 "xmlAddPrevSibling : elem == NULL\n"); 03034 #endif 03035 return(NULL); 03036 } 03037 03038 if (cur == elem) { 03039 #ifdef DEBUG_TREE 03040 xmlGenericError(xmlGenericErrorContext, 03041 "xmlAddPrevSibling : cur == elem\n"); 03042 #endif 03043 return(NULL); 03044 } 03045 03046 xmlUnlinkNode(elem); 03047 03048 if (elem->type == XML_TEXT_NODE) { 03049 if (cur->type == XML_TEXT_NODE) { 03050 xmlChar *tmp; 03051 03052 tmp = xmlStrdup(elem->content); 03053 tmp = xmlStrcat(tmp, cur->content); 03054 xmlNodeSetContent(cur, tmp); 03055 xmlFree(tmp); 03056 xmlFreeNode(elem); 03057 return(cur); 03058 } 03059 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) && 03060 (cur->name == cur->prev->name)) { 03061 xmlNodeAddContent(cur->prev, elem->content); 03062 xmlFreeNode(elem); 03063 return(cur->prev); 03064 } 03065 } else if (elem->type == XML_ATTRIBUTE_NODE) { 03066 return xmlAddPropSibling(cur->prev, cur, elem); 03067 } 03068 03069 if (elem->doc != cur->doc) { 03070 xmlSetTreeDoc(elem, cur->doc); 03071 } 03072 elem->parent = cur->parent; 03073 elem->next = cur; 03074 elem->prev = cur->prev; 03075 cur->prev = elem; 03076 if (elem->prev != NULL) 03077 elem->prev->next = elem; 03078 if ((elem->parent != NULL) && (elem->parent->children == cur)) { 03079 elem->parent->children = elem; 03080 } 03081 return(elem); 03082 } 03083 #endif /* LIBXML_TREE_ENABLED */ 03084 03097 xmlNodePtr 03098 xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) { 03099 xmlNodePtr parent; 03100 03101 if (cur == NULL) { 03102 #ifdef DEBUG_TREE 03103 xmlGenericError(xmlGenericErrorContext, 03104 "xmlAddSibling : cur == NULL\n"); 03105 #endif 03106 return(NULL); 03107 } 03108 03109 if (elem == NULL) { 03110 #ifdef DEBUG_TREE 03111 xmlGenericError(xmlGenericErrorContext, 03112 "xmlAddSibling : elem == NULL\n"); 03113 #endif 03114 return(NULL); 03115 } 03116 03117 if (cur == elem) { 03118 #ifdef DEBUG_TREE 03119 xmlGenericError(xmlGenericErrorContext, 03120 "xmlAddSibling : cur == elem\n"); 03121 #endif 03122 return(NULL); 03123 } 03124 03125 /* 03126 * Constant time is we can rely on the ->parent->last to find 03127 * the last sibling. 03128 */ 03129 if ((cur->type != XML_ATTRIBUTE_NODE) && (cur->parent != NULL) && 03130 (cur->parent->children != NULL) && 03131 (cur->parent->last != NULL) && 03132 (cur->parent->last->next == NULL)) { 03133 cur = cur->parent->last; 03134 } else { 03135 while (cur->next != NULL) cur = cur->next; 03136 } 03137 03138 xmlUnlinkNode(elem); 03139 03140 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) && 03141 (cur->name == elem->name)) { 03142 xmlNodeAddContent(cur, elem->content); 03143 xmlFreeNode(elem); 03144 return(cur); 03145 } else if (elem->type == XML_ATTRIBUTE_NODE) { 03146 return xmlAddPropSibling(cur, cur, elem); 03147 } 03148 03149 if (elem->doc != cur->doc) { 03150 xmlSetTreeDoc(elem, cur->doc); 03151 } 03152 parent = cur->parent; 03153 elem->prev = cur; 03154 elem->next = NULL; 03155 elem->parent = parent; 03156 cur->next = elem; 03157 if (parent != NULL) 03158 parent->last = elem; 03159 03160 return(elem); 03161 } 03162 03173 xmlNodePtr 03174 xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) { 03175 xmlNodePtr prev; 03176 03177 if (parent == NULL) { 03178 #ifdef DEBUG_TREE 03179 xmlGenericError(xmlGenericErrorContext, 03180 "xmlAddChildList : parent == NULL\n"); 03181 #endif 03182 return(NULL); 03183 } 03184 03185 if (cur == NULL) { 03186 #ifdef DEBUG_TREE 03187 xmlGenericError(xmlGenericErrorContext, 03188 "xmlAddChildList : child == NULL\n"); 03189 #endif 03190 return(NULL); 03191 } 03192 03193 if ((cur->doc != NULL) && (parent->doc != NULL) && 03194 (cur->doc != parent->doc)) { 03195 #ifdef DEBUG_TREE 03196 xmlGenericError(xmlGenericErrorContext, 03197 "Elements moved to a different document\n"); 03198 #endif 03199 } 03200 03201 /* 03202 * add the first element at the end of the children list. 03203 */ 03204 03205 if (parent->children == NULL) { 03206 parent->children = cur; 03207 } else { 03208 /* 03209 * If cur and parent->last both are TEXT nodes, then merge them. 03210 */ 03211 if ((cur->type == XML_TEXT_NODE) && 03212 (parent->last->type == XML_TEXT_NODE) && 03213 (cur->name == parent->last->name)) { 03214 xmlNodeAddContent(parent->last, cur->content); 03215 /* 03216 * if it's the only child, nothing more to be done. 03217 */ 03218 if (cur->next == NULL) { 03219 xmlFreeNode(cur); 03220 return(parent->last); 03221 } 03222 prev = cur; 03223 cur = cur->next; 03224 xmlFreeNode(prev); 03225 } 03226 prev = parent->last; 03227 prev->next = cur; 03228 cur->prev = prev; 03229 } 03230 while (cur->next != NULL) { 03231 cur->parent = parent; 03232 if (cur->doc != parent->doc) { 03233 xmlSetTreeDoc(cur, parent->doc); 03234 } 03235 cur = cur->next; 03236 } 03237 cur->parent = parent; 03238 /* the parent may not be linked to a doc ! */ 03239 if (cur->doc != parent->doc) { 03240 xmlSetTreeDoc(cur, parent->doc); 03241 } 03242 parent->last = cur; 03243 03244 return(cur); 03245 } 03246 03259 xmlNodePtr 03260 xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) { 03261 xmlNodePtr prev; 03262 03263 if (parent == NULL) { 03264 #ifdef DEBUG_TREE 03265 xmlGenericError(xmlGenericErrorContext, 03266 "xmlAddChild : parent == NULL\n"); 03267 #endif 03268 return(NULL); 03269 } 03270 03271 if (cur == NULL) { 03272 #ifdef DEBUG_TREE 03273 xmlGenericError(xmlGenericErrorContext, 03274 "xmlAddChild : child == NULL\n"); 03275 #endif 03276 return(NULL); 03277 } 03278 03279 if (parent == cur) { 03280 #ifdef DEBUG_TREE 03281 xmlGenericError(xmlGenericErrorContext, 03282 "xmlAddChild : parent == cur\n"); 03283 #endif 03284 return(NULL); 03285 } 03286 /* 03287 * If cur is a TEXT node, merge its content with adjacent TEXT nodes 03288 * cur is then freed. 03289 */ 03290 if (cur->type == XML_TEXT_NODE) { 03291 if ((parent->type == XML_TEXT_NODE) && 03292 (parent->content != NULL) && 03293 (parent->name == cur->name)) { 03294 xmlNodeAddContent(parent, cur->content); 03295 xmlFreeNode(cur); 03296 return(parent); 03297 } 03298 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) && 03299 (parent->last->name == cur->name) && 03300 (parent->last != cur)) { 03301 xmlNodeAddContent(parent->last, cur->content); 03302 xmlFreeNode(cur); 03303 return(parent->last); 03304 } 03305 } 03306 03307 /* 03308 * add the new element at the end of the children list. 03309 */ 03310 prev = cur->parent; 03311 cur->parent = parent; 03312 if (cur->doc != parent->doc) { 03313 xmlSetTreeDoc(cur, parent->doc); 03314 } 03315 /* this check prevents a loop on tree-traversions if a developer 03316 * tries to add a node to its parent multiple times 03317 */ 03318 if (prev == parent) 03319 return(cur); 03320 03321 /* 03322 * Coalescing 03323 */ 03324 if ((parent->type == XML_TEXT_NODE) && 03325 (parent->content != NULL) && 03326 (parent != cur)) { 03327 xmlNodeAddContent(parent, cur->content); 03328 xmlFreeNode(cur); 03329 return(parent); 03330 } 03331 if (cur->type == XML_ATTRIBUTE_NODE) { 03332 if (parent->type != XML_ELEMENT_NODE) 03333 return(NULL); 03334 if (parent->properties != NULL) { 03335 /* check if an attribute with the same name exists */ 03336 xmlAttrPtr lastattr; 03337 03338 if (cur->ns == NULL) 03339 lastattr = xmlHasNsProp(parent, cur->name, NULL); 03340 else 03341 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href); 03342 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur) && (lastattr->type != XML_ATTRIBUTE_DECL)) { 03343 /* different instance, destroy it (attributes must be unique) */ 03344 xmlUnlinkNode((xmlNodePtr) lastattr); 03345 xmlFreeProp(lastattr); 03346 } 03347 if (lastattr == (xmlAttrPtr) cur) 03348 return(cur); 03349 03350 } 03351 if (parent->properties == NULL) { 03352 parent->properties = (xmlAttrPtr) cur; 03353 } else { 03354 /* find the end */ 03355 xmlAttrPtr lastattr = parent->properties; 03356 while (lastattr->next != NULL) { 03357 lastattr = lastattr->next; 03358 } 03359 lastattr->next = (xmlAttrPtr) cur; 03360 ((xmlAttrPtr) cur)->prev = lastattr; 03361 } 03362 } else { 03363 if (parent->children == NULL) { 03364 parent->children = cur; 03365 parent->last = cur; 03366 } else { 03367 prev = parent->last; 03368 prev->next = cur; 03369 cur->prev = prev; 03370 parent->last = cur; 03371 } 03372 } 03373 return(cur); 03374 } 03375 03383 xmlNodePtr 03384 xmlGetLastChild(xmlNodePtr parent) { 03385 if (parent == NULL) { 03386 #ifdef DEBUG_TREE 03387 xmlGenericError(xmlGenericErrorContext, 03388 "xmlGetLastChild : parent == NULL\n"); 03389 #endif 03390 return(NULL); 03391 } 03392 return(parent->last); 03393 } 03394 03395 #ifdef LIBXML_TREE_ENABLED 03396 /* 03397 * 5 interfaces from DOM ElementTraversal 03398 */ 03399 03412 unsigned long 03413 xmlChildElementCount(xmlNodePtr parent) { 03414 unsigned long ret = 0; 03415 xmlNodePtr cur = NULL; 03416 03417 if (parent == NULL) 03418 return(0); 03419 switch (parent->type) { 03420 case XML_ELEMENT_NODE: 03421 case XML_ENTITY_NODE: 03422 case XML_DOCUMENT_NODE: 03423 case XML_HTML_DOCUMENT_NODE: 03424 cur = parent->children; 03425 break; 03426 default: 03427 return(0); 03428 } 03429 while (cur != NULL) { 03430 if (cur->type == XML_ELEMENT_NODE) 03431 ret++; 03432 cur = cur->next; 03433 } 03434 return(ret); 03435 } 03436 03448 xmlNodePtr 03449 xmlFirstElementChild(xmlNodePtr parent) { 03450 xmlNodePtr cur = NULL; 03451 03452 if (parent == NULL) 03453 return(NULL); 03454 switch (parent->type) { 03455 case XML_ELEMENT_NODE: 03456 case XML_ENTITY_NODE: 03457 case XML_DOCUMENT_NODE: 03458 case XML_HTML_DOCUMENT_NODE: 03459 cur = parent->children; 03460 break; 03461 default: 03462 return(NULL); 03463 } 03464 while (cur != NULL) { 03465 if (cur->type == XML_ELEMENT_NODE) 03466 return(cur); 03467 cur = cur->next; 03468 } 03469 return(NULL); 03470 } 03471 03483 xmlNodePtr 03484 xmlLastElementChild(xmlNodePtr parent) { 03485 xmlNodePtr cur = NULL; 03486 03487 if (parent == NULL) 03488 return(NULL); 03489 switch (parent->type) { 03490 case XML_ELEMENT_NODE: 03491 case XML_ENTITY_NODE: 03492 case XML_DOCUMENT_NODE: 03493 case XML_HTML_DOCUMENT_NODE: 03494 cur = parent->last; 03495 break; 03496 default: 03497 return(NULL); 03498 } 03499 while (cur != NULL) { 03500 if (cur->type == XML_ELEMENT_NODE) 03501 return(cur); 03502 cur = cur->prev; 03503 } 03504 return(NULL); 03505 } 03506 03519 xmlNodePtr 03520 xmlPreviousElementSibling(xmlNodePtr node) { 03521 if (node == NULL) 03522 return(NULL); 03523 switch (node->type) { 03524 case XML_ELEMENT_NODE: 03525 case XML_TEXT_NODE: 03526 case XML_CDATA_SECTION_NODE: 03527 case XML_ENTITY_REF_NODE: 03528 case XML_ENTITY_NODE: 03529 case XML_PI_NODE: 03530 case XML_COMMENT_NODE: 03531 case XML_XINCLUDE_START: 03532 case XML_XINCLUDE_END: 03533 node = node->prev; 03534 break; 03535 default: 03536 return(NULL); 03537 } 03538 while (node != NULL) { 03539 if (node->type == XML_ELEMENT_NODE) 03540 return(node); 03541 node = node->prev; 03542 } 03543 return(NULL); 03544 } 03545 03558 xmlNodePtr 03559 xmlNextElementSibling(xmlNodePtr node) { 03560 if (node == NULL) 03561 return(NULL); 03562 switch (node->type) { 03563 case XML_ELEMENT_NODE: 03564 case XML_TEXT_NODE: 03565 case XML_CDATA_SECTION_NODE: 03566 case XML_ENTITY_REF_NODE: 03567 case XML_ENTITY_NODE: 03568 case XML_PI_NODE: 03569 case XML_COMMENT_NODE: 03570 case XML_DTD_NODE: 03571 case XML_XINCLUDE_START: 03572 case XML_XINCLUDE_END: 03573 node = node->next; 03574 break; 03575 default: 03576 return(NULL); 03577 } 03578 while (node != NULL) { 03579 if (node->type == XML_ELEMENT_NODE) 03580 return(node); 03581 node = node->next; 03582 } 03583 return(NULL); 03584 } 03585 03586 #endif /* LIBXML_TREE_ENABLED */ 03587 03595 void 03596 xmlFreeNodeList(xmlNodePtr cur) { 03597 xmlNodePtr next; 03598 xmlDictPtr dict = NULL; 03599 03600 if (cur == NULL) return; 03601 if (cur->type == XML_NAMESPACE_DECL) { 03602 xmlFreeNsList((xmlNsPtr) cur); 03603 return; 03604 } 03605 if ((cur->type == XML_DOCUMENT_NODE) || 03606 #ifdef LIBXML_DOCB_ENABLED 03607 (cur->type == XML_DOCB_DOCUMENT_NODE) || 03608 #endif 03609 (cur->type == XML_HTML_DOCUMENT_NODE)) { 03610 xmlFreeDoc((xmlDocPtr) cur); 03611 return; 03612 } 03613 if (cur->doc != NULL) dict = cur->doc->dict; 03614 while (cur != NULL) { 03615 next = cur->next; 03616 if (cur->type != XML_DTD_NODE) { 03617 03618 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue)) 03619 xmlDeregisterNodeDefaultValue(cur); 03620 03621 if ((cur->children != NULL) && 03622 (cur->type != XML_ENTITY_REF_NODE)) 03623 xmlFreeNodeList(cur->children); 03624 if (((cur->type == XML_ELEMENT_NODE) || 03625 (cur->type == XML_XINCLUDE_START) || 03626 (cur->type == XML_XINCLUDE_END)) && 03627 (cur->properties != NULL)) 03628 xmlFreePropList(cur->properties); 03629 if ((cur->type != XML_ELEMENT_NODE) && 03630 (cur->type != XML_XINCLUDE_START) && 03631 (cur->type != XML_XINCLUDE_END) && 03632 (cur->type != XML_ENTITY_REF_NODE) && 03633 (cur->content != (xmlChar *) &(cur->properties))) { 03634 DICT_FREE(cur->content) 03635 } 03636 if (((cur->type == XML_ELEMENT_NODE) || 03637 (cur->type == XML_XINCLUDE_START) || 03638 (cur->type == XML_XINCLUDE_END)) && 03639 (cur->nsDef != NULL)) 03640 xmlFreeNsList(cur->nsDef); 03641 03642 /* 03643 * When a node is a text node or a comment, it uses a global static 03644 * variable for the name of the node. 03645 * Otherwise the node name might come from the document's 03646 * dictionnary 03647 */ 03648 if ((cur->name != NULL) && 03649 (cur->type != XML_TEXT_NODE) && 03650 (cur->type != XML_COMMENT_NODE)) 03651 DICT_FREE(cur->name) 03652 xmlFree(cur); 03653 } 03654 cur = next; 03655 } 03656 } 03657 03665 void 03666 xmlFreeNode(xmlNodePtr cur) { 03667 xmlDictPtr dict = NULL; 03668 03669 if (cur == NULL) return; 03670 03671 /* use xmlFreeDtd for DTD nodes */ 03672 if (cur->type == XML_DTD_NODE) { 03673 xmlFreeDtd((xmlDtdPtr) cur); 03674 return; 03675 } 03676 if (cur->type == XML_NAMESPACE_DECL) { 03677 xmlFreeNs((xmlNsPtr) cur); 03678 return; 03679 } 03680 if (cur->type == XML_ATTRIBUTE_NODE) { 03681 xmlFreeProp((xmlAttrPtr) cur); 03682 return; 03683 } 03684 03685 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue)) 03686 xmlDeregisterNodeDefaultValue(cur); 03687 03688 if (cur->doc != NULL) dict = cur->doc->dict; 03689 03690 if (cur->type == XML_ENTITY_DECL) { 03691 xmlEntityPtr ent = (xmlEntityPtr) cur; 03692 DICT_FREE(ent->SystemID); 03693 DICT_FREE(ent->ExternalID); 03694 } 03695 if ((cur->children != NULL) && 03696 (cur->type != XML_ENTITY_REF_NODE)) 03697 xmlFreeNodeList(cur->children); 03698 if (((cur->type == XML_ELEMENT_NODE) || 03699 (cur->type == XML_XINCLUDE_START) || 03700 (cur->type == XML_XINCLUDE_END)) && 03701 (cur->properties != NULL)) 03702 xmlFreePropList(cur->properties); 03703 if ((cur->type != XML_ELEMENT_NODE) && 03704 (cur->content != NULL) && 03705 (cur->type != XML_ENTITY_REF_NODE) && 03706 (cur->type != XML_XINCLUDE_END) && 03707 (cur->type != XML_XINCLUDE_START) && 03708 (cur->content != (xmlChar *) &(cur->properties))) { 03709 DICT_FREE(cur->content) 03710 } 03711 03712 /* 03713 * When a node is a text node or a comment, it uses a global static 03714 * variable for the name of the node. 03715 * Otherwise the node name might come from the document's dictionnary 03716 */ 03717 if ((cur->name != NULL) && 03718 (cur->type != XML_TEXT_NODE) && 03719 (cur->type != XML_COMMENT_NODE)) 03720 DICT_FREE(cur->name) 03721 03722 if (((cur->type == XML_ELEMENT_NODE) || 03723 (cur->type == XML_XINCLUDE_START) || 03724 (cur->type == XML_XINCLUDE_END)) && 03725 (cur->nsDef != NULL)) 03726 xmlFreeNsList(cur->nsDef); 03727 xmlFree(cur); 03728 } 03729 03736 void 03737 xmlUnlinkNode(xmlNodePtr cur) { 03738 if (cur == NULL) { 03739 #ifdef DEBUG_TREE 03740 xmlGenericError(xmlGenericErrorContext, 03741 "xmlUnlinkNode : node == NULL\n"); 03742 #endif 03743 return; 03744 } 03745 if (cur->type == XML_DTD_NODE) { 03746 xmlDocPtr doc; 03747 doc = cur->doc; 03748 if (doc != NULL) { 03749 if (doc->intSubset == (xmlDtdPtr) cur) 03750 doc->intSubset = NULL; 03751 if (doc->extSubset == (xmlDtdPtr) cur) 03752 doc->extSubset = NULL; 03753 } 03754 } 03755 if (cur->type == XML_ENTITY_DECL) { 03756 xmlDocPtr doc; 03757 doc = cur->doc; 03758 if (doc != NULL) { 03759 if (doc->intSubset != NULL) { 03760 if (xmlHashLookup(doc->intSubset->entities, cur->name) == cur) 03761 xmlHashRemoveEntry(doc->intSubset->entities, cur->name, 03762 NULL); 03763 if (xmlHashLookup(doc->intSubset->pentities, cur->name) == cur) 03764 xmlHashRemoveEntry(doc->intSubset->pentities, cur->name, 03765 NULL); 03766 } 03767 if (doc->extSubset != NULL) { 03768 if (xmlHashLookup(doc->extSubset->entities, cur->name) == cur) 03769 xmlHashRemoveEntry(doc->extSubset->entities, cur->name, 03770 NULL); 03771 if (xmlHashLookup(doc->extSubset->pentities, cur->name) == cur) 03772 xmlHashRemoveEntry(doc->extSubset->pentities, cur->name, 03773 NULL); 03774 } 03775 } 03776 } 03777 if (cur->parent != NULL) { 03778 xmlNodePtr parent; 03779 parent = cur->parent; 03780 if (cur->type == XML_ATTRIBUTE_NODE) { 03781 if (parent->properties == (xmlAttrPtr) cur) 03782 parent->properties = ((xmlAttrPtr) cur)->next; 03783 } else { 03784 if (parent->children == cur) 03785 parent->children = cur->next; 03786 if (parent->last == cur) 03787 parent->last = cur->prev; 03788 } 03789 cur->parent = NULL; 03790 } 03791 if (cur->next != NULL) 03792 cur->next->prev = cur->prev; 03793 if (cur->prev != NULL) 03794 cur->prev->next = cur->next; 03795 cur->next = cur->prev = NULL; 03796 } 03797 03798 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED) 03799 03810 xmlNodePtr 03811 xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) { 03812 if (old == cur) return(NULL); 03813 if ((old == NULL) || (old->parent == NULL)) { 03814 #ifdef DEBUG_TREE 03815 xmlGenericError(xmlGenericErrorContext, 03816 "xmlReplaceNode : old == NULL or without parent\n"); 03817 #endif 03818 return(NULL); 03819 } 03820 if (cur == NULL) { 03821 xmlUnlinkNode(old); 03822 return(old); 03823 } 03824 if (cur == old) { 03825 return(old); 03826 } 03827 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) { 03828 #ifdef DEBUG_TREE 03829 xmlGenericError(xmlGenericErrorContext, 03830 "xmlReplaceNode : Trying to replace attribute node with other node type\n"); 03831 #endif 03832 return(old); 03833 } 03834 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) { 03835 #ifdef DEBUG_TREE 03836 xmlGenericError(xmlGenericErrorContext, 03837 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n"); 03838 #endif 03839 return(old); 03840 } 03841 xmlUnlinkNode(cur); 03842 xmlSetTreeDoc(cur, old->doc); 03843 cur->parent = old->parent; 03844 cur->next = old->next; 03845 if (cur->next != NULL) 03846 cur->next->prev = cur; 03847 cur->prev = old->prev; 03848 if (cur->prev != NULL) 03849 cur->prev->next = cur; 03850 if (cur->parent != NULL) { 03851 if (cur->type == XML_ATTRIBUTE_NODE) { 03852 if (cur->parent->properties == (xmlAttrPtr)old) 03853 cur->parent->properties = ((xmlAttrPtr) cur); 03854 } else { 03855 if (cur->parent->children == old) 03856 cur->parent->children = cur; 03857 if (cur->parent->last == old) 03858 cur->parent->last = cur; 03859 } 03860 } 03861 old->next = old->prev = NULL; 03862 old->parent = NULL; 03863 return(old); 03864 } 03865 #endif /* LIBXML_TREE_ENABLED */ 03866 03867 /************************************************************************ 03868 * * 03869 * Copy operations * 03870 * * 03871 ************************************************************************/ 03872 03881 xmlNsPtr 03882 xmlCopyNamespace(xmlNsPtr cur) { 03883 xmlNsPtr ret; 03884 03885 if (cur == NULL) return(NULL); 03886 switch (cur->type) { 03887 case XML_LOCAL_NAMESPACE: 03888 ret = xmlNewNs(NULL, cur->href, cur->prefix); 03889 break; 03890 default: 03891 #ifdef DEBUG_TREE 03892 xmlGenericError(xmlGenericErrorContext, 03893 "xmlCopyNamespace: invalid type %d\n", cur->type); 03894 #endif 03895 return(NULL); 03896 } 03897 return(ret); 03898 } 03899 03908 xmlNsPtr 03909 xmlCopyNamespaceList(xmlNsPtr cur) { 03910 xmlNsPtr ret = NULL; 03911 xmlNsPtr p = NULL,q; 03912 03913 while (cur != NULL) { 03914 q = xmlCopyNamespace(cur); 03915 if (p == NULL) { 03916 ret = p = q; 03917 } else { 03918 p->next = q; 03919 p = q; 03920 } 03921 cur = cur->next; 03922 } 03923 return(ret); 03924 } 03925 03926 static xmlNodePtr 03927 xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent); 03928 03929 static xmlAttrPtr 03930 xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) { 03931 xmlAttrPtr ret; 03932 03933 if (cur == NULL) return(NULL); 03934 if (target != NULL) 03935 ret = xmlNewDocProp(target->doc, cur->name, NULL); 03936 else if (doc != NULL) 03937 ret = xmlNewDocProp(doc, cur->name, NULL); 03938 else if (cur->parent != NULL) 03939 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL); 03940 else if (cur->children != NULL) 03941 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL); 03942 else 03943 ret = xmlNewDocProp(NULL, cur->name, NULL); 03944 if (ret == NULL) return(NULL); 03945 ret->parent = target; 03946 03947 if ((cur->ns != NULL) && (target != NULL)) { 03948 xmlNsPtr ns; 03949 03950 ns = xmlSearchNs(target->doc, target, cur->ns->prefix); 03951 if (ns == NULL) { 03952 /* 03953 * Humm, we are copying an element whose namespace is defined 03954 * out of the new tree scope. Search it in the original tree 03955 * and add it at the top of the new tree 03956 */ 03957 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix); 03958 if (ns != NULL) { 03959 xmlNodePtr root = target; 03960 xmlNodePtr pred = NULL; 03961 03962 while (root->parent != NULL) { 03963 pred = root; 03964 root = root->parent; 03965 } 03966 if (root == (xmlNodePtr) target->doc) { 03967 /* correct possibly cycling above the document elt */ 03968 root = pred; 03969 } 03970 ret->ns = xmlNewNs(root, ns->href, ns->prefix); 03971 } 03972 } else { 03973 /* 03974 * we have to find something appropriate here since 03975 * we cant be sure, that the namespce we found is identified 03976 * by the prefix 03977 */ 03978 if (xmlStrEqual(ns->href, cur->ns->href)) { 03979 /* this is the nice case */ 03980 ret->ns = ns; 03981 } else { 03982 /* 03983 * we are in trouble: we need a new reconcilied namespace. 03984 * This is expensive 03985 */ 03986 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns); 03987 } 03988 } 03989 03990 } else 03991 ret->ns = NULL; 03992 03993 if (cur->children != NULL) { 03994 xmlNodePtr tmp; 03995 03996 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret); 03997 ret->last = NULL; 03998 tmp = ret->children; 03999 while (tmp != NULL) { 04000 /* tmp->parent = (xmlNodePtr)ret; */ 04001 if (tmp->next == NULL) 04002 ret->last = tmp; 04003 tmp = tmp->next; 04004 } 04005 } 04006 /* 04007 * Try to handle IDs 04008 */ 04009 if ((target!= NULL) && (cur!= NULL) && 04010 (target->doc != NULL) && (cur->doc != NULL) && 04011 (cur->doc->ids != NULL) && (cur->parent != NULL)) { 04012 if (xmlIsID(cur->doc, cur->parent, cur)) { 04013 xmlChar *id; 04014 04015 id = xmlNodeListGetString(cur->doc, cur->children, 1); 04016 if (id != NULL) { 04017 xmlAddID(NULL, target->doc, id, ret); 04018 xmlFree(id); 04019 } 04020 } 04021 } 04022 return(ret); 04023 } 04024 04034 xmlAttrPtr 04035 xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) { 04036 return xmlCopyPropInternal(NULL, target, cur); 04037 } 04038 04048 xmlAttrPtr 04049 xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) { 04050 xmlAttrPtr ret = NULL; 04051 xmlAttrPtr p = NULL,q; 04052 04053 while (cur != NULL) { 04054 q = xmlCopyProp(target, cur); 04055 if (q == NULL) 04056 return(NULL); 04057 if (p == NULL) { 04058 ret = p = q; 04059 } else { 04060 p->next = q; 04061 q->prev = p; 04062 p = q; 04063 } 04064 cur = cur->next; 04065 } 04066 return(ret); 04067 } 04068 04069 /* 04070 * NOTE about the CopyNode operations ! 04071 * 04072 * They are split into external and internal parts for one 04073 * tricky reason: namespaces. Doing a direct copy of a node 04074 * say RPM:Copyright without changing the namespace pointer to 04075 * something else can produce stale links. One way to do it is 04076 * to keep a reference counter but this doesn't work as soon 04077 * as one move the element or the subtree out of the scope of 04078 * the existing namespace. The actual solution seems to add 04079 * a copy of the namespace at the top of the copied tree if 04080 * not available in the subtree. 04081 * Hence two functions, the public front-end call the inner ones 04082 * The argument "recursive" normally indicates a recursive copy 04083 * of the node with values 0 (no) and 1 (yes). For XInclude, 04084 * however, we allow a value of 2 to indicate copy properties and 04085 * namespace info, but don't recurse on children. 04086 */ 04087 04088 static xmlNodePtr 04089 xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent, 04090 int extended) { 04091 xmlNodePtr ret; 04092 04093 if (node == NULL) return(NULL); 04094 switch (node->type) { 04095 case XML_TEXT_NODE: 04096 case XML_CDATA_SECTION_NODE: 04097 case XML_ELEMENT_NODE: 04098 case XML_DOCUMENT_FRAG_NODE: 04099 case XML_ENTITY_REF_NODE: 04100 case XML_ENTITY_NODE: 04101 case XML_PI_NODE: 04102 case XML_COMMENT_NODE: 04103 case XML_XINCLUDE_START: 04104 case XML_XINCLUDE_END: 04105 break; 04106 case XML_ATTRIBUTE_NODE: 04107 return((xmlNodePtr) xmlCopyPropInternal(doc, parent, (xmlAttrPtr) node)); 04108 case XML_NAMESPACE_DECL: 04109 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node)); 04110 04111 case XML_DOCUMENT_NODE: 04112 case XML_HTML_DOCUMENT_NODE: 04113 #ifdef LIBXML_DOCB_ENABLED 04114 case XML_DOCB_DOCUMENT_NODE: 04115 #endif 04116 #ifdef LIBXML_TREE_ENABLED 04117 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended)); 04118 #endif /* LIBXML_TREE_ENABLED */ 04119 case XML_DOCUMENT_TYPE_NODE: 04120 case XML_NOTATION_NODE: 04121 case XML_DTD_NODE: 04122 case XML_ELEMENT_DECL: 04123 case XML_ATTRIBUTE_DECL: 04124 case XML_ENTITY_DECL: 04125 return(NULL); 04126 } 04127 04128 /* 04129 * Allocate a new node and fill the fields. 04130 */ 04131 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); 04132 if (ret == NULL) { 04133 xmlTreeErrMemory("copying node"); 04134 return(NULL); 04135 } 04136 memset(ret, 0, sizeof(xmlNode)); 04137 ret->type = node->type; 04138 04139 ret->doc = doc; 04140 ret->parent = parent; 04141 if (node->name == xmlStringText) 04142 ret->name = xmlStringText; 04143 else if (node->name == xmlStringTextNoenc) 04144 ret->name = xmlStringTextNoenc; 04145 else if (node->name == xmlStringComment) 04146 ret->name = xmlStringComment; 04147 else if (node->name != NULL) { 04148 if ((doc != NULL) && (doc->dict != NULL)) 04149 ret->name = xmlDictLookup(doc->dict, node->name, -1); 04150 else 04151 ret->name = xmlStrdup(node->name); 04152 } 04153 if ((node->type != XML_ELEMENT_NODE) && 04154 (node->content != NULL) && 04155 (node->type != XML_ENTITY_REF_NODE) && 04156 (node->type != XML_XINCLUDE_END) && 04157 (node->type != XML_XINCLUDE_START)) { 04158 ret->content = xmlStrdup(node->content); 04159 }else{ 04160 if (node->type == XML_ELEMENT_NODE) 04161 ret->line = node->line; 04162 } 04163 if (parent != NULL) { 04164 xmlNodePtr tmp; 04165 04166 /* 04167 * this is a tricky part for the node register thing: 04168 * in case ret does get coalesced in xmlAddChild 04169 * the deregister-node callback is called; so we register ret now already 04170 */ 04171 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 04172 xmlRegisterNodeDefaultValue((xmlNodePtr)ret); 04173 04174 tmp = xmlAddChild(parent, ret); 04175 /* node could have coalesced */ 04176 if (tmp != ret) 04177 return(tmp); 04178 } 04179 04180 if (!extended) 04181 goto out; 04182 if (((node->type == XML_ELEMENT_NODE) || 04183 (node->type == XML_XINCLUDE_START)) && (node->nsDef != NULL)) 04184 ret->nsDef = xmlCopyNamespaceList(node->nsDef); 04185 04186 if (node->ns != NULL) { 04187 xmlNsPtr ns; 04188 04189 ns = xmlSearchNs(doc, ret, node->ns->prefix); 04190 if (ns == NULL) { 04191 /* 04192 * Humm, we are copying an element whose namespace is defined 04193 * out of the new tree scope. Search it in the original tree 04194 * and add it at the top of the new tree 04195 */ 04196 ns = xmlSearchNs(node->doc, node, node->ns->prefix); 04197 if (ns != NULL) { 04198 xmlNodePtr root = ret; 04199 04200 while (root->parent != NULL) root = root->parent; 04201 ret->ns = xmlNewNs(root, ns->href, ns->prefix); 04202 } else { 04203 ret->ns = xmlNewReconciliedNs(doc, ret, node->ns); 04204 } 04205 } else { 04206 /* 04207 * reference the existing namespace definition in our own tree. 04208 */ 04209 ret->ns = ns; 04210 } 04211 } 04212 if (((node->type == XML_ELEMENT_NODE) || 04213 (node->type == XML_XINCLUDE_START)) && (node->properties != NULL)) 04214 ret->properties = xmlCopyPropList(ret, node->properties); 04215 if (node->type == XML_ENTITY_REF_NODE) { 04216 if ((doc == NULL) || (node->doc != doc)) { 04217 /* 04218 * The copied node will go into a separate document, so 04219 * to avoid dangling references to the ENTITY_DECL node 04220 * we cannot keep the reference. Try to find it in the 04221 * target document. 04222 */ 04223 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name); 04224 } else { 04225 ret->children = node->children; 04226 } 04227 ret->last = ret->children; 04228 } else if ((node->children != NULL) && (extended != 2)) { 04229 ret->children = xmlStaticCopyNodeList(node->children, doc, ret); 04230 UPDATE_LAST_CHILD_AND_PARENT(ret) 04231 } 04232 04233 out: 04234 /* if parent != NULL we already registered the node above */ 04235 if ((parent == NULL) && 04236 ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))) 04237 xmlRegisterNodeDefaultValue((xmlNodePtr)ret); 04238 return(ret); 04239 } 04240 04241 static xmlNodePtr 04242 xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) { 04243 xmlNodePtr ret = NULL; 04244 xmlNodePtr p = NULL,q; 04245 04246 while (node != NULL) { 04247 #ifdef LIBXML_TREE_ENABLED 04248 if (node->type == XML_DTD_NODE ) { 04249 if (doc == NULL) { 04250 node = node->next; 04251 continue; 04252 } 04253 if (doc->intSubset == NULL) { 04254 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node ); 04255 q->doc = doc; 04256 q->parent = parent; 04257 doc->intSubset = (xmlDtdPtr) q; 04258 xmlAddChild(parent, q); 04259 } else { 04260 q = (xmlNodePtr) doc->intSubset; 04261 xmlAddChild(parent, q); 04262 } 04263 } else 04264 #endif /* LIBXML_TREE_ENABLED */ 04265 q = xmlStaticCopyNode(node, doc, parent, 1); 04266 if (ret == NULL) { 04267 q->prev = NULL; 04268 ret = p = q; 04269 } else if (p != q) { 04270 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */ 04271 p->next = q; 04272 q->prev = p; 04273 p = q; 04274 } 04275 node = node->next; 04276 } 04277 return(ret); 04278 } 04279 04291 xmlNodePtr 04292 xmlCopyNode(const xmlNodePtr node, int extended) { 04293 xmlNodePtr ret; 04294 04295 ret = xmlStaticCopyNode(node, NULL, NULL, extended); 04296 return(ret); 04297 } 04298 04311 xmlNodePtr 04312 xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int extended) { 04313 xmlNodePtr ret; 04314 04315 ret = xmlStaticCopyNode(node, doc, NULL, extended); 04316 return(ret); 04317 } 04318 04328 xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, const xmlNodePtr node) { 04329 xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL); 04330 return(ret); 04331 } 04332 04342 xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) { 04343 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL); 04344 return(ret); 04345 } 04346 04347 #if defined(LIBXML_TREE_ENABLED) 04348 04356 xmlDtdPtr 04357 xmlCopyDtd(xmlDtdPtr dtd) { 04358 xmlDtdPtr ret; 04359 xmlNodePtr cur, p = NULL, q; 04360 04361 if (dtd == NULL) return(NULL); 04362 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID); 04363 if (ret == NULL) return(NULL); 04364 if (dtd->entities != NULL) 04365 ret->entities = (void *) xmlCopyEntitiesTable( 04366 (xmlEntitiesTablePtr) dtd->entities); 04367 if (dtd->notations != NULL) 04368 ret->notations = (void *) xmlCopyNotationTable( 04369 (xmlNotationTablePtr) dtd->notations); 04370 if (dtd->elements != NULL) 04371 ret->elements = (void *) xmlCopyElementTable( 04372 (xmlElementTablePtr) dtd->elements); 04373 if (dtd->attributes != NULL) 04374 ret->attributes = (void *) xmlCopyAttributeTable( 04375 (xmlAttributeTablePtr) dtd->attributes); 04376 if (dtd->pentities != NULL) 04377 ret->pentities = (void *) xmlCopyEntitiesTable( 04378 (xmlEntitiesTablePtr) dtd->pentities); 04379 04380 cur = dtd->children; 04381 while (cur != NULL) { 04382 q = NULL; 04383 04384 if (cur->type == XML_ENTITY_DECL) { 04385 xmlEntityPtr tmp = (xmlEntityPtr) cur; 04386 switch (tmp->etype) { 04387 case XML_INTERNAL_GENERAL_ENTITY: 04388 case XML_EXTERNAL_GENERAL_PARSED_ENTITY: 04389 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: 04390 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name); 04391 break; 04392 case XML_INTERNAL_PARAMETER_ENTITY: 04393 case XML_EXTERNAL_PARAMETER_ENTITY: 04394 q = (xmlNodePtr) 04395 xmlGetParameterEntityFromDtd(ret, tmp->name); 04396 break; 04397 case XML_INTERNAL_PREDEFINED_ENTITY: 04398 break; 04399 } 04400 } else if (cur->type == XML_ELEMENT_DECL) { 04401 xmlElementPtr tmp = (xmlElementPtr) cur; 04402 q = (xmlNodePtr) 04403 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix); 04404 } else if (cur->type == XML_ATTRIBUTE_DECL) { 04405 xmlAttributePtr tmp = (xmlAttributePtr) cur; 04406 q = (xmlNodePtr) 04407 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix); 04408 } else if (cur->type == XML_COMMENT_NODE) { 04409 q = xmlCopyNode(cur, 0); 04410 } 04411 04412 if (q == NULL) { 04413 cur = cur->next; 04414 continue; 04415 } 04416 04417 if (p == NULL) 04418 ret->children = q; 04419 else 04420 p->next = q; 04421 04422 q->prev = p; 04423 q->parent = (xmlNodePtr) ret; 04424 q->next = NULL; 04425 ret->last = q; 04426 p = q; 04427 cur = cur->next; 04428 } 04429 04430 return(ret); 04431 } 04432 #endif 04433 04434 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) 04435 04445 xmlDocPtr 04446 xmlCopyDoc(xmlDocPtr doc, int recursive) { 04447 xmlDocPtr ret; 04448 04449 if (doc == NULL) return(NULL); 04450 ret = xmlNewDoc(doc->version); 04451 if (ret == NULL) return(NULL); 04452 if (doc->name != NULL) 04453 ret->name = xmlMemStrdup(doc->name); 04454 if (doc->encoding != NULL) 04455 ret->encoding = xmlStrdup(doc->encoding); 04456 if (doc->URL != NULL) 04457 ret->URL = xmlStrdup(doc->URL); 04458 ret->charset = doc->charset; 04459 ret->compression = doc->compression; 04460 ret->standalone = doc->standalone; 04461 if (!recursive) return(ret); 04462 04463 ret->last = NULL; 04464 ret->children = NULL; 04465 #ifdef LIBXML_TREE_ENABLED 04466 if (doc->intSubset != NULL) { 04467 ret->intSubset = xmlCopyDtd(doc->intSubset); 04468 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret); 04469 ret->intSubset->parent = ret; 04470 } 04471 #endif 04472 if (doc->oldNs != NULL) 04473 ret->oldNs = xmlCopyNamespaceList(doc->oldNs); 04474 if (doc->children != NULL) { 04475 xmlNodePtr tmp; 04476 04477 ret->children = xmlStaticCopyNodeList(doc->children, ret, 04478 (xmlNodePtr)ret); 04479 ret->last = NULL; 04480 tmp = ret->children; 04481 while (tmp != NULL) { 04482 if (tmp->next == NULL) 04483 ret->last = tmp; 04484 tmp = tmp->next; 04485 } 04486 } 04487 return(ret); 04488 } 04489 #endif /* LIBXML_TREE_ENABLED */ 04490 04491 /************************************************************************ 04492 * * 04493 * Content access functions * 04494 * * 04495 ************************************************************************/ 04496 04506 long 04507 xmlGetLineNo(xmlNodePtr node) 04508 { 04509 long result = -1; 04510 04511 if (!node) 04512 return result; 04513 if ((node->type == XML_ELEMENT_NODE) || 04514 (node->type == XML_TEXT_NODE) || 04515 (node->type == XML_COMMENT_NODE) || 04516 (node->type == XML_PI_NODE)) 04517 result = (long) node->line; 04518 else if ((node->prev != NULL) && 04519 ((node->prev->type == XML_ELEMENT_NODE) || 04520 (node->prev->type == XML_TEXT_NODE) || 04521 (node->prev->type == XML_COMMENT_NODE) || 04522 (node->prev->type == XML_PI_NODE))) 04523 result = xmlGetLineNo(node->prev); 04524 else if ((node->parent != NULL) && 04525 (node->parent->type == XML_ELEMENT_NODE)) 04526 result = xmlGetLineNo(node->parent); 04527 04528 return result; 04529 } 04530 04531 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED) 04532 04541 xmlChar * 04542 xmlGetNodePath(xmlNodePtr node) 04543 { 04544 xmlNodePtr cur, tmp, next; 04545 xmlChar *buffer = NULL, *temp; 04546 size_t buf_len; 04547 xmlChar *buf; 04548 const char *sep; 04549 const char *name; 04550 char nametemp[100]; 04551 int occur = 0, generic; 04552 04553 if (node == NULL) 04554 return (NULL); 04555 04556 buf_len = 500; 04557 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar)); 04558 if (buffer == NULL) { 04559 xmlTreeErrMemory("getting node path"); 04560 return (NULL); 04561 } 04562 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar)); 04563 if (buf == NULL) { 04564 xmlTreeErrMemory("getting node path"); 04565 xmlFree(buffer); 04566 return (NULL); 04567 } 04568 04569 buffer[0] = 0; 04570 cur = node; 04571 do { 04572 name = ""; 04573 sep = "?"; 04574 occur = 0; 04575 if ((cur->type == XML_DOCUMENT_NODE) || 04576 (cur->type == XML_HTML_DOCUMENT_NODE)) { 04577 if (buffer[0] == '/') 04578 break; 04579 sep = "/"; 04580 next = NULL; 04581 } else if (cur->type == XML_ELEMENT_NODE) { 04582 generic = 0; 04583 sep = "/"; 04584 name = (const char *) cur->name; 04585 if (cur->ns) { 04586 if (cur->ns->prefix != NULL) { 04587 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s", 04588 (char *)cur->ns->prefix, (char *)cur->name); 04589 nametemp[sizeof(nametemp) - 1] = 0; 04590 name = nametemp; 04591 } else { 04592 /* 04593 * We cannot express named elements in the default 04594 * namespace, so use "*". 04595 */ 04596 generic = 1; 04597 name = "*"; 04598 } 04599 } 04600 next = cur->parent; 04601 04602 /* 04603 * Thumbler index computation 04604 * TODO: the ocurence test seems bogus for namespaced names 04605 */ 04606 tmp = cur->prev; 04607 while (tmp != NULL) { 04608 if ((tmp->type == XML_ELEMENT_NODE) && 04609 (generic || 04610 (xmlStrEqual(cur->name, tmp->name) && 04611 ((tmp->ns == cur->ns) || 04612 ((tmp->ns != NULL) && (cur->ns != NULL) && 04613 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix))))))) 04614 occur++; 04615 tmp = tmp->prev; 04616 } 04617 if (occur == 0) { 04618 tmp = cur->next; 04619 while (tmp != NULL && occur == 0) { 04620 if ((tmp->type == XML_ELEMENT_NODE) && 04621 (generic || 04622 (xmlStrEqual(cur->name, tmp->name) && 04623 ((tmp->ns == cur->ns) || 04624 ((tmp->ns != NULL) && (cur->ns != NULL) && 04625 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix))))))) 04626 occur++; 04627 tmp = tmp->next; 04628 } 04629 if (occur != 0) 04630 occur = 1; 04631 } else 04632 occur++; 04633 } else if (cur->type == XML_COMMENT_NODE) { 04634 sep = "/"; 04635 name = "comment()"; 04636 next = cur->parent; 04637 04638 /* 04639 * Thumbler index computation 04640 */ 04641 tmp = cur->prev; 04642 while (tmp != NULL) { 04643 if (tmp->type == XML_COMMENT_NODE) 04644 occur++; 04645 tmp = tmp->prev; 04646 } 04647 if (occur == 0) { 04648 tmp = cur->next; 04649 while (tmp != NULL && occur == 0) { 04650 if (tmp->type == XML_COMMENT_NODE) 04651 occur++; 04652 tmp = tmp->next; 04653 } 04654 if (occur != 0) 04655 occur = 1; 04656 } else 04657 occur++; 04658 } else if ((cur->type == XML_TEXT_NODE) || 04659 (cur->type == XML_CDATA_SECTION_NODE)) { 04660 sep = "/"; 04661 name = "text()"; 04662 next = cur->parent; 04663 04664 /* 04665 * Thumbler index computation 04666 */ 04667 tmp = cur->prev; 04668 while (tmp != NULL) { 04669 if ((tmp->type == XML_TEXT_NODE) || 04670 (tmp->type == XML_CDATA_SECTION_NODE)) 04671 occur++; 04672 tmp = tmp->prev; 04673 } 04674 /* 04675 * Evaluate if this is the only text- or CDATA-section-node; 04676 * if yes, then we'll get "text()", otherwise "text()[1]". 04677 */ 04678 if (occur == 0) { 04679 tmp = cur->next; 04680 while (tmp != NULL) { 04681 if ((tmp->type == XML_TEXT_NODE) || 04682 (tmp->type == XML_CDATA_SECTION_NODE)) 04683 { 04684 occur = 1; 04685 break; 04686 } 04687 tmp = tmp->next; 04688 } 04689 } else 04690 occur++; 04691 } else if (cur->type == XML_PI_NODE) { 04692 sep = "/"; 04693 snprintf(nametemp, sizeof(nametemp) - 1, 04694 "processing-instruction('%s')", (char *)cur->name); 04695 nametemp[sizeof(nametemp) - 1] = 0; 04696 name = nametemp; 04697 04698 next = cur->parent; 04699 04700 /* 04701 * Thumbler index computation 04702 */ 04703 tmp = cur->prev; 04704 while (tmp != NULL) { 04705 if ((tmp->type == XML_PI_NODE) && 04706 (xmlStrEqual(cur->name, tmp->name))) 04707 occur++; 04708 tmp = tmp->prev; 04709 } 04710 if (occur == 0) { 04711 tmp = cur->next; 04712 while (tmp != NULL && occur == 0) { 04713 if ((tmp->type == XML_PI_NODE) && 04714 (xmlStrEqual(cur->name, tmp->name))) 04715 occur++; 04716 tmp = tmp->next; 04717 } 04718 if (occur != 0) 04719 occur = 1; 04720 } else 04721 occur++; 04722 04723 } else if (cur->type == XML_ATTRIBUTE_NODE) { 04724 sep = "/@"; 04725 name = (const char *) (((xmlAttrPtr) cur)->name); 04726 if (cur->ns) { 04727 if (cur->ns->prefix != NULL) 04728 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s", 04729 (char *)cur->ns->prefix, (char *)cur->name); 04730 else 04731 snprintf(nametemp, sizeof(nametemp) - 1, "%s", 04732 (char *)cur->name); 04733 nametemp[sizeof(nametemp) - 1] = 0; 04734 name = nametemp; 04735 } 04736 next = ((xmlAttrPtr) cur)->parent; 04737 } else { 04738 next = cur->parent; 04739 } 04740 04741 /* 04742 * Make sure there is enough room 04743 */ 04744 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) { 04745 buf_len = 04746 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20; 04747 temp = (xmlChar *) xmlRealloc(buffer, buf_len); 04748 if (temp == NULL) { 04749 xmlTreeErrMemory("getting node path"); 04750 xmlFree(buf); 04751 xmlFree(buffer); 04752 return (NULL); 04753 } 04754 buffer = temp; 04755 temp = (xmlChar *) xmlRealloc(buf, buf_len); 04756 if (temp == NULL) { 04757 xmlTreeErrMemory("getting node path"); 04758 xmlFree(buf); 04759 xmlFree(buffer); 04760 return (NULL); 04761 } 04762 buf = temp; 04763 } 04764 if (occur == 0) 04765 snprintf((char *) buf, buf_len, "%s%s%s", 04766 sep, name, (char *) buffer); 04767 else 04768 snprintf((char *) buf, buf_len, "%s%s[%d]%s", 04769 sep, name, occur, (char *) buffer); 04770 snprintf((char *) buffer, buf_len, "%s", (char *)buf); 04771 cur = next; 04772 } while (cur != NULL); 04773 xmlFree(buf); 04774 return (buffer); 04775 } 04776 #endif /* LIBXML_TREE_ENABLED */ 04777 04787 xmlNodePtr 04788 xmlDocGetRootElement(xmlDocPtr doc) { 04789 xmlNodePtr ret; 04790 04791 if (doc == NULL) return(NULL); 04792 ret = doc->children; 04793 while (ret != NULL) { 04794 if (ret->type == XML_ELEMENT_NODE) 04795 return(ret); 04796 ret = ret->next; 04797 } 04798 return(ret); 04799 } 04800 04801 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED) 04802 04813 xmlNodePtr 04814 xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) { 04815 xmlNodePtr old = NULL; 04816 04817 if (doc == NULL) return(NULL); 04818 if (root == NULL) 04819 return(NULL); 04820 xmlUnlinkNode(root); 04821 xmlSetTreeDoc(root, doc); 04822 root->parent = (xmlNodePtr) doc; 04823 old = doc->children; 04824 while (old != NULL) { 04825 if (old->type == XML_ELEMENT_NODE) 04826 break; 04827 old = old->next; 04828 } 04829 if (old == NULL) { 04830 if (doc->children == NULL) { 04831 doc->children = root; 04832 doc->last = root; 04833 } else { 04834 xmlAddSibling(doc->children, root); 04835 } 04836 } else { 04837 xmlReplaceNode(old, root); 04838 } 04839 return(old); 04840 } 04841 #endif 04842 04843 #if defined(LIBXML_TREE_ENABLED) 04844 04852 void 04853 xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) { 04854 xmlNsPtr ns; 04855 04856 if (cur == NULL) return; 04857 switch(cur->type) { 04858 case XML_TEXT_NODE: 04859 case XML_CDATA_SECTION_NODE: 04860 case XML_COMMENT_NODE: 04861 case XML_DOCUMENT_NODE: 04862 case XML_DOCUMENT_TYPE_NODE: 04863 case XML_DOCUMENT_FRAG_NODE: 04864 case XML_NOTATION_NODE: 04865 case XML_HTML_DOCUMENT_NODE: 04866 case XML_DTD_NODE: 04867 case XML_ELEMENT_DECL: 04868 case XML_ATTRIBUTE_DECL: 04869 case XML_ENTITY_DECL: 04870 case XML_PI_NODE: 04871 case XML_ENTITY_REF_NODE: 04872 case XML_ENTITY_NODE: 04873 case XML_NAMESPACE_DECL: 04874 #ifdef LIBXML_DOCB_ENABLED 04875 case XML_DOCB_DOCUMENT_NODE: 04876 #endif 04877 case XML_XINCLUDE_START: 04878 case XML_XINCLUDE_END: 04879 return; 04880 case XML_ELEMENT_NODE: 04881 case XML_ATTRIBUTE_NODE: 04882 break; 04883 } 04884 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE); 04885 if (ns == NULL) 04886 return; 04887 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang); 04888 } 04889 #endif /* LIBXML_TREE_ENABLED */ 04890 04901 xmlChar * 04902 xmlNodeGetLang(xmlNodePtr cur) { 04903 xmlChar *lang; 04904 04905 while (cur != NULL) { 04906 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE); 04907 if (lang != NULL) 04908 return(lang); 04909 cur = cur->parent; 04910 } 04911 return(NULL); 04912 } 04913 04914 04915 #ifdef LIBXML_TREE_ENABLED 04916 04924 void 04925 xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) { 04926 xmlNsPtr ns; 04927 04928 if (cur == NULL) return; 04929 switch(cur->type) { 04930 case XML_TEXT_NODE: 04931 case XML_CDATA_SECTION_NODE: 04932 case XML_COMMENT_NODE: 04933 case XML_DOCUMENT_NODE: 04934 case XML_DOCUMENT_TYPE_NODE: 04935 case XML_DOCUMENT_FRAG_NODE: 04936 case XML_NOTATION_NODE: 04937 case XML_HTML_DOCUMENT_NODE: 04938 case XML_DTD_NODE: 04939 case XML_ELEMENT_DECL: 04940 case XML_ATTRIBUTE_DECL: 04941 case XML_ENTITY_DECL: 04942 case XML_PI_NODE: 04943 case XML_ENTITY_REF_NODE: 04944 case XML_ENTITY_NODE: 04945 case XML_NAMESPACE_DECL: 04946 case XML_XINCLUDE_START: 04947 case XML_XINCLUDE_END: 04948 #ifdef LIBXML_DOCB_ENABLED 04949 case XML_DOCB_DOCUMENT_NODE: 04950 #endif 04951 return; 04952 case XML_ELEMENT_NODE: 04953 case XML_ATTRIBUTE_NODE: 04954 break; 04955 } 04956 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE); 04957 if (ns == NULL) 04958 return; 04959 switch (val) { 04960 case 0: 04961 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default"); 04962 break; 04963 case 1: 04964 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve"); 04965 break; 04966 } 04967 } 04968 #endif /* LIBXML_TREE_ENABLED */ 04969 04980 int 04981 xmlNodeGetSpacePreserve(xmlNodePtr cur) { 04982 xmlChar *space; 04983 04984 while (cur != NULL) { 04985 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE); 04986 if (space != NULL) { 04987 if (xmlStrEqual(space, BAD_CAST "preserve")) { 04988 xmlFree(space); 04989 return(1); 04990 } 04991 if (xmlStrEqual(space, BAD_CAST "default")) { 04992 xmlFree(space); 04993 return(0); 04994 } 04995 xmlFree(space); 04996 } 04997 cur = cur->parent; 04998 } 04999 return(-1); 05000 } 05001 05002 #ifdef LIBXML_TREE_ENABLED 05003 05010 void 05011 xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) { 05012 xmlDocPtr doc; 05013 xmlDictPtr dict; 05014 05015 if (cur == NULL) return; 05016 if (name == NULL) return; 05017 switch(cur->type) { 05018 case XML_TEXT_NODE: 05019 case XML_CDATA_SECTION_NODE: 05020 case XML_COMMENT_NODE: 05021 case XML_DOCUMENT_TYPE_NODE: 05022 case XML_DOCUMENT_FRAG_NODE: 05023 case XML_NOTATION_NODE: 05024 case XML_HTML_DOCUMENT_NODE: 05025 case XML_NAMESPACE_DECL: 05026 case XML_XINCLUDE_START: 05027 case XML_XINCLUDE_END: 05028 #ifdef LIBXML_DOCB_ENABLED 05029 case XML_DOCB_DOCUMENT_NODE: 05030 #endif 05031 return; 05032 case XML_ELEMENT_NODE: 05033 case XML_ATTRIBUTE_NODE: 05034 case XML_PI_NODE: 05035 case XML_ENTITY_REF_NODE: 05036 case XML_ENTITY_NODE: 05037 case XML_DTD_NODE: 05038 case XML_DOCUMENT_NODE: 05039 case XML_ELEMENT_DECL: 05040 case XML_ATTRIBUTE_DECL: 05041 case XML_ENTITY_DECL: 05042 break; 05043 } 05044 doc = cur->doc; 05045 if (doc != NULL) 05046 dict = doc->dict; 05047 else 05048 dict = NULL; 05049 if (dict != NULL) { 05050 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name))) 05051 xmlFree((xmlChar *) cur->name); 05052 cur->name = xmlDictLookup(dict, name, -1); 05053 } else { 05054 if (cur->name != NULL) xmlFree((xmlChar *) cur->name); 05055 cur->name = xmlStrdup(name); 05056 } 05057 } 05058 #endif 05059 05060 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) 05061 05069 void 05070 xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) { 05071 xmlNsPtr ns; 05072 xmlChar* fixed; 05073 05074 if (cur == NULL) return; 05075 switch(cur->type) { 05076 case XML_TEXT_NODE: 05077 case XML_CDATA_SECTION_NODE: 05078 case XML_COMMENT_NODE: 05079 case XML_DOCUMENT_TYPE_NODE: 05080 case XML_DOCUMENT_FRAG_NODE: 05081 case XML_NOTATION_NODE: 05082 case XML_DTD_NODE: 05083 case XML_ELEMENT_DECL: 05084 case XML_ATTRIBUTE_DECL: 05085 case XML_ENTITY_DECL: 05086 case XML_PI_NODE: 05087 case XML_ENTITY_REF_NODE: 05088 case XML_ENTITY_NODE: 05089 case XML_NAMESPACE_DECL: 05090 case XML_XINCLUDE_START: 05091 case XML_XINCLUDE_END: 05092 return; 05093 case XML_ELEMENT_NODE: 05094 case XML_ATTRIBUTE_NODE: 05095 break; 05096 case XML_DOCUMENT_NODE: 05097 #ifdef LIBXML_DOCB_ENABLED 05098 case XML_DOCB_DOCUMENT_NODE: 05099 #endif 05100 case XML_HTML_DOCUMENT_NODE: { 05101 xmlDocPtr doc = (xmlDocPtr) cur; 05102 05103 if (doc->URL != NULL) 05104 xmlFree((xmlChar *) doc->URL); 05105 if (uri == NULL) 05106 doc->URL = NULL; 05107 else 05108 doc->URL = xmlPathToURI(uri); 05109 return; 05110 } 05111 } 05112 05113 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE); 05114 if (ns == NULL) 05115 return; 05116 fixed = xmlPathToURI(uri); 05117 if (fixed != NULL) { 05118 xmlSetNsProp(cur, ns, BAD_CAST "base", fixed); 05119 xmlFree(fixed); 05120 } else { 05121 xmlSetNsProp(cur, ns, BAD_CAST "base", uri); 05122 } 05123 } 05124 #endif /* LIBXML_TREE_ENABLED */ 05125 05143 xmlChar * 05144 xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) { 05145 xmlChar *oldbase = NULL; 05146 xmlChar *base, *newbase; 05147 05148 if ((cur == NULL) && (doc == NULL)) 05149 return(NULL); 05150 if (doc == NULL) doc = cur->doc; 05151 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) { 05152 cur = doc->children; 05153 while ((cur != NULL) && (cur->name != NULL)) { 05154 if (cur->type != XML_ELEMENT_NODE) { 05155 cur = cur->next; 05156 continue; 05157 } 05158 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) { 05159 cur = cur->children; 05160 continue; 05161 } 05162 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) { 05163 cur = cur->children; 05164 continue; 05165 } 05166 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) { 05167 return(xmlGetProp(cur, BAD_CAST "href")); 05168 } 05169 cur = cur->next; 05170 } 05171 return(NULL); 05172 } 05173 while (cur != NULL) { 05174 if (cur->type == XML_ENTITY_DECL) { 05175 xmlEntityPtr ent = (xmlEntityPtr) cur; 05176 return(xmlStrdup(ent->URI)); 05177 } 05178 if (cur->type == XML_ELEMENT_NODE) { 05179 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE); 05180 if (base != NULL) { 05181 if (oldbase != NULL) { 05182 newbase = xmlBuildURI(oldbase, base); 05183 if (newbase != NULL) { 05184 xmlFree(oldbase); 05185 xmlFree(base); 05186 oldbase = newbase; 05187 } else { 05188 xmlFree(oldbase); 05189 xmlFree(base); 05190 return(NULL); 05191 } 05192 } else { 05193 oldbase = base; 05194 } 05195 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) || 05196 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) || 05197 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4))) 05198 return(oldbase); 05199 } 05200 } 05201 cur = cur->parent; 05202 } 05203 if ((doc != NULL) && (doc->URL != NULL)) { 05204 if (oldbase == NULL) 05205 return(xmlStrdup(doc->URL)); 05206 newbase = xmlBuildURI(oldbase, doc->URL); 05207 xmlFree(oldbase); 05208 return(newbase); 05209 } 05210 return(oldbase); 05211 } 05212 05226 int 05227 xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur) 05228 { 05229 if ((cur == NULL) || (buffer == NULL)) return(-1); 05230 switch (cur->type) { 05231 case XML_CDATA_SECTION_NODE: 05232 case XML_TEXT_NODE: 05233 xmlBufferCat(buffer, cur->content); 05234 break; 05235 case XML_DOCUMENT_FRAG_NODE: 05236 case XML_ELEMENT_NODE:{ 05237 xmlNodePtr tmp = cur; 05238 05239 while (tmp != NULL) { 05240 switch (tmp->type) { 05241 case XML_CDATA_SECTION_NODE: 05242 case XML_TEXT_NODE: 05243 if (tmp->content != NULL) 05244 xmlBufferCat(buffer, tmp->content); 05245 break; 05246 case XML_ENTITY_REF_NODE: 05247 xmlNodeBufGetContent(buffer, tmp); 05248 break; 05249 default: 05250 break; 05251 } 05252 /* 05253 * Skip to next node 05254 */ 05255 if (tmp->children != NULL) { 05256 if (tmp->children->type != XML_ENTITY_DECL) { 05257 tmp = tmp->children; 05258 continue; 05259 } 05260 } 05261 if (tmp == cur) 05262 break; 05263 05264 if (tmp->next != NULL) { 05265 tmp = tmp->next; 05266 continue; 05267 } 05268 05269 do { 05270 tmp = tmp->parent; 05271 if (tmp == NULL) 05272 break; 05273 if (tmp == cur) { 05274 tmp = NULL; 05275 break; 05276 } 05277 if (tmp->next != NULL) { 05278 tmp = tmp->next; 05279 break; 05280 } 05281 } while (tmp != NULL); 05282 } 05283 break; 05284 } 05285 case XML_ATTRIBUTE_NODE:{ 05286 xmlAttrPtr attr = (xmlAttrPtr) cur; 05287 xmlNodePtr tmp = attr->children; 05288 05289 while (tmp != NULL) { 05290 if (tmp->type == XML_TEXT_NODE) 05291 xmlBufferCat(buffer, tmp->content); 05292 else 05293 xmlNodeBufGetContent(buffer, tmp); 05294 tmp = tmp->next; 05295 } 05296 break; 05297 } 05298 case XML_COMMENT_NODE: 05299 case XML_PI_NODE: 05300 xmlBufferCat(buffer, cur->content); 05301 break; 05302 case XML_ENTITY_REF_NODE:{ 05303 xmlEntityPtr ent; 05304 xmlNodePtr tmp; 05305 05306 /* lookup entity declaration */ 05307 ent = xmlGetDocEntity(cur->doc, cur->name); 05308 if (ent == NULL) 05309 return(-1); 05310 05311 /* an entity content can be any "well balanced chunk", 05312 * i.e. the result of the content [43] production: 05313 * http://www.w3.org/TR/REC-xml#NT-content 05314 * -> we iterate through child nodes and recursive call 05315 * xmlNodeGetContent() which handles all possible node types */ 05316 tmp = ent->children; 05317 while (tmp) { 05318 xmlNodeBufGetContent(buffer, tmp); 05319 tmp = tmp->next; 05320 } 05321 break; 05322 } 05323 case XML_ENTITY_NODE: 05324 case XML_DOCUMENT_TYPE_NODE: 05325 case XML_NOTATION_NODE: 05326 case XML_DTD_NODE: 05327 case XML_XINCLUDE_START: 05328 case XML_XINCLUDE_END: 05329 break; 05330 case XML_DOCUMENT_NODE: 05331 #ifdef LIBXML_DOCB_ENABLED 05332 case XML_DOCB_DOCUMENT_NODE: 05333 #endif 05334 case XML_HTML_DOCUMENT_NODE: 05335 cur = cur->children; 05336 while (cur!= NULL) { 05337 if ((cur->type == XML_ELEMENT_NODE) || 05338 (cur->type == XML_TEXT_NODE) || 05339 (cur->type == XML_CDATA_SECTION_NODE)) { 05340 xmlNodeBufGetContent(buffer, cur); 05341 } 05342 cur = cur->next; 05343 } 05344 break; 05345 case XML_NAMESPACE_DECL: 05346 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href); 05347 break; 05348 case XML_ELEMENT_DECL: 05349 case XML_ATTRIBUTE_DECL: 05350 case XML_ENTITY_DECL: 05351 break; 05352 } 05353 return(0); 05354 } 05366 xmlChar * 05367 xmlNodeGetContent(xmlNodePtr cur) 05368 { 05369 if (cur == NULL) 05370 return (NULL); 05371 switch (cur->type) { 05372 case XML_DOCUMENT_FRAG_NODE: 05373 case XML_ELEMENT_NODE:{ 05374 xmlBufferPtr buffer; 05375 xmlChar *ret; 05376 05377 buffer = xmlBufferCreateSize(64); 05378 if (buffer == NULL) 05379 return (NULL); 05380 xmlNodeBufGetContent(buffer, cur); 05381 ret = buffer->content; 05382 buffer->content = NULL; 05383 xmlBufferFree(buffer); 05384 return (ret); 05385 } 05386 case XML_ATTRIBUTE_NODE: 05387 return(xmlGetPropNodeValueInternal((xmlAttrPtr) cur)); 05388 case XML_COMMENT_NODE: 05389 case XML_PI_NODE: 05390 if (cur->content != NULL) 05391 return (xmlStrdup(cur->content)); 05392 return (NULL); 05393 case XML_ENTITY_REF_NODE:{ 05394 xmlEntityPtr ent; 05395 xmlBufferPtr buffer; 05396 xmlChar *ret; 05397 05398 /* lookup entity declaration */ 05399 ent = xmlGetDocEntity(cur->doc, cur->name); 05400 if (ent == NULL) 05401 return (NULL); 05402 05403 buffer = xmlBufferCreate(); 05404 if (buffer == NULL) 05405 return (NULL); 05406 05407 xmlNodeBufGetContent(buffer, cur); 05408 05409 ret = buffer->content; 05410 buffer->content = NULL; 05411 xmlBufferFree(buffer); 05412 return (ret); 05413 } 05414 case XML_ENTITY_NODE: 05415 case XML_DOCUMENT_TYPE_NODE: 05416 case XML_NOTATION_NODE: 05417 case XML_DTD_NODE: 05418 case XML_XINCLUDE_START: 05419 case XML_XINCLUDE_END: 05420 return (NULL); 05421 case XML_DOCUMENT_NODE: 05422 #ifdef LIBXML_DOCB_ENABLED 05423 case XML_DOCB_DOCUMENT_NODE: 05424 #endif 05425 case XML_HTML_DOCUMENT_NODE: { 05426 xmlBufferPtr buffer; 05427 xmlChar *ret; 05428 05429 buffer = xmlBufferCreate(); 05430 if (buffer == NULL) 05431 return (NULL); 05432 05433 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur); 05434 05435 ret = buffer->content; 05436 buffer->content = NULL; 05437 xmlBufferFree(buffer); 05438 return (ret); 05439 } 05440 case XML_NAMESPACE_DECL: { 05441 xmlChar *tmp; 05442 05443 tmp = xmlStrdup(((xmlNsPtr) cur)->href); 05444 return (tmp); 05445 } 05446 case XML_ELEMENT_DECL: 05447 /* TODO !!! */ 05448 return (NULL); 05449 case XML_ATTRIBUTE_DECL: 05450 /* TODO !!! */ 05451 return (NULL); 05452 case XML_ENTITY_DECL: 05453 /* TODO !!! */ 05454 return (NULL); 05455 case XML_CDATA_SECTION_NODE: 05456 case XML_TEXT_NODE: 05457 if (cur->content != NULL) 05458 return (xmlStrdup(cur->content)); 05459 return (NULL); 05460 } 05461 return (NULL); 05462 } 05463 05474 void 05475 xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) { 05476 if (cur == NULL) { 05477 #ifdef DEBUG_TREE 05478 xmlGenericError(xmlGenericErrorContext, 05479 "xmlNodeSetContent : node == NULL\n"); 05480 #endif 05481 return; 05482 } 05483 switch (cur->type) { 05484 case XML_DOCUMENT_FRAG_NODE: 05485 case XML_ELEMENT_NODE: 05486 case XML_ATTRIBUTE_NODE: 05487 if (cur->children != NULL) xmlFreeNodeList(cur->children); 05488 cur->children = xmlStringGetNodeList(cur->doc, content); 05489 UPDATE_LAST_CHILD_AND_PARENT(cur) 05490 break; 05491 case XML_TEXT_NODE: 05492 case XML_CDATA_SECTION_NODE: 05493 case XML_ENTITY_REF_NODE: 05494 case XML_ENTITY_NODE: 05495 case XML_PI_NODE: 05496 case XML_COMMENT_NODE: 05497 if ((cur->content != NULL) && 05498 (cur->content != (xmlChar *) &(cur->properties))) { 05499 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) && 05500 (xmlDictOwns(cur->doc->dict, cur->content)))) 05501 xmlFree(cur->content); 05502 } 05503 if (cur->children != NULL) xmlFreeNodeList(cur->children); 05504 cur->last = cur->children = NULL; 05505 if (content != NULL) { 05506 cur->content = xmlStrdup(content); 05507 } else 05508 cur->content = NULL; 05509 cur->properties = NULL; 05510 cur->nsDef = NULL; 05511 break; 05512 case XML_DOCUMENT_NODE: 05513 case XML_HTML_DOCUMENT_NODE: 05514 case XML_DOCUMENT_TYPE_NODE: 05515 case XML_XINCLUDE_START: 05516 case XML_XINCLUDE_END: 05517 #ifdef LIBXML_DOCB_ENABLED 05518 case XML_DOCB_DOCUMENT_NODE: 05519 #endif 05520 break; 05521 case XML_NOTATION_NODE: 05522 break; 05523 case XML_DTD_NODE: 05524 break; 05525 case XML_NAMESPACE_DECL: 05526 break; 05527 case XML_ELEMENT_DECL: 05528 /* TODO !!! */ 05529 break; 05530 case XML_ATTRIBUTE_DECL: 05531 /* TODO !!! */ 05532 break; 05533 case XML_ENTITY_DECL: 05534 /* TODO !!! */ 05535 break; 05536 } 05537 } 05538 05539 #ifdef LIBXML_TREE_ENABLED 05540 05551 void 05552 xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) { 05553 if (cur == NULL) { 05554 #ifdef DEBUG_TREE 05555 xmlGenericError(xmlGenericErrorContext, 05556 "xmlNodeSetContentLen : node == NULL\n"); 05557 #endif 05558 return; 05559 } 05560 switch (cur->type) { 05561 case XML_DOCUMENT_FRAG_NODE: 05562 case XML_ELEMENT_NODE: 05563 case XML_ATTRIBUTE_NODE: 05564 if (cur->children != NULL) xmlFreeNodeList(cur->children); 05565 cur->children = xmlStringLenGetNodeList(cur->doc, content, len); 05566 UPDATE_LAST_CHILD_AND_PARENT(cur) 05567 break; 05568 case XML_TEXT_NODE: 05569 case XML_CDATA_SECTION_NODE: 05570 case XML_ENTITY_REF_NODE: 05571 case XML_ENTITY_NODE: 05572 case XML_PI_NODE: 05573 case XML_COMMENT_NODE: 05574 case XML_NOTATION_NODE: 05575 if ((cur->content != NULL) && 05576 (cur->content != (xmlChar *) &(cur->properties))) { 05577 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) && 05578 (xmlDictOwns(cur->doc->dict, cur->content)))) 05579 xmlFree(cur->content); 05580 } 05581 if (cur->children != NULL) xmlFreeNodeList(cur->children); 05582 cur->children = cur->last = NULL; 05583 if (content != NULL) { 05584 cur->content = xmlStrndup(content, len); 05585 } else 05586 cur->content = NULL; 05587 cur->properties = NULL; 05588 cur->nsDef = NULL; 05589 break; 05590 case XML_DOCUMENT_NODE: 05591 case XML_DTD_NODE: 05592 case XML_HTML_DOCUMENT_NODE: 05593 case XML_DOCUMENT_TYPE_NODE: 05594 case XML_NAMESPACE_DECL: 05595 case XML_XINCLUDE_START: 05596 case XML_XINCLUDE_END: 05597 #ifdef LIBXML_DOCB_ENABLED 05598 case XML_DOCB_DOCUMENT_NODE: 05599 #endif 05600 break; 05601 case XML_ELEMENT_DECL: 05602 /* TODO !!! */ 05603 break; 05604 case XML_ATTRIBUTE_DECL: 05605 /* TODO !!! */ 05606 break; 05607 case XML_ENTITY_DECL: 05608 /* TODO !!! */ 05609 break; 05610 } 05611 } 05612 #endif /* LIBXML_TREE_ENABLED */ 05613 05625 void 05626 xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) { 05627 if (cur == NULL) { 05628 #ifdef DEBUG_TREE 05629 xmlGenericError(xmlGenericErrorContext, 05630 "xmlNodeAddContentLen : node == NULL\n"); 05631 #endif 05632 return; 05633 } 05634 if (len <= 0) return; 05635 switch (cur->type) { 05636 case XML_DOCUMENT_FRAG_NODE: 05637 case XML_ELEMENT_NODE: { 05638 xmlNodePtr last, newNode, tmp; 05639 05640 last = cur->last; 05641 newNode = xmlNewTextLen(content, len); 05642 if (newNode != NULL) { 05643 tmp = xmlAddChild(cur, newNode); 05644 if (tmp != newNode) 05645 return; 05646 if ((last != NULL) && (last->next == newNode)) { 05647 xmlTextMerge(last, newNode); 05648 } 05649 } 05650 break; 05651 } 05652 case XML_ATTRIBUTE_NODE: 05653 break; 05654 case XML_TEXT_NODE: 05655 case XML_CDATA_SECTION_NODE: 05656 case XML_ENTITY_REF_NODE: 05657 case XML_ENTITY_NODE: 05658 case XML_PI_NODE: 05659 case XML_COMMENT_NODE: 05660 case XML_NOTATION_NODE: 05661 if (content != NULL) { 05662 if ((cur->content == (xmlChar *) &(cur->properties)) || 05663 ((cur->doc != NULL) && (cur->doc->dict != NULL) && 05664 xmlDictOwns(cur->doc->dict, cur->content))) { 05665 cur->content = xmlStrncatNew(cur->content, content, len); 05666 cur->properties = NULL; 05667 cur->nsDef = NULL; 05668 break; 05669 } 05670 cur->content = xmlStrncat(cur->content, content, len); 05671 } 05672 case XML_DOCUMENT_NODE: 05673 case XML_DTD_NODE: 05674 case XML_HTML_DOCUMENT_NODE: 05675 case XML_DOCUMENT_TYPE_NODE: 05676 case XML_NAMESPACE_DECL: 05677 case XML_XINCLUDE_START: 05678 case XML_XINCLUDE_END: 05679 #ifdef LIBXML_DOCB_ENABLED 05680 case XML_DOCB_DOCUMENT_NODE: 05681 #endif 05682 break; 05683 case XML_ELEMENT_DECL: 05684 case XML_ATTRIBUTE_DECL: 05685 case XML_ENTITY_DECL: 05686 break; 05687 } 05688 } 05689 05700 void 05701 xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) { 05702 int len; 05703 05704 if (cur == NULL) { 05705 #ifdef DEBUG_TREE 05706 xmlGenericError(xmlGenericErrorContext, 05707 "xmlNodeAddContent : node == NULL\n"); 05708 #endif 05709 return; 05710 } 05711 if (content == NULL) return; 05712 len = xmlStrlen(content); 05713 xmlNodeAddContentLen(cur, content, len); 05714 } 05715 05724 xmlNodePtr 05725 xmlTextMerge(xmlNodePtr first, xmlNodePtr second) { 05726 if (first == NULL) return(second); 05727 if (second == NULL) return(first); 05728 if (first->type != XML_TEXT_NODE) return(first); 05729 if (second->type != XML_TEXT_NODE) return(first); 05730 if (second->name != first->name) 05731 return(first); 05732 xmlNodeAddContent(first, second->content); 05733 xmlUnlinkNode(second); 05734 xmlFreeNode(second); 05735 return(first); 05736 } 05737 05738 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) 05739 05749 xmlNsPtr * 05750 xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node) 05751 { 05752 xmlNsPtr cur; 05753 xmlNsPtr *ret = NULL; 05754 int nbns = 0; 05755 int maxns = 10; 05756 int i; 05757 05758 while (node != NULL) { 05759 if (node->type == XML_ELEMENT_NODE) { 05760 cur = node->nsDef; 05761 while (cur != NULL) { 05762 if (ret == NULL) { 05763 ret = 05764 (xmlNsPtr *) xmlMalloc((maxns + 1) * 05765 sizeof(xmlNsPtr)); 05766 if (ret == NULL) { 05767 xmlTreeErrMemory("getting namespace list"); 05768 return (NULL); 05769 } 05770 ret[nbns] = NULL; 05771 } 05772 for (i = 0; i < nbns; i++) { 05773 if ((cur->prefix == ret[i]->prefix) || 05774 (xmlStrEqual(cur->prefix, ret[i]->prefix))) 05775 break; 05776 } 05777 if (i >= nbns) { 05778 if (nbns >= maxns) { 05779 maxns *= 2; 05780 ret = (xmlNsPtr *) xmlRealloc(ret, 05781 (maxns + 05782 1) * 05783 sizeof(xmlNsPtr)); 05784 if (ret == NULL) { 05785 xmlTreeErrMemory("getting namespace list"); 05786 return (NULL); 05787 } 05788 } 05789 ret[nbns++] = cur; 05790 ret[nbns] = NULL; 05791 } 05792 05793 cur = cur->next; 05794 } 05795 } 05796 node = node->parent; 05797 } 05798 return (ret); 05799 } 05800 #endif /* LIBXML_TREE_ENABLED */ 05801 05802 /* 05803 * xmlTreeEnsureXMLDecl: 05804 * @doc: the doc 05805 * 05806 * Ensures that there is an XML namespace declaration on the doc. 05807 * 05808 * Returns the XML ns-struct or NULL on API and internal errors. 05809 */ 05810 static xmlNsPtr 05811 xmlTreeEnsureXMLDecl(xmlDocPtr doc) 05812 { 05813 if (doc == NULL) 05814 return (NULL); 05815 if (doc->oldNs != NULL) 05816 return (doc->oldNs); 05817 { 05818 xmlNsPtr ns; 05819 ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 05820 if (ns == NULL) { 05821 xmlTreeErrMemory( 05822 "allocating the XML namespace"); 05823 return (NULL); 05824 } 05825 memset(ns, 0, sizeof(xmlNs)); 05826 ns->type = XML_LOCAL_NAMESPACE; 05827 ns->href = xmlStrdup(XML_XML_NAMESPACE); 05828 ns->prefix = xmlStrdup((const xmlChar *)"xml"); 05829 doc->oldNs = ns; 05830 return (ns); 05831 } 05832 } 05833 05850 xmlNsPtr 05851 xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) { 05852 05853 xmlNsPtr cur; 05854 xmlNodePtr orig = node; 05855 05856 if (node == NULL) return(NULL); 05857 if ((nameSpace != NULL) && 05858 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) { 05859 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) { 05860 /* 05861 * The XML-1.0 namespace is normally held on the root 05862 * element. In this case exceptionally create it on the 05863 * node element. 05864 */ 05865 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 05866 if (cur == NULL) { 05867 xmlTreeErrMemory("searching namespace"); 05868 return(NULL); 05869 } 05870 memset(cur, 0, sizeof(xmlNs)); 05871 cur->type = XML_LOCAL_NAMESPACE; 05872 cur->href = xmlStrdup(XML_XML_NAMESPACE); 05873 cur->prefix = xmlStrdup((const xmlChar *)"xml"); 05874 cur->next = node->nsDef; 05875 node->nsDef = cur; 05876 return(cur); 05877 } 05878 if (doc == NULL) { 05879 doc = node->doc; 05880 if (doc == NULL) 05881 return(NULL); 05882 } 05883 /* 05884 * Return the XML namespace declaration held by the doc. 05885 */ 05886 if (doc->oldNs == NULL) 05887 return(xmlTreeEnsureXMLDecl(doc)); 05888 else 05889 return(doc->oldNs); 05890 } 05891 while (node != NULL) { 05892 if ((node->type == XML_ENTITY_REF_NODE) || 05893 (node->type == XML_ENTITY_NODE) || 05894 (node->type == XML_ENTITY_DECL)) 05895 return(NULL); 05896 if (node->type == XML_ELEMENT_NODE) { 05897 cur = node->nsDef; 05898 while (cur != NULL) { 05899 if ((cur->prefix == NULL) && (nameSpace == NULL) && 05900 (cur->href != NULL)) 05901 return(cur); 05902 if ((cur->prefix != NULL) && (nameSpace != NULL) && 05903 (cur->href != NULL) && 05904 (xmlStrEqual(cur->prefix, nameSpace))) 05905 return(cur); 05906 cur = cur->next; 05907 } 05908 if (orig != node) { 05909 cur = node->ns; 05910 if (cur != NULL) { 05911 if ((cur->prefix == NULL) && (nameSpace == NULL) && 05912 (cur->href != NULL)) 05913 return(cur); 05914 if ((cur->prefix != NULL) && (nameSpace != NULL) && 05915 (cur->href != NULL) && 05916 (xmlStrEqual(cur->prefix, nameSpace))) 05917 return(cur); 05918 } 05919 } 05920 } 05921 node = node->parent; 05922 } 05923 return(NULL); 05924 } 05925 05938 static int 05939 xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node, 05940 xmlNodePtr ancestor, const xmlChar * prefix) 05941 { 05942 xmlNsPtr tst; 05943 05944 while ((node != NULL) && (node != ancestor)) { 05945 if ((node->type == XML_ENTITY_REF_NODE) || 05946 (node->type == XML_ENTITY_NODE) || 05947 (node->type == XML_ENTITY_DECL)) 05948 return (-1); 05949 if (node->type == XML_ELEMENT_NODE) { 05950 tst = node->nsDef; 05951 while (tst != NULL) { 05952 if ((tst->prefix == NULL) 05953 && (prefix == NULL)) 05954 return (0); 05955 if ((tst->prefix != NULL) 05956 && (prefix != NULL) 05957 && (xmlStrEqual(tst->prefix, prefix))) 05958 return (0); 05959 tst = tst->next; 05960 } 05961 } 05962 node = node->parent; 05963 } 05964 if (node != ancestor) 05965 return (-1); 05966 return (1); 05967 } 05968 05979 xmlNsPtr 05980 xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href) 05981 { 05982 xmlNsPtr cur; 05983 xmlNodePtr orig = node; 05984 int is_attr; 05985 05986 if ((node == NULL) || (href == NULL)) 05987 return (NULL); 05988 if (xmlStrEqual(href, XML_XML_NAMESPACE)) { 05989 /* 05990 * Only the document can hold the XML spec namespace. 05991 */ 05992 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) { 05993 /* 05994 * The XML-1.0 namespace is normally held on the root 05995 * element. In this case exceptionally create it on the 05996 * node element. 05997 */ 05998 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 05999 if (cur == NULL) { 06000 xmlTreeErrMemory("searching namespace"); 06001 return (NULL); 06002 } 06003 memset(cur, 0, sizeof(xmlNs)); 06004 cur->type = XML_LOCAL_NAMESPACE; 06005 cur->href = xmlStrdup(XML_XML_NAMESPACE); 06006 cur->prefix = xmlStrdup((const xmlChar *) "xml"); 06007 cur->next = node->nsDef; 06008 node->nsDef = cur; 06009 return (cur); 06010 } 06011 if (doc == NULL) { 06012 doc = node->doc; 06013 if (doc == NULL) 06014 return(NULL); 06015 } 06016 /* 06017 * Return the XML namespace declaration held by the doc. 06018 */ 06019 if (doc->oldNs == NULL) 06020 return(xmlTreeEnsureXMLDecl(doc)); 06021 else 06022 return(doc->oldNs); 06023 } 06024 is_attr = (node->type == XML_ATTRIBUTE_NODE); 06025 while (node != NULL) { 06026 if ((node->type == XML_ENTITY_REF_NODE) || 06027 (node->type == XML_ENTITY_NODE) || 06028 (node->type == XML_ENTITY_DECL)) 06029 return (NULL); 06030 if (node->type == XML_ELEMENT_NODE) { 06031 cur = node->nsDef; 06032 while (cur != NULL) { 06033 if ((cur->href != NULL) && (href != NULL) && 06034 (xmlStrEqual(cur->href, href))) { 06035 if (((!is_attr) || (cur->prefix != NULL)) && 06036 (xmlNsInScope(doc, orig, node, cur->prefix) == 1)) 06037 return (cur); 06038 } 06039 cur = cur->next; 06040 } 06041 if (orig != node) { 06042 cur = node->ns; 06043 if (cur != NULL) { 06044 if ((cur->href != NULL) && (href != NULL) && 06045 (xmlStrEqual(cur->href, href))) { 06046 if (((!is_attr) || (cur->prefix != NULL)) && 06047 (xmlNsInScope(doc, orig, node, cur->prefix) == 1)) 06048 return (cur); 06049 } 06050 } 06051 } 06052 } 06053 node = node->parent; 06054 } 06055 return (NULL); 06056 } 06057 06071 static xmlNsPtr 06072 xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) { 06073 xmlNsPtr def; 06074 xmlChar prefix[50]; 06075 int counter = 1; 06076 06077 if (tree == NULL) { 06078 #ifdef DEBUG_TREE 06079 xmlGenericError(xmlGenericErrorContext, 06080 "xmlNewReconciliedNs : tree == NULL\n"); 06081 #endif 06082 return(NULL); 06083 } 06084 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) { 06085 #ifdef DEBUG_TREE 06086 xmlGenericError(xmlGenericErrorContext, 06087 "xmlNewReconciliedNs : ns == NULL\n"); 06088 #endif 06089 return(NULL); 06090 } 06091 /* 06092 * Search an existing namespace definition inherited. 06093 */ 06094 def = xmlSearchNsByHref(doc, tree, ns->href); 06095 if (def != NULL) 06096 return(def); 06097 06098 /* 06099 * Find a close prefix which is not already in use. 06100 * Let's strip namespace prefixes longer than 20 chars ! 06101 */ 06102 if (ns->prefix == NULL) 06103 snprintf((char *) prefix, sizeof(prefix), "default"); 06104 else 06105 snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix); 06106 06107 def = xmlSearchNs(doc, tree, prefix); 06108 while (def != NULL) { 06109 if (counter > 1000) return(NULL); 06110 if (ns->prefix == NULL) 06111 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++); 06112 else 06113 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", 06114 (char *)ns->prefix, counter++); 06115 def = xmlSearchNs(doc, tree, prefix); 06116 } 06117 06118 /* 06119 * OK, now we are ready to create a new one. 06120 */ 06121 def = xmlNewNs(tree, ns->href, prefix); 06122 return(def); 06123 } 06124 06125 #ifdef LIBXML_TREE_ENABLED 06126 06140 int 06141 xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) { 06142 xmlNsPtr *oldNs = NULL; 06143 xmlNsPtr *newNs = NULL; 06144 int sizeCache = 0; 06145 int nbCache = 0; 06146 06147 xmlNsPtr n; 06148 xmlNodePtr node = tree; 06149 xmlAttrPtr attr; 06150 int ret = 0, i; 06151 06152 if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1); 06153 if ((doc == NULL) || (doc->type != XML_DOCUMENT_NODE)) return(-1); 06154 if (node->doc != doc) return(-1); 06155 while (node != NULL) { 06156 /* 06157 * Reconciliate the node namespace 06158 */ 06159 if (node->ns != NULL) { 06160 /* 06161 * initialize the cache if needed 06162 */ 06163 if (sizeCache == 0) { 06164 sizeCache = 10; 06165 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache * 06166 sizeof(xmlNsPtr)); 06167 if (oldNs == NULL) { 06168 xmlTreeErrMemory("fixing namespaces"); 06169 return(-1); 06170 } 06171 newNs = (xmlNsPtr *) xmlMalloc(sizeCache * 06172 sizeof(xmlNsPtr)); 06173 if (newNs == NULL) { 06174 xmlTreeErrMemory("fixing namespaces"); 06175 xmlFree(oldNs); 06176 return(-1); 06177 } 06178 } 06179 for (i = 0;i < nbCache;i++) { 06180 if (oldNs[i] == node->ns) { 06181 node->ns = newNs[i]; 06182 break; 06183 } 06184 } 06185 if (i == nbCache) { 06186 /* 06187 * OK we need to recreate a new namespace definition 06188 */ 06189 n = xmlNewReconciliedNs(doc, tree, node->ns); 06190 if (n != NULL) { /* :-( what if else ??? */ 06191 /* 06192 * check if we need to grow the cache buffers. 06193 */ 06194 if (sizeCache <= nbCache) { 06195 sizeCache *= 2; 06196 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache * 06197 sizeof(xmlNsPtr)); 06198 if (oldNs == NULL) { 06199 xmlTreeErrMemory("fixing namespaces"); 06200 xmlFree(newNs); 06201 return(-1); 06202 } 06203 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache * 06204 sizeof(xmlNsPtr)); 06205 if (newNs == NULL) { 06206 xmlTreeErrMemory("fixing namespaces"); 06207 xmlFree(oldNs); 06208 return(-1); 06209 } 06210 } 06211 newNs[nbCache] = n; 06212 oldNs[nbCache++] = node->ns; 06213 node->ns = n; 06214 } 06215 } 06216 } 06217 /* 06218 * now check for namespace hold by attributes on the node. 06219 */ 06220 if (node->type == XML_ELEMENT_NODE) { 06221 attr = node->properties; 06222 while (attr != NULL) { 06223 if (attr->ns != NULL) { 06224 /* 06225 * initialize the cache if needed 06226 */ 06227 if (sizeCache == 0) { 06228 sizeCache = 10; 06229 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache * 06230 sizeof(xmlNsPtr)); 06231 if (oldNs == NULL) { 06232 xmlTreeErrMemory("fixing namespaces"); 06233 return(-1); 06234 } 06235 newNs = (xmlNsPtr *) xmlMalloc(sizeCache * 06236 sizeof(xmlNsPtr)); 06237 if (newNs == NULL) { 06238 xmlTreeErrMemory("fixing namespaces"); 06239 xmlFree(oldNs); 06240 return(-1); 06241 } 06242 } 06243 for (i = 0;i < nbCache;i++) { 06244 if (oldNs[i] == attr->ns) { 06245 attr->ns = newNs[i]; 06246 break; 06247 } 06248 } 06249 if (i == nbCache) { 06250 /* 06251 * OK we need to recreate a new namespace definition 06252 */ 06253 n = xmlNewReconciliedNs(doc, tree, attr->ns); 06254 if (n != NULL) { /* :-( what if else ??? */ 06255 /* 06256 * check if we need to grow the cache buffers. 06257 */ 06258 if (sizeCache <= nbCache) { 06259 sizeCache *= 2; 06260 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, 06261 sizeCache * sizeof(xmlNsPtr)); 06262 if (oldNs == NULL) { 06263 xmlTreeErrMemory("fixing namespaces"); 06264 xmlFree(newNs); 06265 return(-1); 06266 } 06267 newNs = (xmlNsPtr *) xmlRealloc(newNs, 06268 sizeCache * sizeof(xmlNsPtr)); 06269 if (newNs == NULL) { 06270 xmlTreeErrMemory("fixing namespaces"); 06271 xmlFree(oldNs); 06272 return(-1); 06273 } 06274 } 06275 newNs[nbCache] = n; 06276 oldNs[nbCache++] = attr->ns; 06277 attr->ns = n; 06278 } 06279 } 06280 } 06281 attr = attr->next; 06282 } 06283 } 06284 06285 /* 06286 * Browse the full subtree, deep first 06287 */ 06288 if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) { 06289 /* deep first */ 06290 node = node->children; 06291 } else if ((node != tree) && (node->next != NULL)) { 06292 /* then siblings */ 06293 node = node->next; 06294 } else if (node != tree) { 06295 /* go up to parents->next if needed */ 06296 while (node != tree) { 06297 if (node->parent != NULL) 06298 node = node->parent; 06299 if ((node != tree) && (node->next != NULL)) { 06300 node = node->next; 06301 break; 06302 } 06303 if (node->parent == NULL) { 06304 node = NULL; 06305 break; 06306 } 06307 } 06308 /* exit condition */ 06309 if (node == tree) 06310 node = NULL; 06311 } else 06312 break; 06313 } 06314 if (oldNs != NULL) 06315 xmlFree(oldNs); 06316 if (newNs != NULL) 06317 xmlFree(newNs); 06318 return(ret); 06319 } 06320 #endif /* LIBXML_TREE_ENABLED */ 06321 06322 static xmlAttrPtr 06323 xmlGetPropNodeInternal(xmlNodePtr node, const xmlChar *name, 06324 const xmlChar *nsName, int useDTD) 06325 { 06326 xmlAttrPtr prop; 06327 06328 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL)) 06329 return(NULL); 06330 06331 if (node->properties != NULL) { 06332 prop = node->properties; 06333 if (nsName == NULL) { 06334 /* 06335 * We want the attr to be in no namespace. 06336 */ 06337 do { 06338 if ((prop->ns == NULL) && xmlStrEqual(prop->name, name)) { 06339 return(prop); 06340 } 06341 prop = prop->next; 06342 } while (prop != NULL); 06343 } else { 06344 /* 06345 * We want the attr to be in the specified namespace. 06346 */ 06347 do { 06348 if ((prop->ns != NULL) && xmlStrEqual(prop->name, name) && 06349 ((prop->ns->href == nsName) || 06350 xmlStrEqual(prop->ns->href, nsName))) 06351 { 06352 return(prop); 06353 } 06354 prop = prop->next; 06355 } while (prop != NULL); 06356 } 06357 } 06358 06359 #ifdef LIBXML_TREE_ENABLED 06360 if (! useDTD) 06361 return(NULL); 06362 /* 06363 * Check if there is a default/fixed attribute declaration in 06364 * the internal or external subset. 06365 */ 06366 if ((node->doc != NULL) && (node->doc->intSubset != NULL)) { 06367 xmlDocPtr doc = node->doc; 06368 xmlAttributePtr attrDecl = NULL; 06369 xmlChar *elemQName, *tmpstr = NULL; 06370 06371 /* 06372 * We need the QName of the element for the DTD-lookup. 06373 */ 06374 if ((node->ns != NULL) && (node->ns->prefix != NULL)) { 06375 tmpstr = xmlStrdup(node->ns->prefix); 06376 tmpstr = xmlStrcat(tmpstr, BAD_CAST ":"); 06377 tmpstr = xmlStrcat(tmpstr, node->name); 06378 if (tmpstr == NULL) 06379 return(NULL); 06380 elemQName = tmpstr; 06381 } else 06382 elemQName = (xmlChar *) node->name; 06383 if (nsName == NULL) { 06384 /* 06385 * The common and nice case: Attr in no namespace. 06386 */ 06387 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, 06388 elemQName, name, NULL); 06389 if ((attrDecl == NULL) && (doc->extSubset != NULL)) { 06390 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, 06391 elemQName, name, NULL); 06392 } 06393 } else { 06394 xmlNsPtr *nsList, *cur; 06395 06396 /* 06397 * The ugly case: Search using the prefixes of in-scope 06398 * ns-decls corresponding to @nsName. 06399 */ 06400 nsList = xmlGetNsList(node->doc, node); 06401 if (nsList == NULL) { 06402 if (tmpstr != NULL) 06403 xmlFree(tmpstr); 06404 return(NULL); 06405 } 06406 cur = nsList; 06407 while (*cur != NULL) { 06408 if (xmlStrEqual((*cur)->href, nsName)) { 06409 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elemQName, 06410 name, (*cur)->prefix); 06411 if (attrDecl) 06412 break; 06413 if (doc->extSubset != NULL) { 06414 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elemQName, 06415 name, (*cur)->prefix); 06416 if (attrDecl) 06417 break; 06418 } 06419 } 06420 cur++; 06421 } 06422 xmlFree(nsList); 06423 } 06424 if (tmpstr != NULL) 06425 xmlFree(tmpstr); 06426 /* 06427 * Only default/fixed attrs are relevant. 06428 */ 06429 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL)) 06430 return((xmlAttrPtr) attrDecl); 06431 } 06432 #endif /* LIBXML_TREE_ENABLED */ 06433 return(NULL); 06434 } 06435 06436 static xmlChar* 06437 xmlGetPropNodeValueInternal(xmlAttrPtr prop) 06438 { 06439 if (prop == NULL) 06440 return(NULL); 06441 if (prop->type == XML_ATTRIBUTE_NODE) { 06442 /* 06443 * Note that we return at least the empty string. 06444 * TODO: Do we really always want that? 06445 */ 06446 if (prop->children != NULL) { 06447 if ((prop->children->next == NULL) && 06448 ((prop->children->type == XML_TEXT_NODE) || 06449 (prop->children->type == XML_CDATA_SECTION_NODE))) 06450 { 06451 /* 06452 * Optimization for the common case: only 1 text node. 06453 */ 06454 return(xmlStrdup(prop->children->content)); 06455 } else { 06456 xmlChar *ret; 06457 06458 ret = xmlNodeListGetString(prop->doc, prop->children, 1); 06459 if (ret != NULL) 06460 return(ret); 06461 } 06462 } 06463 return(xmlStrdup((xmlChar *)"")); 06464 } else if (prop->type == XML_ATTRIBUTE_DECL) { 06465 return(xmlStrdup(((xmlAttributePtr)prop)->defaultValue)); 06466 } 06467 return(NULL); 06468 } 06469 06482 xmlAttrPtr 06483 xmlHasProp(xmlNodePtr node, const xmlChar *name) { 06484 xmlAttrPtr prop; 06485 xmlDocPtr doc; 06486 06487 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL)) 06488 return(NULL); 06489 /* 06490 * Check on the properties attached to the node 06491 */ 06492 prop = node->properties; 06493 while (prop != NULL) { 06494 if (xmlStrEqual(prop->name, name)) { 06495 return(prop); 06496 } 06497 prop = prop->next; 06498 } 06499 if (!xmlCheckDTD) return(NULL); 06500 06501 /* 06502 * Check if there is a default declaration in the internal 06503 * or external subsets 06504 */ 06505 doc = node->doc; 06506 if (doc != NULL) { 06507 xmlAttributePtr attrDecl; 06508 if (doc->intSubset != NULL) { 06509 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name); 06510 if ((attrDecl == NULL) && (doc->extSubset != NULL)) 06511 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name); 06512 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL)) 06513 /* return attribute declaration only if a default value is given 06514 (that includes #FIXED declarations) */ 06515 return((xmlAttrPtr) attrDecl); 06516 } 06517 } 06518 return(NULL); 06519 } 06520 06537 xmlAttrPtr 06538 xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) { 06539 06540 return(xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD)); 06541 } 06542 06559 xmlChar * 06560 xmlGetProp(xmlNodePtr node, const xmlChar *name) { 06561 xmlAttrPtr prop; 06562 06563 prop = xmlHasProp(node, name); 06564 if (prop == NULL) 06565 return(NULL); 06566 return(xmlGetPropNodeValueInternal(prop)); 06567 } 06568 06584 xmlChar * 06585 xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) { 06586 xmlAttrPtr prop; 06587 06588 prop = xmlGetPropNodeInternal(node, name, NULL, xmlCheckDTD); 06589 if (prop == NULL) 06590 return(NULL); 06591 return(xmlGetPropNodeValueInternal(prop)); 06592 } 06593 06609 xmlChar * 06610 xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) { 06611 xmlAttrPtr prop; 06612 06613 prop = xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD); 06614 if (prop == NULL) 06615 return(NULL); 06616 return(xmlGetPropNodeValueInternal(prop)); 06617 } 06618 06619 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) 06620 06629 int 06630 xmlUnsetProp(xmlNodePtr node, const xmlChar *name) { 06631 xmlAttrPtr prop; 06632 06633 prop = xmlGetPropNodeInternal(node, name, NULL, 0); 06634 if (prop == NULL) 06635 return(-1); 06636 xmlUnlinkNode((xmlNodePtr) prop); 06637 xmlFreeProp(prop); 06638 return(0); 06639 } 06640 06650 int 06651 xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) { 06652 xmlAttrPtr prop; 06653 06654 prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0); 06655 if (prop == NULL) 06656 return(-1); 06657 xmlUnlinkNode((xmlNodePtr) prop); 06658 xmlFreeProp(prop); 06659 return(0); 06660 } 06661 #endif 06662 06663 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED) 06664 06678 xmlAttrPtr 06679 xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) { 06680 int len; 06681 const xmlChar *nqname; 06682 06683 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE)) 06684 return(NULL); 06685 06686 /* 06687 * handle QNames 06688 */ 06689 nqname = xmlSplitQName3(name, &len); 06690 if (nqname != NULL) { 06691 xmlNsPtr ns; 06692 xmlChar *prefix = xmlStrndup(name, len); 06693 ns = xmlSearchNs(node->doc, node, prefix); 06694 if (prefix != NULL) 06695 xmlFree(prefix); 06696 if (ns != NULL) 06697 return(xmlSetNsProp(node, ns, nqname, value)); 06698 } 06699 return(xmlSetNsProp(node, NULL, name, value)); 06700 } 06701 06714 xmlAttrPtr 06715 xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name, 06716 const xmlChar *value) 06717 { 06718 xmlAttrPtr prop; 06719 06720 if (ns && (ns->href == NULL)) 06721 return(NULL); 06722 prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0); 06723 if (prop != NULL) { 06724 /* 06725 * Modify the attribute's value. 06726 */ 06727 if (prop->atype == XML_ATTRIBUTE_ID) { 06728 xmlRemoveID(node->doc, prop); 06729 prop->atype = XML_ATTRIBUTE_ID; 06730 } 06731 if (prop->children != NULL) 06732 xmlFreeNodeList(prop->children); 06733 prop->children = NULL; 06734 prop->last = NULL; 06735 prop->ns = ns; 06736 if (value != NULL) { 06737 xmlNodePtr tmp; 06738 06739 if(!xmlCheckUTF8(value)) { 06740 xmlTreeErr(XML_TREE_NOT_UTF8, (xmlNodePtr) node->doc, 06741 NULL); 06742 if (node->doc != NULL) 06743 node->doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1"); 06744 } 06745 prop->children = xmlNewDocText(node->doc, value); 06746 prop->last = NULL; 06747 tmp = prop->children; 06748 while (tmp != NULL) { 06749 tmp->parent = (xmlNodePtr) prop; 06750 if (tmp->next == NULL) 06751 prop->last = tmp; 06752 tmp = tmp->next; 06753 } 06754 } 06755 if (prop->atype == XML_ATTRIBUTE_ID) 06756 xmlAddID(NULL, node->doc, value, prop); 06757 return(prop); 06758 } 06759 /* 06760 * No equal attr found; create a new one. 06761 */ 06762 return(xmlNewPropInternal(node, ns, name, value, 0)); 06763 } 06764 06765 #endif /* LIBXML_TREE_ENABLED */ 06766 06774 int 06775 xmlNodeIsText(xmlNodePtr node) { 06776 if (node == NULL) return(0); 06777 06778 if (node->type == XML_TEXT_NODE) return(1); 06779 return(0); 06780 } 06781 06791 int 06792 xmlIsBlankNode(xmlNodePtr node) { 06793 const xmlChar *cur; 06794 if (node == NULL) return(0); 06795 06796 if ((node->type != XML_TEXT_NODE) && 06797 (node->type != XML_CDATA_SECTION_NODE)) 06798 return(0); 06799 if (node->content == NULL) return(1); 06800 cur = node->content; 06801 while (*cur != 0) { 06802 if (!IS_BLANK_CH(*cur)) return(0); 06803 cur++; 06804 } 06805 06806 return(1); 06807 } 06808 06820 int 06821 xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) { 06822 if (node == NULL) return(-1); 06823 06824 if ((node->type != XML_TEXT_NODE) && 06825 (node->type != XML_CDATA_SECTION_NODE) && 06826 (node->type != XML_COMMENT_NODE) && 06827 (node->type != XML_PI_NODE)) { 06828 #ifdef DEBUG_TREE 06829 xmlGenericError(xmlGenericErrorContext, 06830 "xmlTextConcat: node is not text nor CDATA\n"); 06831 #endif 06832 return(-1); 06833 } 06834 /* need to check if content is currently in the dictionary */ 06835 if ((node->content == (xmlChar *) &(node->properties)) || 06836 ((node->doc != NULL) && (node->doc->dict != NULL) && 06837 xmlDictOwns(node->doc->dict, node->content))) { 06838 node->content = xmlStrncatNew(node->content, content, len); 06839 } else { 06840 node->content = xmlStrncat(node->content, content, len); 06841 } 06842 node->properties = NULL; 06843 if (node->content == NULL) 06844 return(-1); 06845 return(0); 06846 } 06847 06848 /************************************************************************ 06849 * * 06850 * Output : to a FILE or in memory * 06851 * * 06852 ************************************************************************/ 06853 06860 xmlBufferPtr 06861 xmlBufferCreate(void) { 06862 xmlBufferPtr ret; 06863 06864 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer)); 06865 if (ret == NULL) { 06866 xmlTreeErrMemory("creating buffer"); 06867 return(NULL); 06868 } 06869 ret->use = 0; 06870 ret->size = xmlDefaultBufferSize; 06871 ret->alloc = xmlBufferAllocScheme; 06872 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar)); 06873 if (ret->content == NULL) { 06874 xmlTreeErrMemory("creating buffer"); 06875 xmlFree(ret); 06876 return(NULL); 06877 } 06878 ret->content[0] = 0; 06879 ret->contentIO = NULL; 06880 return(ret); 06881 } 06882 06890 xmlBufferPtr 06891 xmlBufferCreateSize(size_t size) { 06892 xmlBufferPtr ret; 06893 06894 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer)); 06895 if (ret == NULL) { 06896 xmlTreeErrMemory("creating buffer"); 06897 return(NULL); 06898 } 06899 ret->use = 0; 06900 ret->alloc = xmlBufferAllocScheme; 06901 ret->size = (size ? size+2 : 0); /* +1 for ending null */ 06902 if (ret->size){ 06903 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar)); 06904 if (ret->content == NULL) { 06905 xmlTreeErrMemory("creating buffer"); 06906 xmlFree(ret); 06907 return(NULL); 06908 } 06909 ret->content[0] = 0; 06910 } else 06911 ret->content = NULL; 06912 ret->contentIO = NULL; 06913 return(ret); 06914 } 06915 06927 xmlBufferPtr 06928 xmlBufferCreateStatic(void *mem, size_t size) { 06929 xmlBufferPtr ret; 06930 06931 if ((mem == NULL) || (size == 0)) 06932 return(NULL); 06933 06934 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer)); 06935 if (ret == NULL) { 06936 xmlTreeErrMemory("creating buffer"); 06937 return(NULL); 06938 } 06939 ret->use = size; 06940 ret->size = size; 06941 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE; 06942 ret->content = (xmlChar *) mem; 06943 return(ret); 06944 } 06945 06953 void 06954 xmlBufferSetAllocationScheme(xmlBufferPtr buf, 06955 xmlBufferAllocationScheme scheme) { 06956 if (buf == NULL) { 06957 #ifdef DEBUG_BUFFER 06958 xmlGenericError(xmlGenericErrorContext, 06959 "xmlBufferSetAllocationScheme: buf == NULL\n"); 06960 #endif 06961 return; 06962 } 06963 if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) || 06964 (buf->alloc == XML_BUFFER_ALLOC_IO)) return; 06965 if ((scheme == XML_BUFFER_ALLOC_DOUBLEIT) || 06966 (scheme == XML_BUFFER_ALLOC_EXACT) || 06967 (scheme == XML_BUFFER_ALLOC_IMMUTABLE)) 06968 buf->alloc = scheme; 06969 } 06970 06978 void 06979 xmlBufferFree(xmlBufferPtr buf) { 06980 if (buf == NULL) { 06981 #ifdef DEBUG_BUFFER 06982 xmlGenericError(xmlGenericErrorContext, 06983 "xmlBufferFree: buf == NULL\n"); 06984 #endif 06985 return; 06986 } 06987 06988 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && 06989 (buf->contentIO != NULL)) { 06990 xmlFree(buf->contentIO); 06991 } else if ((buf->content != NULL) && 06992 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) { 06993 xmlFree(buf->content); 06994 } 06995 xmlFree(buf); 06996 } 06997 07004 void 07005 xmlBufferEmpty(xmlBufferPtr buf) { 07006 if (buf == NULL) return; 07007 if (buf->content == NULL) return; 07008 buf->use = 0; 07009 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) { 07010 buf->content = BAD_CAST ""; 07011 } else if ((buf->alloc == XML_BUFFER_ALLOC_IO) && 07012 (buf->contentIO != NULL)) { 07013 size_t start_buf = buf->content - buf->contentIO; 07014 07015 buf->size += start_buf; 07016 buf->content = buf->contentIO; 07017 buf->content[0] = 0; 07018 } else { 07019 buf->content[0] = 0; 07020 } 07021 } 07022 07032 int 07033 xmlBufferShrink(xmlBufferPtr buf, unsigned int len) { 07034 if (buf == NULL) return(-1); 07035 if (len == 0) return(0); 07036 if (len > buf->use) return(-1); 07037 07038 buf->use -= len; 07039 if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) || 07040 ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL))) { 07041 /* 07042 * we just move the content pointer, but also make sure 07043 * the perceived buffer size has shrinked accordingly 07044 */ 07045 buf->content += len; 07046 buf->size -= len; 07047 07048 /* 07049 * sometimes though it maybe be better to really shrink 07050 * on IO buffers 07051 */ 07052 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) { 07053 size_t start_buf = buf->content - buf->contentIO; 07054 if (start_buf >= buf->size) { 07055 memmove(buf->contentIO, &buf->content[0], buf->use); 07056 buf->content = buf->contentIO; 07057 buf->content[buf->use] = 0; 07058 buf->size += start_buf; 07059 } 07060 } 07061 } else { 07062 memmove(buf->content, &buf->content[len], buf->use); 07063 buf->content[buf->use] = 0; 07064 } 07065 return(len); 07066 } 07067 07077 int 07078 xmlBufferGrow(xmlBufferPtr buf, unsigned int len) { 07079 int size; 07080 xmlChar *newbuf; 07081 07082 if (buf == NULL) return(-1); 07083 07084 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0); 07085 if (len + buf->use < buf->size) return(0); 07086 07087 /* 07088 * Windows has a BIG problem on realloc timing, so we try to double 07089 * the buffer size (if that's enough) (bug 146697) 07090 * Apparently BSD too, and it's probably best for linux too 07091 * On an embedded system this may be something to change 07092 */ 07093 #if 1 07094 if (buf->size > len) 07095 size = buf->size * 2; 07096 else 07097 size = buf->use + len + 100; 07098 #else 07099 size = buf->use + len + 100; 07100 #endif 07101 07102 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) { 07103 size_t start_buf = buf->content - buf->contentIO; 07104 07105 newbuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + size); 07106 if (newbuf == NULL) { 07107 xmlTreeErrMemory("growing buffer"); 07108 return(-1); 07109 } 07110 buf->contentIO = newbuf; 07111 buf->content = newbuf + start_buf; 07112 } else { 07113 newbuf = (xmlChar *) xmlRealloc(buf->content, size); 07114 if (newbuf == NULL) { 07115 xmlTreeErrMemory("growing buffer"); 07116 return(-1); 07117 } 07118 buf->content = newbuf; 07119 } 07120 buf->size = size; 07121 return(buf->size - buf->use); 07122 } 07123 07132 int 07133 xmlBufferDump(FILE *file, xmlBufferPtr buf) { 07134 int ret; 07135 07136 if (buf == NULL) { 07137 #ifdef DEBUG_BUFFER 07138 xmlGenericError(xmlGenericErrorContext, 07139 "xmlBufferDump: buf == NULL\n"); 07140 #endif 07141 return(0); 07142 } 07143 if (buf->content == NULL) { 07144 #ifdef DEBUG_BUFFER 07145 xmlGenericError(xmlGenericErrorContext, 07146 "xmlBufferDump: buf->content == NULL\n"); 07147 #endif 07148 return(0); 07149 } 07150 if (file == NULL) 07151 file = stdout; 07152 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file); 07153 return(ret); 07154 } 07155 07165 const xmlChar * 07166 xmlBufferContent(const xmlBufferPtr buf) 07167 { 07168 if(!buf) 07169 return NULL; 07170 07171 return buf->content; 07172 } 07173 07183 int 07184 xmlBufferLength(const xmlBufferPtr buf) 07185 { 07186 if(!buf) 07187 return 0; 07188 07189 return buf->use; 07190 } 07191 07201 int 07202 xmlBufferResize(xmlBufferPtr buf, unsigned int size) 07203 { 07204 unsigned int newSize; 07205 xmlChar* rebuf = NULL; 07206 size_t start_buf; 07207 07208 if (buf == NULL) 07209 return(0); 07210 07211 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0); 07212 07213 /* Don't resize if we don't have to */ 07214 if (size < buf->size) 07215 return 1; 07216 07217 /* figure out new size */ 07218 switch (buf->alloc){ 07219 case XML_BUFFER_ALLOC_IO: 07220 case XML_BUFFER_ALLOC_DOUBLEIT: 07221 /*take care of empty case*/ 07222 newSize = (buf->size ? buf->size*2 : size + 10); 07223 while (size > newSize) { 07224 if (newSize > UINT_MAX / 2) { 07225 xmlTreeErrMemory("growing buffer"); 07226 return 0; 07227 } 07228 newSize *= 2; 07229 } 07230 break; 07231 case XML_BUFFER_ALLOC_EXACT: 07232 newSize = size+10; 07233 break; 07234 default: 07235 newSize = size+10; 07236 break; 07237 } 07238 07239 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) { 07240 start_buf = buf->content - buf->contentIO; 07241 07242 if (start_buf > newSize) { 07243 /* move data back to start */ 07244 memmove(buf->contentIO, buf->content, buf->use); 07245 buf->content = buf->contentIO; 07246 buf->content[buf->use] = 0; 07247 buf->size += start_buf; 07248 } else { 07249 rebuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + newSize); 07250 if (rebuf == NULL) { 07251 xmlTreeErrMemory("growing buffer"); 07252 return 0; 07253 } 07254 buf->contentIO = rebuf; 07255 buf->content = rebuf + start_buf; 07256 } 07257 } else { 07258 if (buf->content == NULL) { 07259 rebuf = (xmlChar *) xmlMallocAtomic(newSize); 07260 } else if (buf->size - buf->use < 100) { 07261 rebuf = (xmlChar *) xmlRealloc(buf->content, newSize); 07262 } else { 07263 /* 07264 * if we are reallocating a buffer far from being full, it's 07265 * better to make a new allocation and copy only the used range 07266 * and free the old one. 07267 */ 07268 rebuf = (xmlChar *) xmlMallocAtomic(newSize); 07269 if (rebuf != NULL) { 07270 memcpy(rebuf, buf->content, buf->use); 07271 xmlFree(buf->content); 07272 rebuf[buf->use] = 0; 07273 } 07274 } 07275 if (rebuf == NULL) { 07276 xmlTreeErrMemory("growing buffer"); 07277 return 0; 07278 } 07279 buf->content = rebuf; 07280 } 07281 buf->size = newSize; 07282 07283 return 1; 07284 } 07285 07298 int 07299 xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) { 07300 unsigned int needSize; 07301 07302 if ((str == NULL) || (buf == NULL)) { 07303 return -1; 07304 } 07305 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1; 07306 if (len < -1) { 07307 #ifdef DEBUG_BUFFER 07308 xmlGenericError(xmlGenericErrorContext, 07309 "xmlBufferAdd: len < 0\n"); 07310 #endif 07311 return -1; 07312 } 07313 if (len == 0) return 0; 07314 07315 if (len < 0) 07316 len = xmlStrlen(str); 07317 07318 if (len < 0) return -1; 07319 if (len == 0) return 0; 07320 07321 needSize = buf->use + len + 2; 07322 if (needSize > buf->size){ 07323 if (!xmlBufferResize(buf, needSize)){ 07324 xmlTreeErrMemory("growing buffer"); 07325 return XML_ERR_NO_MEMORY; 07326 } 07327 } 07328 07329 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar)); 07330 buf->use += len; 07331 buf->content[buf->use] = 0; 07332 return 0; 07333 } 07334 07347 int 07348 xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) { 07349 unsigned int needSize; 07350 07351 if (buf == NULL) 07352 return(-1); 07353 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1; 07354 if (str == NULL) { 07355 #ifdef DEBUG_BUFFER 07356 xmlGenericError(xmlGenericErrorContext, 07357 "xmlBufferAddHead: str == NULL\n"); 07358 #endif 07359 return -1; 07360 } 07361 if (len < -1) { 07362 #ifdef DEBUG_BUFFER 07363 xmlGenericError(xmlGenericErrorContext, 07364 "xmlBufferAddHead: len < 0\n"); 07365 #endif 07366 return -1; 07367 } 07368 if (len == 0) return 0; 07369 07370 if (len < 0) 07371 len = xmlStrlen(str); 07372 07373 if (len <= 0) return -1; 07374 07375 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) { 07376 size_t start_buf = buf->content - buf->contentIO; 07377 07378 if (start_buf > (unsigned int) len) { 07379 /* 07380 * We can add it in the space previously shrinked 07381 */ 07382 buf->content -= len; 07383 memmove(&buf->content[0], str, len); 07384 buf->use += len; 07385 buf->size += len; 07386 return(0); 07387 } 07388 } 07389 needSize = buf->use + len + 2; 07390 if (needSize > buf->size){ 07391 if (!xmlBufferResize(buf, needSize)){ 07392 xmlTreeErrMemory("growing buffer"); 07393 return XML_ERR_NO_MEMORY; 07394 } 07395 } 07396 07397 memmove(&buf->content[len], &buf->content[0], buf->use); 07398 memmove(&buf->content[0], str, len); 07399 buf->use += len; 07400 buf->content[buf->use] = 0; 07401 return 0; 07402 } 07403 07414 int 07415 xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) { 07416 if (buf == NULL) 07417 return(-1); 07418 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1; 07419 if (str == NULL) return -1; 07420 return xmlBufferAdd(buf, str, -1); 07421 } 07422 07433 int 07434 xmlBufferCCat(xmlBufferPtr buf, const char *str) { 07435 const char *cur; 07436 07437 if (buf == NULL) 07438 return(-1); 07439 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1; 07440 if (str == NULL) { 07441 #ifdef DEBUG_BUFFER 07442 xmlGenericError(xmlGenericErrorContext, 07443 "xmlBufferCCat: str == NULL\n"); 07444 #endif 07445 return -1; 07446 } 07447 for (cur = str;*cur != 0;cur++) { 07448 if (buf->use + 10 >= buf->size) { 07449 if (!xmlBufferResize(buf, buf->use+10)){ 07450 xmlTreeErrMemory("growing buffer"); 07451 return XML_ERR_NO_MEMORY; 07452 } 07453 } 07454 buf->content[buf->use++] = *cur; 07455 } 07456 buf->content[buf->use] = 0; 07457 return 0; 07458 } 07459 07468 void 07469 xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) { 07470 if (buf == NULL) 07471 return; 07472 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return; 07473 xmlBufferCat(buf, string); 07474 } 07475 07484 void 07485 xmlBufferWriteChar(xmlBufferPtr buf, const char *string) { 07486 if (buf == NULL) 07487 return; 07488 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return; 07489 xmlBufferCCat(buf, string); 07490 } 07491 07492 07502 void 07503 xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) { 07504 const xmlChar *cur, *base; 07505 if (buf == NULL) 07506 return; 07507 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return; 07508 if (xmlStrchr(string, '\"')) { 07509 if (xmlStrchr(string, '\'')) { 07510 #ifdef DEBUG_BUFFER 07511 xmlGenericError(xmlGenericErrorContext, 07512 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n"); 07513 #endif 07514 xmlBufferCCat(buf, "\""); 07515 base = cur = string; 07516 while(*cur != 0){ 07517 if(*cur == '"'){ 07518 if (base != cur) 07519 xmlBufferAdd(buf, base, cur - base); 07520 xmlBufferAdd(buf, BAD_CAST """, 6); 07521 cur++; 07522 base = cur; 07523 } 07524 else { 07525 cur++; 07526 } 07527 } 07528 if (base != cur) 07529 xmlBufferAdd(buf, base, cur - base); 07530 xmlBufferCCat(buf, "\""); 07531 } 07532 else{ 07533 xmlBufferCCat(buf, "\'"); 07534 xmlBufferCat(buf, string); 07535 xmlBufferCCat(buf, "\'"); 07536 } 07537 } else { 07538 xmlBufferCCat(buf, "\""); 07539 xmlBufferCat(buf, string); 07540 xmlBufferCCat(buf, "\""); 07541 } 07542 } 07543 07544 07552 int 07553 xmlGetDocCompressMode (xmlDocPtr doc) { 07554 if (doc == NULL) return(-1); 07555 return(doc->compression); 07556 } 07557 07566 void 07567 xmlSetDocCompressMode (xmlDocPtr doc, int mode) { 07568 if (doc == NULL) return; 07569 if (mode < 0) doc->compression = 0; 07570 else if (mode > 9) doc->compression = 9; 07571 else doc->compression = mode; 07572 } 07573 07580 int 07581 xmlGetCompressMode(void) 07582 { 07583 return (xmlCompressMode); 07584 } 07585 07593 void 07594 xmlSetCompressMode(int mode) { 07595 if (mode < 0) xmlCompressMode = 0; 07596 else if (mode > 9) xmlCompressMode = 9; 07597 else xmlCompressMode = mode; 07598 } 07599 07600 #define XML_TREE_NSMAP_PARENT -1 07601 #define XML_TREE_NSMAP_XML -2 07602 #define XML_TREE_NSMAP_DOC -3 07603 #define XML_TREE_NSMAP_CUSTOM -4 07604 07605 typedef struct xmlNsMapItem *xmlNsMapItemPtr; 07606 struct xmlNsMapItem { 07607 xmlNsMapItemPtr next; 07608 xmlNsMapItemPtr prev; 07609 xmlNsPtr oldNs; /* old ns decl reference */ 07610 xmlNsPtr newNs; /* new ns decl reference */ 07611 int shadowDepth; /* Shadowed at this depth */ 07612 /* 07613 * depth: 07614 * >= 0 == @node's ns-decls 07615 * -1 == @parent's ns-decls 07616 * -2 == the doc->oldNs XML ns-decl 07617 * -3 == the doc->oldNs storage ns-decls 07618 * -4 == ns-decls provided via custom ns-handling 07619 */ 07620 int depth; 07621 }; 07622 07623 typedef struct xmlNsMap *xmlNsMapPtr; 07624 struct xmlNsMap { 07625 xmlNsMapItemPtr first; 07626 xmlNsMapItemPtr last; 07627 xmlNsMapItemPtr pool; 07628 }; 07629 07630 #define XML_NSMAP_NOTEMPTY(m) (((m) != NULL) && ((m)->first != NULL)) 07631 #define XML_NSMAP_FOREACH(m, i) for (i = (m)->first; i != NULL; i = (i)->next) 07632 #define XML_NSMAP_POP(m, i) \ 07633 i = (m)->last; \ 07634 (m)->last = (i)->prev; \ 07635 if ((m)->last == NULL) \ 07636 (m)->first = NULL; \ 07637 else \ 07638 (m)->last->next = NULL; \ 07639 (i)->next = (m)->pool; \ 07640 (m)->pool = i; 07641 07642 /* 07643 * xmlDOMWrapNsMapFree: 07644 * @map: the ns-map 07645 * 07646 * Frees the ns-map 07647 */ 07648 static void 07649 xmlDOMWrapNsMapFree(xmlNsMapPtr nsmap) 07650 { 07651 xmlNsMapItemPtr cur, tmp; 07652 07653 if (nsmap == NULL) 07654 return; 07655 cur = nsmap->pool; 07656 while (cur != NULL) { 07657 tmp = cur; 07658 cur = cur->next; 07659 xmlFree(tmp); 07660 } 07661 cur = nsmap->first; 07662 while (cur != NULL) { 07663 tmp = cur; 07664 cur = cur->next; 07665 xmlFree(tmp); 07666 } 07667 xmlFree(nsmap); 07668 } 07669 07670 /* 07671 * xmlDOMWrapNsMapAddItem: 07672 * @map: the ns-map 07673 * @oldNs: the old ns-struct 07674 * @newNs: the new ns-struct 07675 * @depth: depth and ns-kind information 07676 * 07677 * Adds an ns-mapping item. 07678 */ 07679 static xmlNsMapItemPtr 07680 xmlDOMWrapNsMapAddItem(xmlNsMapPtr *nsmap, int position, 07681 xmlNsPtr oldNs, xmlNsPtr newNs, int depth) 07682 { 07683 xmlNsMapItemPtr ret; 07684 xmlNsMapPtr map; 07685 07686 if (nsmap == NULL) 07687 return(NULL); 07688 if ((position != -1) && (position != 0)) 07689 return(NULL); 07690 map = *nsmap; 07691 07692 if (map == NULL) { 07693 /* 07694 * Create the ns-map. 07695 */ 07696 map = (xmlNsMapPtr) xmlMalloc(sizeof(struct xmlNsMap)); 07697 if (map == NULL) { 07698 xmlTreeErrMemory("allocating namespace map"); 07699 return (NULL); 07700 } 07701 memset(map, 0, sizeof(struct xmlNsMap)); 07702 *nsmap = map; 07703 } 07704 07705 if (map->pool != NULL) { 07706 /* 07707 * Reuse an item from the pool. 07708 */ 07709 ret = map->pool; 07710 map->pool = ret->next; 07711 memset(ret, 0, sizeof(struct xmlNsMapItem)); 07712 } else { 07713 /* 07714 * Create a new item. 07715 */ 07716 ret = (xmlNsMapItemPtr) xmlMalloc(sizeof(struct xmlNsMapItem)); 07717 if (ret == NULL) { 07718 xmlTreeErrMemory("allocating namespace map item"); 07719 return (NULL); 07720 } 07721 memset(ret, 0, sizeof(struct xmlNsMapItem)); 07722 } 07723 07724 if (map->first == NULL) { 07725 /* 07726 * First ever. 07727 */ 07728 map->first = ret; 07729 map->last = ret; 07730 } else if (position == -1) { 07731 /* 07732 * Append. 07733 */ 07734 ret->prev = map->last; 07735 map->last->next = ret; 07736 map->last = ret; 07737 } else if (position == 0) { 07738 /* 07739 * Set on first position. 07740 */ 07741 map->first->prev = ret; 07742 ret->next = map->first; 07743 map->first = ret; 07744 } else 07745 return(NULL); 07746 07747 ret->oldNs = oldNs; 07748 ret->newNs = newNs; 07749 ret->shadowDepth = -1; 07750 ret->depth = depth; 07751 return (ret); 07752 } 07753 07754 /* 07755 * xmlDOMWrapStoreNs: 07756 * @doc: the doc 07757 * @nsName: the namespace name 07758 * @prefix: the prefix 07759 * 07760 * Creates or reuses an xmlNs struct on doc->oldNs with 07761 * the given prefix and namespace name. 07762 * 07763 * Returns the aquired ns struct or NULL in case of an API 07764 * or internal error. 07765 */ 07766 static xmlNsPtr 07767 xmlDOMWrapStoreNs(xmlDocPtr doc, 07768 const xmlChar *nsName, 07769 const xmlChar *prefix) 07770 { 07771 xmlNsPtr ns; 07772 07773 if (doc == NULL) 07774 return (NULL); 07775 ns = xmlTreeEnsureXMLDecl(doc); 07776 if (ns == NULL) 07777 return (NULL); 07778 if (ns->next != NULL) { 07779 /* Reuse. */ 07780 ns = ns->next; 07781 while (ns != NULL) { 07782 if (((ns->prefix == prefix) || 07783 xmlStrEqual(ns->prefix, prefix)) && 07784 xmlStrEqual(ns->href, nsName)) { 07785 return (ns); 07786 } 07787 if (ns->next == NULL) 07788 break; 07789 ns = ns->next; 07790 } 07791 } 07792 /* Create. */ 07793 if (ns != NULL) { 07794 ns->next = xmlNewNs(NULL, nsName, prefix); 07795 return (ns->next); 07796 } 07797 return(NULL); 07798 } 07799 07800 /* 07801 * xmlDOMWrapNewCtxt: 07802 * 07803 * Allocates and initializes a new DOM-wrapper context. 07804 * 07805 * Returns the xmlDOMWrapCtxtPtr or NULL in case of an internal errror. 07806 */ 07807 xmlDOMWrapCtxtPtr 07808 xmlDOMWrapNewCtxt(void) 07809 { 07810 xmlDOMWrapCtxtPtr ret; 07811 07812 ret = xmlMalloc(sizeof(xmlDOMWrapCtxt)); 07813 if (ret == NULL) { 07814 xmlTreeErrMemory("allocating DOM-wrapper context"); 07815 return (NULL); 07816 } 07817 memset(ret, 0, sizeof(xmlDOMWrapCtxt)); 07818 return (ret); 07819 } 07820 07821 /* 07822 * xmlDOMWrapFreeCtxt: 07823 * @ctxt: the DOM-wrapper context 07824 * 07825 * Frees the DOM-wrapper context. 07826 */ 07827 void 07828 xmlDOMWrapFreeCtxt(xmlDOMWrapCtxtPtr ctxt) 07829 { 07830 if (ctxt == NULL) 07831 return; 07832 if (ctxt->namespaceMap != NULL) 07833 xmlDOMWrapNsMapFree((xmlNsMapPtr) ctxt->namespaceMap); 07834 /* 07835 * TODO: Store the namespace map in the context. 07836 */ 07837 xmlFree(ctxt); 07838 } 07839 07840 /* 07841 * xmlTreeLookupNsListByPrefix: 07842 * @nsList: a list of ns-structs 07843 * @prefix: the searched prefix 07844 * 07845 * Searches for a ns-decl with the given prefix in @nsList. 07846 * 07847 * Returns the ns-decl if found, NULL if not found and on 07848 * API errors. 07849 */ 07850 static xmlNsPtr 07851 xmlTreeNSListLookupByPrefix(xmlNsPtr nsList, const xmlChar *prefix) 07852 { 07853 if (nsList == NULL) 07854 return (NULL); 07855 { 07856 xmlNsPtr ns; 07857 ns = nsList; 07858 do { 07859 if ((prefix == ns->prefix) || 07860 xmlStrEqual(prefix, ns->prefix)) { 07861 return (ns); 07862 } 07863 ns = ns->next; 07864 } while (ns != NULL); 07865 } 07866 return (NULL); 07867 } 07868 07869 /* 07870 * 07871 * xmlDOMWrapNSNormGatherInScopeNs: 07872 * @map: the namespace map 07873 * @node: the node to start with 07874 * 07875 * Puts in-scope namespaces into the ns-map. 07876 * 07877 * Returns 0 on success, -1 on API or internal errors. 07878 */ 07879 static int 07880 xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapPtr *map, 07881 xmlNodePtr node) 07882 { 07883 xmlNodePtr cur; 07884 xmlNsPtr ns; 07885 xmlNsMapItemPtr mi; 07886 int shadowed; 07887 07888 if ((map == NULL) || (*map != NULL)) 07889 return (-1); 07890 /* 07891 * Get in-scope ns-decls of @parent. 07892 */ 07893 cur = node; 07894 while ((cur != NULL) && (cur != (xmlNodePtr) cur->doc)) { 07895 if (cur->type == XML_ELEMENT_NODE) { 07896 if (cur->nsDef != NULL) { 07897 ns = cur->nsDef; 07898 do { 07899 shadowed = 0; 07900 if (XML_NSMAP_NOTEMPTY(*map)) { 07901 /* 07902 * Skip shadowed prefixes. 07903 */ 07904 XML_NSMAP_FOREACH(*map, mi) { 07905 if ((ns->prefix == mi->newNs->prefix) || 07906 xmlStrEqual(ns->prefix, mi->newNs->prefix)) { 07907 shadowed = 1; 07908 break; 07909 } 07910 } 07911 } 07912 /* 07913 * Insert mapping. 07914 */ 07915 mi = xmlDOMWrapNsMapAddItem(map, 0, NULL, 07916 ns, XML_TREE_NSMAP_PARENT); 07917 if (mi == NULL) 07918 return (-1); 07919 if (shadowed) 07920 mi->shadowDepth = 0; 07921 ns = ns->next; 07922 } while (ns != NULL); 07923 } 07924 } 07925 cur = cur->parent; 07926 } 07927 return (0); 07928 } 07929 07930 /* 07931 * XML_TREE_ADOPT_STR: If we have a dest-dict, put @str in the dict; 07932 * otherwise copy it, when it was in the source-dict. 07933 */ 07934 #define XML_TREE_ADOPT_STR(str) \ 07935 if (adoptStr && (str != NULL)) { \ 07936 if (destDoc->dict) { \ 07937 const xmlChar *old = str; \ 07938 str = xmlDictLookup(destDoc->dict, str, -1); \ 07939 if ((sourceDoc == NULL) || (sourceDoc->dict == NULL) || \ 07940 (!xmlDictOwns(sourceDoc->dict, old))) \ 07941 xmlFree((char *)old); \ 07942 } else if ((sourceDoc) && (sourceDoc->dict) && \ 07943 xmlDictOwns(sourceDoc->dict, str)) { \ 07944 str = BAD_CAST xmlStrdup(str); \ 07945 } \ 07946 } 07947 07948 /* 07949 * XML_TREE_ADOPT_STR_2: If @str was in the source-dict, then 07950 * put it in dest-dict or copy it. 07951 */ 07952 #define XML_TREE_ADOPT_STR_2(str) \ 07953 if (adoptStr && (str != NULL) && (sourceDoc != NULL) && \ 07954 (sourceDoc->dict != NULL) && \ 07955 xmlDictOwns(sourceDoc->dict, cur->content)) { \ 07956 if (destDoc->dict) \ 07957 cur->content = (xmlChar *) \ 07958 xmlDictLookup(destDoc->dict, cur->content, -1); \ 07959 else \ 07960 cur->content = xmlStrdup(BAD_CAST cur->content); \ 07961 } 07962 07963 /* 07964 * xmlDOMWrapNSNormAddNsMapItem2: 07965 * 07966 * For internal use. Adds a ns-decl mapping. 07967 * 07968 * Returns 0 on success, -1 on internal errors. 07969 */ 07970 static int 07971 xmlDOMWrapNSNormAddNsMapItem2(xmlNsPtr **list, int *size, int *number, 07972 xmlNsPtr oldNs, xmlNsPtr newNs) 07973 { 07974 if (*list == NULL) { 07975 *list = (xmlNsPtr *) xmlMalloc(6 * sizeof(xmlNsPtr)); 07976 if (*list == NULL) { 07977 xmlTreeErrMemory("alloc ns map item"); 07978 return(-1); 07979 } 07980 *size = 3; 07981 *number = 0; 07982 } else if ((*number) >= (*size)) { 07983 *size *= 2; 07984 *list = (xmlNsPtr *) xmlRealloc(*list, 07985 (*size) * 2 * sizeof(xmlNsPtr)); 07986 if (*list == NULL) { 07987 xmlTreeErrMemory("realloc ns map item"); 07988 return(-1); 07989 } 07990 } 07991 (*list)[2 * (*number)] = oldNs; 07992 (*list)[2 * (*number) +1] = newNs; 07993 (*number)++; 07994 return (0); 07995 } 07996 07997 /* 07998 * xmlDOMWrapRemoveNode: 07999 * @ctxt: a DOM wrapper context 08000 * @doc: the doc 08001 * @node: the node to be removed. 08002 * @options: set of options, unused at the moment 08003 * 08004 * Unlinks the given node from its owner. 08005 * This will substitute ns-references to node->nsDef for 08006 * ns-references to doc->oldNs, thus ensuring the removed 08007 * branch to be autark wrt ns-references. 08008 * 08009 * NOTE: This function was not intensively tested. 08010 * 08011 * Returns 0 on success, 1 if the node is not supported, 08012 * -1 on API and internal errors. 08013 */ 08014 int 08015 xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc, 08016 xmlNodePtr node, int options ATTRIBUTE_UNUSED) 08017 { 08018 xmlNsPtr *list = NULL; 08019 int sizeList, nbList, i, j; 08020 xmlNsPtr ns; 08021 08022 if ((node == NULL) || (doc == NULL) || (node->doc != doc)) 08023 return (-1); 08024 08025 /* TODO: 0 or -1 ? */ 08026 if (node->parent == NULL) 08027 return (0); 08028 08029 switch (node->type) { 08030 case XML_TEXT_NODE: 08031 case XML_CDATA_SECTION_NODE: 08032 case XML_ENTITY_REF_NODE: 08033 case XML_PI_NODE: 08034 case XML_COMMENT_NODE: 08035 xmlUnlinkNode(node); 08036 return (0); 08037 case XML_ELEMENT_NODE: 08038 case XML_ATTRIBUTE_NODE: 08039 break; 08040 default: 08041 return (1); 08042 } 08043 xmlUnlinkNode(node); 08044 /* 08045 * Save out-of-scope ns-references in doc->oldNs. 08046 */ 08047 do { 08048 switch (node->type) { 08049 case XML_ELEMENT_NODE: 08050 if ((ctxt == NULL) && (node->nsDef != NULL)) { 08051 ns = node->nsDef; 08052 do { 08053 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList, 08054 &nbList, ns, ns) == -1) 08055 goto internal_error; 08056 ns = ns->next; 08057 } while (ns != NULL); 08058 } 08059 /* No break on purpose. */ 08060 case XML_ATTRIBUTE_NODE: 08061 if (node->ns != NULL) { 08062 /* 08063 * Find a mapping. 08064 */ 08065 if (list != NULL) { 08066 for (i = 0, j = 0; i < nbList; i++, j += 2) { 08067 if (node->ns == list[j]) { 08068 node->ns = list[++j]; 08069 goto next_node; 08070 } 08071 } 08072 } 08073 ns = NULL; 08074 if (ctxt != NULL) { 08075 /* 08076 * User defined. 08077 */ 08078 } else { 08079 /* 08080 * Add to doc's oldNs. 08081 */ 08082 ns = xmlDOMWrapStoreNs(doc, node->ns->href, 08083 node->ns->prefix); 08084 if (ns == NULL) 08085 goto internal_error; 08086 } 08087 if (ns != NULL) { 08088 /* 08089 * Add mapping. 08090 */ 08091 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList, 08092 &nbList, node->ns, ns) == -1) 08093 goto internal_error; 08094 } 08095 node->ns = ns; 08096 } 08097 if ((node->type == XML_ELEMENT_NODE) && 08098 (node->properties != NULL)) { 08099 node = (xmlNodePtr) node->properties; 08100 continue; 08101 } 08102 break; 08103 default: 08104 goto next_sibling; 08105 } 08106 next_node: 08107 if ((node->type == XML_ELEMENT_NODE) && 08108 (node->children != NULL)) { 08109 node = node->children; 08110 continue; 08111 } 08112 next_sibling: 08113 if (node == NULL) 08114 break; 08115 if (node->next != NULL) 08116 node = node->next; 08117 else { 08118 node = node->parent; 08119 goto next_sibling; 08120 } 08121 } while (node != NULL); 08122 08123 if (list != NULL) 08124 xmlFree(list); 08125 return (0); 08126 08127 internal_error: 08128 if (list != NULL) 08129 xmlFree(list); 08130 return (-1); 08131 } 08132 08133 /* 08134 * xmlSearchNsByNamespaceStrict: 08135 * @doc: the document 08136 * @node: the start node 08137 * @nsName: the searched namespace name 08138 * @retNs: the resulting ns-decl 08139 * @prefixed: if the found ns-decl must have a prefix (for attributes) 08140 * 08141 * Dynamically searches for a ns-declaration which matches 08142 * the given @nsName in the ancestor-or-self axis of @node. 08143 * 08144 * Returns 1 if a ns-decl was found, 0 if not and -1 on API 08145 * and internal errors. 08146 */ 08147 static int 08148 xmlSearchNsByNamespaceStrict(xmlDocPtr doc, xmlNodePtr node, 08149 const xmlChar* nsName, 08150 xmlNsPtr *retNs, int prefixed) 08151 { 08152 xmlNodePtr cur, prev = NULL, out = NULL; 08153 xmlNsPtr ns, prevns; 08154 08155 if ((doc == NULL) || (nsName == NULL) || (retNs == NULL)) 08156 return (-1); 08157 08158 *retNs = NULL; 08159 if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) { 08160 *retNs = xmlTreeEnsureXMLDecl(doc); 08161 if (*retNs == NULL) 08162 return (-1); 08163 return (1); 08164 } 08165 cur = node; 08166 do { 08167 if (cur->type == XML_ELEMENT_NODE) { 08168 if (cur->nsDef != NULL) { 08169 for (ns = cur->nsDef; ns != NULL; ns = ns->next) { 08170 if (prefixed && (ns->prefix == NULL)) 08171 continue; 08172 if (prev != NULL) { 08173 /* 08174 * Check the last level of ns-decls for a 08175 * shadowing prefix. 08176 */ 08177 prevns = prev->nsDef; 08178 do { 08179 if ((prevns->prefix == ns->prefix) || 08180 ((prevns->prefix != NULL) && 08181 (ns->prefix != NULL) && 08182 xmlStrEqual(prevns->prefix, ns->prefix))) { 08183 /* 08184 * Shadowed. 08185 */ 08186 break; 08187 } 08188 prevns = prevns->next; 08189 } while (prevns != NULL); 08190 if (prevns != NULL) 08191 continue; 08192 } 08193 /* 08194 * Ns-name comparison. 08195 */ 08196 if ((nsName == ns->href) || 08197 xmlStrEqual(nsName, ns->href)) { 08198 /* 08199 * At this point the prefix can only be shadowed, 08200 * if we are the the (at least) 3rd level of 08201 * ns-decls. 08202 */ 08203 if (out) { 08204 int ret; 08205 08206 ret = xmlNsInScope(doc, node, prev, ns->prefix); 08207 if (ret < 0) 08208 return (-1); 08209 /* 08210 * TODO: Should we try to find a matching ns-name 08211 * only once? This here keeps on searching. 08212 * I think we should try further since, there might 08213 * be an other matching ns-decl with an unshadowed 08214 * prefix. 08215 */ 08216 if (! ret) 08217 continue; 08218 } 08219 *retNs = ns; 08220 return (1); 08221 } 08222 } 08223 out = prev; 08224 prev = cur; 08225 } 08226 } else if ((cur->type == XML_ENTITY_NODE) || 08227 (cur->type == XML_ENTITY_DECL)) 08228 return (0); 08229 cur = cur->parent; 08230 } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur)); 08231 return (0); 08232 } 08233 08234 /* 08235 * xmlSearchNsByPrefixStrict: 08236 * @doc: the document 08237 * @node: the start node 08238 * @prefix: the searched namespace prefix 08239 * @retNs: the resulting ns-decl 08240 * 08241 * Dynamically searches for a ns-declaration which matches 08242 * the given @nsName in the ancestor-or-self axis of @node. 08243 * 08244 * Returns 1 if a ns-decl was found, 0 if not and -1 on API 08245 * and internal errors. 08246 */ 08247 static int 08248 xmlSearchNsByPrefixStrict(xmlDocPtr doc, xmlNodePtr node, 08249 const xmlChar* prefix, 08250 xmlNsPtr *retNs) 08251 { 08252 xmlNodePtr cur; 08253 xmlNsPtr ns; 08254 08255 if ((doc == NULL) || (node == NULL)) 08256 return (-1); 08257 08258 if (retNs) 08259 *retNs = NULL; 08260 if (IS_STR_XML(prefix)) { 08261 if (retNs) { 08262 *retNs = xmlTreeEnsureXMLDecl(doc); 08263 if (*retNs == NULL) 08264 return (-1); 08265 } 08266 return (1); 08267 } 08268 cur = node; 08269 do { 08270 if (cur->type == XML_ELEMENT_NODE) { 08271 if (cur->nsDef != NULL) { 08272 ns = cur->nsDef; 08273 do { 08274 if ((prefix == ns->prefix) || 08275 xmlStrEqual(prefix, ns->prefix)) 08276 { 08277 /* 08278 * Disabled namespaces, e.g. xmlns:abc="". 08279 */ 08280 if (ns->href == NULL) 08281 return(0); 08282 if (retNs) 08283 *retNs = ns; 08284 return (1); 08285 } 08286 ns = ns->next; 08287 } while (ns != NULL); 08288 } 08289 } else if ((cur->type == XML_ENTITY_NODE) || 08290 (cur->type == XML_ENTITY_DECL)) 08291 return (0); 08292 cur = cur->parent; 08293 } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur)); 08294 return (0); 08295 } 08296 08297 /* 08298 * xmlDOMWrapNSNormDeclareNsForced: 08299 * @doc: the doc 08300 * @elem: the element-node to declare on 08301 * @nsName: the namespace-name of the ns-decl 08302 * @prefix: the preferred prefix of the ns-decl 08303 * @checkShadow: ensure that the new ns-decl doesn't shadow ancestor ns-decls 08304 * 08305 * Declares a new namespace on @elem. It tries to use the 08306 * given @prefix; if a ns-decl with the given prefix is already existent 08307 * on @elem, it will generate an other prefix. 08308 * 08309 * Returns 1 if a ns-decl was found, 0 if not and -1 on API 08310 * and internal errors. 08311 */ 08312 static xmlNsPtr 08313 xmlDOMWrapNSNormDeclareNsForced(xmlDocPtr doc, 08314 xmlNodePtr elem, 08315 const xmlChar *nsName, 08316 const xmlChar *prefix, 08317 int checkShadow) 08318 { 08319 08320 xmlNsPtr ret; 08321 char buf[50]; 08322 const xmlChar *pref; 08323 int counter = 0; 08324 /* 08325 * Create a ns-decl on @anchor. 08326 */ 08327 pref = prefix; 08328 while (1) { 08329 /* 08330 * Lookup whether the prefix is unused in elem's ns-decls. 08331 */ 08332 if ((elem->nsDef != NULL) && 08333 (xmlTreeNSListLookupByPrefix(elem->nsDef, pref) != NULL)) 08334 goto ns_next_prefix; 08335 if (checkShadow && elem->parent && 08336 ((xmlNodePtr) elem->parent->doc != elem->parent)) { 08337 /* 08338 * Does it shadow ancestor ns-decls? 08339 */ 08340 if (xmlSearchNsByPrefixStrict(doc, elem->parent, pref, NULL) == 1) 08341 goto ns_next_prefix; 08342 } 08343 ret = xmlNewNs(NULL, nsName, pref); 08344 if (ret == NULL) 08345 return (NULL); 08346 if (elem->nsDef == NULL) 08347 elem->nsDef = ret; 08348 else { 08349 xmlNsPtr ns2 = elem->nsDef; 08350 while (ns2->next != NULL) 08351 ns2 = ns2->next; 08352 ns2->next = ret; 08353 } 08354 return (ret); 08355 ns_next_prefix: 08356 counter++; 08357 if (counter > 1000) 08358 return (NULL); 08359 if (prefix == NULL) { 08360 snprintf((char *) buf, sizeof(buf), 08361 "ns_%d", counter); 08362 } else 08363 snprintf((char *) buf, sizeof(buf), 08364 "%.30s_%d", (char *)prefix, counter); 08365 pref = BAD_CAST buf; 08366 } 08367 } 08368 08369 /* 08370 * xmlDOMWrapNSNormAquireNormalizedNs: 08371 * @doc: the doc 08372 * @elem: the element-node to declare namespaces on 08373 * @ns: the ns-struct to use for the search 08374 * @retNs: the found/created ns-struct 08375 * @nsMap: the ns-map 08376 * @depth: the current tree depth 08377 * @ancestorsOnly: search in ancestor ns-decls only 08378 * @prefixed: if the searched ns-decl must have a prefix (for attributes) 08379 * 08380 * Searches for a matching ns-name in the ns-decls of @nsMap, if not 08381 * found it will either declare it on @elem, or store it in doc->oldNs. 08382 * If a new ns-decl needs to be declared on @elem, it tries to use the 08383 * @ns->prefix for it, if this prefix is already in use on @elem, it will 08384 * change the prefix or the new ns-decl. 08385 * 08386 * Returns 0 if succeeded, -1 otherwise and on API/internal errors. 08387 */ 08388 static int 08389 xmlDOMWrapNSNormAquireNormalizedNs(xmlDocPtr doc, 08390 xmlNodePtr elem, 08391 xmlNsPtr ns, 08392 xmlNsPtr *retNs, 08393 xmlNsMapPtr *nsMap, 08394 08395 int depth, 08396 int ancestorsOnly, 08397 int prefixed) 08398 { 08399 xmlNsMapItemPtr mi; 08400 08401 if ((doc == NULL) || (ns == NULL) || (retNs == NULL) || 08402 (nsMap == NULL)) 08403 return (-1); 08404 08405 *retNs = NULL; 08406 /* 08407 * Handle XML namespace. 08408 */ 08409 if (IS_STR_XML(ns->prefix)) { 08410 /* 08411 * Insert XML namespace mapping. 08412 */ 08413 *retNs = xmlTreeEnsureXMLDecl(doc); 08414 if (*retNs == NULL) 08415 return (-1); 08416 return (0); 08417 } 08418 /* 08419 * If the search should be done in ancestors only and no 08420 * @elem (the first ancestor) was specified, then skip the search. 08421 */ 08422 if ((XML_NSMAP_NOTEMPTY(*nsMap)) && 08423 (! (ancestorsOnly && (elem == NULL)))) 08424 { 08425 /* 08426 * Try to find an equal ns-name in in-scope ns-decls. 08427 */ 08428 XML_NSMAP_FOREACH(*nsMap, mi) { 08429 if ((mi->depth >= XML_TREE_NSMAP_PARENT) && 08430 /* 08431 * ancestorsOnly: This should be turned on to gain speed, 08432 * if one knows that the branch itself was already 08433 * ns-wellformed and no stale references existed. 08434 * I.e. it searches in the ancestor axis only. 08435 */ 08436 ((! ancestorsOnly) || (mi->depth == XML_TREE_NSMAP_PARENT)) && 08437 /* Skip shadowed prefixes. */ 08438 (mi->shadowDepth == -1) && 08439 /* Skip xmlns="" or xmlns:foo="". */ 08440 ((mi->newNs->href != NULL) && 08441 (mi->newNs->href[0] != 0)) && 08442 /* Ensure a prefix if wanted. */ 08443 ((! prefixed) || (mi->newNs->prefix != NULL)) && 08444 /* Equal ns name */ 08445 ((mi->newNs->href == ns->href) || 08446 xmlStrEqual(mi->newNs->href, ns->href))) { 08447 /* Set the mapping. */ 08448 mi->oldNs = ns; 08449 *retNs = mi->newNs; 08450 return (0); 08451 } 08452 } 08453 } 08454 /* 08455 * No luck, the namespace is out of scope or shadowed. 08456 */ 08457 if (elem == NULL) { 08458 xmlNsPtr tmpns; 08459 08460 /* 08461 * Store ns-decls in "oldNs" of the document-node. 08462 */ 08463 tmpns = xmlDOMWrapStoreNs(doc, ns->href, ns->prefix); 08464 if (tmpns == NULL) 08465 return (-1); 08466 /* 08467 * Insert mapping. 08468 */ 08469 if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns, 08470 tmpns, XML_TREE_NSMAP_DOC) == NULL) { 08471 xmlFreeNs(tmpns); 08472 return (-1); 08473 } 08474 *retNs = tmpns; 08475 } else { 08476 xmlNsPtr tmpns; 08477 08478 tmpns = xmlDOMWrapNSNormDeclareNsForced(doc, elem, ns->href, 08479 ns->prefix, 0); 08480 if (tmpns == NULL) 08481 return (-1); 08482 08483 if (*nsMap != NULL) { 08484 /* 08485 * Does it shadow ancestor ns-decls? 08486 */ 08487 XML_NSMAP_FOREACH(*nsMap, mi) { 08488 if ((mi->depth < depth) && 08489 (mi->shadowDepth == -1) && 08490 ((ns->prefix == mi->newNs->prefix) || 08491 xmlStrEqual(ns->prefix, mi->newNs->prefix))) { 08492 /* 08493 * Shadows. 08494 */ 08495 mi->shadowDepth = depth; 08496 break; 08497 } 08498 } 08499 } 08500 if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns, tmpns, depth) == NULL) { 08501 xmlFreeNs(tmpns); 08502 return (-1); 08503 } 08504 *retNs = tmpns; 08505 } 08506 return (0); 08507 } 08508 08509 typedef enum { 08510 XML_DOM_RECONNS_REMOVEREDUND = 1<<0 08511 } xmlDOMReconcileNSOptions; 08512 08513 /* 08514 * xmlDOMWrapReconcileNamespaces: 08515 * @ctxt: DOM wrapper context, unused at the moment 08516 * @elem: the element-node 08517 * @options: option flags 08518 * 08519 * Ensures that ns-references point to ns-decls hold on element-nodes. 08520 * Ensures that the tree is namespace wellformed by creating additional 08521 * ns-decls where needed. Note that, since prefixes of already existent 08522 * ns-decls can be shadowed by this process, it could break QNames in 08523 * attribute values or element content. 08524 * 08525 * NOTE: This function was not intensively tested. 08526 * 08527 * Returns 0 if succeeded, -1 otherwise and on API/internal errors. 08528 */ 08529 08530 int 08531 xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED, 08532 xmlNodePtr elem, 08533 int options) 08534 { 08535 int depth = -1, adoptns = 0, parnsdone = 0; 08536 xmlNsPtr ns, prevns; 08537 xmlDocPtr doc; 08538 xmlNodePtr cur, curElem = NULL; 08539 xmlNsMapPtr nsMap = NULL; 08540 xmlNsMapItemPtr /* topmi = NULL, */ mi; 08541 /* @ancestorsOnly should be set by an option flag. */ 08542 int ancestorsOnly = 0; 08543 int optRemoveRedundantNS = 08544 ((xmlDOMReconcileNSOptions) options & XML_DOM_RECONNS_REMOVEREDUND) ? 1 : 0; 08545 xmlNsPtr *listRedund = NULL; 08546 int sizeRedund = 0, nbRedund = 0, ret, i, j; 08547 08548 if ((elem == NULL) || (elem->doc == NULL) || 08549 (elem->type != XML_ELEMENT_NODE)) 08550 return (-1); 08551 08552 doc = elem->doc; 08553 cur = elem; 08554 do { 08555 switch (cur->type) { 08556 case XML_ELEMENT_NODE: 08557 adoptns = 1; 08558 curElem = cur; 08559 depth++; 08560 /* 08561 * Namespace declarations. 08562 */ 08563 if (cur->nsDef != NULL) { 08564 prevns = NULL; 08565 ns = cur->nsDef; 08566 while (ns != NULL) { 08567 if (! parnsdone) { 08568 if ((elem->parent) && 08569 ((xmlNodePtr) elem->parent->doc != elem->parent)) { 08570 /* 08571 * Gather ancestor in-scope ns-decls. 08572 */ 08573 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, 08574 elem->parent) == -1) 08575 goto internal_error; 08576 } 08577 parnsdone = 1; 08578 } 08579 08580 /* 08581 * Lookup the ns ancestor-axis for equal ns-decls in scope. 08582 */ 08583 if (optRemoveRedundantNS && XML_NSMAP_NOTEMPTY(nsMap)) { 08584 XML_NSMAP_FOREACH(nsMap, mi) { 08585 if ((mi->depth >= XML_TREE_NSMAP_PARENT) && 08586 (mi->shadowDepth == -1) && 08587 ((ns->prefix == mi->newNs->prefix) || 08588 xmlStrEqual(ns->prefix, mi->newNs->prefix)) && 08589 ((ns->href == mi->newNs->href) || 08590 xmlStrEqual(ns->href, mi->newNs->href))) 08591 { 08592 /* 08593 * A redundant ns-decl was found. 08594 * Add it to the list of redundant ns-decls. 08595 */ 08596 if (xmlDOMWrapNSNormAddNsMapItem2(&listRedund, 08597 &sizeRedund, &nbRedund, ns, mi->newNs) == -1) 08598 goto internal_error; 08599 /* 08600 * Remove the ns-decl from the element-node. 08601 */ 08602 if (prevns) 08603 prevns->next = ns->next; 08604 else 08605 cur->nsDef = ns->next; 08606 goto next_ns_decl; 08607 } 08608 } 08609 } 08610 08611 /* 08612 * Skip ns-references handling if the referenced 08613 * ns-decl is declared on the same element. 08614 */ 08615 if ((cur->ns != NULL) && adoptns && (cur->ns == ns)) 08616 adoptns = 0; 08617 /* 08618 * Does it shadow any ns-decl? 08619 */ 08620 if (XML_NSMAP_NOTEMPTY(nsMap)) { 08621 XML_NSMAP_FOREACH(nsMap, mi) { 08622 if ((mi->depth >= XML_TREE_NSMAP_PARENT) && 08623 (mi->shadowDepth == -1) && 08624 ((ns->prefix == mi->newNs->prefix) || 08625 xmlStrEqual(ns->prefix, mi->newNs->prefix))) { 08626 08627 mi->shadowDepth = depth; 08628 } 08629 } 08630 } 08631 /* 08632 * Push mapping. 08633 */ 08634 if (xmlDOMWrapNsMapAddItem(&nsMap, -1, ns, ns, 08635 depth) == NULL) 08636 goto internal_error; 08637 08638 prevns = ns; 08639 next_ns_decl: 08640 ns = ns->next; 08641 } 08642 } 08643 if (! adoptns) 08644 goto ns_end; 08645 /* No break on purpose. */ 08646 case XML_ATTRIBUTE_NODE: 08647 /* No ns, no fun. */ 08648 if (cur->ns == NULL) 08649 goto ns_end; 08650 08651 if (! parnsdone) { 08652 if ((elem->parent) && 08653 ((xmlNodePtr) elem->parent->doc != elem->parent)) { 08654 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, 08655 elem->parent) == -1) 08656 goto internal_error; 08657 } 08658 parnsdone = 1; 08659 } 08660 /* 08661 * Adjust the reference if this was a redundant ns-decl. 08662 */ 08663 if (listRedund) { 08664 for (i = 0, j = 0; i < nbRedund; i++, j += 2) { 08665 if (cur->ns == listRedund[j]) { 08666 cur->ns = listRedund[++j]; 08667 break; 08668 } 08669 } 08670 } 08671 /* 08672 * Adopt ns-references. 08673 */ 08674 if (XML_NSMAP_NOTEMPTY(nsMap)) { 08675 /* 08676 * Search for a mapping. 08677 */ 08678 XML_NSMAP_FOREACH(nsMap, mi) { 08679 if ((mi->shadowDepth == -1) && 08680 (cur->ns == mi->oldNs)) { 08681 08682 cur->ns = mi->newNs; 08683 goto ns_end; 08684 } 08685 } 08686 } 08687 /* 08688 * Aquire a normalized ns-decl and add it to the map. 08689 */ 08690 if (xmlDOMWrapNSNormAquireNormalizedNs(doc, curElem, 08691 cur->ns, &ns, 08692 &nsMap, depth, 08693 ancestorsOnly, 08694 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1) 08695 goto internal_error; 08696 cur->ns = ns; 08697 08698 ns_end: 08699 if ((cur->type == XML_ELEMENT_NODE) && 08700 (cur->properties != NULL)) { 08701 /* 08702 * Process attributes. 08703 */ 08704 cur = (xmlNodePtr) cur->properties; 08705 continue; 08706 } 08707 break; 08708 default: 08709 goto next_sibling; 08710 } 08711 into_content: 08712 if ((cur->type == XML_ELEMENT_NODE) && 08713 (cur->children != NULL)) { 08714 /* 08715 * Process content of element-nodes only. 08716 */ 08717 cur = cur->children; 08718 continue; 08719 } 08720 next_sibling: 08721 if (cur == elem) 08722 break; 08723 if (cur->type == XML_ELEMENT_NODE) { 08724 if (XML_NSMAP_NOTEMPTY(nsMap)) { 08725 /* 08726 * Pop mappings. 08727 */ 08728 while ((nsMap->last != NULL) && 08729 (nsMap->last->depth >= depth)) 08730 { 08731 XML_NSMAP_POP(nsMap, mi) 08732 } 08733 /* 08734 * Unshadow. 08735 */ 08736 XML_NSMAP_FOREACH(nsMap, mi) { 08737 if (mi->shadowDepth >= depth) 08738 mi->shadowDepth = -1; 08739 } 08740 } 08741 depth--; 08742 } 08743 if (cur->next != NULL) 08744 cur = cur->next; 08745 else { 08746 if (cur->type == XML_ATTRIBUTE_NODE) { 08747 cur = cur->parent; 08748 goto into_content; 08749 } 08750 cur = cur->parent; 08751 goto next_sibling; 08752 } 08753 } while (cur != NULL); 08754 08755 ret = 0; 08756 goto exit; 08757 internal_error: 08758 ret = -1; 08759 exit: 08760 if (listRedund) { 08761 for (i = 0, j = 0; i < nbRedund; i++, j += 2) { 08762 xmlFreeNs(listRedund[j]); 08763 } 08764 xmlFree(listRedund); 08765 } 08766 if (nsMap != NULL) 08767 xmlDOMWrapNsMapFree(nsMap); 08768 return (ret); 08769 } 08770 08771 /* 08772 * xmlDOMWrapAdoptBranch: 08773 * @ctxt: the optional context for custom processing 08774 * @sourceDoc: the optional sourceDoc 08775 * @node: the element-node to start with 08776 * @destDoc: the destination doc for adoption 08777 * @destParent: the optional new parent of @node in @destDoc 08778 * @options: option flags 08779 * 08780 * Ensures that ns-references point to @destDoc: either to 08781 * elements->nsDef entries if @destParent is given, or to 08782 * @destDoc->oldNs otherwise. 08783 * If @destParent is given, it ensures that the tree is namespace 08784 * wellformed by creating additional ns-decls where needed. 08785 * Note that, since prefixes of already existent ns-decls can be 08786 * shadowed by this process, it could break QNames in attribute 08787 * values or element content. 08788 * 08789 * NOTE: This function was not intensively tested. 08790 * 08791 * Returns 0 if succeeded, -1 otherwise and on API/internal errors. 08792 */ 08793 static int 08794 xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt, 08795 xmlDocPtr sourceDoc, 08796 xmlNodePtr node, 08797 xmlDocPtr destDoc, 08798 xmlNodePtr destParent, 08799 int options ATTRIBUTE_UNUSED) 08800 { 08801 int ret = 0; 08802 xmlNodePtr cur, curElem = NULL; 08803 xmlNsMapPtr nsMap = NULL; 08804 xmlNsMapItemPtr mi; 08805 xmlNsPtr ns = NULL; 08806 int depth = -1, adoptStr = 1; 08807 /* gather @parent's ns-decls. */ 08808 int parnsdone; 08809 /* @ancestorsOnly should be set per option. */ 08810 int ancestorsOnly = 0; 08811 08812 /* 08813 * Optimize string adoption for equal or none dicts. 08814 */ 08815 if ((sourceDoc != NULL) && 08816 (sourceDoc->dict == destDoc->dict)) 08817 adoptStr = 0; 08818 else 08819 adoptStr = 1; 08820 08821 /* 08822 * Get the ns-map from the context if available. 08823 */ 08824 if (ctxt) 08825 nsMap = (xmlNsMapPtr) ctxt->namespaceMap; 08826 /* 08827 * Disable search for ns-decls in the parent-axis of the 08828 * desination element, if: 08829 * 1) there's no destination parent 08830 * 2) custom ns-reference handling is used 08831 */ 08832 if ((destParent == NULL) || 08833 (ctxt && ctxt->getNsForNodeFunc)) 08834 { 08835 parnsdone = 1; 08836 } else 08837 parnsdone = 0; 08838 08839 cur = node; 08840 while (cur != NULL) { 08841 /* 08842 * Paranoid source-doc sanity check. 08843 */ 08844 if (cur->doc != sourceDoc) { 08845 /* 08846 * We'll assume XIncluded nodes if the doc differs. 08847 * TODO: Do we need to reconciliate XIncluded nodes? 08848 * This here skips XIncluded nodes and tries to handle 08849 * broken sequences. 08850 */ 08851 if (cur->next == NULL) 08852 goto leave_node; 08853 do { 08854 cur = cur->next; 08855 if ((cur->type == XML_XINCLUDE_END) || 08856 (cur->doc == node->doc)) 08857 break; 08858 } while (cur->next != NULL); 08859 08860 if (cur->doc != node->doc) 08861 goto leave_node; 08862 } 08863 cur->doc = destDoc; 08864 switch (cur->type) { 08865 case XML_XINCLUDE_START: 08866 case XML_XINCLUDE_END: 08867 /* 08868 * TODO 08869 */ 08870 return (-1); 08871 case XML_ELEMENT_NODE: 08872 curElem = cur; 08873 depth++; 08874 /* 08875 * Namespace declarations. 08876 * - ns->href and ns->prefix are never in the dict, so 08877 * we need not move the values over to the destination dict. 08878 * - Note that for custom handling of ns-references, 08879 * the ns-decls need not be stored in the ns-map, 08880 * since they won't be referenced by node->ns. 08881 */ 08882 if ((cur->nsDef) && 08883 ((ctxt == NULL) || (ctxt->getNsForNodeFunc == NULL))) 08884 { 08885 if (! parnsdone) { 08886 /* 08887 * Gather @parent's in-scope ns-decls. 08888 */ 08889 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, 08890 destParent) == -1) 08891 goto internal_error; 08892 parnsdone = 1; 08893 } 08894 for (ns = cur->nsDef; ns != NULL; ns = ns->next) { 08895 /* 08896 * NOTE: ns->prefix and ns->href are never in the dict. 08897 * XML_TREE_ADOPT_STR(ns->prefix) 08898 * XML_TREE_ADOPT_STR(ns->href) 08899 */ 08900 /* 08901 * Does it shadow any ns-decl? 08902 */ 08903 if (XML_NSMAP_NOTEMPTY(nsMap)) { 08904 XML_NSMAP_FOREACH(nsMap, mi) { 08905 if ((mi->depth >= XML_TREE_NSMAP_PARENT) && 08906 (mi->shadowDepth == -1) && 08907 ((ns->prefix == mi->newNs->prefix) || 08908 xmlStrEqual(ns->prefix, 08909 mi->newNs->prefix))) { 08910 08911 mi->shadowDepth = depth; 08912 } 08913 } 08914 } 08915 /* 08916 * Push mapping. 08917 */ 08918 if (xmlDOMWrapNsMapAddItem(&nsMap, -1, 08919 ns, ns, depth) == NULL) 08920 goto internal_error; 08921 } 08922 } 08923 /* No break on purpose. */ 08924 case XML_ATTRIBUTE_NODE: 08925 /* No namespace, no fun. */ 08926 if (cur->ns == NULL) 08927 goto ns_end; 08928 08929 if (! parnsdone) { 08930 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, 08931 destParent) == -1) 08932 goto internal_error; 08933 parnsdone = 1; 08934 } 08935 /* 08936 * Adopt ns-references. 08937 */ 08938 if (XML_NSMAP_NOTEMPTY(nsMap)) { 08939 /* 08940 * Search for a mapping. 08941 */ 08942 XML_NSMAP_FOREACH(nsMap, mi) { 08943 if ((mi->shadowDepth == -1) && 08944 (cur->ns == mi->oldNs)) { 08945 08946 cur->ns = mi->newNs; 08947 goto ns_end; 08948 } 08949 } 08950 } 08951 /* 08952 * No matching namespace in scope. We need a new one. 08953 */ 08954 if ((ctxt) && (ctxt->getNsForNodeFunc)) { 08955 /* 08956 * User-defined behaviour. 08957 */ 08958 ns = ctxt->getNsForNodeFunc(ctxt, cur, 08959 cur->ns->href, cur->ns->prefix); 08960 /* 08961 * Insert mapping if ns is available; it's the users fault 08962 * if not. 08963 */ 08964 if (xmlDOMWrapNsMapAddItem(&nsMap, -1, 08965 cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL) 08966 goto internal_error; 08967 cur->ns = ns; 08968 } else { 08969 /* 08970 * Aquire a normalized ns-decl and add it to the map. 08971 */ 08972 if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc, 08973 /* ns-decls on curElem or on destDoc->oldNs */ 08974 destParent ? curElem : NULL, 08975 cur->ns, &ns, 08976 &nsMap, depth, 08977 ancestorsOnly, 08978 /* ns-decls must be prefixed for attributes. */ 08979 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1) 08980 goto internal_error; 08981 cur->ns = ns; 08982 } 08983 ns_end: 08984 /* 08985 * Further node properties. 08986 * TODO: Is this all? 08987 */ 08988 XML_TREE_ADOPT_STR(cur->name) 08989 if (cur->type == XML_ELEMENT_NODE) { 08990 cur->psvi = NULL; 08991 cur->line = 0; 08992 cur->extra = 0; 08993 /* 08994 * Walk attributes. 08995 */ 08996 if (cur->properties != NULL) { 08997 /* 08998 * Process first attribute node. 08999 */ 09000 cur = (xmlNodePtr) cur->properties; 09001 continue; 09002 } 09003 } else { 09004 /* 09005 * Attributes. 09006 */ 09007 if ((sourceDoc != NULL) && 09008 (((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID)) 09009 { 09010 xmlRemoveID(sourceDoc, (xmlAttrPtr) cur); 09011 } 09012 ((xmlAttrPtr) cur)->atype = 0; 09013 ((xmlAttrPtr) cur)->psvi = NULL; 09014 } 09015 break; 09016 case XML_TEXT_NODE: 09017 case XML_CDATA_SECTION_NODE: 09018 /* 09019 * This puts the content in the dest dict, only if 09020 * it was previously in the source dict. 09021 */ 09022 XML_TREE_ADOPT_STR_2(cur->content) 09023 goto leave_node; 09024 case XML_ENTITY_REF_NODE: 09025 /* 09026 * Remove reference to the entitity-node. 09027 */ 09028 cur->content = NULL; 09029 cur->children = NULL; 09030 cur->last = NULL; 09031 if ((destDoc->intSubset) || (destDoc->extSubset)) { 09032 xmlEntityPtr ent; 09033 /* 09034 * Assign new entity-node if available. 09035 */ 09036 ent = xmlGetDocEntity(destDoc, cur->name); 09037 if (ent != NULL) { 09038 cur->content = ent->content; 09039 cur->children = (xmlNodePtr) ent; 09040 cur->last = (xmlNodePtr) ent; 09041 } 09042 } 09043 goto leave_node; 09044 case XML_PI_NODE: 09045 XML_TREE_ADOPT_STR(cur->name) 09046 XML_TREE_ADOPT_STR_2(cur->content) 09047 break; 09048 case XML_COMMENT_NODE: 09049 break; 09050 default: 09051 goto internal_error; 09052 } 09053 /* 09054 * Walk the tree. 09055 */ 09056 if (cur->children != NULL) { 09057 cur = cur->children; 09058 continue; 09059 } 09060 09061 leave_node: 09062 if (cur == node) 09063 break; 09064 if ((cur->type == XML_ELEMENT_NODE) || 09065 (cur->type == XML_XINCLUDE_START) || 09066 (cur->type == XML_XINCLUDE_END)) 09067 { 09068 /* 09069 * TODO: Do we expect nsDefs on XML_XINCLUDE_START? 09070 */ 09071 if (XML_NSMAP_NOTEMPTY(nsMap)) { 09072 /* 09073 * Pop mappings. 09074 */ 09075 while ((nsMap->last != NULL) && 09076 (nsMap->last->depth >= depth)) 09077 { 09078 XML_NSMAP_POP(nsMap, mi) 09079 } 09080 /* 09081 * Unshadow. 09082 */ 09083 XML_NSMAP_FOREACH(nsMap, mi) { 09084 if (mi->shadowDepth >= depth) 09085 mi->shadowDepth = -1; 09086 } 09087 } 09088 depth--; 09089 } 09090 if (cur->next != NULL) 09091 cur = cur->next; 09092 else if ((cur->type == XML_ATTRIBUTE_NODE) && 09093 (cur->parent->children != NULL)) 09094 { 09095 cur = cur->parent->children; 09096 } else { 09097 cur = cur->parent; 09098 goto leave_node; 09099 } 09100 } 09101 09102 goto exit; 09103 09104 internal_error: 09105 ret = -1; 09106 09107 exit: 09108 /* 09109 * Cleanup. 09110 */ 09111 if (nsMap != NULL) { 09112 if ((ctxt) && (ctxt->namespaceMap == nsMap)) { 09113 /* 09114 * Just cleanup the map but don't free. 09115 */ 09116 if (nsMap->first) { 09117 if (nsMap->pool) 09118 nsMap->last->next = nsMap->pool; 09119 nsMap->pool = nsMap->first; 09120 nsMap->first = NULL; 09121 } 09122 } else 09123 xmlDOMWrapNsMapFree(nsMap); 09124 } 09125 return(ret); 09126 } 09127 09128 /* 09129 * xmlDOMWrapCloneNode: 09130 * @ctxt: the optional context for custom processing 09131 * @sourceDoc: the optional sourceDoc 09132 * @node: the node to start with 09133 * @resNode: the clone of the given @node 09134 * @destDoc: the destination doc 09135 * @destParent: the optional new parent of @node in @destDoc 09136 * @deep: descend into child if set 09137 * @options: option flags 09138 * 09139 * References of out-of scope ns-decls are remapped to point to @destDoc: 09140 * 1) If @destParent is given, then nsDef entries on element-nodes are used 09141 * 2) If *no* @destParent is given, then @destDoc->oldNs entries are used. 09142 * This is the case when you don't know already where the cloned branch 09143 * will be added to. 09144 * 09145 * If @destParent is given, it ensures that the tree is namespace 09146 * wellformed by creating additional ns-decls where needed. 09147 * Note that, since prefixes of already existent ns-decls can be 09148 * shadowed by this process, it could break QNames in attribute 09149 * values or element content. 09150 * TODO: 09151 * 1) What to do with XInclude? Currently this returns an error for XInclude. 09152 * 09153 * Returns 0 if the operation succeeded, 09154 * 1 if a node of unsupported (or not yet supported) type was given, 09155 * -1 on API/internal errors. 09156 */ 09157 09158 int 09159 xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, 09160 xmlDocPtr sourceDoc, 09161 xmlNodePtr node, 09162 xmlNodePtr *resNode, 09163 xmlDocPtr destDoc, 09164 xmlNodePtr destParent, 09165 int deep, 09166 int options ATTRIBUTE_UNUSED) 09167 { 09168 int ret = 0; 09169 xmlNodePtr cur, curElem = NULL; 09170 xmlNsMapPtr nsMap = NULL; 09171 xmlNsMapItemPtr mi; 09172 xmlNsPtr ns; 09173 int depth = -1; 09174 /* int adoptStr = 1; */ 09175 /* gather @parent's ns-decls. */ 09176 int parnsdone = 0; 09177 /* 09178 * @ancestorsOnly: 09179 * TODO: @ancestorsOnly should be set per option. 09180 * 09181 */ 09182 int ancestorsOnly = 0; 09183 xmlNodePtr resultClone = NULL, clone = NULL, parentClone = NULL, prevClone = NULL; 09184 xmlNsPtr cloneNs = NULL, *cloneNsDefSlot = NULL; 09185 xmlDictPtr dict; /* The destination dict */ 09186 09187 if ((node == NULL) || (resNode == NULL) || (destDoc == NULL)) 09188 return(-1); 09189 /* 09190 * TODO: Initially we support only element-nodes. 09191 */ 09192 if (node->type != XML_ELEMENT_NODE) 09193 return(1); 09194 /* 09195 * Check node->doc sanity. 09196 */ 09197 if ((node->doc != NULL) && (sourceDoc != NULL) && 09198 (node->doc != sourceDoc)) { 09199 /* 09200 * Might be an XIncluded node. 09201 */ 09202 return (-1); 09203 } 09204 if (sourceDoc == NULL) 09205 sourceDoc = node->doc; 09206 if (sourceDoc == NULL) 09207 return (-1); 09208 09209 dict = destDoc->dict; 09210 /* 09211 * Reuse the namespace map of the context. 09212 */ 09213 if (ctxt) 09214 nsMap = (xmlNsMapPtr) ctxt->namespaceMap; 09215 09216 *resNode = NULL; 09217 09218 cur = node; 09219 while (cur != NULL) { 09220 if (cur->doc != sourceDoc) { 09221 /* 09222 * We'll assume XIncluded nodes if the doc differs. 09223 * TODO: Do we need to reconciliate XIncluded nodes? 09224 * TODO: This here returns -1 in this case. 09225 */ 09226 goto internal_error; 09227 } 09228 /* 09229 * Create a new node. 09230 */ 09231 switch (cur->type) { 09232 case XML_XINCLUDE_START: 09233 case XML_XINCLUDE_END: 09234 /* 09235 * TODO: What to do with XInclude? 09236 */ 09237 goto internal_error; 09238 break; 09239 case XML_ELEMENT_NODE: 09240 case XML_TEXT_NODE: 09241 case XML_CDATA_SECTION_NODE: 09242 case XML_COMMENT_NODE: 09243 case XML_PI_NODE: 09244 case XML_DOCUMENT_FRAG_NODE: 09245 case XML_ENTITY_REF_NODE: 09246 case XML_ENTITY_NODE: 09247 /* 09248 * Nodes of xmlNode structure. 09249 */ 09250 clone = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); 09251 if (clone == NULL) { 09252 xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating a node"); 09253 goto internal_error; 09254 } 09255 memset(clone, 0, sizeof(xmlNode)); 09256 /* 09257 * Set hierachical links. 09258 */ 09259 if (resultClone != NULL) { 09260 clone->parent = parentClone; 09261 if (prevClone) { 09262 prevClone->next = clone; 09263 clone->prev = prevClone; 09264 } else 09265 parentClone->children = clone; 09266 } else 09267 resultClone = clone; 09268 09269 break; 09270 case XML_ATTRIBUTE_NODE: 09271 /* 09272 * Attributes (xmlAttr). 09273 */ 09274 clone = (xmlNodePtr) xmlMalloc(sizeof(xmlAttr)); 09275 if (clone == NULL) { 09276 xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating an attr-node"); 09277 goto internal_error; 09278 } 09279 memset(clone, 0, sizeof(xmlAttr)); 09280 /* 09281 * Set hierachical links. 09282 * TODO: Change this to add to the end of attributes. 09283 */ 09284 if (resultClone != NULL) { 09285 clone->parent = parentClone; 09286 if (prevClone) { 09287 prevClone->next = clone; 09288 clone->prev = prevClone; 09289 } else 09290 parentClone->properties = (xmlAttrPtr) clone; 09291 } else 09292 resultClone = clone; 09293 break; 09294 default: 09295 /* 09296 * TODO QUESTION: Any other nodes expected? 09297 */ 09298 goto internal_error; 09299 } 09300 09301 clone->type = cur->type; 09302 clone->doc = destDoc; 09303 09304 /* 09305 * Clone the name of the node if any. 09306 */ 09307 if (cur->name == xmlStringText) 09308 clone->name = xmlStringText; 09309 else if (cur->name == xmlStringTextNoenc) 09310 /* 09311 * NOTE: Although xmlStringTextNoenc is never assigned to a node 09312 * in tree.c, it might be set in Libxslt via 09313 * "xsl:disable-output-escaping". 09314 */ 09315 clone->name = xmlStringTextNoenc; 09316 else if (cur->name == xmlStringComment) 09317 clone->name = xmlStringComment; 09318 else if (cur->name != NULL) { 09319 DICT_CONST_COPY(cur->name, clone->name); 09320 } 09321 09322 switch (cur->type) { 09323 case XML_XINCLUDE_START: 09324 case XML_XINCLUDE_END: 09325 /* 09326 * TODO 09327 */ 09328 return (-1); 09329 case XML_ELEMENT_NODE: 09330 curElem = cur; 09331 depth++; 09332 /* 09333 * Namespace declarations. 09334 */ 09335 if (cur->nsDef != NULL) { 09336 if (! parnsdone) { 09337 if (destParent && (ctxt == NULL)) { 09338 /* 09339 * Gather @parent's in-scope ns-decls. 09340 */ 09341 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, 09342 destParent) == -1) 09343 goto internal_error; 09344 } 09345 parnsdone = 1; 09346 } 09347 /* 09348 * Clone namespace declarations. 09349 */ 09350 cloneNsDefSlot = &(clone->nsDef); 09351 for (ns = cur->nsDef; ns != NULL; ns = ns->next) { 09352 /* 09353 * Create a new xmlNs. 09354 */ 09355 cloneNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 09356 if (cloneNs == NULL) { 09357 xmlTreeErrMemory("xmlDOMWrapCloneNode(): " 09358 "allocating namespace"); 09359 return(-1); 09360 } 09361 memset(cloneNs, 0, sizeof(xmlNs)); 09362 cloneNs->type = XML_LOCAL_NAMESPACE; 09363 09364 if (ns->href != NULL) 09365 cloneNs->href = xmlStrdup(ns->href); 09366 if (ns->prefix != NULL) 09367 cloneNs->prefix = xmlStrdup(ns->prefix); 09368 09369 *cloneNsDefSlot = cloneNs; 09370 cloneNsDefSlot = &(cloneNs->next); 09371 09372 /* 09373 * Note that for custom handling of ns-references, 09374 * the ns-decls need not be stored in the ns-map, 09375 * since they won't be referenced by node->ns. 09376 */ 09377 if ((ctxt == NULL) || 09378 (ctxt->getNsForNodeFunc == NULL)) 09379 { 09380 /* 09381 * Does it shadow any ns-decl? 09382 */ 09383 if (XML_NSMAP_NOTEMPTY(nsMap)) { 09384 XML_NSMAP_FOREACH(nsMap, mi) { 09385 if ((mi->depth >= XML_TREE_NSMAP_PARENT) && 09386 (mi->shadowDepth == -1) && 09387 ((ns->prefix == mi->newNs->prefix) || 09388 xmlStrEqual(ns->prefix, 09389 mi->newNs->prefix))) { 09390 /* 09391 * Mark as shadowed at the current 09392 * depth. 09393 */ 09394 mi->shadowDepth = depth; 09395 } 09396 } 09397 } 09398 /* 09399 * Push mapping. 09400 */ 09401 if (xmlDOMWrapNsMapAddItem(&nsMap, -1, 09402 ns, cloneNs, depth) == NULL) 09403 goto internal_error; 09404 } 09405 } 09406 } 09407 /* cur->ns will be processed further down. */ 09408 break; 09409 case XML_ATTRIBUTE_NODE: 09410 /* IDs will be processed further down. */ 09411 /* cur->ns will be processed further down. */ 09412 break; 09413 case XML_TEXT_NODE: 09414 case XML_CDATA_SECTION_NODE: 09415 /* 09416 * Note that this will also cover the values of attributes. 09417 */ 09418 DICT_COPY(cur->content, clone->content); 09419 goto leave_node; 09420 case XML_ENTITY_NODE: 09421 /* TODO: What to do here? */ 09422 goto leave_node; 09423 case XML_ENTITY_REF_NODE: 09424 if (sourceDoc != destDoc) { 09425 if ((destDoc->intSubset) || (destDoc->extSubset)) { 09426 xmlEntityPtr ent; 09427 /* 09428 * Different doc: Assign new entity-node if available. 09429 */ 09430 ent = xmlGetDocEntity(destDoc, cur->name); 09431 if (ent != NULL) { 09432 clone->content = ent->content; 09433 clone->children = (xmlNodePtr) ent; 09434 clone->last = (xmlNodePtr) ent; 09435 } 09436 } 09437 } else { 09438 /* 09439 * Same doc: Use the current node's entity declaration 09440 * and value. 09441 */ 09442 clone->content = cur->content; 09443 clone->children = cur->children; 09444 clone->last = cur->last; 09445 } 09446 goto leave_node; 09447 case XML_PI_NODE: 09448 DICT_COPY(cur->content, clone->content); 09449 goto leave_node; 09450 case XML_COMMENT_NODE: 09451 DICT_COPY(cur->content, clone->content); 09452 goto leave_node; 09453 default: 09454 goto internal_error; 09455 } 09456 09457 if (cur->ns == NULL) 09458 goto end_ns_reference; 09459 09460 /* handle_ns_reference: */ 09461 /* 09462 ** The following will take care of references to ns-decls ******** 09463 ** and is intended only for element- and attribute-nodes. 09464 ** 09465 */ 09466 if (! parnsdone) { 09467 if (destParent && (ctxt == NULL)) { 09468 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, destParent) == -1) 09469 goto internal_error; 09470 } 09471 parnsdone = 1; 09472 } 09473 /* 09474 * Adopt ns-references. 09475 */ 09476 if (XML_NSMAP_NOTEMPTY(nsMap)) { 09477 /* 09478 * Search for a mapping. 09479 */ 09480 XML_NSMAP_FOREACH(nsMap, mi) { 09481 if ((mi->shadowDepth == -1) && 09482 (cur->ns == mi->oldNs)) { 09483 /* 09484 * This is the nice case: a mapping was found. 09485 */ 09486 clone->ns = mi->newNs; 09487 goto end_ns_reference; 09488 } 09489 } 09490 } 09491 /* 09492 * No matching namespace in scope. We need a new one. 09493 */ 09494 if ((ctxt != NULL) && (ctxt->getNsForNodeFunc != NULL)) { 09495 /* 09496 * User-defined behaviour. 09497 */ 09498 ns = ctxt->getNsForNodeFunc(ctxt, cur, 09499 cur->ns->href, cur->ns->prefix); 09500 /* 09501 * Add user's mapping. 09502 */ 09503 if (xmlDOMWrapNsMapAddItem(&nsMap, -1, 09504 cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL) 09505 goto internal_error; 09506 clone->ns = ns; 09507 } else { 09508 /* 09509 * Aquire a normalized ns-decl and add it to the map. 09510 */ 09511 if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc, 09512 /* ns-decls on curElem or on destDoc->oldNs */ 09513 destParent ? curElem : NULL, 09514 cur->ns, &ns, 09515 &nsMap, depth, 09516 /* if we need to search only in the ancestor-axis */ 09517 ancestorsOnly, 09518 /* ns-decls must be prefixed for attributes. */ 09519 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1) 09520 goto internal_error; 09521 clone->ns = ns; 09522 } 09523 09524 end_ns_reference: 09525 09526 /* 09527 * Some post-processing. 09528 * 09529 * Handle ID attributes. 09530 */ 09531 if ((clone->type == XML_ATTRIBUTE_NODE) && 09532 (clone->parent != NULL)) 09533 { 09534 if (xmlIsID(destDoc, clone->parent, (xmlAttrPtr) clone)) { 09535 09536 xmlChar *idVal; 09537 09538 idVal = xmlNodeListGetString(cur->doc, cur->children, 1); 09539 if (idVal != NULL) { 09540 if (xmlAddID(NULL, destDoc, idVal, (xmlAttrPtr) cur) == NULL) { 09541 /* TODO: error message. */ 09542 xmlFree(idVal); 09543 goto internal_error; 09544 } 09545 xmlFree(idVal); 09546 } 09547 } 09548 } 09549 /* 09550 ** 09551 ** The following will traverse the tree ************************** 09552 ** 09553 * 09554 * Walk the element's attributes before descending into child-nodes. 09555 */ 09556 if ((cur->type == XML_ELEMENT_NODE) && (cur->properties != NULL)) { 09557 prevClone = NULL; 09558 parentClone = clone; 09559 cur = (xmlNodePtr) cur->properties; 09560 continue; 09561 } 09562 into_content: 09563 /* 09564 * Descend into child-nodes. 09565 */ 09566 if (cur->children != NULL) { 09567 if (deep || (cur->type == XML_ATTRIBUTE_NODE)) { 09568 prevClone = NULL; 09569 parentClone = clone; 09570 cur = cur->children; 09571 continue; 09572 } 09573 } 09574 09575 leave_node: 09576 /* 09577 * At this point we are done with the node, its content 09578 * and an element-nodes's attribute-nodes. 09579 */ 09580 if (cur == node) 09581 break; 09582 if ((cur->type == XML_ELEMENT_NODE) || 09583 (cur->type == XML_XINCLUDE_START) || 09584 (cur->type == XML_XINCLUDE_END)) { 09585 /* 09586 * TODO: Do we expect nsDefs on XML_XINCLUDE_START? 09587 */ 09588 if (XML_NSMAP_NOTEMPTY(nsMap)) { 09589 /* 09590 * Pop mappings. 09591 */ 09592 while ((nsMap->last != NULL) && 09593 (nsMap->last->depth >= depth)) 09594 { 09595 XML_NSMAP_POP(nsMap, mi) 09596 } 09597 /* 09598 * Unshadow. 09599 */ 09600 XML_NSMAP_FOREACH(nsMap, mi) { 09601 if (mi->shadowDepth >= depth) 09602 mi->shadowDepth = -1; 09603 } 09604 } 09605 depth--; 09606 } 09607 if (cur->next != NULL) { 09608 prevClone = clone; 09609 cur = cur->next; 09610 } else if (cur->type != XML_ATTRIBUTE_NODE) { 09611 /* 09612 * Set clone->last. 09613 */ 09614 if (clone->parent != NULL) 09615 clone->parent->last = clone; 09616 clone = clone->parent; 09617 parentClone = clone->parent; 09618 /* 09619 * Process parent --> next; 09620 */ 09621 cur = cur->parent; 09622 goto leave_node; 09623 } else { 09624 /* This is for attributes only. */ 09625 clone = clone->parent; 09626 parentClone = clone->parent; 09627 /* 09628 * Process parent-element --> children. 09629 */ 09630 cur = cur->parent; 09631 goto into_content; 09632 } 09633 } 09634 goto exit; 09635 09636 internal_error: 09637 ret = -1; 09638 09639 exit: 09640 /* 09641 * Cleanup. 09642 */ 09643 if (nsMap != NULL) { 09644 if ((ctxt) && (ctxt->namespaceMap == nsMap)) { 09645 /* 09646 * Just cleanup the map but don't free. 09647 */ 09648 if (nsMap->first) { 09649 if (nsMap->pool) 09650 nsMap->last->next = nsMap->pool; 09651 nsMap->pool = nsMap->first; 09652 nsMap->first = NULL; 09653 } 09654 } else 09655 xmlDOMWrapNsMapFree(nsMap); 09656 } 09657 /* 09658 * TODO: Should we try a cleanup of the cloned node in case of a 09659 * fatal error? 09660 */ 09661 *resNode = resultClone; 09662 return (ret); 09663 } 09664 09665 /* 09666 * xmlDOMWrapAdoptAttr: 09667 * @ctxt: the optional context for custom processing 09668 * @sourceDoc: the optional source document of attr 09669 * @attr: the attribute-node to be adopted 09670 * @destDoc: the destination doc for adoption 09671 * @destParent: the optional new parent of @attr in @destDoc 09672 * @options: option flags 09673 * 09674 * @attr is adopted by @destDoc. 09675 * Ensures that ns-references point to @destDoc: either to 09676 * elements->nsDef entries if @destParent is given, or to 09677 * @destDoc->oldNs otherwise. 09678 * 09679 * Returns 0 if succeeded, -1 otherwise and on API/internal errors. 09680 */ 09681 static int 09682 xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt, 09683 xmlDocPtr sourceDoc, 09684 xmlAttrPtr attr, 09685 xmlDocPtr destDoc, 09686 xmlNodePtr destParent, 09687 int options ATTRIBUTE_UNUSED) 09688 { 09689 xmlNodePtr cur; 09690 int adoptStr = 1; 09691 09692 if ((attr == NULL) || (destDoc == NULL)) 09693 return (-1); 09694 09695 attr->doc = destDoc; 09696 if (attr->ns != NULL) { 09697 xmlNsPtr ns = NULL; 09698 09699 if (ctxt != NULL) { 09700 /* TODO: User defined. */ 09701 } 09702 /* XML Namespace. */ 09703 if (IS_STR_XML(attr->ns->prefix)) { 09704 ns = xmlTreeEnsureXMLDecl(destDoc); 09705 } else if (destParent == NULL) { 09706 /* 09707 * Store in @destDoc->oldNs. 09708 */ 09709 ns = xmlDOMWrapStoreNs(destDoc, attr->ns->href, attr->ns->prefix); 09710 } else { 09711 /* 09712 * Declare on @destParent. 09713 */ 09714 if (xmlSearchNsByNamespaceStrict(destDoc, destParent, attr->ns->href, 09715 &ns, 1) == -1) 09716 goto internal_error; 09717 if (ns == NULL) { 09718 ns = xmlDOMWrapNSNormDeclareNsForced(destDoc, destParent, 09719 attr->ns->href, attr->ns->prefix, 1); 09720 } 09721 } 09722 if (ns == NULL) 09723 goto internal_error; 09724 attr->ns = ns; 09725 } 09726 09727 XML_TREE_ADOPT_STR(attr->name); 09728 attr->atype = 0; 09729 attr->psvi = NULL; 09730 /* 09731 * Walk content. 09732 */ 09733 if (attr->children == NULL) 09734 return (0); 09735 cur = attr->children; 09736 while (cur != NULL) { 09737 cur->doc = destDoc; 09738 switch (cur->type) { 09739 case XML_TEXT_NODE: 09740 case XML_CDATA_SECTION_NODE: 09741 XML_TREE_ADOPT_STR_2(cur->content) 09742 break; 09743 case XML_ENTITY_REF_NODE: 09744 /* 09745 * Remove reference to the entitity-node. 09746 */ 09747 cur->content = NULL; 09748 cur->children = NULL; 09749 cur->last = NULL; 09750 if ((destDoc->intSubset) || (destDoc->extSubset)) { 09751 xmlEntityPtr ent; 09752 /* 09753 * Assign new entity-node if available. 09754 */ 09755 ent = xmlGetDocEntity(destDoc, cur->name); 09756 if (ent != NULL) { 09757 cur->content = ent->content; 09758 cur->children = (xmlNodePtr) ent; 09759 cur->last = (xmlNodePtr) ent; 09760 } 09761 } 09762 break; 09763 default: 09764 break; 09765 } 09766 if (cur->children != NULL) { 09767 cur = cur->children; 09768 continue; 09769 } 09770 next_sibling: 09771 if (cur == (xmlNodePtr) attr) 09772 break; 09773 if (cur->next != NULL) 09774 cur = cur->next; 09775 else { 09776 cur = cur->parent; 09777 goto next_sibling; 09778 } 09779 } 09780 return (0); 09781 internal_error: 09782 return (-1); 09783 } 09784 09785 /* 09786 * xmlDOMWrapAdoptNode: 09787 * @ctxt: the optional context for custom processing 09788 * @sourceDoc: the optional sourceDoc 09789 * @node: the node to start with 09790 * @destDoc: the destination doc 09791 * @destParent: the optional new parent of @node in @destDoc 09792 * @options: option flags 09793 * 09794 * References of out-of scope ns-decls are remapped to point to @destDoc: 09795 * 1) If @destParent is given, then nsDef entries on element-nodes are used 09796 * 2) If *no* @destParent is given, then @destDoc->oldNs entries are used 09797 * This is the case when you have an unliked node and just want to move it 09798 * to the context of 09799 * 09800 * If @destParent is given, it ensures that the tree is namespace 09801 * wellformed by creating additional ns-decls where needed. 09802 * Note that, since prefixes of already existent ns-decls can be 09803 * shadowed by this process, it could break QNames in attribute 09804 * values or element content. 09805 * NOTE: This function was not intensively tested. 09806 * 09807 * Returns 0 if the operation succeeded, 09808 * 1 if a node of unsupported type was given, 09809 * 2 if a node of not yet supported type was given and 09810 * -1 on API/internal errors. 09811 */ 09812 int 09813 xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt, 09814 xmlDocPtr sourceDoc, 09815 xmlNodePtr node, 09816 xmlDocPtr destDoc, 09817 xmlNodePtr destParent, 09818 int options) 09819 { 09820 if ((node == NULL) || (destDoc == NULL) || 09821 ((destParent != NULL) && (destParent->doc != destDoc))) 09822 return(-1); 09823 /* 09824 * Check node->doc sanity. 09825 */ 09826 if ((node->doc != NULL) && (sourceDoc != NULL) && 09827 (node->doc != sourceDoc)) { 09828 /* 09829 * Might be an XIncluded node. 09830 */ 09831 return (-1); 09832 } 09833 if (sourceDoc == NULL) 09834 sourceDoc = node->doc; 09835 if (sourceDoc == destDoc) 09836 return (-1); 09837 switch (node->type) { 09838 case XML_ELEMENT_NODE: 09839 case XML_ATTRIBUTE_NODE: 09840 case XML_TEXT_NODE: 09841 case XML_CDATA_SECTION_NODE: 09842 case XML_ENTITY_REF_NODE: 09843 case XML_PI_NODE: 09844 case XML_COMMENT_NODE: 09845 break; 09846 case XML_DOCUMENT_FRAG_NODE: 09847 /* TODO: Support document-fragment-nodes. */ 09848 return (2); 09849 default: 09850 return (1); 09851 } 09852 /* 09853 * Unlink only if @node was not already added to @destParent. 09854 */ 09855 if ((node->parent != NULL) && (destParent != node->parent)) 09856 xmlUnlinkNode(node); 09857 09858 if (node->type == XML_ELEMENT_NODE) { 09859 return (xmlDOMWrapAdoptBranch(ctxt, sourceDoc, node, 09860 destDoc, destParent, options)); 09861 } else if (node->type == XML_ATTRIBUTE_NODE) { 09862 return (xmlDOMWrapAdoptAttr(ctxt, sourceDoc, 09863 (xmlAttrPtr) node, destDoc, destParent, options)); 09864 } else { 09865 xmlNodePtr cur = node; 09866 int adoptStr = 1; 09867 09868 cur->doc = destDoc; 09869 /* 09870 * Optimize string adoption. 09871 */ 09872 if ((sourceDoc != NULL) && 09873 (sourceDoc->dict == destDoc->dict)) 09874 adoptStr = 0; 09875 switch (node->type) { 09876 case XML_TEXT_NODE: 09877 case XML_CDATA_SECTION_NODE: 09878 XML_TREE_ADOPT_STR_2(node->content) 09879 break; 09880 case XML_ENTITY_REF_NODE: 09881 /* 09882 * Remove reference to the entitity-node. 09883 */ 09884 node->content = NULL; 09885 node->children = NULL; 09886 node->last = NULL; 09887 if ((destDoc->intSubset) || (destDoc->extSubset)) { 09888 xmlEntityPtr ent; 09889 /* 09890 * Assign new entity-node if available. 09891 */ 09892 ent = xmlGetDocEntity(destDoc, node->name); 09893 if (ent != NULL) { 09894 node->content = ent->content; 09895 node->children = (xmlNodePtr) ent; 09896 node->last = (xmlNodePtr) ent; 09897 } 09898 } 09899 XML_TREE_ADOPT_STR(node->name) 09900 break; 09901 case XML_PI_NODE: { 09902 XML_TREE_ADOPT_STR(node->name) 09903 XML_TREE_ADOPT_STR_2(node->content) 09904 break; 09905 } 09906 default: 09907 break; 09908 } 09909 } 09910 return (0); 09911 } 09912 09913 #define bottom_tree 09914 #include "elfgcchack.h" Generated on Sat May 26 2012 04:22:05 for ReactOS by
1.7.6.1
|