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