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