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 xmlNewReconciliedNs(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 pararmeter 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 detroyed 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 xmlDictPtr dict = NULL; 3668 3669 if (cur == NULL) return; 3670 if (cur->type == XML_NAMESPACE_DECL) { 3671 xmlFreeNsList((xmlNsPtr) cur); 3672 return; 3673 } 3674 if ((cur->type == XML_DOCUMENT_NODE) || 3675 #ifdef LIBXML_DOCB_ENABLED 3676 (cur->type == XML_DOCB_DOCUMENT_NODE) || 3677 #endif 3678 (cur->type == XML_HTML_DOCUMENT_NODE)) { 3679 xmlFreeDoc((xmlDocPtr) cur); 3680 return; 3681 } 3682 if (cur->doc != NULL) dict = cur->doc->dict; 3683 while (cur != NULL) { 3684 next = cur->next; 3685 if (cur->type != XML_DTD_NODE) { 3686 3687 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue)) 3688 xmlDeregisterNodeDefaultValue(cur); 3689 3690 if ((cur->children != NULL) && 3691 (cur->type != XML_ENTITY_REF_NODE)) 3692 xmlFreeNodeList(cur->children); 3693 if (((cur->type == XML_ELEMENT_NODE) || 3694 (cur->type == XML_XINCLUDE_START) || 3695 (cur->type == XML_XINCLUDE_END)) && 3696 (cur->properties != NULL)) 3697 xmlFreePropList(cur->properties); 3698 if ((cur->type != XML_ELEMENT_NODE) && 3699 (cur->type != XML_XINCLUDE_START) && 3700 (cur->type != XML_XINCLUDE_END) && 3701 (cur->type != XML_ENTITY_REF_NODE) && 3702 (cur->content != (xmlChar *) &(cur->properties))) { 3703 DICT_FREE(cur->content) 3704 } 3705 if (((cur->type == XML_ELEMENT_NODE) || 3706 (cur->type == XML_XINCLUDE_START) || 3707 (cur->type == XML_XINCLUDE_END)) && 3708 (cur->nsDef != NULL)) 3709 xmlFreeNsList(cur->nsDef); 3710 3711 /* 3712 * When a node is a text node or a comment, it uses a global static 3713 * variable for the name of the node. 3714 * Otherwise the node name might come from the document's 3715 * dictionary 3716 */ 3717 if ((cur->name != NULL) && 3718 (cur->type != XML_TEXT_NODE) && 3719 (cur->type != XML_COMMENT_NODE)) 3720 DICT_FREE(cur->name) 3721 xmlFree(cur); 3722 } 3723 cur = next; 3724 } 3725 } 3726 3727 /** 3728 * xmlFreeNode: 3729 * @cur: the node 3730 * 3731 * Free a node, this is a recursive behaviour, all the children are freed too. 3732 * This doesn't unlink the child from the list, use xmlUnlinkNode() first. 3733 */ 3734 void 3735 xmlFreeNode(xmlNodePtr cur) { 3736 xmlDictPtr dict = NULL; 3737 3738 if (cur == NULL) return; 3739 3740 /* use xmlFreeDtd for DTD nodes */ 3741 if (cur->type == XML_DTD_NODE) { 3742 xmlFreeDtd((xmlDtdPtr) cur); 3743 return; 3744 } 3745 if (cur->type == XML_NAMESPACE_DECL) { 3746 xmlFreeNs((xmlNsPtr) cur); 3747 return; 3748 } 3749 if (cur->type == XML_ATTRIBUTE_NODE) { 3750 xmlFreeProp((xmlAttrPtr) cur); 3751 return; 3752 } 3753 3754 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue)) 3755 xmlDeregisterNodeDefaultValue(cur); 3756 3757 if (cur->doc != NULL) dict = cur->doc->dict; 3758 3759 if (cur->type == XML_ENTITY_DECL) { 3760 xmlEntityPtr ent = (xmlEntityPtr) cur; 3761 DICT_FREE(ent->SystemID); 3762 DICT_FREE(ent->ExternalID); 3763 } 3764 if ((cur->children != NULL) && 3765 (cur->type != XML_ENTITY_REF_NODE)) 3766 xmlFreeNodeList(cur->children); 3767 if (((cur->type == XML_ELEMENT_NODE) || 3768 (cur->type == XML_XINCLUDE_START) || 3769 (cur->type == XML_XINCLUDE_END)) && 3770 (cur->properties != NULL)) 3771 xmlFreePropList(cur->properties); 3772 if ((cur->type != XML_ELEMENT_NODE) && 3773 (cur->content != NULL) && 3774 (cur->type != XML_ENTITY_REF_NODE) && 3775 (cur->type != XML_XINCLUDE_END) && 3776 (cur->type != XML_XINCLUDE_START) && 3777 (cur->content != (xmlChar *) &(cur->properties))) { 3778 DICT_FREE(cur->content) 3779 } 3780 3781 /* 3782 * When a node is a text node or a comment, it uses a global static 3783 * variable for the name of the node. 3784 * Otherwise the node name might come from the document's dictionary 3785 */ 3786 if ((cur->name != NULL) && 3787 (cur->type != XML_TEXT_NODE) && 3788 (cur->type != XML_COMMENT_NODE)) 3789 DICT_FREE(cur->name) 3790 3791 if (((cur->type == XML_ELEMENT_NODE) || 3792 (cur->type == XML_XINCLUDE_START) || 3793 (cur->type == XML_XINCLUDE_END)) && 3794 (cur->nsDef != NULL)) 3795 xmlFreeNsList(cur->nsDef); 3796 xmlFree(cur); 3797 } 3798 3799 /** 3800 * xmlUnlinkNode: 3801 * @cur: the node 3802 * 3803 * Unlink a node from it's current context, the node is not freed 3804 * If one need to free the node, use xmlFreeNode() routine after the 3805 * unlink to discard it. 3806 * Note that namespace nodes can't be unlinked as they do not have 3807 * pointer to their parent. 3808 */ 3809 void 3810 xmlUnlinkNode(xmlNodePtr cur) { 3811 if (cur == NULL) { 3812 #ifdef DEBUG_TREE 3813 xmlGenericError(xmlGenericErrorContext, 3814 "xmlUnlinkNode : node == NULL\n"); 3815 #endif 3816 return; 3817 } 3818 if (cur->type == XML_NAMESPACE_DECL) 3819 return; 3820 if (cur->type == XML_DTD_NODE) { 3821 xmlDocPtr doc; 3822 doc = cur->doc; 3823 if (doc != NULL) { 3824 if (doc->intSubset == (xmlDtdPtr) cur) 3825 doc->intSubset = NULL; 3826 if (doc->extSubset == (xmlDtdPtr) cur) 3827 doc->extSubset = NULL; 3828 } 3829 } 3830 if (cur->type == XML_ENTITY_DECL) { 3831 xmlDocPtr doc; 3832 doc = cur->doc; 3833 if (doc != NULL) { 3834 if (doc->intSubset != NULL) { 3835 if (xmlHashLookup(doc->intSubset->entities, cur->name) == cur) 3836 xmlHashRemoveEntry(doc->intSubset->entities, cur->name, 3837 NULL); 3838 if (xmlHashLookup(doc->intSubset->pentities, cur->name) == cur) 3839 xmlHashRemoveEntry(doc->intSubset->pentities, cur->name, 3840 NULL); 3841 } 3842 if (doc->extSubset != NULL) { 3843 if (xmlHashLookup(doc->extSubset->entities, cur->name) == cur) 3844 xmlHashRemoveEntry(doc->extSubset->entities, cur->name, 3845 NULL); 3846 if (xmlHashLookup(doc->extSubset->pentities, cur->name) == cur) 3847 xmlHashRemoveEntry(doc->extSubset->pentities, cur->name, 3848 NULL); 3849 } 3850 } 3851 } 3852 if (cur->parent != NULL) { 3853 xmlNodePtr parent; 3854 parent = cur->parent; 3855 if (cur->type == XML_ATTRIBUTE_NODE) { 3856 if (parent->properties == (xmlAttrPtr) cur) 3857 parent->properties = ((xmlAttrPtr) cur)->next; 3858 } else { 3859 if (parent->children == cur) 3860 parent->children = cur->next; 3861 if (parent->last == cur) 3862 parent->last = cur->prev; 3863 } 3864 cur->parent = NULL; 3865 } 3866 if (cur->next != NULL) 3867 cur->next->prev = cur->prev; 3868 if (cur->prev != NULL) 3869 cur->prev->next = cur->next; 3870 cur->next = cur->prev = NULL; 3871 } 3872 3873 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED) 3874 /** 3875 * xmlReplaceNode: 3876 * @old: the old node 3877 * @cur: the node 3878 * 3879 * Unlink the old node from its current context, prune the new one 3880 * at the same place. If @cur was already inserted in a document it is 3881 * first unlinked from its existing context. 3882 * 3883 * Returns the @old node 3884 */ 3885 xmlNodePtr 3886 xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) { 3887 if (old == cur) return(NULL); 3888 if ((old == NULL) || (old->type == XML_NAMESPACE_DECL) || 3889 (old->parent == NULL)) { 3890 #ifdef DEBUG_TREE 3891 xmlGenericError(xmlGenericErrorContext, 3892 "xmlReplaceNode : old == NULL or without parent\n"); 3893 #endif 3894 return(NULL); 3895 } 3896 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) { 3897 xmlUnlinkNode(old); 3898 return(old); 3899 } 3900 if (cur == old) { 3901 return(old); 3902 } 3903 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) { 3904 #ifdef DEBUG_TREE 3905 xmlGenericError(xmlGenericErrorContext, 3906 "xmlReplaceNode : Trying to replace attribute node with other node type\n"); 3907 #endif 3908 return(old); 3909 } 3910 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) { 3911 #ifdef DEBUG_TREE 3912 xmlGenericError(xmlGenericErrorContext, 3913 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n"); 3914 #endif 3915 return(old); 3916 } 3917 xmlUnlinkNode(cur); 3918 xmlSetTreeDoc(cur, old->doc); 3919 cur->parent = old->parent; 3920 cur->next = old->next; 3921 if (cur->next != NULL) 3922 cur->next->prev = cur; 3923 cur->prev = old->prev; 3924 if (cur->prev != NULL) 3925 cur->prev->next = cur; 3926 if (cur->parent != NULL) { 3927 if (cur->type == XML_ATTRIBUTE_NODE) { 3928 if (cur->parent->properties == (xmlAttrPtr)old) 3929 cur->parent->properties = ((xmlAttrPtr) cur); 3930 } else { 3931 if (cur->parent->children == old) 3932 cur->parent->children = cur; 3933 if (cur->parent->last == old) 3934 cur->parent->last = cur; 3935 } 3936 } 3937 old->next = old->prev = NULL; 3938 old->parent = NULL; 3939 return(old); 3940 } 3941 #endif /* LIBXML_TREE_ENABLED */ 3942 3943 /************************************************************************ 3944 * * 3945 * Copy operations * 3946 * * 3947 ************************************************************************/ 3948 3949 /** 3950 * xmlCopyNamespace: 3951 * @cur: the namespace 3952 * 3953 * Do a copy of the namespace. 3954 * 3955 * Returns: a new #xmlNsPtr, or NULL in case of error. 3956 */ 3957 xmlNsPtr 3958 xmlCopyNamespace(xmlNsPtr cur) { 3959 xmlNsPtr ret; 3960 3961 if (cur == NULL) return(NULL); 3962 switch (cur->type) { 3963 case XML_LOCAL_NAMESPACE: 3964 ret = xmlNewNs(NULL, cur->href, cur->prefix); 3965 break; 3966 default: 3967 #ifdef DEBUG_TREE 3968 xmlGenericError(xmlGenericErrorContext, 3969 "xmlCopyNamespace: invalid type %d\n", cur->type); 3970 #endif 3971 return(NULL); 3972 } 3973 return(ret); 3974 } 3975 3976 /** 3977 * xmlCopyNamespaceList: 3978 * @cur: the first namespace 3979 * 3980 * Do a copy of an namespace list. 3981 * 3982 * Returns: a new #xmlNsPtr, or NULL in case of error. 3983 */ 3984 xmlNsPtr 3985 xmlCopyNamespaceList(xmlNsPtr cur) { 3986 xmlNsPtr ret = NULL; 3987 xmlNsPtr p = NULL,q; 3988 3989 while (cur != NULL) { 3990 q = xmlCopyNamespace(cur); 3991 if (p == NULL) { 3992 ret = p = q; 3993 } else { 3994 p->next = q; 3995 p = q; 3996 } 3997 cur = cur->next; 3998 } 3999 return(ret); 4000 } 4001 4002 static xmlNodePtr 4003 xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent); 4004 4005 static xmlAttrPtr 4006 xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) { 4007 xmlAttrPtr ret; 4008 4009 if (cur == NULL) return(NULL); 4010 if ((target != NULL) && (target->type != XML_ELEMENT_NODE)) 4011 return(NULL); 4012 if (target != NULL) 4013 ret = xmlNewDocProp(target->doc, cur->name, NULL); 4014 else if (doc != NULL) 4015 ret = xmlNewDocProp(doc, cur->name, NULL); 4016 else if (cur->parent != NULL) 4017 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL); 4018 else if (cur->children != NULL) 4019 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL); 4020 else 4021 ret = xmlNewDocProp(NULL, cur->name, NULL); 4022 if (ret == NULL) return(NULL); 4023 ret->parent = target; 4024 4025 if ((cur->ns != NULL) && (target != NULL)) { 4026 xmlNsPtr ns; 4027 4028 ns = xmlSearchNs(target->doc, target, cur->ns->prefix); 4029 if (ns == NULL) { 4030 /* 4031 * Humm, we are copying an element whose namespace is defined 4032 * out of the new tree scope. Search it in the original tree 4033 * and add it at the top of the new tree 4034 */ 4035 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix); 4036 if (ns != NULL) { 4037 xmlNodePtr root = target; 4038 xmlNodePtr pred = NULL; 4039 4040 while (root->parent != NULL) { 4041 pred = root; 4042 root = root->parent; 4043 } 4044 if (root == (xmlNodePtr) target->doc) { 4045 /* correct possibly cycling above the document elt */ 4046 root = pred; 4047 } 4048 ret->ns = xmlNewNs(root, ns->href, ns->prefix); 4049 } 4050 } else { 4051 /* 4052 * we have to find something appropriate here since 4053 * we cant be sure, that the namespce we found is identified 4054 * by the prefix 4055 */ 4056 if (xmlStrEqual(ns->href, cur->ns->href)) { 4057 /* this is the nice case */ 4058 ret->ns = ns; 4059 } else { 4060 /* 4061 * we are in trouble: we need a new reconcilied namespace. 4062 * This is expensive 4063 */ 4064 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns); 4065 } 4066 } 4067 4068 } else 4069 ret->ns = NULL; 4070 4071 if (cur->children != NULL) { 4072 xmlNodePtr tmp; 4073 4074 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret); 4075 ret->last = NULL; 4076 tmp = ret->children; 4077 while (tmp != NULL) { 4078 /* tmp->parent = (xmlNodePtr)ret; */ 4079 if (tmp->next == NULL) 4080 ret->last = tmp; 4081 tmp = tmp->next; 4082 } 4083 } 4084 /* 4085 * Try to handle IDs 4086 */ 4087 if ((target!= NULL) && (cur!= NULL) && 4088 (target->doc != NULL) && (cur->doc != NULL) && 4089 (cur->doc->ids != NULL) && (cur->parent != NULL)) { 4090 if (xmlIsID(cur->doc, cur->parent, cur)) { 4091 xmlChar *id; 4092 4093 id = xmlNodeListGetString(cur->doc, cur->children, 1); 4094 if (id != NULL) { 4095 xmlAddID(NULL, target->doc, id, ret); 4096 xmlFree(id); 4097 } 4098 } 4099 } 4100 return(ret); 4101 } 4102 4103 /** 4104 * xmlCopyProp: 4105 * @target: the element where the attribute will be grafted 4106 * @cur: the attribute 4107 * 4108 * Do a copy of the attribute. 4109 * 4110 * Returns: a new #xmlAttrPtr, or NULL in case of error. 4111 */ 4112 xmlAttrPtr 4113 xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) { 4114 return xmlCopyPropInternal(NULL, target, cur); 4115 } 4116 4117 /** 4118 * xmlCopyPropList: 4119 * @target: the element where the attributes will be grafted 4120 * @cur: the first attribute 4121 * 4122 * Do a copy of an attribute list. 4123 * 4124 * Returns: a new #xmlAttrPtr, or NULL in case of error. 4125 */ 4126 xmlAttrPtr 4127 xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) { 4128 xmlAttrPtr ret = NULL; 4129 xmlAttrPtr p = NULL,q; 4130 4131 if ((target != NULL) && (target->type != XML_ELEMENT_NODE)) 4132 return(NULL); 4133 while (cur != NULL) { 4134 q = xmlCopyProp(target, cur); 4135 if (q == NULL) 4136 return(NULL); 4137 if (p == NULL) { 4138 ret = p = q; 4139 } else { 4140 p->next = q; 4141 q->prev = p; 4142 p = q; 4143 } 4144 cur = cur->next; 4145 } 4146 return(ret); 4147 } 4148 4149 /* 4150 * NOTE about the CopyNode operations ! 4151 * 4152 * They are split into external and internal parts for one 4153 * tricky reason: namespaces. Doing a direct copy of a node 4154 * say RPM:Copyright without changing the namespace pointer to 4155 * something else can produce stale links. One way to do it is 4156 * to keep a reference counter but this doesn't work as soon 4157 * as one move the element or the subtree out of the scope of 4158 * the existing namespace. The actual solution seems to add 4159 * a copy of the namespace at the top of the copied tree if 4160 * not available in the subtree. 4161 * Hence two functions, the public front-end call the inner ones 4162 * The argument "recursive" normally indicates a recursive copy 4163 * of the node with values 0 (no) and 1 (yes). For XInclude, 4164 * however, we allow a value of 2 to indicate copy properties and 4165 * namespace info, but don't recurse on children. 4166 */ 4167 4168 static xmlNodePtr 4169 xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent, 4170 int extended) { 4171 xmlNodePtr ret; 4172 4173 if (node == NULL) return(NULL); 4174 switch (node->type) { 4175 case XML_TEXT_NODE: 4176 case XML_CDATA_SECTION_NODE: 4177 case XML_ELEMENT_NODE: 4178 case XML_DOCUMENT_FRAG_NODE: 4179 case XML_ENTITY_REF_NODE: 4180 case XML_ENTITY_NODE: 4181 case XML_PI_NODE: 4182 case XML_COMMENT_NODE: 4183 case XML_XINCLUDE_START: 4184 case XML_XINCLUDE_END: 4185 break; 4186 case XML_ATTRIBUTE_NODE: 4187 return((xmlNodePtr) xmlCopyPropInternal(doc, parent, (xmlAttrPtr) node)); 4188 case XML_NAMESPACE_DECL: 4189 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node)); 4190 4191 case XML_DOCUMENT_NODE: 4192 case XML_HTML_DOCUMENT_NODE: 4193 #ifdef LIBXML_DOCB_ENABLED 4194 case XML_DOCB_DOCUMENT_NODE: 4195 #endif 4196 #ifdef LIBXML_TREE_ENABLED 4197 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended)); 4198 #endif /* LIBXML_TREE_ENABLED */ 4199 case XML_DOCUMENT_TYPE_NODE: 4200 case XML_NOTATION_NODE: 4201 case XML_DTD_NODE: 4202 case XML_ELEMENT_DECL: 4203 case XML_ATTRIBUTE_DECL: 4204 case XML_ENTITY_DECL: 4205 return(NULL); 4206 } 4207 4208 /* 4209 * Allocate a new node and fill the fields. 4210 */ 4211 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); 4212 if (ret == NULL) { 4213 xmlTreeErrMemory("copying node"); 4214 return(NULL); 4215 } 4216 memset(ret, 0, sizeof(xmlNode)); 4217 ret->type = node->type; 4218 4219 ret->doc = doc; 4220 ret->parent = parent; 4221 if (node->name == xmlStringText) 4222 ret->name = xmlStringText; 4223 else if (node->name == xmlStringTextNoenc) 4224 ret->name = xmlStringTextNoenc; 4225 else if (node->name == xmlStringComment) 4226 ret->name = xmlStringComment; 4227 else if (node->name != NULL) { 4228 if ((doc != NULL) && (doc->dict != NULL)) 4229 ret->name = xmlDictLookup(doc->dict, node->name, -1); 4230 else 4231 ret->name = xmlStrdup(node->name); 4232 } 4233 if ((node->type != XML_ELEMENT_NODE) && 4234 (node->content != NULL) && 4235 (node->type != XML_ENTITY_REF_NODE) && 4236 (node->type != XML_XINCLUDE_END) && 4237 (node->type != XML_XINCLUDE_START)) { 4238 ret->content = xmlStrdup(node->content); 4239 }else{ 4240 if (node->type == XML_ELEMENT_NODE) 4241 ret->line = node->line; 4242 } 4243 if (parent != NULL) { 4244 xmlNodePtr tmp; 4245 4246 /* 4247 * this is a tricky part for the node register thing: 4248 * in case ret does get coalesced in xmlAddChild 4249 * the deregister-node callback is called; so we register ret now already 4250 */ 4251 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 4252 xmlRegisterNodeDefaultValue((xmlNodePtr)ret); 4253 4254 tmp = xmlAddChild(parent, ret); 4255 /* node could have coalesced */ 4256 if (tmp != ret) 4257 return(tmp); 4258 } 4259 4260 if (!extended) 4261 goto out; 4262 if (((node->type == XML_ELEMENT_NODE) || 4263 (node->type == XML_XINCLUDE_START)) && (node->nsDef != NULL)) 4264 ret->nsDef = xmlCopyNamespaceList(node->nsDef); 4265 4266 if (node->ns != NULL) { 4267 xmlNsPtr ns; 4268 4269 ns = xmlSearchNs(doc, ret, node->ns->prefix); 4270 if (ns == NULL) { 4271 /* 4272 * Humm, we are copying an element whose namespace is defined 4273 * out of the new tree scope. Search it in the original tree 4274 * and add it at the top of the new tree 4275 */ 4276 ns = xmlSearchNs(node->doc, node, node->ns->prefix); 4277 if (ns != NULL) { 4278 xmlNodePtr root = ret; 4279 4280 while (root->parent != NULL) root = root->parent; 4281 ret->ns = xmlNewNs(root, ns->href, ns->prefix); 4282 } else { 4283 ret->ns = xmlNewReconciliedNs(doc, ret, node->ns); 4284 } 4285 } else { 4286 /* 4287 * reference the existing namespace definition in our own tree. 4288 */ 4289 ret->ns = ns; 4290 } 4291 } 4292 if (((node->type == XML_ELEMENT_NODE) || 4293 (node->type == XML_XINCLUDE_START)) && (node->properties != NULL)) 4294 ret->properties = xmlCopyPropList(ret, node->properties); 4295 if (node->type == XML_ENTITY_REF_NODE) { 4296 if ((doc == NULL) || (node->doc != doc)) { 4297 /* 4298 * The copied node will go into a separate document, so 4299 * to avoid dangling references to the ENTITY_DECL node 4300 * we cannot keep the reference. Try to find it in the 4301 * target document. 4302 */ 4303 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name); 4304 } else { 4305 ret->children = node->children; 4306 } 4307 ret->last = ret->children; 4308 } else if ((node->children != NULL) && (extended != 2)) { 4309 ret->children = xmlStaticCopyNodeList(node->children, doc, ret); 4310 UPDATE_LAST_CHILD_AND_PARENT(ret) 4311 } 4312 4313 out: 4314 /* if parent != NULL we already registered the node above */ 4315 if ((parent == NULL) && 4316 ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))) 4317 xmlRegisterNodeDefaultValue((xmlNodePtr)ret); 4318 return(ret); 4319 } 4320 4321 static xmlNodePtr 4322 xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) { 4323 xmlNodePtr ret = NULL; 4324 xmlNodePtr p = NULL,q; 4325 4326 while (node != NULL) { 4327 #ifdef LIBXML_TREE_ENABLED 4328 if (node->type == XML_DTD_NODE ) { 4329 if (doc == NULL) { 4330 node = node->next; 4331 continue; 4332 } 4333 if (doc->intSubset == NULL) { 4334 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node ); 4335 if (q == NULL) return(NULL); 4336 q->doc = doc; 4337 q->parent = parent; 4338 doc->intSubset = (xmlDtdPtr) q; 4339 xmlAddChild(parent, q); 4340 } else { 4341 q = (xmlNodePtr) doc->intSubset; 4342 xmlAddChild(parent, q); 4343 } 4344 } else 4345 #endif /* LIBXML_TREE_ENABLED */ 4346 q = xmlStaticCopyNode(node, doc, parent, 1); 4347 if (q == NULL) return(NULL); 4348 if (ret == NULL) { 4349 q->prev = NULL; 4350 ret = p = q; 4351 } else if (p != q) { 4352 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */ 4353 p->next = q; 4354 q->prev = p; 4355 p = q; 4356 } 4357 node = node->next; 4358 } 4359 return(ret); 4360 } 4361 4362 /** 4363 * xmlCopyNode: 4364 * @node: the node 4365 * @extended: if 1 do a recursive copy (properties, namespaces and children 4366 * when applicable) 4367 * if 2 copy properties and namespaces (when applicable) 4368 * 4369 * Do a copy of the node. 4370 * 4371 * Returns: a new #xmlNodePtr, or NULL in case of error. 4372 */ 4373 xmlNodePtr 4374 xmlCopyNode(xmlNodePtr node, int extended) { 4375 xmlNodePtr ret; 4376 4377 ret = xmlStaticCopyNode(node, NULL, NULL, extended); 4378 return(ret); 4379 } 4380 4381 /** 4382 * xmlDocCopyNode: 4383 * @node: the node 4384 * @doc: the document 4385 * @extended: if 1 do a recursive copy (properties, namespaces and children 4386 * when applicable) 4387 * if 2 copy properties and namespaces (when applicable) 4388 * 4389 * Do a copy of the node to a given document. 4390 * 4391 * Returns: a new #xmlNodePtr, or NULL in case of error. 4392 */ 4393 xmlNodePtr 4394 xmlDocCopyNode(xmlNodePtr node, xmlDocPtr doc, int extended) { 4395 xmlNodePtr ret; 4396 4397 ret = xmlStaticCopyNode(node, doc, NULL, extended); 4398 return(ret); 4399 } 4400 4401 /** 4402 * xmlDocCopyNodeList: 4403 * @doc: the target document 4404 * @node: the first node in the list. 4405 * 4406 * Do a recursive copy of the node list. 4407 * 4408 * Returns: a new #xmlNodePtr, or NULL in case of error. 4409 */ 4410 xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, xmlNodePtr node) { 4411 xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL); 4412 return(ret); 4413 } 4414 4415 /** 4416 * xmlCopyNodeList: 4417 * @node: the first node in the list. 4418 * 4419 * Do a recursive copy of the node list. 4420 * Use xmlDocCopyNodeList() if possible to ensure string interning. 4421 * 4422 * Returns: a new #xmlNodePtr, or NULL in case of error. 4423 */ 4424 xmlNodePtr xmlCopyNodeList(xmlNodePtr node) { 4425 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL); 4426 return(ret); 4427 } 4428 4429 #if defined(LIBXML_TREE_ENABLED) 4430 /** 4431 * xmlCopyDtd: 4432 * @dtd: the dtd 4433 * 4434 * Do a copy of the dtd. 4435 * 4436 * Returns: a new #xmlDtdPtr, or NULL in case of error. 4437 */ 4438 xmlDtdPtr 4439 xmlCopyDtd(xmlDtdPtr dtd) { 4440 xmlDtdPtr ret; 4441 xmlNodePtr cur, p = NULL, q; 4442 4443 if (dtd == NULL) return(NULL); 4444 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID); 4445 if (ret == NULL) return(NULL); 4446 if (dtd->entities != NULL) 4447 ret->entities = (void *) xmlCopyEntitiesTable( 4448 (xmlEntitiesTablePtr) dtd->entities); 4449 if (dtd->notations != NULL) 4450 ret->notations = (void *) xmlCopyNotationTable( 4451 (xmlNotationTablePtr) dtd->notations); 4452 if (dtd->elements != NULL) 4453 ret->elements = (void *) xmlCopyElementTable( 4454 (xmlElementTablePtr) dtd->elements); 4455 if (dtd->attributes != NULL) 4456 ret->attributes = (void *) xmlCopyAttributeTable( 4457 (xmlAttributeTablePtr) dtd->attributes); 4458 if (dtd->pentities != NULL) 4459 ret->pentities = (void *) xmlCopyEntitiesTable( 4460 (xmlEntitiesTablePtr) dtd->pentities); 4461 4462 cur = dtd->children; 4463 while (cur != NULL) { 4464 q = NULL; 4465 4466 if (cur->type == XML_ENTITY_DECL) { 4467 xmlEntityPtr tmp = (xmlEntityPtr) cur; 4468 switch (tmp->etype) { 4469 case XML_INTERNAL_GENERAL_ENTITY: 4470 case XML_EXTERNAL_GENERAL_PARSED_ENTITY: 4471 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: 4472 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name); 4473 break; 4474 case XML_INTERNAL_PARAMETER_ENTITY: 4475 case XML_EXTERNAL_PARAMETER_ENTITY: 4476 q = (xmlNodePtr) 4477 xmlGetParameterEntityFromDtd(ret, tmp->name); 4478 break; 4479 case XML_INTERNAL_PREDEFINED_ENTITY: 4480 break; 4481 } 4482 } else if (cur->type == XML_ELEMENT_DECL) { 4483 xmlElementPtr tmp = (xmlElementPtr) cur; 4484 q = (xmlNodePtr) 4485 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix); 4486 } else if (cur->type == XML_ATTRIBUTE_DECL) { 4487 xmlAttributePtr tmp = (xmlAttributePtr) cur; 4488 q = (xmlNodePtr) 4489 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix); 4490 } else if (cur->type == XML_COMMENT_NODE) { 4491 q = xmlCopyNode(cur, 0); 4492 } 4493 4494 if (q == NULL) { 4495 cur = cur->next; 4496 continue; 4497 } 4498 4499 if (p == NULL) 4500 ret->children = q; 4501 else 4502 p->next = q; 4503 4504 q->prev = p; 4505 q->parent = (xmlNodePtr) ret; 4506 q->next = NULL; 4507 ret->last = q; 4508 p = q; 4509 cur = cur->next; 4510 } 4511 4512 return(ret); 4513 } 4514 #endif 4515 4516 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) 4517 /** 4518 * xmlCopyDoc: 4519 * @doc: the document 4520 * @recursive: if not zero do a recursive copy. 4521 * 4522 * Do a copy of the document info. If recursive, the content tree will 4523 * be copied too as well as DTD, namespaces and entities. 4524 * 4525 * Returns: a new #xmlDocPtr, or NULL in case of error. 4526 */ 4527 xmlDocPtr 4528 xmlCopyDoc(xmlDocPtr doc, int recursive) { 4529 xmlDocPtr ret; 4530 4531 if (doc == NULL) return(NULL); 4532 ret = xmlNewDoc(doc->version); 4533 if (ret == NULL) return(NULL); 4534 if (doc->name != NULL) 4535 ret->name = xmlMemStrdup(doc->name); 4536 if (doc->encoding != NULL) 4537 ret->encoding = xmlStrdup(doc->encoding); 4538 if (doc->URL != NULL) 4539 ret->URL = xmlStrdup(doc->URL); 4540 ret->charset = doc->charset; 4541 ret->compression = doc->compression; 4542 ret->standalone = doc->standalone; 4543 if (!recursive) return(ret); 4544 4545 ret->last = NULL; 4546 ret->children = NULL; 4547 #ifdef LIBXML_TREE_ENABLED 4548 if (doc->intSubset != NULL) { 4549 ret->intSubset = xmlCopyDtd(doc->intSubset); 4550 if (ret->intSubset == NULL) { 4551 xmlFreeDoc(ret); 4552 return(NULL); 4553 } 4554 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret); 4555 ret->intSubset->parent = ret; 4556 } 4557 #endif 4558 if (doc->oldNs != NULL) 4559 ret->oldNs = xmlCopyNamespaceList(doc->oldNs); 4560 if (doc->children != NULL) { 4561 xmlNodePtr tmp; 4562 4563 ret->children = xmlStaticCopyNodeList(doc->children, ret, 4564 (xmlNodePtr)ret); 4565 ret->last = NULL; 4566 tmp = ret->children; 4567 while (tmp != NULL) { 4568 if (tmp->next == NULL) 4569 ret->last = tmp; 4570 tmp = tmp->next; 4571 } 4572 } 4573 return(ret); 4574 } 4575 #endif /* LIBXML_TREE_ENABLED */ 4576 4577 /************************************************************************ 4578 * * 4579 * Content access functions * 4580 * * 4581 ************************************************************************/ 4582 4583 /** 4584 * xmlGetLineNoInternal: 4585 * @node: valid node 4586 * @depth: used to limit any risk of recursion 4587 * 4588 * Get line number of @node. 4589 * Try to override the limitation of lines being store in 16 bits ints 4590 * 4591 * Returns the line number if successful, -1 otherwise 4592 */ 4593 static long 4594 xmlGetLineNoInternal(const xmlNode *node, int depth) 4595 { 4596 long result = -1; 4597 4598 if (depth >= 5) 4599 return(-1); 4600 4601 if (!node) 4602 return result; 4603 if ((node->type == XML_ELEMENT_NODE) || 4604 (node->type == XML_TEXT_NODE) || 4605 (node->type == XML_COMMENT_NODE) || 4606 (node->type == XML_PI_NODE)) { 4607 if (node->line == 65535) { 4608 if ((node->type == XML_TEXT_NODE) && (node->psvi != NULL)) 4609 result = (long) (ptrdiff_t) node->psvi; 4610 else if ((node->type == XML_ELEMENT_NODE) && 4611 (node->children != NULL)) 4612 result = xmlGetLineNoInternal(node->children, depth + 1); 4613 else if (node->next != NULL) 4614 result = xmlGetLineNoInternal(node->next, depth + 1); 4615 else if (node->prev != NULL) 4616 result = xmlGetLineNoInternal(node->prev, depth + 1); 4617 } 4618 if ((result == -1) || (result == 65535)) 4619 result = (long) node->line; 4620 } else if ((node->prev != NULL) && 4621 ((node->prev->type == XML_ELEMENT_NODE) || 4622 (node->prev->type == XML_TEXT_NODE) || 4623 (node->prev->type == XML_COMMENT_NODE) || 4624 (node->prev->type == XML_PI_NODE))) 4625 result = xmlGetLineNoInternal(node->prev, depth + 1); 4626 else if ((node->parent != NULL) && 4627 (node->parent->type == XML_ELEMENT_NODE)) 4628 result = xmlGetLineNoInternal(node->parent, depth + 1); 4629 4630 return result; 4631 } 4632 4633 /** 4634 * xmlGetLineNo: 4635 * @node: valid node 4636 * 4637 * Get line number of @node. 4638 * Try to override the limitation of lines being store in 16 bits ints 4639 * if XML_PARSE_BIG_LINES parser option was used 4640 * 4641 * Returns the line number if successful, -1 otherwise 4642 */ 4643 long 4644 xmlGetLineNo(const xmlNode *node) 4645 { 4646 return(xmlGetLineNoInternal(node, 0)); 4647 } 4648 4649 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED) 4650 /** 4651 * xmlGetNodePath: 4652 * @node: a node 4653 * 4654 * Build a structure based Path for the given node 4655 * 4656 * Returns the new path or NULL in case of error. The caller must free 4657 * the returned string 4658 */ 4659 xmlChar * 4660 xmlGetNodePath(const xmlNode *node) 4661 { 4662 const xmlNode *cur, *tmp, *next; 4663 xmlChar *buffer = NULL, *temp; 4664 size_t buf_len; 4665 xmlChar *buf; 4666 const char *sep; 4667 const char *name; 4668 char nametemp[100]; 4669 int occur = 0, generic; 4670 4671 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) 4672 return (NULL); 4673 4674 buf_len = 500; 4675 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar)); 4676 if (buffer == NULL) { 4677 xmlTreeErrMemory("getting node path"); 4678 return (NULL); 4679 } 4680 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar)); 4681 if (buf == NULL) { 4682 xmlTreeErrMemory("getting node path"); 4683 xmlFree(buffer); 4684 return (NULL); 4685 } 4686 4687 buffer[0] = 0; 4688 cur = node; 4689 do { 4690 name = ""; 4691 sep = "?"; 4692 occur = 0; 4693 if ((cur->type == XML_DOCUMENT_NODE) || 4694 (cur->type == XML_HTML_DOCUMENT_NODE)) { 4695 if (buffer[0] == '/') 4696 break; 4697 sep = "/"; 4698 next = NULL; 4699 } else if (cur->type == XML_ELEMENT_NODE) { 4700 generic = 0; 4701 sep = "/"; 4702 name = (const char *) cur->name; 4703 if (cur->ns) { 4704 if (cur->ns->prefix != NULL) { 4705 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s", 4706 (char *)cur->ns->prefix, (char *)cur->name); 4707 nametemp[sizeof(nametemp) - 1] = 0; 4708 name = nametemp; 4709 } else { 4710 /* 4711 * We cannot express named elements in the default 4712 * namespace, so use "*". 4713 */ 4714 generic = 1; 4715 name = "*"; 4716 } 4717 } 4718 next = cur->parent; 4719 4720 /* 4721 * Thumbler index computation 4722 * TODO: the ocurence test seems bogus for namespaced names 4723 */ 4724 tmp = cur->prev; 4725 while (tmp != NULL) { 4726 if ((tmp->type == XML_ELEMENT_NODE) && 4727 (generic || 4728 (xmlStrEqual(cur->name, tmp->name) && 4729 ((tmp->ns == cur->ns) || 4730 ((tmp->ns != NULL) && (cur->ns != NULL) && 4731 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix))))))) 4732 occur++; 4733 tmp = tmp->prev; 4734 } 4735 if (occur == 0) { 4736 tmp = cur->next; 4737 while (tmp != NULL && occur == 0) { 4738 if ((tmp->type == XML_ELEMENT_NODE) && 4739 (generic || 4740 (xmlStrEqual(cur->name, tmp->name) && 4741 ((tmp->ns == cur->ns) || 4742 ((tmp->ns != NULL) && (cur->ns != NULL) && 4743 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix))))))) 4744 occur++; 4745 tmp = tmp->next; 4746 } 4747 if (occur != 0) 4748 occur = 1; 4749 } else 4750 occur++; 4751 } else if (cur->type == XML_COMMENT_NODE) { 4752 sep = "/"; 4753 name = "comment()"; 4754 next = cur->parent; 4755 4756 /* 4757 * Thumbler index computation 4758 */ 4759 tmp = cur->prev; 4760 while (tmp != NULL) { 4761 if (tmp->type == XML_COMMENT_NODE) 4762 occur++; 4763 tmp = tmp->prev; 4764 } 4765 if (occur == 0) { 4766 tmp = cur->next; 4767 while (tmp != NULL && occur == 0) { 4768 if (tmp->type == XML_COMMENT_NODE) 4769 occur++; 4770 tmp = tmp->next; 4771 } 4772 if (occur != 0) 4773 occur = 1; 4774 } else 4775 occur++; 4776 } else if ((cur->type == XML_TEXT_NODE) || 4777 (cur->type == XML_CDATA_SECTION_NODE)) { 4778 sep = "/"; 4779 name = "text()"; 4780 next = cur->parent; 4781 4782 /* 4783 * Thumbler index computation 4784 */ 4785 tmp = cur->prev; 4786 while (tmp != NULL) { 4787 if ((tmp->type == XML_TEXT_NODE) || 4788 (tmp->type == XML_CDATA_SECTION_NODE)) 4789 occur++; 4790 tmp = tmp->prev; 4791 } 4792 /* 4793 * Evaluate if this is the only text- or CDATA-section-node; 4794 * if yes, then we'll get "text()", otherwise "text()[1]". 4795 */ 4796 if (occur == 0) { 4797 tmp = cur->next; 4798 while (tmp != NULL) { 4799 if ((tmp->type == XML_TEXT_NODE) || 4800 (tmp->type == XML_CDATA_SECTION_NODE)) 4801 { 4802 occur = 1; 4803 break; 4804 } 4805 tmp = tmp->next; 4806 } 4807 } else 4808 occur++; 4809 } else if (cur->type == XML_PI_NODE) { 4810 sep = "/"; 4811 snprintf(nametemp, sizeof(nametemp) - 1, 4812 "processing-instruction('%s')", (char *)cur->name); 4813 nametemp[sizeof(nametemp) - 1] = 0; 4814 name = nametemp; 4815 4816 next = cur->parent; 4817 4818 /* 4819 * Thumbler index computation 4820 */ 4821 tmp = cur->prev; 4822 while (tmp != NULL) { 4823 if ((tmp->type == XML_PI_NODE) && 4824 (xmlStrEqual(cur->name, tmp->name))) 4825 occur++; 4826 tmp = tmp->prev; 4827 } 4828 if (occur == 0) { 4829 tmp = cur->next; 4830 while (tmp != NULL && occur == 0) { 4831 if ((tmp->type == XML_PI_NODE) && 4832 (xmlStrEqual(cur->name, tmp->name))) 4833 occur++; 4834 tmp = tmp->next; 4835 } 4836 if (occur != 0) 4837 occur = 1; 4838 } else 4839 occur++; 4840 4841 } else if (cur->type == XML_ATTRIBUTE_NODE) { 4842 sep = "/@"; 4843 name = (const char *) (((xmlAttrPtr) cur)->name); 4844 if (cur->ns) { 4845 if (cur->ns->prefix != NULL) 4846 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s", 4847 (char *)cur->ns->prefix, (char *)cur->name); 4848 else 4849 snprintf(nametemp, sizeof(nametemp) - 1, "%s", 4850 (char *)cur->name); 4851 nametemp[sizeof(nametemp) - 1] = 0; 4852 name = nametemp; 4853 } 4854 next = ((xmlAttrPtr) cur)->parent; 4855 } else { 4856 next = cur->parent; 4857 } 4858 4859 /* 4860 * Make sure there is enough room 4861 */ 4862 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) { 4863 buf_len = 4864 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20; 4865 temp = (xmlChar *) xmlRealloc(buffer, buf_len); 4866 if (temp == NULL) { 4867 xmlTreeErrMemory("getting node path"); 4868 xmlFree(buf); 4869 xmlFree(buffer); 4870 return (NULL); 4871 } 4872 buffer = temp; 4873 temp = (xmlChar *) xmlRealloc(buf, buf_len); 4874 if (temp == NULL) { 4875 xmlTreeErrMemory("getting node path"); 4876 xmlFree(buf); 4877 xmlFree(buffer); 4878 return (NULL); 4879 } 4880 buf = temp; 4881 } 4882 if (occur == 0) 4883 snprintf((char *) buf, buf_len, "%s%s%s", 4884 sep, name, (char *) buffer); 4885 else 4886 snprintf((char *) buf, buf_len, "%s%s[%d]%s", 4887 sep, name, occur, (char *) buffer); 4888 snprintf((char *) buffer, buf_len, "%s", (char *)buf); 4889 cur = next; 4890 } while (cur != NULL); 4891 xmlFree(buf); 4892 return (buffer); 4893 } 4894 #endif /* LIBXML_TREE_ENABLED */ 4895 4896 /** 4897 * xmlDocGetRootElement: 4898 * @doc: the document 4899 * 4900 * Get the root element of the document (doc->children is a list 4901 * containing possibly comments, PIs, etc ...). 4902 * 4903 * Returns the #xmlNodePtr for the root or NULL 4904 */ 4905 xmlNodePtr 4906 xmlDocGetRootElement(const xmlDoc *doc) { 4907 xmlNodePtr ret; 4908 4909 if (doc == NULL) return(NULL); 4910 ret = doc->children; 4911 while (ret != NULL) { 4912 if (ret->type == XML_ELEMENT_NODE) 4913 return(ret); 4914 ret = ret->next; 4915 } 4916 return(ret); 4917 } 4918 4919 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED) 4920 /** 4921 * xmlDocSetRootElement: 4922 * @doc: the document 4923 * @root: the new document root element, if root is NULL no action is taken, 4924 * to remove a node from a document use xmlUnlinkNode(root) instead. 4925 * 4926 * Set the root element of the document (doc->children is a list 4927 * containing possibly comments, PIs, etc ...). 4928 * 4929 * Returns the old root element if any was found, NULL if root was NULL 4930 */ 4931 xmlNodePtr 4932 xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) { 4933 xmlNodePtr old = NULL; 4934 4935 if (doc == NULL) return(NULL); 4936 if ((root == NULL) || (root->type == XML_NAMESPACE_DECL)) 4937 return(NULL); 4938 xmlUnlinkNode(root); 4939 xmlSetTreeDoc(root, doc); 4940 root->parent = (xmlNodePtr) doc; 4941 old = doc->children; 4942 while (old != NULL) { 4943 if (old->type == XML_ELEMENT_NODE) 4944 break; 4945 old = old->next; 4946 } 4947 if (old == NULL) { 4948 if (doc->children == NULL) { 4949 doc->children = root; 4950 doc->last = root; 4951 } else { 4952 xmlAddSibling(doc->children, root); 4953 } 4954 } else { 4955 xmlReplaceNode(old, root); 4956 } 4957 return(old); 4958 } 4959 #endif 4960 4961 #if defined(LIBXML_TREE_ENABLED) 4962 /** 4963 * xmlNodeSetLang: 4964 * @cur: the node being changed 4965 * @lang: the language description 4966 * 4967 * Set the language of a node, i.e. the values of the xml:lang 4968 * attribute. 4969 */ 4970 void 4971 xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) { 4972 xmlNsPtr ns; 4973 4974 if (cur == NULL) return; 4975 switch(cur->type) { 4976 case XML_TEXT_NODE: 4977 case XML_CDATA_SECTION_NODE: 4978 case XML_COMMENT_NODE: 4979 case XML_DOCUMENT_NODE: 4980 case XML_DOCUMENT_TYPE_NODE: 4981 case XML_DOCUMENT_FRAG_NODE: 4982 case XML_NOTATION_NODE: 4983 case XML_HTML_DOCUMENT_NODE: 4984 case XML_DTD_NODE: 4985 case XML_ELEMENT_DECL: 4986 case XML_ATTRIBUTE_DECL: 4987 case XML_ENTITY_DECL: 4988 case XML_PI_NODE: 4989 case XML_ENTITY_REF_NODE: 4990 case XML_ENTITY_NODE: 4991 case XML_NAMESPACE_DECL: 4992 #ifdef LIBXML_DOCB_ENABLED 4993 case XML_DOCB_DOCUMENT_NODE: 4994 #endif 4995 case XML_XINCLUDE_START: 4996 case XML_XINCLUDE_END: 4997 return; 4998 case XML_ELEMENT_NODE: 4999 case XML_ATTRIBUTE_NODE: 5000 break; 5001 } 5002 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE); 5003 if (ns == NULL) 5004 return; 5005 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang); 5006 } 5007 #endif /* LIBXML_TREE_ENABLED */ 5008 5009 /** 5010 * xmlNodeGetLang: 5011 * @cur: the node being checked 5012 * 5013 * Searches the language of a node, i.e. the values of the xml:lang 5014 * attribute or the one carried by the nearest ancestor. 5015 * 5016 * Returns a pointer to the lang value, or NULL if not found 5017 * It's up to the caller to free the memory with xmlFree(). 5018 */ 5019 xmlChar * 5020 xmlNodeGetLang(const xmlNode *cur) { 5021 xmlChar *lang; 5022 5023 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) 5024 return(NULL); 5025 while (cur != NULL) { 5026 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE); 5027 if (lang != NULL) 5028 return(lang); 5029 cur = cur->parent; 5030 } 5031 return(NULL); 5032 } 5033 5034 5035 #ifdef LIBXML_TREE_ENABLED 5036 /** 5037 * xmlNodeSetSpacePreserve: 5038 * @cur: the node being changed 5039 * @val: the xml:space value ("0": default, 1: "preserve") 5040 * 5041 * Set (or reset) the space preserving behaviour of a node, i.e. the 5042 * value of the xml:space attribute. 5043 */ 5044 void 5045 xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) { 5046 xmlNsPtr ns; 5047 5048 if (cur == NULL) return; 5049 switch(cur->type) { 5050 case XML_TEXT_NODE: 5051 case XML_CDATA_SECTION_NODE: 5052 case XML_COMMENT_NODE: 5053 case XML_DOCUMENT_NODE: 5054 case XML_DOCUMENT_TYPE_NODE: 5055 case XML_DOCUMENT_FRAG_NODE: 5056 case XML_NOTATION_NODE: 5057 case XML_HTML_DOCUMENT_NODE: 5058 case XML_DTD_NODE: 5059 case XML_ELEMENT_DECL: 5060 case XML_ATTRIBUTE_DECL: 5061 case XML_ENTITY_DECL: 5062 case XML_PI_NODE: 5063 case XML_ENTITY_REF_NODE: 5064 case XML_ENTITY_NODE: 5065 case XML_NAMESPACE_DECL: 5066 case XML_XINCLUDE_START: 5067 case XML_XINCLUDE_END: 5068 #ifdef LIBXML_DOCB_ENABLED 5069 case XML_DOCB_DOCUMENT_NODE: 5070 #endif 5071 return; 5072 case XML_ELEMENT_NODE: 5073 case XML_ATTRIBUTE_NODE: 5074 break; 5075 } 5076 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE); 5077 if (ns == NULL) 5078 return; 5079 switch (val) { 5080 case 0: 5081 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default"); 5082 break; 5083 case 1: 5084 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve"); 5085 break; 5086 } 5087 } 5088 #endif /* LIBXML_TREE_ENABLED */ 5089 5090 /** 5091 * xmlNodeGetSpacePreserve: 5092 * @cur: the node being checked 5093 * 5094 * Searches the space preserving behaviour of a node, i.e. the values 5095 * of the xml:space attribute or the one carried by the nearest 5096 * ancestor. 5097 * 5098 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve" 5099 */ 5100 int 5101 xmlNodeGetSpacePreserve(const xmlNode *cur) { 5102 xmlChar *space; 5103 5104 if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE)) 5105 return(-1); 5106 while (cur != NULL) { 5107 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE); 5108 if (space != NULL) { 5109 if (xmlStrEqual(space, BAD_CAST "preserve")) { 5110 xmlFree(space); 5111 return(1); 5112 } 5113 if (xmlStrEqual(space, BAD_CAST "default")) { 5114 xmlFree(space); 5115 return(0); 5116 } 5117 xmlFree(space); 5118 } 5119 cur = cur->parent; 5120 } 5121 return(-1); 5122 } 5123 5124 #ifdef LIBXML_TREE_ENABLED 5125 /** 5126 * xmlNodeSetName: 5127 * @cur: the node being changed 5128 * @name: the new tag name 5129 * 5130 * Set (or reset) the name of a node. 5131 */ 5132 void 5133 xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) { 5134 xmlDocPtr doc; 5135 xmlDictPtr dict; 5136 const xmlChar *freeme = NULL; 5137 5138 if (cur == NULL) return; 5139 if (name == NULL) return; 5140 switch(cur->type) { 5141 case XML_TEXT_NODE: 5142 case XML_CDATA_SECTION_NODE: 5143 case XML_COMMENT_NODE: 5144 case XML_DOCUMENT_TYPE_NODE: 5145 case XML_DOCUMENT_FRAG_NODE: 5146 case XML_NOTATION_NODE: 5147 case XML_HTML_DOCUMENT_NODE: 5148 case XML_NAMESPACE_DECL: 5149 case XML_XINCLUDE_START: 5150 case XML_XINCLUDE_END: 5151 #ifdef LIBXML_DOCB_ENABLED 5152 case XML_DOCB_DOCUMENT_NODE: 5153 #endif 5154 return; 5155 case XML_ELEMENT_NODE: 5156 case XML_ATTRIBUTE_NODE: 5157 case XML_PI_NODE: 5158 case XML_ENTITY_REF_NODE: 5159 case XML_ENTITY_NODE: 5160 case XML_DTD_NODE: 5161 case XML_DOCUMENT_NODE: 5162 case XML_ELEMENT_DECL: 5163 case XML_ATTRIBUTE_DECL: 5164 case XML_ENTITY_DECL: 5165 break; 5166 } 5167 doc = cur->doc; 5168 if (doc != NULL) 5169 dict = doc->dict; 5170 else 5171 dict = NULL; 5172 if (dict != NULL) { 5173 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name))) 5174 freeme = cur->name; 5175 cur->name = xmlDictLookup(dict, name, -1); 5176 } else { 5177 if (cur->name != NULL) 5178 freeme = cur->name; 5179 cur->name = xmlStrdup(name); 5180 } 5181 5182 if (freeme) 5183 xmlFree((xmlChar *) freeme); 5184 } 5185 #endif 5186 5187 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) 5188 /** 5189 * xmlNodeSetBase: 5190 * @cur: the node being changed 5191 * @uri: the new base URI 5192 * 5193 * Set (or reset) the base URI of a node, i.e. the value of the 5194 * xml:base attribute. 5195 */ 5196 void 5197 xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) { 5198 xmlNsPtr ns; 5199 xmlChar* fixed; 5200 5201 if (cur == NULL) return; 5202 switch(cur->type) { 5203 case XML_TEXT_NODE: 5204 case XML_CDATA_SECTION_NODE: 5205 case XML_COMMENT_NODE: 5206 case XML_DOCUMENT_TYPE_NODE: 5207 case XML_DOCUMENT_FRAG_NODE: 5208 case XML_NOTATION_NODE: 5209 case XML_DTD_NODE: 5210 case XML_ELEMENT_DECL: 5211 case XML_ATTRIBUTE_DECL: 5212 case XML_ENTITY_DECL: 5213 case XML_PI_NODE: 5214 case XML_ENTITY_REF_NODE: 5215 case XML_ENTITY_NODE: 5216 case XML_NAMESPACE_DECL: 5217 case XML_XINCLUDE_START: 5218 case XML_XINCLUDE_END: 5219 return; 5220 case XML_ELEMENT_NODE: 5221 case XML_ATTRIBUTE_NODE: 5222 break; 5223 case XML_DOCUMENT_NODE: 5224 #ifdef LIBXML_DOCB_ENABLED 5225 case XML_DOCB_DOCUMENT_NODE: 5226 #endif 5227 case XML_HTML_DOCUMENT_NODE: { 5228 xmlDocPtr doc = (xmlDocPtr) cur; 5229 5230 if (doc->URL != NULL) 5231 xmlFree((xmlChar *) doc->URL); 5232 if (uri == NULL) 5233 doc->URL = NULL; 5234 else 5235 doc->URL = xmlPathToURI(uri); 5236 return; 5237 } 5238 } 5239 5240 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE); 5241 if (ns == NULL) 5242 return; 5243 fixed = xmlPathToURI(uri); 5244 if (fixed != NULL) { 5245 xmlSetNsProp(cur, ns, BAD_CAST "base", fixed); 5246 xmlFree(fixed); 5247 } else { 5248 xmlSetNsProp(cur, ns, BAD_CAST "base", uri); 5249 } 5250 } 5251 #endif /* LIBXML_TREE_ENABLED */ 5252 5253 /** 5254 * xmlNodeGetBase: 5255 * @doc: the document the node pertains to 5256 * @cur: the node being checked 5257 * 5258 * Searches for the BASE URL. The code should work on both XML 5259 * and HTML document even if base mechanisms are completely different. 5260 * It returns the base as defined in RFC 2396 sections 5261 * 5.1.1. Base URI within Document Content 5262 * and 5263 * 5.1.2. Base URI from the Encapsulating Entity 5264 * However it does not return the document base (5.1.3), use 5265 * doc->URL in this case 5266 * 5267 * Returns a pointer to the base URL, or NULL if not found 5268 * It's up to the caller to free the memory with xmlFree(). 5269 */ 5270 xmlChar * 5271 xmlNodeGetBase(const xmlDoc *doc, const xmlNode *cur) { 5272 xmlChar *oldbase = NULL; 5273 xmlChar *base, *newbase; 5274 5275 if ((cur == NULL) && (doc == NULL)) 5276 return(NULL); 5277 if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL)) 5278 return(NULL); 5279 if (doc == NULL) doc = cur->doc; 5280 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) { 5281 cur = doc->children; 5282 while ((cur != NULL) && (cur->name != NULL)) { 5283 if (cur->type != XML_ELEMENT_NODE) { 5284 cur = cur->next; 5285 continue; 5286 } 5287 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) { 5288 cur = cur->children; 5289 continue; 5290 } 5291 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) { 5292 cur = cur->children; 5293 continue; 5294 } 5295 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) { 5296 return(xmlGetProp(cur, BAD_CAST "href")); 5297 } 5298 cur = cur->next; 5299 } 5300 return(NULL); 5301 } 5302 while (cur != NULL) { 5303 if (cur->type == XML_ENTITY_DECL) { 5304 xmlEntityPtr ent = (xmlEntityPtr) cur; 5305 return(xmlStrdup(ent->URI)); 5306 } 5307 if (cur->type == XML_ELEMENT_NODE) { 5308 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE); 5309 if (base != NULL) { 5310 if (oldbase != NULL) { 5311 newbase = xmlBuildURI(oldbase, base); 5312 if (newbase != NULL) { 5313 xmlFree(oldbase); 5314 xmlFree(base); 5315 oldbase = newbase; 5316 } else { 5317 xmlFree(oldbase); 5318 xmlFree(base); 5319 return(NULL); 5320 } 5321 } else { 5322 oldbase = base; 5323 } 5324 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) || 5325 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) || 5326 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4))) 5327 return(oldbase); 5328 } 5329 } 5330 cur = cur->parent; 5331 } 5332 if ((doc != NULL) && (doc->URL != NULL)) { 5333 if (oldbase == NULL) 5334 return(xmlStrdup(doc->URL)); 5335 newbase = xmlBuildURI(oldbase, doc->URL); 5336 xmlFree(oldbase); 5337 return(newbase); 5338 } 5339 return(oldbase); 5340 } 5341 5342 /** 5343 * xmlNodeBufGetContent: 5344 * @buffer: a buffer 5345 * @cur: the node being read 5346 * 5347 * Read the value of a node @cur, this can be either the text carried 5348 * directly by this node if it's a TEXT node or the aggregate string 5349 * of the values carried by this node child's (TEXT and ENTITY_REF). 5350 * Entity references are substituted. 5351 * Fills up the buffer @buffer with this value 5352 * 5353 * Returns 0 in case of success and -1 in case of error. 5354 */ 5355 int 5356 xmlNodeBufGetContent(xmlBufferPtr buffer, const xmlNode *cur) 5357 { 5358 xmlBufPtr buf; 5359 int ret; 5360 5361 if ((cur == NULL) || (buffer == NULL)) return(-1); 5362 buf = xmlBufFromBuffer(buffer); 5363 ret = xmlBufGetNodeContent(buf, cur); 5364 buffer = xmlBufBackToBuffer(buf); 5365 if ((ret < 0) || (buffer == NULL)) 5366 return(-1); 5367 return(0); 5368 } 5369 5370 /** 5371 * xmlBufGetNodeContent: 5372 * @buf: a buffer xmlBufPtr 5373 * @cur: the node being read 5374 * 5375 * Read the value of a node @cur, this can be either the text carried 5376 * directly by this node if it's a TEXT node or the aggregate string 5377 * of the values carried by this node child's (TEXT and ENTITY_REF). 5378 * Entity references are substituted. 5379 * Fills up the buffer @buf with this value 5380 * 5381 * Returns 0 in case of success and -1 in case of error. 5382 */ 5383 int 5384 xmlBufGetNodeContent(xmlBufPtr buf, const xmlNode *cur) 5385 { 5386 if ((cur == NULL) || (buf == NULL)) return(-1); 5387 switch (cur->type) { 5388 case XML_CDATA_SECTION_NODE: 5389 case XML_TEXT_NODE: 5390 xmlBufCat(buf, cur->content); 5391 break; 5392 case XML_DOCUMENT_FRAG_NODE: 5393 case XML_ELEMENT_NODE:{ 5394 const xmlNode *tmp = cur; 5395 5396 while (tmp != NULL) { 5397 switch (tmp->type) { 5398 case XML_CDATA_SECTION_NODE: 5399 case XML_TEXT_NODE: 5400 if (tmp->content != NULL) 5401 xmlBufCat(buf, tmp->content); 5402 break; 5403 case XML_ENTITY_REF_NODE: 5404 xmlBufGetNodeContent(buf, tmp); 5405 break; 5406 default: 5407 break; 5408 } 5409 /* 5410 * Skip to next node 5411 */ 5412 if (tmp->children != NULL) { 5413 if (tmp->children->type != XML_ENTITY_DECL) { 5414 tmp = tmp->children; 5415 continue; 5416 } 5417 } 5418 if (tmp == cur) 5419 break; 5420 5421 if (tmp->next != NULL) { 5422 tmp = tmp->next; 5423 continue; 5424 } 5425 5426 do { 5427 tmp = tmp->parent; 5428 if (tmp == NULL) 5429 break; 5430 if (tmp == cur) { 5431 tmp = NULL; 5432 break; 5433 } 5434 if (tmp->next != NULL) { 5435 tmp = tmp->next; 5436 break; 5437 } 5438 } while (tmp != NULL); 5439 } 5440 break; 5441 } 5442 case XML_ATTRIBUTE_NODE:{ 5443 xmlAttrPtr attr = (xmlAttrPtr) cur; 5444 xmlNodePtr tmp = attr->children; 5445 5446 while (tmp != NULL) { 5447 if (tmp->type == XML_TEXT_NODE) 5448 xmlBufCat(buf, tmp->content); 5449 else 5450 xmlBufGetNodeContent(buf, tmp); 5451 tmp = tmp->next; 5452 } 5453 break; 5454 } 5455 case XML_COMMENT_NODE: 5456 case XML_PI_NODE: 5457 xmlBufCat(buf, cur->content); 5458 break; 5459 case XML_ENTITY_REF_NODE:{ 5460 xmlEntityPtr ent; 5461 xmlNodePtr tmp; 5462 5463 /* lookup entity declaration */ 5464 ent = xmlGetDocEntity(cur->doc, cur->name); 5465 if (ent == NULL) 5466 return(-1); 5467 5468 /* an entity content can be any "well balanced chunk", 5469 * i.e. the result of the content [43] production: 5470 * http://www.w3.org/TR/REC-xml#NT-content 5471 * -> we iterate through child nodes and recursive call 5472 * xmlNodeGetContent() which handles all possible node types */ 5473 tmp = ent->children; 5474 while (tmp) { 5475 xmlBufGetNodeContent(buf, tmp); 5476 tmp = tmp->next; 5477 } 5478 break; 5479 } 5480 case XML_ENTITY_NODE: 5481 case XML_DOCUMENT_TYPE_NODE: 5482 case XML_NOTATION_NODE: 5483 case XML_DTD_NODE: 5484 case XML_XINCLUDE_START: 5485 case XML_XINCLUDE_END: 5486 break; 5487 case XML_DOCUMENT_NODE: 5488 #ifdef LIBXML_DOCB_ENABLED 5489 case XML_DOCB_DOCUMENT_NODE: 5490 #endif 5491 case XML_HTML_DOCUMENT_NODE: 5492 cur = cur->children; 5493 while (cur!= NULL) { 5494 if ((cur->type == XML_ELEMENT_NODE) || 5495 (cur->type == XML_TEXT_NODE) || 5496 (cur->type == XML_CDATA_SECTION_NODE)) { 5497 xmlBufGetNodeContent(buf, cur); 5498 } 5499 cur = cur->next; 5500 } 5501 break; 5502 case XML_NAMESPACE_DECL: 5503 xmlBufCat(buf, ((xmlNsPtr) cur)->href); 5504 break; 5505 case XML_ELEMENT_DECL: 5506 case XML_ATTRIBUTE_DECL: 5507 case XML_ENTITY_DECL: 5508 break; 5509 } 5510 return(0); 5511 } 5512 5513 /** 5514 * xmlNodeGetContent: 5515 * @cur: the node being read 5516 * 5517 * Read the value of a node, this can be either the text carried 5518 * directly by this node if it's a TEXT node or the aggregate string 5519 * of the values carried by this node child's (TEXT and ENTITY_REF). 5520 * Entity references are substituted. 5521 * Returns a new #xmlChar * or NULL if no content is available. 5522 * It's up to the caller to free the memory with xmlFree(). 5523 */ 5524 xmlChar * 5525 xmlNodeGetContent(const xmlNode *cur) 5526 { 5527 if (cur == NULL) 5528 return (NULL); 5529 switch (cur->type) { 5530 case XML_DOCUMENT_FRAG_NODE: 5531 case XML_ELEMENT_NODE:{ 5532 xmlBufPtr buf; 5533 xmlChar *ret; 5534 5535 buf = xmlBufCreateSize(64); 5536 if (buf == NULL) 5537 return (NULL); 5538 xmlBufGetNodeContent(buf, cur); 5539 ret = xmlBufDetach(buf); 5540 xmlBufFree(buf); 5541 return (ret); 5542 } 5543 case XML_ATTRIBUTE_NODE: 5544 return(xmlGetPropNodeValueInternal((xmlAttrPtr) cur)); 5545 case XML_COMMENT_NODE: 5546 case XML_PI_NODE: 5547 if (cur->content != NULL) 5548 return (xmlStrdup(cur->content)); 5549 return (NULL); 5550 case XML_ENTITY_REF_NODE:{ 5551 xmlEntityPtr ent; 5552 xmlBufPtr buf; 5553 xmlChar *ret; 5554 5555 /* lookup entity declaration */ 5556 ent = xmlGetDocEntity(cur->doc, cur->name); 5557 if (ent == NULL) 5558 return (NULL); 5559 5560 buf = xmlBufCreate(); 5561 if (buf == NULL) 5562 return (NULL); 5563 5564 xmlBufGetNodeContent(buf, cur); 5565 5566 ret = xmlBufDetach(buf); 5567 xmlBufFree(buf); 5568 return (ret); 5569 } 5570 case XML_ENTITY_NODE: 5571 case XML_DOCUMENT_TYPE_NODE: 5572 case XML_NOTATION_NODE: 5573 case XML_DTD_NODE: 5574 case XML_XINCLUDE_START: 5575 case XML_XINCLUDE_END: 5576 return (NULL); 5577 case XML_DOCUMENT_NODE: 5578 #ifdef LIBXML_DOCB_ENABLED 5579 case XML_DOCB_DOCUMENT_NODE: 5580 #endif 5581 case XML_HTML_DOCUMENT_NODE: { 5582 xmlBufPtr buf; 5583 xmlChar *ret; 5584 5585 buf = xmlBufCreate(); 5586 if (buf == NULL) 5587 return (NULL); 5588 5589 xmlBufGetNodeContent(buf, (xmlNodePtr) cur); 5590 5591 ret = xmlBufDetach(buf); 5592 xmlBufFree(buf); 5593 return (ret); 5594 } 5595 case XML_NAMESPACE_DECL: { 5596 xmlChar *tmp; 5597 5598 tmp = xmlStrdup(((xmlNsPtr) cur)->href); 5599 return (tmp); 5600 } 5601 case XML_ELEMENT_DECL: 5602 /* TODO !!! */ 5603 return (NULL); 5604 case XML_ATTRIBUTE_DECL: 5605 /* TODO !!! */ 5606 return (NULL); 5607 case XML_ENTITY_DECL: 5608 /* TODO !!! */ 5609 return (NULL); 5610 case XML_CDATA_SECTION_NODE: 5611 case XML_TEXT_NODE: 5612 if (cur->content != NULL) 5613 return (xmlStrdup(cur->content)); 5614 return (NULL); 5615 } 5616 return (NULL); 5617 } 5618 5619 /** 5620 * xmlNodeSetContent: 5621 * @cur: the node being modified 5622 * @content: the new value of the content 5623 * 5624 * Replace the content of a node. 5625 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity 5626 * references, but XML special chars need to be escaped first by using 5627 * xmlEncodeEntitiesReentrant() resp. xmlEncodeSpecialChars(). 5628 */ 5629 void 5630 xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) { 5631 if (cur == NULL) { 5632 #ifdef DEBUG_TREE 5633 xmlGenericError(xmlGenericErrorContext, 5634 "xmlNodeSetContent : node == NULL\n"); 5635 #endif 5636 return; 5637 } 5638 switch (cur->type) { 5639 case XML_DOCUMENT_FRAG_NODE: 5640 case XML_ELEMENT_NODE: 5641 case XML_ATTRIBUTE_NODE: 5642 if (cur->children != NULL) xmlFreeNodeList(cur->children); 5643 cur->children = xmlStringGetNodeList(cur->doc, content); 5644 UPDATE_LAST_CHILD_AND_PARENT(cur) 5645 break; 5646 case XML_TEXT_NODE: 5647 case XML_CDATA_SECTION_NODE: 5648 case XML_ENTITY_REF_NODE: 5649 case XML_ENTITY_NODE: 5650 case XML_PI_NODE: 5651 case XML_COMMENT_NODE: 5652 if ((cur->content != NULL) && 5653 (cur->content != (xmlChar *) &(cur->properties))) { 5654 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) && 5655 (xmlDictOwns(cur->doc->dict, cur->content)))) 5656 xmlFree(cur->content); 5657 } 5658 if (cur->children != NULL) xmlFreeNodeList(cur->children); 5659 cur->last = cur->children = NULL; 5660 if (content != NULL) { 5661 cur->content = xmlStrdup(content); 5662 } else 5663 cur->content = NULL; 5664 cur->properties = NULL; 5665 cur->nsDef = NULL; 5666 break; 5667 case XML_DOCUMENT_NODE: 5668 case XML_HTML_DOCUMENT_NODE: 5669 case XML_DOCUMENT_TYPE_NODE: 5670 case XML_XINCLUDE_START: 5671 case XML_XINCLUDE_END: 5672 #ifdef LIBXML_DOCB_ENABLED 5673 case XML_DOCB_DOCUMENT_NODE: 5674 #endif 5675 break; 5676 case XML_NOTATION_NODE: 5677 break; 5678 case XML_DTD_NODE: 5679 break; 5680 case XML_NAMESPACE_DECL: 5681 break; 5682 case XML_ELEMENT_DECL: 5683 /* TODO !!! */ 5684 break; 5685 case XML_ATTRIBUTE_DECL: 5686 /* TODO !!! */ 5687 break; 5688 case XML_ENTITY_DECL: 5689 /* TODO !!! */ 5690 break; 5691 } 5692 } 5693 5694 #ifdef LIBXML_TREE_ENABLED 5695 /** 5696 * xmlNodeSetContentLen: 5697 * @cur: the node being modified 5698 * @content: the new value of the content 5699 * @len: the size of @content 5700 * 5701 * Replace the content of a node. 5702 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity 5703 * references, but XML special chars need to be escaped first by using 5704 * xmlEncodeEntitiesReentrant() resp. xmlEncodeSpecialChars(). 5705 */ 5706 void 5707 xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) { 5708 if (cur == NULL) { 5709 #ifdef DEBUG_TREE 5710 xmlGenericError(xmlGenericErrorContext, 5711 "xmlNodeSetContentLen : node == NULL\n"); 5712 #endif 5713 return; 5714 } 5715 switch (cur->type) { 5716 case XML_DOCUMENT_FRAG_NODE: 5717 case XML_ELEMENT_NODE: 5718 case XML_ATTRIBUTE_NODE: 5719 if (cur->children != NULL) xmlFreeNodeList(cur->children); 5720 cur->children = xmlStringLenGetNodeList(cur->doc, content, len); 5721 UPDATE_LAST_CHILD_AND_PARENT(cur) 5722 break; 5723 case XML_TEXT_NODE: 5724 case XML_CDATA_SECTION_NODE: 5725 case XML_ENTITY_REF_NODE: 5726 case XML_ENTITY_NODE: 5727 case XML_PI_NODE: 5728 case XML_COMMENT_NODE: 5729 case XML_NOTATION_NODE: 5730 if ((cur->content != NULL) && 5731 (cur->content != (xmlChar *) &(cur->properties))) { 5732 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) && 5733 (xmlDictOwns(cur->doc->dict, cur->content)))) 5734 xmlFree(cur->content); 5735 } 5736 if (cur->children != NULL) xmlFreeNodeList(cur->children); 5737 cur->children = cur->last = NULL; 5738 if (content != NULL) { 5739 cur->content = xmlStrndup(content, len); 5740 } else 5741 cur->content = NULL; 5742 cur->properties = NULL; 5743 cur->nsDef = NULL; 5744 break; 5745 case XML_DOCUMENT_NODE: 5746 case XML_DTD_NODE: 5747 case XML_HTML_DOCUMENT_NODE: 5748 case XML_DOCUMENT_TYPE_NODE: 5749 case XML_NAMESPACE_DECL: 5750 case XML_XINCLUDE_START: 5751 case XML_XINCLUDE_END: 5752 #ifdef LIBXML_DOCB_ENABLED 5753 case XML_DOCB_DOCUMENT_NODE: 5754 #endif 5755 break; 5756 case XML_ELEMENT_DECL: 5757 /* TODO !!! */ 5758 break; 5759 case XML_ATTRIBUTE_DECL: 5760 /* TODO !!! */ 5761 break; 5762 case XML_ENTITY_DECL: 5763 /* TODO !!! */ 5764 break; 5765 } 5766 } 5767 #endif /* LIBXML_TREE_ENABLED */ 5768 5769 /** 5770 * xmlNodeAddContentLen: 5771 * @cur: the node being modified 5772 * @content: extra content 5773 * @len: the size of @content 5774 * 5775 * Append the extra substring to the node content. 5776 * NOTE: In contrast to xmlNodeSetContentLen(), @content is supposed to be 5777 * raw text, so unescaped XML special chars are allowed, entity 5778 * references are not supported. 5779 */ 5780 void 5781 xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) { 5782 if (cur == NULL) { 5783 #ifdef DEBUG_TREE 5784 xmlGenericError(xmlGenericErrorContext, 5785 "xmlNodeAddContentLen : node == NULL\n"); 5786 #endif 5787 return; 5788 } 5789 if (len <= 0) return; 5790 switch (cur->type) { 5791 case XML_DOCUMENT_FRAG_NODE: 5792 case XML_ELEMENT_NODE: { 5793 xmlNodePtr last, newNode, tmp; 5794 5795 last = cur->last; 5796 newNode = xmlNewTextLen(content, len); 5797 if (newNode != NULL) { 5798 tmp = xmlAddChild(cur, newNode); 5799 if (tmp != newNode) 5800 return; 5801 if ((last != NULL) && (last->next == newNode)) { 5802 xmlTextMerge(last, newNode); 5803 } 5804 } 5805 break; 5806 } 5807 case XML_ATTRIBUTE_NODE: 5808 break; 5809 case XML_TEXT_NODE: 5810 case XML_CDATA_SECTION_NODE: 5811 case XML_ENTITY_REF_NODE: 5812 case XML_ENTITY_NODE: 5813 case XML_PI_NODE: 5814 case XML_COMMENT_NODE: 5815 case XML_NOTATION_NODE: 5816 if (content != NULL) { 5817 if ((cur->content == (xmlChar *) &(cur->properties)) || 5818 ((cur->doc != NULL) && (cur->doc->dict != NULL) && 5819 xmlDictOwns(cur->doc->dict, cur->content))) { 5820 cur->content = xmlStrncatNew(cur->content, content, len); 5821 cur->properties = NULL; 5822 cur->nsDef = NULL; 5823 break; 5824 } 5825 cur->content = xmlStrncat(cur->content, content, len); 5826 } 5827 case XML_DOCUMENT_NODE: 5828 case XML_DTD_NODE: 5829 case XML_HTML_DOCUMENT_NODE: 5830 case XML_DOCUMENT_TYPE_NODE: 5831 case XML_NAMESPACE_DECL: 5832 case XML_XINCLUDE_START: 5833 case XML_XINCLUDE_END: 5834 #ifdef LIBXML_DOCB_ENABLED 5835 case XML_DOCB_DOCUMENT_NODE: 5836 #endif 5837 break; 5838 case XML_ELEMENT_DECL: 5839 case XML_ATTRIBUTE_DECL: 5840 case XML_ENTITY_DECL: 5841 break; 5842 } 5843 } 5844 5845 /** 5846 * xmlNodeAddContent: 5847 * @cur: the node being modified 5848 * @content: extra content 5849 * 5850 * Append the extra substring to the node content. 5851 * NOTE: In contrast to xmlNodeSetContent(), @content is supposed to be 5852 * raw text, so unescaped XML special chars are allowed, entity 5853 * references are not supported. 5854 */ 5855 void 5856 xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) { 5857 int len; 5858 5859 if (cur == NULL) { 5860 #ifdef DEBUG_TREE 5861 xmlGenericError(xmlGenericErrorContext, 5862 "xmlNodeAddContent : node == NULL\n"); 5863 #endif 5864 return; 5865 } 5866 if (content == NULL) return; 5867 len = xmlStrlen(content); 5868 xmlNodeAddContentLen(cur, content, len); 5869 } 5870 5871 /** 5872 * xmlTextMerge: 5873 * @first: the first text node 5874 * @second: the second text node being merged 5875 * 5876 * Merge two text nodes into one 5877 * Returns the first text node augmented 5878 */ 5879 xmlNodePtr 5880 xmlTextMerge(xmlNodePtr first, xmlNodePtr second) { 5881 if (first == NULL) return(second); 5882 if (second == NULL) return(first); 5883 if (first->type != XML_TEXT_NODE) return(first); 5884 if (second->type != XML_TEXT_NODE) return(first); 5885 if (second->name != first->name) 5886 return(first); 5887 xmlNodeAddContent(first, second->content); 5888 xmlUnlinkNode(second); 5889 xmlFreeNode(second); 5890 return(first); 5891 } 5892 5893 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) 5894 /** 5895 * xmlGetNsList: 5896 * @doc: the document 5897 * @node: the current node 5898 * 5899 * Search all the namespace applying to a given element. 5900 * Returns an NULL terminated array of all the #xmlNsPtr found 5901 * that need to be freed by the caller or NULL if no 5902 * namespace if defined 5903 */ 5904 xmlNsPtr * 5905 xmlGetNsList(const xmlDoc *doc ATTRIBUTE_UNUSED, const xmlNode *node) 5906 { 5907 xmlNsPtr cur; 5908 xmlNsPtr *ret = NULL; 5909 int nbns = 0; 5910 int maxns = 10; 5911 int i; 5912 5913 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) 5914 return(NULL); 5915 5916 while (node != NULL) { 5917 if (node->type == XML_ELEMENT_NODE) { 5918 cur = node->nsDef; 5919 while (cur != NULL) { 5920 if (ret == NULL) { 5921 ret = 5922 (xmlNsPtr *) xmlMalloc((maxns + 1) * 5923 sizeof(xmlNsPtr)); 5924 if (ret == NULL) { 5925 xmlTreeErrMemory("getting namespace list"); 5926 return (NULL); 5927 } 5928 ret[nbns] = NULL; 5929 } 5930 for (i = 0; i < nbns; i++) { 5931 if ((cur->prefix == ret[i]->prefix) || 5932 (xmlStrEqual(cur->prefix, ret[i]->prefix))) 5933 break; 5934 } 5935 if (i >= nbns) { 5936 if (nbns >= maxns) { 5937 maxns *= 2; 5938 ret = (xmlNsPtr *) xmlRealloc(ret, 5939 (maxns + 5940 1) * 5941 sizeof(xmlNsPtr)); 5942 if (ret == NULL) { 5943 xmlTreeErrMemory("getting namespace list"); 5944 return (NULL); 5945 } 5946 } 5947 ret[nbns++] = cur; 5948 ret[nbns] = NULL; 5949 } 5950 5951 cur = cur->next; 5952 } 5953 } 5954 node = node->parent; 5955 } 5956 return (ret); 5957 } 5958 #endif /* LIBXML_TREE_ENABLED */ 5959 5960 /* 5961 * xmlTreeEnsureXMLDecl: 5962 * @doc: the doc 5963 * 5964 * Ensures that there is an XML namespace declaration on the doc. 5965 * 5966 * Returns the XML ns-struct or NULL on API and internal errors. 5967 */ 5968 static xmlNsPtr 5969 xmlTreeEnsureXMLDecl(xmlDocPtr doc) 5970 { 5971 if (doc == NULL) 5972 return (NULL); 5973 if (doc->oldNs != NULL) 5974 return (doc->oldNs); 5975 { 5976 xmlNsPtr ns; 5977 ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 5978 if (ns == NULL) { 5979 xmlTreeErrMemory( 5980 "allocating the XML namespace"); 5981 return (NULL); 5982 } 5983 memset(ns, 0, sizeof(xmlNs)); 5984 ns->type = XML_LOCAL_NAMESPACE; 5985 ns->href = xmlStrdup(XML_XML_NAMESPACE); 5986 ns->prefix = xmlStrdup((const xmlChar *)"xml"); 5987 doc->oldNs = ns; 5988 return (ns); 5989 } 5990 } 5991 5992 /** 5993 * xmlSearchNs: 5994 * @doc: the document 5995 * @node: the current node 5996 * @nameSpace: the namespace prefix 5997 * 5998 * Search a Ns registered under a given name space for a document. 5999 * recurse on the parents until it finds the defined namespace 6000 * or return NULL otherwise. 6001 * @nameSpace can be NULL, this is a search for the default namespace. 6002 * We don't allow to cross entities boundaries. If you don't declare 6003 * the namespace within those you will be in troubles !!! A warning 6004 * is generated to cover this case. 6005 * 6006 * Returns the namespace pointer or NULL. 6007 */ 6008 xmlNsPtr 6009 xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) { 6010 6011 xmlNsPtr cur; 6012 const xmlNode *orig = node; 6013 6014 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) return(NULL); 6015 if ((nameSpace != NULL) && 6016 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) { 6017 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) { 6018 /* 6019 * The XML-1.0 namespace is normally held on the root 6020 * element. In this case exceptionally create it on the 6021 * node element. 6022 */ 6023 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 6024 if (cur == NULL) { 6025 xmlTreeErrMemory("searching namespace"); 6026 return(NULL); 6027 } 6028 memset(cur, 0, sizeof(xmlNs)); 6029 cur->type = XML_LOCAL_NAMESPACE; 6030 cur->href = xmlStrdup(XML_XML_NAMESPACE); 6031 cur->prefix = xmlStrdup((const xmlChar *)"xml"); 6032 cur->next = node->nsDef; 6033 node->nsDef = cur; 6034 return(cur); 6035 } 6036 if (doc == NULL) { 6037 doc = node->doc; 6038 if (doc == NULL) 6039 return(NULL); 6040 } 6041 /* 6042 * Return the XML namespace declaration held by the doc. 6043 */ 6044 if (doc->oldNs == NULL) 6045 return(xmlTreeEnsureXMLDecl(doc)); 6046 else 6047 return(doc->oldNs); 6048 } 6049 while (node != NULL) { 6050 if ((node->type == XML_ENTITY_REF_NODE) || 6051 (node->type == XML_ENTITY_NODE) || 6052 (node->type == XML_ENTITY_DECL)) 6053 return(NULL); 6054 if (node->type == XML_ELEMENT_NODE) { 6055 cur = node->nsDef; 6056 while (cur != NULL) { 6057 if ((cur->prefix == NULL) && (nameSpace == NULL) && 6058 (cur->href != NULL)) 6059 return(cur); 6060 if ((cur->prefix != NULL) && (nameSpace != NULL) && 6061 (cur->href != NULL) && 6062 (xmlStrEqual(cur->prefix, nameSpace))) 6063 return(cur); 6064 cur = cur->next; 6065 } 6066 if (orig != node) { 6067 cur = node->ns; 6068 if (cur != NULL) { 6069 if ((cur->prefix == NULL) && (nameSpace == NULL) && 6070 (cur->href != NULL)) 6071 return(cur); 6072 if ((cur->prefix != NULL) && (nameSpace != NULL) && 6073 (cur->href != NULL) && 6074 (xmlStrEqual(cur->prefix, nameSpace))) 6075 return(cur); 6076 } 6077 } 6078 } 6079 node = node->parent; 6080 } 6081 return(NULL); 6082 } 6083 6084 /** 6085 * xmlNsInScope: 6086 * @doc: the document 6087 * @node: the current node 6088 * @ancestor: the ancestor carrying the namespace 6089 * @prefix: the namespace prefix 6090 * 6091 * Verify that the given namespace held on @ancestor is still in scope 6092 * on node. 6093 * 6094 * Returns 1 if true, 0 if false and -1 in case of error. 6095 */ 6096 static int 6097 xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node, 6098 xmlNodePtr ancestor, const xmlChar * prefix) 6099 { 6100 xmlNsPtr tst; 6101 6102 while ((node != NULL) && (node != ancestor)) { 6103 if ((node->type == XML_ENTITY_REF_NODE) || 6104 (node->type == XML_ENTITY_NODE) || 6105 (node->type == XML_ENTITY_DECL)) 6106 return (-1); 6107 if (node->type == XML_ELEMENT_NODE) { 6108 tst = node->nsDef; 6109 while (tst != NULL) { 6110 if ((tst->prefix == NULL) 6111 && (prefix == NULL)) 6112 return (0); 6113 if ((tst->prefix != NULL) 6114 && (prefix != NULL) 6115 && (xmlStrEqual(tst->prefix, prefix))) 6116 return (0); 6117 tst = tst->next; 6118 } 6119 } 6120 node = node->parent; 6121 } 6122 if (node != ancestor) 6123 return (-1); 6124 return (1); 6125 } 6126 6127 /** 6128 * xmlSearchNsByHref: 6129 * @doc: the document 6130 * @node: the current node 6131 * @href: the namespace value 6132 * 6133 * Search a Ns aliasing a given URI. Recurse on the parents until it finds 6134 * the defined namespace or return NULL otherwise. 6135 * Returns the namespace pointer or NULL. 6136 */ 6137 xmlNsPtr 6138 xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href) 6139 { 6140 xmlNsPtr cur; 6141 xmlNodePtr orig = node; 6142 int is_attr; 6143 6144 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) || (href == NULL)) 6145 return (NULL); 6146 if (xmlStrEqual(href, XML_XML_NAMESPACE)) { 6147 /* 6148 * Only the document can hold the XML spec namespace. 6149 */ 6150 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) { 6151 /* 6152 * The XML-1.0 namespace is normally held on the root 6153 * element. In this case exceptionally create it on the 6154 * node element. 6155 */ 6156 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 6157 if (cur == NULL) { 6158 xmlTreeErrMemory("searching namespace"); 6159 return (NULL); 6160 } 6161 memset(cur, 0, sizeof(xmlNs)); 6162 cur->type = XML_LOCAL_NAMESPACE; 6163 cur->href = xmlStrdup(XML_XML_NAMESPACE); 6164 cur->prefix = xmlStrdup((const xmlChar *) "xml"); 6165 cur->next = node->nsDef; 6166 node->nsDef = cur; 6167 return (cur); 6168 } 6169 if (doc == NULL) { 6170 doc = node->doc; 6171 if (doc == NULL) 6172 return(NULL); 6173 } 6174 /* 6175 * Return the XML namespace declaration held by the doc. 6176 */ 6177 if (doc->oldNs == NULL) 6178 return(xmlTreeEnsureXMLDecl(doc)); 6179 else 6180 return(doc->oldNs); 6181 } 6182 is_attr = (node->type == XML_ATTRIBUTE_NODE); 6183 while (node != NULL) { 6184 if ((node->type == XML_ENTITY_REF_NODE) || 6185 (node->type == XML_ENTITY_NODE) || 6186 (node->type == XML_ENTITY_DECL)) 6187 return (NULL); 6188 if (node->type == XML_ELEMENT_NODE) { 6189 cur = node->nsDef; 6190 while (cur != NULL) { 6191 if ((cur->href != NULL) && (href != NULL) && 6192 (xmlStrEqual(cur->href, href))) { 6193 if (((!is_attr) || (cur->prefix != NULL)) && 6194 (xmlNsInScope(doc, orig, node, cur->prefix) == 1)) 6195 return (cur); 6196 } 6197 cur = cur->next; 6198 } 6199 if (orig != node) { 6200 cur = node->ns; 6201 if (cur != NULL) { 6202 if ((cur->href != NULL) && (href != NULL) && 6203 (xmlStrEqual(cur->href, href))) { 6204 if (((!is_attr) || (cur->prefix != NULL)) && 6205 (xmlNsInScope(doc, orig, node, cur->prefix) == 1)) 6206 return (cur); 6207 } 6208 } 6209 } 6210 } 6211 node = node->parent; 6212 } 6213 return (NULL); 6214 } 6215 6216 /** 6217 * xmlNewReconciliedNs: 6218 * @doc: the document 6219 * @tree: a node expected to hold the new namespace 6220 * @ns: the original namespace 6221 * 6222 * This function tries to locate a namespace definition in a tree 6223 * ancestors, or create a new namespace definition node similar to 6224 * @ns trying to reuse the same prefix. However if the given prefix is 6225 * null (default namespace) or reused within the subtree defined by 6226 * @tree or on one of its ancestors then a new prefix is generated. 6227 * Returns the (new) namespace definition or NULL in case of error 6228 */ 6229 static xmlNsPtr 6230 xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) { 6231 xmlNsPtr def; 6232 xmlChar prefix[50]; 6233 int counter = 1; 6234 6235 if ((tree == NULL) || (tree->type != XML_ELEMENT_NODE)) { 6236 #ifdef DEBUG_TREE 6237 xmlGenericError(xmlGenericErrorContext, 6238 "xmlNewReconciliedNs : tree == NULL\n"); 6239 #endif 6240 return(NULL); 6241 } 6242 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) { 6243 #ifdef DEBUG_TREE 6244 xmlGenericError(xmlGenericErrorContext, 6245 "xmlNewReconciliedNs : ns == NULL\n"); 6246 #endif 6247 return(NULL); 6248 } 6249 /* 6250 * Search an existing namespace definition inherited. 6251 */ 6252 def = xmlSearchNsByHref(doc, tree, ns->href); 6253 if (def != NULL) 6254 return(def); 6255 6256 /* 6257 * Find a close prefix which is not already in use. 6258 * Let's strip namespace prefixes longer than 20 chars ! 6259 */ 6260 if (ns->prefix == NULL) 6261 snprintf((char *) prefix, sizeof(prefix), "default"); 6262 else 6263 snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix); 6264 6265 def = xmlSearchNs(doc, tree, prefix); 6266 while (def != NULL) { 6267 if (counter > 1000) return(NULL); 6268 if (ns->prefix == NULL) 6269 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++); 6270 else 6271 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", 6272 (char *)ns->prefix, counter++); 6273 def = xmlSearchNs(doc, tree, prefix); 6274 } 6275 6276 /* 6277 * OK, now we are ready to create a new one. 6278 */ 6279 def = xmlNewNs(tree, ns->href, prefix); 6280 return(def); 6281 } 6282 6283 #ifdef LIBXML_TREE_ENABLED 6284 /** 6285 * xmlReconciliateNs: 6286 * @doc: the document 6287 * @tree: a node defining the subtree to reconciliate 6288 * 6289 * This function checks that all the namespaces declared within the given 6290 * tree are properly declared. This is needed for example after Copy or Cut 6291 * and then paste operations. The subtree may still hold pointers to 6292 * namespace declarations outside the subtree or invalid/masked. As much 6293 * as possible the function try to reuse the existing namespaces found in 6294 * the new environment. If not possible the new namespaces are redeclared 6295 * on @tree at the top of the given subtree. 6296 * Returns the number of namespace declarations created or -1 in case of error. 6297 */ 6298 int 6299 xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) { 6300 xmlNsPtr *oldNs = NULL; 6301 xmlNsPtr *newNs = NULL; 6302 int sizeCache = 0; 6303 int nbCache = 0; 6304 6305 xmlNsPtr n; 6306 xmlNodePtr node = tree; 6307 xmlAttrPtr attr; 6308 int ret = 0, i; 6309 6310 if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1); 6311 if ((doc == NULL) || (doc->type != XML_DOCUMENT_NODE)) return(-1); 6312 if (node->doc != doc) return(-1); 6313 while (node != NULL) { 6314 /* 6315 * Reconciliate the node namespace 6316 */ 6317 if (node->ns != NULL) { 6318 /* 6319 * initialize the cache if needed 6320 */ 6321 if (sizeCache == 0) { 6322 sizeCache = 10; 6323 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache * 6324 sizeof(xmlNsPtr)); 6325 if (oldNs == NULL) { 6326 xmlTreeErrMemory("fixing namespaces"); 6327 return(-1); 6328 } 6329 newNs = (xmlNsPtr *) xmlMalloc(sizeCache * 6330 sizeof(xmlNsPtr)); 6331 if (newNs == NULL) { 6332 xmlTreeErrMemory("fixing namespaces"); 6333 xmlFree(oldNs); 6334 return(-1); 6335 } 6336 } 6337 for (i = 0;i < nbCache;i++) { 6338 if (oldNs[i] == node->ns) { 6339 node->ns = newNs[i]; 6340 break; 6341 } 6342 } 6343 if (i == nbCache) { 6344 /* 6345 * OK we need to recreate a new namespace definition 6346 */ 6347 n = xmlNewReconciliedNs(doc, tree, node->ns); 6348 if (n != NULL) { /* :-( what if else ??? */ 6349 /* 6350 * check if we need to grow the cache buffers. 6351 */ 6352 if (sizeCache <= nbCache) { 6353 sizeCache *= 2; 6354 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache * 6355 sizeof(xmlNsPtr)); 6356 if (oldNs == NULL) { 6357 xmlTreeErrMemory("fixing namespaces"); 6358 xmlFree(newNs); 6359 return(-1); 6360 } 6361 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache * 6362 sizeof(xmlNsPtr)); 6363 if (newNs == NULL) { 6364 xmlTreeErrMemory("fixing namespaces"); 6365 xmlFree(oldNs); 6366 return(-1); 6367 } 6368 } 6369 newNs[nbCache] = n; 6370 oldNs[nbCache++] = node->ns; 6371 node->ns = n; 6372 } 6373 } 6374 } 6375 /* 6376 * now check for namespace hold by attributes on the node. 6377 */ 6378 if (node->type == XML_ELEMENT_NODE) { 6379 attr = node->properties; 6380 while (attr != NULL) { 6381 if (attr->ns != NULL) { 6382 /* 6383 * initialize the cache if needed 6384 */ 6385 if (sizeCache == 0) { 6386 sizeCache = 10; 6387 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache * 6388 sizeof(xmlNsPtr)); 6389 if (oldNs == NULL) { 6390 xmlTreeErrMemory("fixing namespaces"); 6391 return(-1); 6392 } 6393 newNs = (xmlNsPtr *) xmlMalloc(sizeCache * 6394 sizeof(xmlNsPtr)); 6395 if (newNs == NULL) { 6396 xmlTreeErrMemory("fixing namespaces"); 6397 xmlFree(oldNs); 6398 return(-1); 6399 } 6400 } 6401 for (i = 0;i < nbCache;i++) { 6402 if (oldNs[i] == attr->ns) { 6403 attr->ns = newNs[i]; 6404 break; 6405 } 6406 } 6407 if (i == nbCache) { 6408 /* 6409 * OK we need to recreate a new namespace definition 6410 */ 6411 n = xmlNewReconciliedNs(doc, tree, attr->ns); 6412 if (n != NULL) { /* :-( what if else ??? */ 6413 /* 6414 * check if we need to grow the cache buffers. 6415 */ 6416 if (sizeCache <= nbCache) { 6417 sizeCache *= 2; 6418 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, 6419 sizeCache * sizeof(xmlNsPtr)); 6420 if (oldNs == NULL) { 6421 xmlTreeErrMemory("fixing namespaces"); 6422 xmlFree(newNs); 6423 return(-1); 6424 } 6425 newNs = (xmlNsPtr *) xmlRealloc(newNs, 6426 sizeCache * sizeof(xmlNsPtr)); 6427 if (newNs == NULL) { 6428 xmlTreeErrMemory("fixing namespaces"); 6429 xmlFree(oldNs); 6430 return(-1); 6431 } 6432 } 6433 newNs[nbCache] = n; 6434 oldNs[nbCache++] = attr->ns; 6435 attr->ns = n; 6436 } 6437 } 6438 } 6439 attr = attr->next; 6440 } 6441 } 6442 6443 /* 6444 * Browse the full subtree, deep first 6445 */ 6446 if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) { 6447 /* deep first */ 6448 node = node->children; 6449 } else if ((node != tree) && (node->next != NULL)) { 6450 /* then siblings */ 6451 node = node->next; 6452 } else if (node != tree) { 6453 /* go up to parents->next if needed */ 6454 while (node != tree) { 6455 if (node->parent != NULL) 6456 node = node->parent; 6457 if ((node != tree) && (node->next != NULL)) { 6458 node = node->next; 6459 break; 6460 } 6461 if (node->parent == NULL) { 6462 node = NULL; 6463 break; 6464 } 6465 } 6466 /* exit condition */ 6467 if (node == tree) 6468 node = NULL; 6469 } else 6470 break; 6471 } 6472 if (oldNs != NULL) 6473 xmlFree(oldNs); 6474 if (newNs != NULL) 6475 xmlFree(newNs); 6476 return(ret); 6477 } 6478 #endif /* LIBXML_TREE_ENABLED */ 6479 6480 static xmlAttrPtr 6481 xmlGetPropNodeInternal(const xmlNode *node, const xmlChar *name, 6482 const xmlChar *nsName, int useDTD) 6483 { 6484 xmlAttrPtr prop; 6485 6486 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL)) 6487 return(NULL); 6488 6489 if (node->properties != NULL) { 6490 prop = node->properties; 6491 if (nsName == NULL) { 6492 /* 6493 * We want the attr to be in no namespace. 6494 */ 6495 do { 6496 if ((prop->ns == NULL) && xmlStrEqual(prop->name, name)) { 6497 return(prop); 6498 } 6499 prop = prop->next; 6500 } while (prop != NULL); 6501 } else { 6502 /* 6503 * We want the attr to be in the specified namespace. 6504 */ 6505 do { 6506 if ((prop->ns != NULL) && xmlStrEqual(prop->name, name) && 6507 ((prop->ns->href == nsName) || 6508 xmlStrEqual(prop->ns->href, nsName))) 6509 { 6510 return(prop); 6511 } 6512 prop = prop->next; 6513 } while (prop != NULL); 6514 } 6515 } 6516 6517 #ifdef LIBXML_TREE_ENABLED 6518 if (! useDTD) 6519 return(NULL); 6520 /* 6521 * Check if there is a default/fixed attribute declaration in 6522 * the internal or external subset. 6523 */ 6524 if ((node->doc != NULL) && (node->doc->intSubset != NULL)) { 6525 xmlDocPtr doc = node->doc; 6526 xmlAttributePtr attrDecl = NULL; 6527 xmlChar *elemQName, *tmpstr = NULL; 6528 6529 /* 6530 * We need the QName of the element for the DTD-lookup. 6531 */ 6532 if ((node->ns != NULL) && (node->ns->prefix != NULL)) { 6533 tmpstr = xmlStrdup(node->ns->prefix); 6534 tmpstr = xmlStrcat(tmpstr, BAD_CAST ":"); 6535 tmpstr = xmlStrcat(tmpstr, node->name); 6536 if (tmpstr == NULL) 6537 return(NULL); 6538 elemQName = tmpstr; 6539 } else 6540 elemQName = (xmlChar *) node->name; 6541 if (nsName == NULL) { 6542 /* 6543 * The common and nice case: Attr in no namespace. 6544 */ 6545 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, 6546 elemQName, name, NULL); 6547 if ((attrDecl == NULL) && (doc->extSubset != NULL)) { 6548 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, 6549 elemQName, name, NULL); 6550 } 6551 } else { 6552 xmlNsPtr *nsList, *cur; 6553 6554 /* 6555 * The ugly case: Search using the prefixes of in-scope 6556 * ns-decls corresponding to @nsName. 6557 */ 6558 nsList = xmlGetNsList(node->doc, node); 6559 if (nsList == NULL) { 6560 if (tmpstr != NULL) 6561 xmlFree(tmpstr); 6562 return(NULL); 6563 } 6564 cur = nsList; 6565 while (*cur != NULL) { 6566 if (xmlStrEqual((*cur)->href, nsName)) { 6567 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elemQName, 6568 name, (*cur)->prefix); 6569 if (attrDecl) 6570 break; 6571 if (doc->extSubset != NULL) { 6572 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elemQName, 6573 name, (*cur)->prefix); 6574 if (attrDecl) 6575 break; 6576 } 6577 } 6578 cur++; 6579 } 6580 xmlFree(nsList); 6581 } 6582 if (tmpstr != NULL) 6583 xmlFree(tmpstr); 6584 /* 6585 * Only default/fixed attrs are relevant. 6586 */ 6587 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL)) 6588 return((xmlAttrPtr) attrDecl); 6589 } 6590 #endif /* LIBXML_TREE_ENABLED */ 6591 return(NULL); 6592 } 6593 6594 static xmlChar* 6595 xmlGetPropNodeValueInternal(const xmlAttr *prop) 6596 { 6597 if (prop == NULL) 6598 return(NULL); 6599 if (prop->type == XML_ATTRIBUTE_NODE) { 6600 /* 6601 * Note that we return at least the empty string. 6602 * TODO: Do we really always want that? 6603 */ 6604 if (prop->children != NULL) { 6605 if ((prop->children->next == NULL) && 6606 ((prop->children->type == XML_TEXT_NODE) || 6607 (prop->children->type == XML_CDATA_SECTION_NODE))) 6608 { 6609 /* 6610 * Optimization for the common case: only 1 text node. 6611 */ 6612 return(xmlStrdup(prop->children->content)); 6613 } else { 6614 xmlChar *ret; 6615 6616 ret = xmlNodeListGetString(prop->doc, prop->children, 1); 6617 if (ret != NULL) 6618 return(ret); 6619 } 6620 } 6621 return(xmlStrdup((xmlChar *)"")); 6622 } else if (prop->type == XML_ATTRIBUTE_DECL) { 6623 return(xmlStrdup(((xmlAttributePtr)prop)->defaultValue)); 6624 } 6625 return(NULL); 6626 } 6627 6628 /** 6629 * xmlHasProp: 6630 * @node: the node 6631 * @name: the attribute name 6632 * 6633 * Search an attribute associated to a node 6634 * This function also looks in DTD attribute declaration for #FIXED or 6635 * default declaration values unless DTD use has been turned off. 6636 * 6637 * Returns the attribute or the attribute declaration or NULL if 6638 * neither was found. 6639 */ 6640 xmlAttrPtr 6641 xmlHasProp(const xmlNode *node, const xmlChar *name) { 6642 xmlAttrPtr prop; 6643 xmlDocPtr doc; 6644 6645 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL)) 6646 return(NULL); 6647 /* 6648 * Check on the properties attached to the node 6649 */ 6650 prop = node->properties; 6651 while (prop != NULL) { 6652 if (xmlStrEqual(prop->name, name)) { 6653 return(prop); 6654 } 6655 prop = prop->next; 6656 } 6657 if (!xmlCheckDTD) return(NULL); 6658 6659 /* 6660 * Check if there is a default declaration in the internal 6661 * or external subsets 6662 */ 6663 doc = node->doc; 6664 if (doc != NULL) { 6665 xmlAttributePtr attrDecl; 6666 if (doc->intSubset != NULL) { 6667 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name); 6668 if ((attrDecl == NULL) && (doc->extSubset != NULL)) 6669 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name); 6670 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL)) 6671 /* return attribute declaration only if a default value is given 6672 (that includes #FIXED declarations) */ 6673 return((xmlAttrPtr) attrDecl); 6674 } 6675 } 6676 return(NULL); 6677 } 6678 6679 /** 6680 * xmlHasNsProp: 6681 * @node: the node 6682 * @name: the attribute name 6683 * @nameSpace: the URI of the namespace 6684 * 6685 * Search for an attribute associated to a node 6686 * This attribute has to be anchored in the namespace specified. 6687 * This does the entity substitution. 6688 * This function looks in DTD attribute declaration for #FIXED or 6689 * default declaration values unless DTD use has been turned off. 6690 * Note that a namespace of NULL indicates to use the default namespace. 6691 * 6692 * Returns the attribute or the attribute declaration or NULL 6693 * if neither was found. 6694 */ 6695 xmlAttrPtr 6696 xmlHasNsProp(const xmlNode *node, const xmlChar *name, const xmlChar *nameSpace) { 6697 6698 return(xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD)); 6699 } 6700 6701 /** 6702 * xmlGetProp: 6703 * @node: the node 6704 * @name: the attribute name 6705 * 6706 * Search and get the value of an attribute associated to a node 6707 * This does the entity substitution. 6708 * This function looks in DTD attribute declaration for #FIXED or 6709 * default declaration values unless DTD use has been turned off. 6710 * NOTE: this function acts independently of namespaces associated 6711 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp() 6712 * for namespace aware processing. 6713 * 6714 * Returns the attribute value or NULL if not found. 6715 * It's up to the caller to free the memory with xmlFree(). 6716 */ 6717 xmlChar * 6718 xmlGetProp(const xmlNode *node, const xmlChar *name) { 6719 xmlAttrPtr prop; 6720 6721 prop = xmlHasProp(node, name); 6722 if (prop == NULL) 6723 return(NULL); 6724 return(xmlGetPropNodeValueInternal(prop)); 6725 } 6726 6727 /** 6728 * xmlGetNoNsProp: 6729 * @node: the node 6730 * @name: the attribute name 6731 * 6732 * Search and get the value of an attribute associated to a node 6733 * This does the entity substitution. 6734 * This function looks in DTD attribute declaration for #FIXED or 6735 * default declaration values unless DTD use has been turned off. 6736 * This function is similar to xmlGetProp except it will accept only 6737 * an attribute in no namespace. 6738 * 6739 * Returns the attribute value or NULL if not found. 6740 * It's up to the caller to free the memory with xmlFree(). 6741 */ 6742 xmlChar * 6743 xmlGetNoNsProp(const xmlNode *node, const xmlChar *name) { 6744 xmlAttrPtr prop; 6745 6746 prop = xmlGetPropNodeInternal(node, name, NULL, xmlCheckDTD); 6747 if (prop == NULL) 6748 return(NULL); 6749 return(xmlGetPropNodeValueInternal(prop)); 6750 } 6751 6752 /** 6753 * xmlGetNsProp: 6754 * @node: the node 6755 * @name: the attribute name 6756 * @nameSpace: the URI of the namespace 6757 * 6758 * Search and get the value of an attribute associated to a node 6759 * This attribute has to be anchored in the namespace specified. 6760 * This does the entity substitution. 6761 * This function looks in DTD attribute declaration for #FIXED or 6762 * default declaration values unless DTD use has been turned off. 6763 * 6764 * Returns the attribute value or NULL if not found. 6765 * It's up to the caller to free the memory with xmlFree(). 6766 */ 6767 xmlChar * 6768 xmlGetNsProp(const xmlNode *node, const xmlChar *name, const xmlChar *nameSpace) { 6769 xmlAttrPtr prop; 6770 6771 prop = xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD); 6772 if (prop == NULL) 6773 return(NULL); 6774 return(xmlGetPropNodeValueInternal(prop)); 6775 } 6776 6777 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) 6778 /** 6779 * xmlUnsetProp: 6780 * @node: the node 6781 * @name: the attribute name 6782 * 6783 * Remove an attribute carried by a node. 6784 * This handles only attributes in no namespace. 6785 * Returns 0 if successful, -1 if not found 6786 */ 6787 int 6788 xmlUnsetProp(xmlNodePtr node, const xmlChar *name) { 6789 xmlAttrPtr prop; 6790 6791 prop = xmlGetPropNodeInternal(node, name, NULL, 0); 6792 if (prop == NULL) 6793 return(-1); 6794 xmlUnlinkNode((xmlNodePtr) prop); 6795 xmlFreeProp(prop); 6796 return(0); 6797 } 6798 6799 /** 6800 * xmlUnsetNsProp: 6801 * @node: the node 6802 * @ns: the namespace definition 6803 * @name: the attribute name 6804 * 6805 * Remove an attribute carried by a node. 6806 * Returns 0 if successful, -1 if not found 6807 */ 6808 int 6809 xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) { 6810 xmlAttrPtr prop; 6811 6812 prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0); 6813 if (prop == NULL) 6814 return(-1); 6815 xmlUnlinkNode((xmlNodePtr) prop); 6816 xmlFreeProp(prop); 6817 return(0); 6818 } 6819 #endif 6820 6821 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED) 6822 /** 6823 * xmlSetProp: 6824 * @node: the node 6825 * @name: the attribute name (a QName) 6826 * @value: the attribute value 6827 * 6828 * Set (or reset) an attribute carried by a node. 6829 * If @name has a prefix, then the corresponding 6830 * namespace-binding will be used, if in scope; it is an 6831 * error it there's no such ns-binding for the prefix in 6832 * scope. 6833 * Returns the attribute pointer. 6834 * 6835 */ 6836 xmlAttrPtr 6837 xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) { 6838 int len; 6839 const xmlChar *nqname; 6840 6841 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE)) 6842 return(NULL); 6843 6844 /* 6845 * handle QNames 6846 */ 6847 nqname = xmlSplitQName3(name, &len); 6848 if (nqname != NULL) { 6849 xmlNsPtr ns; 6850 xmlChar *prefix = xmlStrndup(name, len); 6851 ns = xmlSearchNs(node->doc, node, prefix); 6852 if (prefix != NULL) 6853 xmlFree(prefix); 6854 if (ns != NULL) 6855 return(xmlSetNsProp(node, ns, nqname, value)); 6856 } 6857 return(xmlSetNsProp(node, NULL, name, value)); 6858 } 6859 6860 /** 6861 * xmlSetNsProp: 6862 * @node: the node 6863 * @ns: the namespace definition 6864 * @name: the attribute name 6865 * @value: the attribute value 6866 * 6867 * Set (or reset) an attribute carried by a node. 6868 * The ns structure must be in scope, this is not checked 6869 * 6870 * Returns the attribute pointer. 6871 */ 6872 xmlAttrPtr 6873 xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name, 6874 const xmlChar *value) 6875 { 6876 xmlAttrPtr prop; 6877 6878 if (ns && (ns->href == NULL)) 6879 return(NULL); 6880 prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0); 6881 if (prop != NULL) { 6882 /* 6883 * Modify the attribute's value. 6884 */ 6885 if (prop->atype == XML_ATTRIBUTE_ID) { 6886 xmlRemoveID(node->doc, prop); 6887 prop->atype = XML_ATTRIBUTE_ID; 6888 } 6889 if (prop->children != NULL) 6890 xmlFreeNodeList(prop->children); 6891 prop->children = NULL; 6892 prop->last = NULL; 6893 prop->ns = ns; 6894 if (value != NULL) { 6895 xmlNodePtr tmp; 6896 6897 if(!xmlCheckUTF8(value)) { 6898 xmlTreeErr(XML_TREE_NOT_UTF8, (xmlNodePtr) node->doc, 6899 NULL); 6900 if (node->doc != NULL) 6901 node->doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1"); 6902 } 6903 prop->children = xmlNewDocText(node->doc, value); 6904 prop->last = NULL; 6905 tmp = prop->children; 6906 while (tmp != NULL) { 6907 tmp->parent = (xmlNodePtr) prop; 6908 if (tmp->next == NULL) 6909 prop->last = tmp; 6910 tmp = tmp->next; 6911 } 6912 } 6913 if (prop->atype == XML_ATTRIBUTE_ID) 6914 xmlAddID(NULL, node->doc, value, prop); 6915 return(prop); 6916 } 6917 /* 6918 * No equal attr found; create a new one. 6919 */ 6920 return(xmlNewPropInternal(node, ns, name, value, 0)); 6921 } 6922 6923 #endif /* LIBXML_TREE_ENABLED */ 6924 6925 /** 6926 * xmlNodeIsText: 6927 * @node: the node 6928 * 6929 * Is this node a Text node ? 6930 * Returns 1 yes, 0 no 6931 */ 6932 int 6933 xmlNodeIsText(const xmlNode *node) { 6934 if (node == NULL) return(0); 6935 6936 if (node->type == XML_TEXT_NODE) return(1); 6937 return(0); 6938 } 6939 6940 /** 6941 * xmlIsBlankNode: 6942 * @node: the node 6943 * 6944 * Checks whether this node is an empty or whitespace only 6945 * (and possibly ignorable) text-node. 6946 * 6947 * Returns 1 yes, 0 no 6948 */ 6949 int 6950 xmlIsBlankNode(const xmlNode *node) { 6951 const xmlChar *cur; 6952 if (node == NULL) return(0); 6953 6954 if ((node->type != XML_TEXT_NODE) && 6955 (node->type != XML_CDATA_SECTION_NODE)) 6956 return(0); 6957 if (node->content == NULL) return(1); 6958 cur = node->content; 6959 while (*cur != 0) { 6960 if (!IS_BLANK_CH(*cur)) return(0); 6961 cur++; 6962 } 6963 6964 return(1); 6965 } 6966 6967 /** 6968 * xmlTextConcat: 6969 * @node: the node 6970 * @content: the content 6971 * @len: @content length 6972 * 6973 * Concat the given string at the end of the existing node content 6974 * 6975 * Returns -1 in case of error, 0 otherwise 6976 */ 6977 6978 int 6979 xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) { 6980 if (node == NULL) return(-1); 6981 6982 if ((node->type != XML_TEXT_NODE) && 6983 (node->type != XML_CDATA_SECTION_NODE) && 6984 (node->type != XML_COMMENT_NODE) && 6985 (node->type != XML_PI_NODE)) { 6986 #ifdef DEBUG_TREE 6987 xmlGenericError(xmlGenericErrorContext, 6988 "xmlTextConcat: node is not text nor CDATA\n"); 6989 #endif 6990 return(-1); 6991 } 6992 /* need to check if content is currently in the dictionary */ 6993 if ((node->content == (xmlChar *) &(node->properties)) || 6994 ((node->doc != NULL) && (node->doc->dict != NULL) && 6995 xmlDictOwns(node->doc->dict, node->content))) { 6996 node->content = xmlStrncatNew(node->content, content, len); 6997 } else { 6998 node->content = xmlStrncat(node->content, content, len); 6999 } 7000 node->properties = NULL; 7001 if (node->content == NULL) 7002 return(-1); 7003 return(0); 7004 } 7005 7006 /************************************************************************ 7007 * * 7008 * Output : to a FILE or in memory * 7009 * * 7010 ************************************************************************/ 7011 7012 /** 7013 * xmlBufferCreate: 7014 * 7015 * routine to create an XML buffer. 7016 * returns the new structure. 7017 */ 7018 xmlBufferPtr 7019 xmlBufferCreate(void) { 7020 xmlBufferPtr ret; 7021 7022 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer)); 7023 if (ret == NULL) { 7024 xmlTreeErrMemory("creating buffer"); 7025 return(NULL); 7026 } 7027 ret->use = 0; 7028 ret->size = xmlDefaultBufferSize; 7029 ret->alloc = xmlBufferAllocScheme; 7030 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar)); 7031 if (ret->content == NULL) { 7032 xmlTreeErrMemory("creating buffer"); 7033 xmlFree(ret); 7034 return(NULL); 7035 } 7036 ret->content[0] = 0; 7037 ret->contentIO = NULL; 7038 return(ret); 7039 } 7040 7041 /** 7042 * xmlBufferCreateSize: 7043 * @size: initial size of buffer 7044 * 7045 * routine to create an XML buffer. 7046 * returns the new structure. 7047 */ 7048 xmlBufferPtr 7049 xmlBufferCreateSize(size_t size) { 7050 xmlBufferPtr ret; 7051 7052 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer)); 7053 if (ret == NULL) { 7054 xmlTreeErrMemory("creating buffer"); 7055 return(NULL); 7056 } 7057 ret->use = 0; 7058 ret->alloc = xmlBufferAllocScheme; 7059 ret->size = (size ? size+2 : 0); /* +1 for ending null */ 7060 if (ret->size){ 7061 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar)); 7062 if (ret->content == NULL) { 7063 xmlTreeErrMemory("creating buffer"); 7064 xmlFree(ret); 7065 return(NULL); 7066 } 7067 ret->content[0] = 0; 7068 } else 7069 ret->content = NULL; 7070 ret->contentIO = NULL; 7071 return(ret); 7072 } 7073 7074 /** 7075 * xmlBufferDetach: 7076 * @buf: the buffer 7077 * 7078 * Remove the string contained in a buffer and gie it back to the 7079 * caller. The buffer is reset to an empty content. 7080 * This doesn't work with immutable buffers as they can't be reset. 7081 * 7082 * Returns the previous string contained by the buffer. 7083 */ 7084 xmlChar * 7085 xmlBufferDetach(xmlBufferPtr buf) { 7086 xmlChar *ret; 7087 7088 if (buf == NULL) 7089 return(NULL); 7090 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) 7091 return(NULL); 7092 7093 ret = buf->content; 7094 buf->content = NULL; 7095 buf->size = 0; 7096 buf->use = 0; 7097 7098 return ret; 7099 } 7100 7101 7102 /** 7103 * xmlBufferCreateStatic: 7104 * @mem: the memory area 7105 * @size: the size in byte 7106 * 7107 * routine to create an XML buffer from an immutable memory area. 7108 * The area won't be modified nor copied, and is expected to be 7109 * present until the end of the buffer lifetime. 7110 * 7111 * returns the new structure. 7112 */ 7113 xmlBufferPtr 7114 xmlBufferCreateStatic(void *mem, size_t size) { 7115 xmlBufferPtr ret; 7116 7117 if ((mem == NULL) || (size == 0)) 7118 return(NULL); 7119 7120 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer)); 7121 if (ret == NULL) { 7122 xmlTreeErrMemory("creating buffer"); 7123 return(NULL); 7124 } 7125 ret->use = size; 7126 ret->size = size; 7127 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE; 7128 ret->content = (xmlChar *) mem; 7129 return(ret); 7130 } 7131 7132 /** 7133 * xmlBufferSetAllocationScheme: 7134 * @buf: the buffer to tune 7135 * @scheme: allocation scheme to use 7136 * 7137 * Sets the allocation scheme for this buffer 7138 */ 7139 void 7140 xmlBufferSetAllocationScheme(xmlBufferPtr buf, 7141 xmlBufferAllocationScheme scheme) { 7142 if (buf == NULL) { 7143 #ifdef DEBUG_BUFFER 7144 xmlGenericError(xmlGenericErrorContext, 7145 "xmlBufferSetAllocationScheme: buf == NULL\n"); 7146 #endif 7147 return; 7148 } 7149 if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) || 7150 (buf->alloc == XML_BUFFER_ALLOC_IO)) return; 7151 if ((scheme == XML_BUFFER_ALLOC_DOUBLEIT) || 7152 (scheme == XML_BUFFER_ALLOC_EXACT) || 7153 (scheme == XML_BUFFER_ALLOC_HYBRID) || 7154 (scheme == XML_BUFFER_ALLOC_IMMUTABLE)) 7155 buf->alloc = scheme; 7156 } 7157 7158 /** 7159 * xmlBufferFree: 7160 * @buf: the buffer to free 7161 * 7162 * Frees an XML buffer. It frees both the content and the structure which 7163 * encapsulate it. 7164 */ 7165 void 7166 xmlBufferFree(xmlBufferPtr buf) { 7167 if (buf == NULL) { 7168 #ifdef DEBUG_BUFFER 7169 xmlGenericError(xmlGenericErrorContext, 7170 "xmlBufferFree: buf == NULL\n"); 7171 #endif 7172 return; 7173 } 7174 7175 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && 7176 (buf->contentIO != NULL)) { 7177 xmlFree(buf->contentIO); 7178 } else if ((buf->content != NULL) && 7179 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) { 7180 xmlFree(buf->content); 7181 } 7182 xmlFree(buf); 7183 } 7184 7185 /** 7186 * xmlBufferEmpty: 7187 * @buf: the buffer 7188 * 7189 * empty a buffer. 7190 */ 7191 void 7192 xmlBufferEmpty(xmlBufferPtr buf) { 7193 if (buf == NULL) return; 7194 if (buf->content == NULL) return; 7195 buf->use = 0; 7196 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) { 7197 buf->content = BAD_CAST ""; 7198 } else if ((buf->alloc == XML_BUFFER_ALLOC_IO) && 7199 (buf->contentIO != NULL)) { 7200 size_t start_buf = buf->content - buf->contentIO; 7201 7202 buf->size += start_buf; 7203 buf->content = buf->contentIO; 7204 buf->content[0] = 0; 7205 } else { 7206 buf->content[0] = 0; 7207 } 7208 } 7209 7210 /** 7211 * xmlBufferShrink: 7212 * @buf: the buffer to dump 7213 * @len: the number of xmlChar to remove 7214 * 7215 * Remove the beginning of an XML buffer. 7216 * 7217 * Returns the number of #xmlChar removed, or -1 in case of failure. 7218 */ 7219 int 7220 xmlBufferShrink(xmlBufferPtr buf, unsigned int len) { 7221 if (buf == NULL) return(-1); 7222 if (len == 0) return(0); 7223 if (len > buf->use) return(-1); 7224 7225 buf->use -= len; 7226 if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) || 7227 ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL))) { 7228 /* 7229 * we just move the content pointer, but also make sure 7230 * the perceived buffer size has shrinked accordingly 7231 */ 7232 buf->content += len; 7233 buf->size -= len; 7234 7235 /* 7236 * sometimes though it maybe be better to really shrink 7237 * on IO buffers 7238 */ 7239 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) { 7240 size_t start_buf = buf->content - buf->contentIO; 7241 if (start_buf >= buf->size) { 7242 memmove(buf->contentIO, &buf->content[0], buf->use); 7243 buf->content = buf->contentIO; 7244 buf->content[buf->use] = 0; 7245 buf->size += start_buf; 7246 } 7247 } 7248 } else { 7249 memmove(buf->content, &buf->content[len], buf->use); 7250 buf->content[buf->use] = 0; 7251 } 7252 return(len); 7253 } 7254 7255 /** 7256 * xmlBufferGrow: 7257 * @buf: the buffer 7258 * @len: the minimum free size to allocate 7259 * 7260 * Grow the available space of an XML buffer. 7261 * 7262 * Returns the new available space or -1 in case of error 7263 */ 7264 int 7265 xmlBufferGrow(xmlBufferPtr buf, unsigned int len) { 7266 int size; 7267 xmlChar *newbuf; 7268 7269 if (buf == NULL) return(-1); 7270 7271 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0); 7272 if (len + buf->use < buf->size) return(0); 7273 7274 /* 7275 * Windows has a BIG problem on realloc timing, so we try to double 7276 * the buffer size (if that's enough) (bug 146697) 7277 * Apparently BSD too, and it's probably best for linux too 7278 * On an embedded system this may be something to change 7279 */ 7280 #if 1 7281 if (buf->size > len) 7282 size = buf->size * 2; 7283 else 7284 size = buf->use + len + 100; 7285 #else 7286 size = buf->use + len + 100; 7287 #endif 7288 7289 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) { 7290 size_t start_buf = buf->content - buf->contentIO; 7291 7292 newbuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + size); 7293 if (newbuf == NULL) { 7294 xmlTreeErrMemory("growing buffer"); 7295 return(-1); 7296 } 7297 buf->contentIO = newbuf; 7298 buf->content = newbuf + start_buf; 7299 } else { 7300 newbuf = (xmlChar *) xmlRealloc(buf->content, size); 7301 if (newbuf == NULL) { 7302 xmlTreeErrMemory("growing buffer"); 7303 return(-1); 7304 } 7305 buf->content = newbuf; 7306 } 7307 buf->size = size; 7308 return(buf->size - buf->use); 7309 } 7310 7311 /** 7312 * xmlBufferDump: 7313 * @file: the file output 7314 * @buf: the buffer to dump 7315 * 7316 * Dumps an XML buffer to a FILE *. 7317 * Returns the number of #xmlChar written 7318 */ 7319 int 7320 xmlBufferDump(FILE *file, xmlBufferPtr buf) { 7321 int ret; 7322 7323 if (buf == NULL) { 7324 #ifdef DEBUG_BUFFER 7325 xmlGenericError(xmlGenericErrorContext, 7326 "xmlBufferDump: buf == NULL\n"); 7327 #endif 7328 return(0); 7329 } 7330 if (buf->content == NULL) { 7331 #ifdef DEBUG_BUFFER 7332 xmlGenericError(xmlGenericErrorContext, 7333 "xmlBufferDump: buf->content == NULL\n"); 7334 #endif 7335 return(0); 7336 } 7337 if (file == NULL) 7338 file = stdout; 7339 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file); 7340 return(ret); 7341 } 7342 7343 /** 7344 * xmlBufferContent: 7345 * @buf: the buffer 7346 * 7347 * Function to extract the content of a buffer 7348 * 7349 * Returns the internal content 7350 */ 7351 7352 const xmlChar * 7353 xmlBufferContent(const xmlBuffer *buf) 7354 { 7355 if(!buf) 7356 return NULL; 7357 7358 return buf->content; 7359 } 7360 7361 /** 7362 * xmlBufferLength: 7363 * @buf: the buffer 7364 * 7365 * Function to get the length of a buffer 7366 * 7367 * Returns the length of data in the internal content 7368 */ 7369 7370 int 7371 xmlBufferLength(const xmlBuffer *buf) 7372 { 7373 if(!buf) 7374 return 0; 7375 7376 return buf->use; 7377 } 7378 7379 /** 7380 * xmlBufferResize: 7381 * @buf: the buffer to resize 7382 * @size: the desired size 7383 * 7384 * Resize a buffer to accommodate minimum size of @size. 7385 * 7386 * Returns 0 in case of problems, 1 otherwise 7387 */ 7388 int 7389 xmlBufferResize(xmlBufferPtr buf, unsigned int size) 7390 { 7391 unsigned int newSize; 7392 xmlChar* rebuf = NULL; 7393 size_t start_buf; 7394 7395 if (buf == NULL) 7396 return(0); 7397 7398 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0); 7399 7400 /* Don't resize if we don't have to */ 7401 if (size < buf->size) 7402 return 1; 7403 7404 /* figure out new size */ 7405 switch (buf->alloc){ 7406 case XML_BUFFER_ALLOC_IO: 7407 case XML_BUFFER_ALLOC_DOUBLEIT: 7408 /*take care of empty case*/ 7409 newSize = (buf->size ? buf->size*2 : size + 10); 7410 while (size > newSize) { 7411 if (newSize > UINT_MAX / 2) { 7412 xmlTreeErrMemory("growing buffer"); 7413 return 0; 7414 } 7415 newSize *= 2; 7416 } 7417 break; 7418 case XML_BUFFER_ALLOC_EXACT: 7419 newSize = size+10; 7420 break; 7421 case XML_BUFFER_ALLOC_HYBRID: 7422 if (buf->use < BASE_BUFFER_SIZE) 7423 newSize = size; 7424 else { 7425 newSize = buf->size * 2; 7426 while (size > newSize) { 7427 if (newSize > UINT_MAX / 2) { 7428 xmlTreeErrMemory("growing buffer"); 7429 return 0; 7430 } 7431 newSize *= 2; 7432 } 7433 } 7434 break; 7435 7436 default: 7437 newSize = size+10; 7438 break; 7439 } 7440 7441 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) { 7442 start_buf = buf->content - buf->contentIO; 7443 7444 if (start_buf > newSize) { 7445 /* move data back to start */ 7446 memmove(buf->contentIO, buf->content, buf->use); 7447 buf->content = buf->contentIO; 7448 buf->content[buf->use] = 0; 7449 buf->size += start_buf; 7450 } else { 7451 rebuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + newSize); 7452 if (rebuf == NULL) { 7453 xmlTreeErrMemory("growing buffer"); 7454 return 0; 7455 } 7456 buf->contentIO = rebuf; 7457 buf->content = rebuf + start_buf; 7458 } 7459 } else { 7460 if (buf->content == NULL) { 7461 rebuf = (xmlChar *) xmlMallocAtomic(newSize); 7462 } else if (buf->size - buf->use < 100) { 7463 rebuf = (xmlChar *) xmlRealloc(buf->content, newSize); 7464 } else { 7465 /* 7466 * if we are reallocating a buffer far from being full, it's 7467 * better to make a new allocation and copy only the used range 7468 * and free the old one. 7469 */ 7470 rebuf = (xmlChar *) xmlMallocAtomic(newSize); 7471 if (rebuf != NULL) { 7472 memcpy(rebuf, buf->content, buf->use); 7473 xmlFree(buf->content); 7474 rebuf[buf->use] = 0; 7475 } 7476 } 7477 if (rebuf == NULL) { 7478 xmlTreeErrMemory("growing buffer"); 7479 return 0; 7480 } 7481 buf->content = rebuf; 7482 } 7483 buf->size = newSize; 7484 7485 return 1; 7486 } 7487 7488 /** 7489 * xmlBufferAdd: 7490 * @buf: the buffer to dump 7491 * @str: the #xmlChar string 7492 * @len: the number of #xmlChar to add 7493 * 7494 * Add a string range to an XML buffer. if len == -1, the length of 7495 * str is recomputed. 7496 * 7497 * Returns 0 successful, a positive error code number otherwise 7498 * and -1 in case of internal or API error. 7499 */ 7500 int 7501 xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) { 7502 unsigned int needSize; 7503 7504 if ((str == NULL) || (buf == NULL)) { 7505 return -1; 7506 } 7507 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1; 7508 if (len < -1) { 7509 #ifdef DEBUG_BUFFER 7510 xmlGenericError(xmlGenericErrorContext, 7511 "xmlBufferAdd: len < 0\n"); 7512 #endif 7513 return -1; 7514 } 7515 if (len == 0) return 0; 7516 7517 if (len < 0) 7518 len = xmlStrlen(str); 7519 7520 if (len < 0) return -1; 7521 if (len == 0) return 0; 7522 7523 needSize = buf->use + len + 2; 7524 if (needSize > buf->size){ 7525 if (!xmlBufferResize(buf, needSize)){ 7526 xmlTreeErrMemory("growing buffer"); 7527 return XML_ERR_NO_MEMORY; 7528 } 7529 } 7530 7531 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar)); 7532 buf->use += len; 7533 buf->content[buf->use] = 0; 7534 return 0; 7535 } 7536 7537 /** 7538 * xmlBufferAddHead: 7539 * @buf: the buffer 7540 * @str: the #xmlChar string 7541 * @len: the number of #xmlChar to add 7542 * 7543 * Add a string range to the beginning of an XML buffer. 7544 * if len == -1, the length of @str is recomputed. 7545 * 7546 * Returns 0 successful, a positive error code number otherwise 7547 * and -1 in case of internal or API error. 7548 */ 7549 int 7550 xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) { 7551 unsigned int needSize; 7552 7553 if (buf == NULL) 7554 return(-1); 7555 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1; 7556 if (str == NULL) { 7557 #ifdef DEBUG_BUFFER 7558 xmlGenericError(xmlGenericErrorContext, 7559 "xmlBufferAddHead: str == NULL\n"); 7560 #endif 7561 return -1; 7562 } 7563 if (len < -1) { 7564 #ifdef DEBUG_BUFFER 7565 xmlGenericError(xmlGenericErrorContext, 7566 "xmlBufferAddHead: len < 0\n"); 7567 #endif 7568 return -1; 7569 } 7570 if (len == 0) return 0; 7571 7572 if (len < 0) 7573 len = xmlStrlen(str); 7574 7575 if (len <= 0) return -1; 7576 7577 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) { 7578 size_t start_buf = buf->content - buf->contentIO; 7579 7580 if (start_buf > (unsigned int) len) { 7581 /* 7582 * We can add it in the space previously shrinked 7583 */ 7584 buf->content -= len; 7585 memmove(&buf->content[0], str, len); 7586 buf->use += len; 7587 buf->size += len; 7588 return(0); 7589 } 7590 } 7591 needSize = buf->use + len + 2; 7592 if (needSize > buf->size){ 7593 if (!xmlBufferResize(buf, needSize)){ 7594 xmlTreeErrMemory("growing buffer"); 7595 return XML_ERR_NO_MEMORY; 7596 } 7597 } 7598 7599 memmove(&buf->content[len], &buf->content[0], buf->use); 7600 memmove(&buf->content[0], str, len); 7601 buf->use += len; 7602 buf->content[buf->use] = 0; 7603 return 0; 7604 } 7605 7606 /** 7607 * xmlBufferCat: 7608 * @buf: the buffer to add to 7609 * @str: the #xmlChar string 7610 * 7611 * Append a zero terminated string to an XML buffer. 7612 * 7613 * Returns 0 successful, a positive error code number otherwise 7614 * and -1 in case of internal or API error. 7615 */ 7616 int 7617 xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) { 7618 if (buf == NULL) 7619 return(-1); 7620 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1; 7621 if (str == NULL) return -1; 7622 return xmlBufferAdd(buf, str, -1); 7623 } 7624 7625 /** 7626 * xmlBufferCCat: 7627 * @buf: the buffer to dump 7628 * @str: the C char string 7629 * 7630 * Append a zero terminated C string to an XML buffer. 7631 * 7632 * Returns 0 successful, a positive error code number otherwise 7633 * and -1 in case of internal or API error. 7634 */ 7635 int 7636 xmlBufferCCat(xmlBufferPtr buf, const char *str) { 7637 const char *cur; 7638 7639 if (buf == NULL) 7640 return(-1); 7641 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1; 7642 if (str == NULL) { 7643 #ifdef DEBUG_BUFFER 7644 xmlGenericError(xmlGenericErrorContext, 7645 "xmlBufferCCat: str == NULL\n"); 7646 #endif 7647 return -1; 7648 } 7649 for (cur = str;*cur != 0;cur++) { 7650 if (buf->use + 10 >= buf->size) { 7651 if (!xmlBufferResize(buf, buf->use+10)){ 7652 xmlTreeErrMemory("growing buffer"); 7653 return XML_ERR_NO_MEMORY; 7654 } 7655 } 7656 buf->content[buf->use++] = *cur; 7657 } 7658 buf->content[buf->use] = 0; 7659 return 0; 7660 } 7661 7662 /** 7663 * xmlBufferWriteCHAR: 7664 * @buf: the XML buffer 7665 * @string: the string to add 7666 * 7667 * routine which manages and grows an output buffer. This one adds 7668 * xmlChars at the end of the buffer. 7669 */ 7670 void 7671 xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) { 7672 if (buf == NULL) 7673 return; 7674 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return; 7675 xmlBufferCat(buf, string); 7676 } 7677 7678 /** 7679 * xmlBufferWriteChar: 7680 * @buf: the XML buffer output 7681 * @string: the string to add 7682 * 7683 * routine which manage and grows an output buffer. This one add 7684 * C chars at the end of the array. 7685 */ 7686 void 7687 xmlBufferWriteChar(xmlBufferPtr buf, const char *string) { 7688 if (buf == NULL) 7689 return; 7690 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return; 7691 xmlBufferCCat(buf, string); 7692 } 7693 7694 7695 /** 7696 * xmlBufferWriteQuotedString: 7697 * @buf: the XML buffer output 7698 * @string: the string to add 7699 * 7700 * routine which manage and grows an output buffer. This one writes 7701 * a quoted or double quoted #xmlChar string, checking first if it holds 7702 * quote or double-quotes internally 7703 */ 7704 void 7705 xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) { 7706 const xmlChar *cur, *base; 7707 if (buf == NULL) 7708 return; 7709 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return; 7710 if (xmlStrchr(string, '\"')) { 7711 if (xmlStrchr(string, '\'')) { 7712 #ifdef DEBUG_BUFFER 7713 xmlGenericError(xmlGenericErrorContext, 7714 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n"); 7715 #endif 7716 xmlBufferCCat(buf, "\""); 7717 base = cur = string; 7718 while(*cur != 0){ 7719 if(*cur == '"'){ 7720 if (base != cur) 7721 xmlBufferAdd(buf, base, cur - base); 7722 xmlBufferAdd(buf, BAD_CAST """, 6); 7723 cur++; 7724 base = cur; 7725 } 7726 else { 7727 cur++; 7728 } 7729 } 7730 if (base != cur) 7731 xmlBufferAdd(buf, base, cur - base); 7732 xmlBufferCCat(buf, "\""); 7733 } 7734 else{ 7735 xmlBufferCCat(buf, "\'"); 7736 xmlBufferCat(buf, string); 7737 xmlBufferCCat(buf, "\'"); 7738 } 7739 } else { 7740 xmlBufferCCat(buf, "\""); 7741 xmlBufferCat(buf, string); 7742 xmlBufferCCat(buf, "\""); 7743 } 7744 } 7745 7746 7747 /** 7748 * xmlGetDocCompressMode: 7749 * @doc: the document 7750 * 7751 * get the compression ratio for a document, ZLIB based 7752 * Returns 0 (uncompressed) to 9 (max compression) 7753 */ 7754 int 7755 xmlGetDocCompressMode (const xmlDoc *doc) { 7756 if (doc == NULL) return(-1); 7757 return(doc->compression); 7758 } 7759 7760 /** 7761 * xmlSetDocCompressMode: 7762 * @doc: the document 7763 * @mode: the compression ratio 7764 * 7765 * set the compression ratio for a document, ZLIB based 7766 * Correct values: 0 (uncompressed) to 9 (max compression) 7767 */ 7768 void 7769 xmlSetDocCompressMode (xmlDocPtr doc, int mode) { 7770 if (doc == NULL) return; 7771 if (mode < 0) doc->compression = 0; 7772 else if (mode > 9) doc->compression = 9; 7773 else doc->compression = mode; 7774 } 7775 7776 /** 7777 * xmlGetCompressMode: 7778 * 7779 * get the default compression mode used, ZLIB based. 7780 * Returns 0 (uncompressed) to 9 (max compression) 7781 */ 7782 int 7783 xmlGetCompressMode(void) 7784 { 7785 return (xmlCompressMode); 7786 } 7787 7788 /** 7789 * xmlSetCompressMode: 7790 * @mode: the compression ratio 7791 * 7792 * set the default compression mode used, ZLIB based 7793 * Correct values: 0 (uncompressed) to 9 (max compression) 7794 */ 7795 void 7796 xmlSetCompressMode(int mode) { 7797 if (mode < 0) xmlCompressMode = 0; 7798 else if (mode > 9) xmlCompressMode = 9; 7799 else xmlCompressMode = mode; 7800 } 7801 7802 #define XML_TREE_NSMAP_PARENT -1 7803 #define XML_TREE_NSMAP_XML -2 7804 #define XML_TREE_NSMAP_DOC -3 7805 #define XML_TREE_NSMAP_CUSTOM -4 7806 7807 typedef struct xmlNsMapItem *xmlNsMapItemPtr; 7808 struct xmlNsMapItem { 7809 xmlNsMapItemPtr next; 7810 xmlNsMapItemPtr prev; 7811 xmlNsPtr oldNs; /* old ns decl reference */ 7812 xmlNsPtr newNs; /* new ns decl reference */ 7813 int shadowDepth; /* Shadowed at this depth */ 7814 /* 7815 * depth: 7816 * >= 0 == @node's ns-decls 7817 * -1 == @parent's ns-decls 7818 * -2 == the doc->oldNs XML ns-decl 7819 * -3 == the doc->oldNs storage ns-decls 7820 * -4 == ns-decls provided via custom ns-handling 7821 */ 7822 int depth; 7823 }; 7824 7825 typedef struct xmlNsMap *xmlNsMapPtr; 7826 struct xmlNsMap { 7827 xmlNsMapItemPtr first; 7828 xmlNsMapItemPtr last; 7829 xmlNsMapItemPtr pool; 7830 }; 7831 7832 #define XML_NSMAP_NOTEMPTY(m) (((m) != NULL) && ((m)->first != NULL)) 7833 #define XML_NSMAP_FOREACH(m, i) for (i = (m)->first; i != NULL; i = (i)->next) 7834 #define XML_NSMAP_POP(m, i) \ 7835 i = (m)->last; \ 7836 (m)->last = (i)->prev; \ 7837 if ((m)->last == NULL) \ 7838 (m)->first = NULL; \ 7839 else \ 7840 (m)->last->next = NULL; \ 7841 (i)->next = (m)->pool; \ 7842 (m)->pool = i; 7843 7844 /* 7845 * xmlDOMWrapNsMapFree: 7846 * @map: the ns-map 7847 * 7848 * Frees the ns-map 7849 */ 7850 static void 7851 xmlDOMWrapNsMapFree(xmlNsMapPtr nsmap) 7852 { 7853 xmlNsMapItemPtr cur, tmp; 7854 7855 if (nsmap == NULL) 7856 return; 7857 cur = nsmap->pool; 7858 while (cur != NULL) { 7859 tmp = cur; 7860 cur = cur->next; 7861 xmlFree(tmp); 7862 } 7863 cur = nsmap->first; 7864 while (cur != NULL) { 7865 tmp = cur; 7866 cur = cur->next; 7867 xmlFree(tmp); 7868 } 7869 xmlFree(nsmap); 7870 } 7871 7872 /* 7873 * xmlDOMWrapNsMapAddItem: 7874 * @map: the ns-map 7875 * @oldNs: the old ns-struct 7876 * @newNs: the new ns-struct 7877 * @depth: depth and ns-kind information 7878 * 7879 * Adds an ns-mapping item. 7880 */ 7881 static xmlNsMapItemPtr 7882 xmlDOMWrapNsMapAddItem(xmlNsMapPtr *nsmap, int position, 7883 xmlNsPtr oldNs, xmlNsPtr newNs, int depth) 7884 { 7885 xmlNsMapItemPtr ret; 7886 xmlNsMapPtr map; 7887 7888 if (nsmap == NULL) 7889 return(NULL); 7890 if ((position != -1) && (position != 0)) 7891 return(NULL); 7892 map = *nsmap; 7893 7894 if (map == NULL) { 7895 /* 7896 * Create the ns-map. 7897 */ 7898 map = (xmlNsMapPtr) xmlMalloc(sizeof(struct xmlNsMap)); 7899 if (map == NULL) { 7900 xmlTreeErrMemory("allocating namespace map"); 7901 return (NULL); 7902 } 7903 memset(map, 0, sizeof(struct xmlNsMap)); 7904 *nsmap = map; 7905 } 7906 7907 if (map->pool != NULL) { 7908 /* 7909 * Reuse an item from the pool. 7910 */ 7911 ret = map->pool; 7912 map->pool = ret->next; 7913 memset(ret, 0, sizeof(struct xmlNsMapItem)); 7914 } else { 7915 /* 7916 * Create a new item. 7917 */ 7918 ret = (xmlNsMapItemPtr) xmlMalloc(sizeof(struct xmlNsMapItem)); 7919 if (ret == NULL) { 7920 xmlTreeErrMemory("allocating namespace map item"); 7921 return (NULL); 7922 } 7923 memset(ret, 0, sizeof(struct xmlNsMapItem)); 7924 } 7925 7926 if (map->first == NULL) { 7927 /* 7928 * First ever. 7929 */ 7930 map->first = ret; 7931 map->last = ret; 7932 } else if (position == -1) { 7933 /* 7934 * Append. 7935 */ 7936 ret->prev = map->last; 7937 map->last->next = ret; 7938 map->last = ret; 7939 } else if (position == 0) { 7940 /* 7941 * Set on first position. 7942 */ 7943 map->first->prev = ret; 7944 ret->next = map->first; 7945 map->first = ret; 7946 } 7947 7948 ret->oldNs = oldNs; 7949 ret->newNs = newNs; 7950 ret->shadowDepth = -1; 7951 ret->depth = depth; 7952 return (ret); 7953 } 7954 7955 /* 7956 * xmlDOMWrapStoreNs: 7957 * @doc: the doc 7958 * @nsName: the namespace name 7959 * @prefix: the prefix 7960 * 7961 * Creates or reuses an xmlNs struct on doc->oldNs with 7962 * the given prefix and namespace name. 7963 * 7964 * Returns the aquired ns struct or NULL in case of an API 7965 * or internal error. 7966 */ 7967 static xmlNsPtr 7968 xmlDOMWrapStoreNs(xmlDocPtr doc, 7969 const xmlChar *nsName, 7970 const xmlChar *prefix) 7971 { 7972 xmlNsPtr ns; 7973 7974 if (doc == NULL) 7975 return (NULL); 7976 ns = xmlTreeEnsureXMLDecl(doc); 7977 if (ns == NULL) 7978 return (NULL); 7979 if (ns->next != NULL) { 7980 /* Reuse. */ 7981 ns = ns->next; 7982 while (ns != NULL) { 7983 if (((ns->prefix == prefix) || 7984 xmlStrEqual(ns->prefix, prefix)) && 7985 xmlStrEqual(ns->href, nsName)) { 7986 return (ns); 7987 } 7988 if (ns->next == NULL) 7989 break; 7990 ns = ns->next; 7991 } 7992 } 7993 /* Create. */ 7994 if (ns != NULL) { 7995 ns->next = xmlNewNs(NULL, nsName, prefix); 7996 return (ns->next); 7997 } 7998 return(NULL); 7999 } 8000 8001 /* 8002 * xmlDOMWrapNewCtxt: 8003 * 8004 * Allocates and initializes a new DOM-wrapper context. 8005 * 8006 * Returns the xmlDOMWrapCtxtPtr or NULL in case of an internal error. 8007 */ 8008 xmlDOMWrapCtxtPtr 8009 xmlDOMWrapNewCtxt(void) 8010 { 8011 xmlDOMWrapCtxtPtr ret; 8012 8013 ret = xmlMalloc(sizeof(xmlDOMWrapCtxt)); 8014 if (ret == NULL) { 8015 xmlTreeErrMemory("allocating DOM-wrapper context"); 8016 return (NULL); 8017 } 8018 memset(ret, 0, sizeof(xmlDOMWrapCtxt)); 8019 return (ret); 8020 } 8021 8022 /* 8023 * xmlDOMWrapFreeCtxt: 8024 * @ctxt: the DOM-wrapper context 8025 * 8026 * Frees the DOM-wrapper context. 8027 */ 8028 void 8029 xmlDOMWrapFreeCtxt(xmlDOMWrapCtxtPtr ctxt) 8030 { 8031 if (ctxt == NULL) 8032 return; 8033 if (ctxt->namespaceMap != NULL) 8034 xmlDOMWrapNsMapFree((xmlNsMapPtr) ctxt->namespaceMap); 8035 /* 8036 * TODO: Store the namespace map in the context. 8037 */ 8038 xmlFree(ctxt); 8039 } 8040 8041 /* 8042 * xmlTreeLookupNsListByPrefix: 8043 * @nsList: a list of ns-structs 8044 * @prefix: the searched prefix 8045 * 8046 * Searches for a ns-decl with the given prefix in @nsList. 8047 * 8048 * Returns the ns-decl if found, NULL if not found and on 8049 * API errors. 8050 */ 8051 static xmlNsPtr 8052 xmlTreeNSListLookupByPrefix(xmlNsPtr nsList, const xmlChar *prefix) 8053 { 8054 if (nsList == NULL) 8055 return (NULL); 8056 { 8057 xmlNsPtr ns; 8058 ns = nsList; 8059 do { 8060 if ((prefix == ns->prefix) || 8061 xmlStrEqual(prefix, ns->prefix)) { 8062 return (ns); 8063 } 8064 ns = ns->next; 8065 } while (ns != NULL); 8066 } 8067 return (NULL); 8068 } 8069 8070 /* 8071 * 8072 * xmlDOMWrapNSNormGatherInScopeNs: 8073 * @map: the namespace map 8074 * @node: the node to start with 8075 * 8076 * Puts in-scope namespaces into the ns-map. 8077 * 8078 * Returns 0 on success, -1 on API or internal errors. 8079 */ 8080 static int 8081 xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapPtr *map, 8082 xmlNodePtr node) 8083 { 8084 xmlNodePtr cur; 8085 xmlNsPtr ns; 8086 xmlNsMapItemPtr mi; 8087 int shadowed; 8088 8089 if ((map == NULL) || (*map != NULL)) 8090 return (-1); 8091 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) 8092 return (-1); 8093 /* 8094 * Get in-scope ns-decls of @parent. 8095 */ 8096 cur = node; 8097 while ((cur != NULL) && (cur != (xmlNodePtr) cur->doc)) { 8098 if (cur->type == XML_ELEMENT_NODE) { 8099 if (cur->nsDef != NULL) { 8100 ns = cur->nsDef; 8101 do { 8102 shadowed = 0; 8103 if (XML_NSMAP_NOTEMPTY(*map)) { 8104 /* 8105 * Skip shadowed prefixes. 8106 */ 8107 XML_NSMAP_FOREACH(*map, mi) { 8108 if ((ns->prefix == mi->newNs->prefix) || 8109 xmlStrEqual(ns->prefix, mi->newNs->prefix)) { 8110 shadowed = 1; 8111 break; 8112 } 8113 } 8114 } 8115 /* 8116 * Insert mapping. 8117 */ 8118 mi = xmlDOMWrapNsMapAddItem(map, 0, NULL, 8119 ns, XML_TREE_NSMAP_PARENT); 8120 if (mi == NULL) 8121 return (-1); 8122 if (shadowed) 8123 mi->shadowDepth = 0; 8124 ns = ns->next; 8125 } while (ns != NULL); 8126 } 8127 } 8128 cur = cur->parent; 8129 } 8130 return (0); 8131 } 8132 8133 /* 8134 * XML_TREE_ADOPT_STR: If we have a dest-dict, put @str in the dict; 8135 * otherwise copy it, when it was in the source-dict. 8136 */ 8137 #define XML_TREE_ADOPT_STR(str) \ 8138 if (adoptStr && (str != NULL)) { \ 8139 if (destDoc->dict) { \ 8140 const xmlChar *old = str; \ 8141 str = xmlDictLookup(destDoc->dict, str, -1); \ 8142 if ((sourceDoc == NULL) || (sourceDoc->dict == NULL) || \ 8143 (!xmlDictOwns(sourceDoc->dict, old))) \ 8144 xmlFree((char *)old); \ 8145 } else if ((sourceDoc) && (sourceDoc->dict) && \ 8146 xmlDictOwns(sourceDoc->dict, str)) { \ 8147 str = BAD_CAST xmlStrdup(str); \ 8148 } \ 8149 } 8150 8151 /* 8152 * XML_TREE_ADOPT_STR_2: If @str was in the source-dict, then 8153 * put it in dest-dict or copy it. 8154 */ 8155 #define XML_TREE_ADOPT_STR_2(str) \ 8156 if (adoptStr && (str != NULL) && (sourceDoc != NULL) && \ 8157 (sourceDoc->dict != NULL) && \ 8158 xmlDictOwns(sourceDoc->dict, cur->content)) { \ 8159 if (destDoc->dict) \ 8160 cur->content = (xmlChar *) \ 8161 xmlDictLookup(destDoc->dict, cur->content, -1); \ 8162 else \ 8163 cur->content = xmlStrdup(BAD_CAST cur->content); \ 8164 } 8165 8166 /* 8167 * xmlDOMWrapNSNormAddNsMapItem2: 8168 * 8169 * For internal use. Adds a ns-decl mapping. 8170 * 8171 * Returns 0 on success, -1 on internal errors. 8172 */ 8173 static int 8174 xmlDOMWrapNSNormAddNsMapItem2(xmlNsPtr **list, int *size, int *number, 8175 xmlNsPtr oldNs, xmlNsPtr newNs) 8176 { 8177 if (*list == NULL) { 8178 *list = (xmlNsPtr *) xmlMalloc(6 * sizeof(xmlNsPtr)); 8179 if (*list == NULL) { 8180 xmlTreeErrMemory("alloc ns map item"); 8181 return(-1); 8182 } 8183 *size = 3; 8184 *number = 0; 8185 } else if ((*number) >= (*size)) { 8186 *size *= 2; 8187 *list = (xmlNsPtr *) xmlRealloc(*list, 8188 (*size) * 2 * sizeof(xmlNsPtr)); 8189 if (*list == NULL) { 8190 xmlTreeErrMemory("realloc ns map item"); 8191 return(-1); 8192 } 8193 } 8194 (*list)[2 * (*number)] = oldNs; 8195 (*list)[2 * (*number) +1] = newNs; 8196 (*number)++; 8197 return (0); 8198 } 8199 8200 /* 8201 * xmlDOMWrapRemoveNode: 8202 * @ctxt: a DOM wrapper context 8203 * @doc: the doc 8204 * @node: the node to be removed. 8205 * @options: set of options, unused at the moment 8206 * 8207 * Unlinks the given node from its owner. 8208 * This will substitute ns-references to node->nsDef for 8209 * ns-references to doc->oldNs, thus ensuring the removed 8210 * branch to be autark wrt ns-references. 8211 * 8212 * NOTE: This function was not intensively tested. 8213 * 8214 * Returns 0 on success, 1 if the node is not supported, 8215 * -1 on API and internal errors. 8216 */ 8217 int 8218 xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc, 8219 xmlNodePtr node, int options ATTRIBUTE_UNUSED) 8220 { 8221 xmlNsPtr *list = NULL; 8222 int sizeList, nbList, i, j; 8223 xmlNsPtr ns; 8224 8225 if ((node == NULL) || (doc == NULL) || (node->doc != doc)) 8226 return (-1); 8227 8228 /* TODO: 0 or -1 ? */ 8229 if (node->parent == NULL) 8230 return (0); 8231 8232 switch (node->type) { 8233 case XML_TEXT_NODE: 8234 case XML_CDATA_SECTION_NODE: 8235 case XML_ENTITY_REF_NODE: 8236 case XML_PI_NODE: 8237 case XML_COMMENT_NODE: 8238 xmlUnlinkNode(node); 8239 return (0); 8240 case XML_ELEMENT_NODE: 8241 case XML_ATTRIBUTE_NODE: 8242 break; 8243 default: 8244 return (1); 8245 } 8246 xmlUnlinkNode(node); 8247 /* 8248 * Save out-of-scope ns-references in doc->oldNs. 8249 */ 8250 do { 8251 switch (node->type) { 8252 case XML_ELEMENT_NODE: 8253 if ((ctxt == NULL) && (node->nsDef != NULL)) { 8254 ns = node->nsDef; 8255 do { 8256 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList, 8257 &nbList, ns, ns) == -1) 8258 goto internal_error; 8259 ns = ns->next; 8260 } while (ns != NULL); 8261 } 8262 /* Falls through. */ 8263 case XML_ATTRIBUTE_NODE: 8264 if (node->ns != NULL) { 8265 /* 8266 * Find a mapping. 8267 */ 8268 if (list != NULL) { 8269 for (i = 0, j = 0; i < nbList; i++, j += 2) { 8270 if (node->ns == list[j]) { 8271 node->ns = list[++j]; 8272 goto next_node; 8273 } 8274 } 8275 } 8276 ns = NULL; 8277 if (ctxt != NULL) { 8278 /* 8279 * User defined. 8280 */ 8281 } else { 8282 /* 8283 * Add to doc's oldNs. 8284 */ 8285 ns = xmlDOMWrapStoreNs(doc, node->ns->href, 8286 node->ns->prefix); 8287 if (ns == NULL) 8288 goto internal_error; 8289 } 8290 if (ns != NULL) { 8291 /* 8292 * Add mapping. 8293 */ 8294 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList, 8295 &nbList, node->ns, ns) == -1) 8296 goto internal_error; 8297 } 8298 node->ns = ns; 8299 } 8300 if ((node->type == XML_ELEMENT_NODE) && 8301 (node->properties != NULL)) { 8302 node = (xmlNodePtr) node->properties; 8303 continue; 8304 } 8305 break; 8306 default: 8307 goto next_sibling; 8308 } 8309 next_node: 8310 if ((node->type == XML_ELEMENT_NODE) && 8311 (node->children != NULL)) { 8312 node = node->children; 8313 continue; 8314 } 8315 next_sibling: 8316 if (node == NULL) 8317 break; 8318 if (node->next != NULL) 8319 node = node->next; 8320 else { 8321 node = node->parent; 8322 goto next_sibling; 8323 } 8324 } while (node != NULL); 8325 8326 if (list != NULL) 8327 xmlFree(list); 8328 return (0); 8329 8330 internal_error: 8331 if (list != NULL) 8332 xmlFree(list); 8333 return (-1); 8334 } 8335 8336 /* 8337 * xmlSearchNsByNamespaceStrict: 8338 * @doc: the document 8339 * @node: the start node 8340 * @nsName: the searched namespace name 8341 * @retNs: the resulting ns-decl 8342 * @prefixed: if the found ns-decl must have a prefix (for attributes) 8343 * 8344 * Dynamically searches for a ns-declaration which matches 8345 * the given @nsName in the ancestor-or-self axis of @node. 8346 * 8347 * Returns 1 if a ns-decl was found, 0 if not and -1 on API 8348 * and internal errors. 8349 */ 8350 static int 8351 xmlSearchNsByNamespaceStrict(xmlDocPtr doc, xmlNodePtr node, 8352 const xmlChar* nsName, 8353 xmlNsPtr *retNs, int prefixed) 8354 { 8355 xmlNodePtr cur, prev = NULL, out = NULL; 8356 xmlNsPtr ns, prevns; 8357 8358 if ((doc == NULL) || (nsName == NULL) || (retNs == NULL)) 8359 return (-1); 8360 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) 8361 return(-1); 8362 8363 *retNs = NULL; 8364 if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) { 8365 *retNs = xmlTreeEnsureXMLDecl(doc); 8366 if (*retNs == NULL) 8367 return (-1); 8368 return (1); 8369 } 8370 cur = node; 8371 do { 8372 if (cur->type == XML_ELEMENT_NODE) { 8373 if (cur->nsDef != NULL) { 8374 for (ns = cur->nsDef; ns != NULL; ns = ns->next) { 8375 if (prefixed && (ns->prefix == NULL)) 8376 continue; 8377 if (prev != NULL) { 8378 /* 8379 * Check the last level of ns-decls for a 8380 * shadowing prefix. 8381 */ 8382 prevns = prev->nsDef; 8383 do { 8384 if ((prevns->prefix == ns->prefix) || 8385 ((prevns->prefix != NULL) && 8386 (ns->prefix != NULL) && 8387 xmlStrEqual(prevns->prefix, ns->prefix))) { 8388 /* 8389 * Shadowed. 8390 */ 8391 break; 8392 } 8393 prevns = prevns->next; 8394 } while (prevns != NULL); 8395 if (prevns != NULL) 8396 continue; 8397 } 8398 /* 8399 * Ns-name comparison. 8400 */ 8401 if ((nsName == ns->href) || 8402 xmlStrEqual(nsName, ns->href)) { 8403 /* 8404 * At this point the prefix can only be shadowed, 8405 * if we are the the (at least) 3rd level of 8406 * ns-decls. 8407 */ 8408 if (out) { 8409 int ret; 8410 8411 ret = xmlNsInScope(doc, node, prev, ns->prefix); 8412 if (ret < 0) 8413 return (-1); 8414 /* 8415 * TODO: Should we try to find a matching ns-name 8416 * only once? This here keeps on searching. 8417 * I think we should try further since, there might 8418 * be an other matching ns-decl with an unshadowed 8419 * prefix. 8420 */ 8421 if (! ret) 8422 continue; 8423 } 8424 *retNs = ns; 8425 return (1); 8426 } 8427 } 8428 out = prev; 8429 prev = cur; 8430 } 8431 } else if ((cur->type == XML_ENTITY_NODE) || 8432 (cur->type == XML_ENTITY_DECL)) 8433 return (0); 8434 cur = cur->parent; 8435 } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur)); 8436 return (0); 8437 } 8438 8439 /* 8440 * xmlSearchNsByPrefixStrict: 8441 * @doc: the document 8442 * @node: the start node 8443 * @prefix: the searched namespace prefix 8444 * @retNs: the resulting ns-decl 8445 * 8446 * Dynamically searches for a ns-declaration which matches 8447 * the given @nsName in the ancestor-or-self axis of @node. 8448 * 8449 * Returns 1 if a ns-decl was found, 0 if not and -1 on API 8450 * and internal errors. 8451 */ 8452 static int 8453 xmlSearchNsByPrefixStrict(xmlDocPtr doc, xmlNodePtr node, 8454 const xmlChar* prefix, 8455 xmlNsPtr *retNs) 8456 { 8457 xmlNodePtr cur; 8458 xmlNsPtr ns; 8459 8460 if ((doc == NULL) || (node == NULL) || (node->type == XML_NAMESPACE_DECL)) 8461 return(-1); 8462 8463 if (retNs) 8464 *retNs = NULL; 8465 if (IS_STR_XML(prefix)) { 8466 if (retNs) { 8467 *retNs = xmlTreeEnsureXMLDecl(doc); 8468 if (*retNs == NULL) 8469 return (-1); 8470 } 8471 return (1); 8472 } 8473 cur = node; 8474 do { 8475 if (cur->type == XML_ELEMENT_NODE) { 8476 if (cur->nsDef != NULL) { 8477 ns = cur->nsDef; 8478 do { 8479 if ((prefix == ns->prefix) || 8480 xmlStrEqual(prefix, ns->prefix)) 8481 { 8482 /* 8483 * Disabled namespaces, e.g. xmlns:abc="". 8484 */ 8485 if (ns->href == NULL) 8486 return(0); 8487 if (retNs) 8488 *retNs = ns; 8489 return (1); 8490 } 8491 ns = ns->next; 8492 } while (ns != NULL); 8493 } 8494 } else if ((cur->type == XML_ENTITY_NODE) || 8495 (cur->type == XML_ENTITY_DECL)) 8496 return (0); 8497 cur = cur->parent; 8498 } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur)); 8499 return (0); 8500 } 8501 8502 /* 8503 * xmlDOMWrapNSNormDeclareNsForced: 8504 * @doc: the doc 8505 * @elem: the element-node to declare on 8506 * @nsName: the namespace-name of the ns-decl 8507 * @prefix: the preferred prefix of the ns-decl 8508 * @checkShadow: ensure that the new ns-decl doesn't shadow ancestor ns-decls 8509 * 8510 * Declares a new namespace on @elem. It tries to use the 8511 * given @prefix; if a ns-decl with the given prefix is already existent 8512 * on @elem, it will generate an other prefix. 8513 * 8514 * Returns 1 if a ns-decl was found, 0 if not and -1 on API 8515 * and internal errors. 8516 */ 8517 static xmlNsPtr 8518 xmlDOMWrapNSNormDeclareNsForced(xmlDocPtr doc, 8519 xmlNodePtr elem, 8520 const xmlChar *nsName, 8521 const xmlChar *prefix, 8522 int checkShadow) 8523 { 8524 8525 xmlNsPtr ret; 8526 char buf[50]; 8527 const xmlChar *pref; 8528 int counter = 0; 8529 8530 if ((doc == NULL) || (elem == NULL) || (elem->type != XML_ELEMENT_NODE)) 8531 return(NULL); 8532 /* 8533 * Create a ns-decl on @anchor. 8534 */ 8535 pref = prefix; 8536 while (1) { 8537 /* 8538 * Lookup whether the prefix is unused in elem's ns-decls. 8539 */ 8540 if ((elem->nsDef != NULL) && 8541 (xmlTreeNSListLookupByPrefix(elem->nsDef, pref) != NULL)) 8542 goto ns_next_prefix; 8543 if (checkShadow && elem->parent && 8544 ((xmlNodePtr) elem->parent->doc != elem->parent)) { 8545 /* 8546 * Does it shadow ancestor ns-decls? 8547 */ 8548 if (xmlSearchNsByPrefixStrict(doc, elem->parent, pref, NULL) == 1) 8549 goto ns_next_prefix; 8550 } 8551 ret = xmlNewNs(NULL, nsName, pref); 8552 if (ret == NULL) 8553 return (NULL); 8554 if (elem->nsDef == NULL) 8555 elem->nsDef = ret; 8556 else { 8557 xmlNsPtr ns2 = elem->nsDef; 8558 while (ns2->next != NULL) 8559 ns2 = ns2->next; 8560 ns2->next = ret; 8561 } 8562 return (ret); 8563 ns_next_prefix: 8564 counter++; 8565 if (counter > 1000) 8566 return (NULL); 8567 if (prefix == NULL) { 8568 snprintf((char *) buf, sizeof(buf), 8569 "ns_%d", counter); 8570 } else 8571 snprintf((char *) buf, sizeof(buf), 8572 "%.30s_%d", (char *)prefix, counter); 8573 pref = BAD_CAST buf; 8574 } 8575 } 8576 8577 /* 8578 * xmlDOMWrapNSNormAquireNormalizedNs: 8579 * @doc: the doc 8580 * @elem: the element-node to declare namespaces on 8581 * @ns: the ns-struct to use for the search 8582 * @retNs: the found/created ns-struct 8583 * @nsMap: the ns-map 8584 * @depth: the current tree depth 8585 * @ancestorsOnly: search in ancestor ns-decls only 8586 * @prefixed: if the searched ns-decl must have a prefix (for attributes) 8587 * 8588 * Searches for a matching ns-name in the ns-decls of @nsMap, if not 8589 * found it will either declare it on @elem, or store it in doc->oldNs. 8590 * If a new ns-decl needs to be declared on @elem, it tries to use the 8591 * @ns->prefix for it, if this prefix is already in use on @elem, it will 8592 * change the prefix or the new ns-decl. 8593 * 8594 * Returns 0 if succeeded, -1 otherwise and on API/internal errors. 8595 */ 8596 static int 8597 xmlDOMWrapNSNormAquireNormalizedNs(xmlDocPtr doc, 8598 xmlNodePtr elem, 8599 xmlNsPtr ns, 8600 xmlNsPtr *retNs, 8601 xmlNsMapPtr *nsMap, 8602 8603 int depth, 8604 int ancestorsOnly, 8605 int prefixed) 8606 { 8607 xmlNsMapItemPtr mi; 8608 8609 if ((doc == NULL) || (ns == NULL) || (retNs == NULL) || 8610 (nsMap == NULL)) 8611 return (-1); 8612 8613 *retNs = NULL; 8614 /* 8615 * Handle XML namespace. 8616 */ 8617 if (IS_STR_XML(ns->prefix)) { 8618 /* 8619 * Insert XML namespace mapping. 8620 */ 8621 *retNs = xmlTreeEnsureXMLDecl(doc); 8622 if (*retNs == NULL) 8623 return (-1); 8624 return (0); 8625 } 8626 /* 8627 * If the search should be done in ancestors only and no 8628 * @elem (the first ancestor) was specified, then skip the search. 8629 */ 8630 if ((XML_NSMAP_NOTEMPTY(*nsMap)) && 8631 (! (ancestorsOnly && (elem == NULL)))) 8632 { 8633 /* 8634 * Try to find an equal ns-name in in-scope ns-decls. 8635 */ 8636 XML_NSMAP_FOREACH(*nsMap, mi) { 8637 if ((mi->depth >= XML_TREE_NSMAP_PARENT) && 8638 /* 8639 * ancestorsOnly: This should be turned on to gain speed, 8640 * if one knows that the branch itself was already 8641 * ns-wellformed and no stale references existed. 8642 * I.e. it searches in the ancestor axis only. 8643 */ 8644 ((! ancestorsOnly) || (mi->depth == XML_TREE_NSMAP_PARENT)) && 8645 /* Skip shadowed prefixes. */ 8646 (mi->shadowDepth == -1) && 8647 /* Skip xmlns="" or xmlns:foo="". */ 8648 ((mi->newNs->href != NULL) && 8649 (mi->newNs->href[0] != 0)) && 8650 /* Ensure a prefix if wanted. */ 8651 ((! prefixed) || (mi->newNs->prefix != NULL)) && 8652 /* Equal ns name */ 8653 ((mi->newNs->href == ns->href) || 8654 xmlStrEqual(mi->newNs->href, ns->href))) { 8655 /* Set the mapping. */ 8656 mi->oldNs = ns; 8657 *retNs = mi->newNs; 8658 return (0); 8659 } 8660 } 8661 } 8662 /* 8663 * No luck, the namespace is out of scope or shadowed. 8664 */ 8665 if (elem == NULL) { 8666 xmlNsPtr tmpns; 8667 8668 /* 8669 * Store ns-decls in "oldNs" of the document-node. 8670 */ 8671 tmpns = xmlDOMWrapStoreNs(doc, ns->href, ns->prefix); 8672 if (tmpns == NULL) 8673 return (-1); 8674 /* 8675 * Insert mapping. 8676 */ 8677 if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns, 8678 tmpns, XML_TREE_NSMAP_DOC) == NULL) { 8679 xmlFreeNs(tmpns); 8680 return (-1); 8681 } 8682 *retNs = tmpns; 8683 } else { 8684 xmlNsPtr tmpns; 8685 8686 tmpns = xmlDOMWrapNSNormDeclareNsForced(doc, elem, ns->href, 8687 ns->prefix, 0); 8688 if (tmpns == NULL) 8689 return (-1); 8690 8691 if (*nsMap != NULL) { 8692 /* 8693 * Does it shadow ancestor ns-decls? 8694 */ 8695 XML_NSMAP_FOREACH(*nsMap, mi) { 8696 if ((mi->depth < depth) && 8697 (mi->shadowDepth == -1) && 8698 ((ns->prefix == mi->newNs->prefix) || 8699 xmlStrEqual(ns->prefix, mi->newNs->prefix))) { 8700 /* 8701 * Shadows. 8702 */ 8703 mi->shadowDepth = depth; 8704 break; 8705 } 8706 } 8707 } 8708 if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns, tmpns, depth) == NULL) { 8709 xmlFreeNs(tmpns); 8710 return (-1); 8711 } 8712 *retNs = tmpns; 8713 } 8714 return (0); 8715 } 8716 8717 typedef enum { 8718 XML_DOM_RECONNS_REMOVEREDUND = 1<<0 8719 } xmlDOMReconcileNSOptions; 8720 8721 /* 8722 * xmlDOMWrapReconcileNamespaces: 8723 * @ctxt: DOM wrapper context, unused at the moment 8724 * @elem: the element-node 8725 * @options: option flags 8726 * 8727 * Ensures that ns-references point to ns-decls hold on element-nodes. 8728 * Ensures that the tree is namespace wellformed by creating additional 8729 * ns-decls where needed. Note that, since prefixes of already existent 8730 * ns-decls can be shadowed by this process, it could break QNames in 8731 * attribute values or element content. 8732 * 8733 * NOTE: This function was not intensively tested. 8734 * 8735 * Returns 0 if succeeded, -1 otherwise and on API/internal errors. 8736 */ 8737 8738 int 8739 xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED, 8740 xmlNodePtr elem, 8741 int options) 8742 { 8743 int depth = -1, adoptns = 0, parnsdone = 0; 8744 xmlNsPtr ns, prevns; 8745 xmlDocPtr doc; 8746 xmlNodePtr cur, curElem = NULL; 8747 xmlNsMapPtr nsMap = NULL; 8748 xmlNsMapItemPtr /* topmi = NULL, */ mi; 8749 /* @ancestorsOnly should be set by an option flag. */ 8750 int ancestorsOnly = 0; 8751 int optRemoveRedundantNS = 8752 ((xmlDOMReconcileNSOptions) options & XML_DOM_RECONNS_REMOVEREDUND) ? 1 : 0; 8753 xmlNsPtr *listRedund = NULL; 8754 int sizeRedund = 0, nbRedund = 0, ret, i, j; 8755 8756 if ((elem == NULL) || (elem->doc == NULL) || 8757 (elem->type != XML_ELEMENT_NODE)) 8758 return (-1); 8759 8760 doc = elem->doc; 8761 cur = elem; 8762 do { 8763 switch (cur->type) { 8764 case XML_ELEMENT_NODE: 8765 adoptns = 1; 8766 curElem = cur; 8767 depth++; 8768 /* 8769 * Namespace declarations. 8770 */ 8771 if (cur->nsDef != NULL) { 8772 prevns = NULL; 8773 ns = cur->nsDef; 8774 while (ns != NULL) { 8775 if (! parnsdone) { 8776 if ((elem->parent) && 8777 ((xmlNodePtr) elem->parent->doc != elem->parent)) { 8778 /* 8779 * Gather ancestor in-scope ns-decls. 8780 */ 8781 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, 8782 elem->parent) == -1) 8783 goto internal_error; 8784 } 8785 parnsdone = 1; 8786 } 8787 8788 /* 8789 * Lookup the ns ancestor-axis for equal ns-decls in scope. 8790 */ 8791 if (optRemoveRedundantNS && XML_NSMAP_NOTEMPTY(nsMap)) { 8792 XML_NSMAP_FOREACH(nsMap, mi) { 8793 if ((mi->depth >= XML_TREE_NSMAP_PARENT) && 8794 (mi->shadowDepth == -1) && 8795 ((ns->prefix == mi->newNs->prefix) || 8796 xmlStrEqual(ns->prefix, mi->newNs->prefix)) && 8797 ((ns->href == mi->newNs->href) || 8798 xmlStrEqual(ns->href, mi->newNs->href))) 8799 { 8800 /* 8801 * A redundant ns-decl was found. 8802 * Add it to the list of redundant ns-decls. 8803 */ 8804 if (xmlDOMWrapNSNormAddNsMapItem2(&listRedund, 8805 &sizeRedund, &nbRedund, ns, mi->newNs) == -1) 8806 goto internal_error; 8807 /* 8808 * Remove the ns-decl from the element-node. 8809 */ 8810 if (prevns) 8811 prevns->next = ns->next; 8812 else 8813 cur->nsDef = ns->next; 8814 goto next_ns_decl; 8815 } 8816 } 8817 } 8818 8819 /* 8820 * Skip ns-references handling if the referenced 8821 * ns-decl is declared on the same element. 8822 */ 8823 if ((cur->ns != NULL) && adoptns && (cur->ns == ns)) 8824 adoptns = 0; 8825 /* 8826 * Does it shadow any ns-decl? 8827 */ 8828 if (XML_NSMAP_NOTEMPTY(nsMap)) { 8829 XML_NSMAP_FOREACH(nsMap, mi) { 8830 if ((mi->depth >= XML_TREE_NSMAP_PARENT) && 8831 (mi->shadowDepth == -1) && 8832 ((ns->prefix == mi->newNs->prefix) || 8833 xmlStrEqual(ns->prefix, mi->newNs->prefix))) { 8834 8835 mi->shadowDepth = depth; 8836 } 8837 } 8838 } 8839 /* 8840 * Push mapping. 8841 */ 8842 if (xmlDOMWrapNsMapAddItem(&nsMap, -1, ns, ns, 8843 depth) == NULL) 8844 goto internal_error; 8845 8846 prevns = ns; 8847 next_ns_decl: 8848 ns = ns->next; 8849 } 8850 } 8851 if (! adoptns) 8852 goto ns_end; 8853 /* Falls through. */ 8854 case XML_ATTRIBUTE_NODE: 8855 /* No ns, no fun. */ 8856 if (cur->ns == NULL) 8857 goto ns_end; 8858 8859 if (! parnsdone) { 8860 if ((elem->parent) && 8861 ((xmlNodePtr) elem->parent->doc != elem->parent)) { 8862 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, 8863 elem->parent) == -1) 8864 goto internal_error; 8865 } 8866 parnsdone = 1; 8867 } 8868 /* 8869 * Adjust the reference if this was a redundant ns-decl. 8870 */ 8871 if (listRedund) { 8872 for (i = 0, j = 0; i < nbRedund; i++, j += 2) { 8873 if (cur->ns == listRedund[j]) { 8874 cur->ns = listRedund[++j]; 8875 break; 8876 } 8877 } 8878 } 8879 /* 8880 * Adopt ns-references. 8881 */ 8882 if (XML_NSMAP_NOTEMPTY(nsMap)) { 8883 /* 8884 * Search for a mapping. 8885 */ 8886 XML_NSMAP_FOREACH(nsMap, mi) { 8887 if ((mi->shadowDepth == -1) && 8888 (cur->ns == mi->oldNs)) { 8889 8890 cur->ns = mi->newNs; 8891 goto ns_end; 8892 } 8893 } 8894 } 8895 /* 8896 * Aquire a normalized ns-decl and add it to the map. 8897 */ 8898 if (xmlDOMWrapNSNormAquireNormalizedNs(doc, curElem, 8899 cur->ns, &ns, 8900 &nsMap, depth, 8901 ancestorsOnly, 8902 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1) 8903 goto internal_error; 8904 cur->ns = ns; 8905 8906 ns_end: 8907 if ((cur->type == XML_ELEMENT_NODE) && 8908 (cur->properties != NULL)) { 8909 /* 8910 * Process attributes. 8911 */ 8912 cur = (xmlNodePtr) cur->properties; 8913 continue; 8914 } 8915 break; 8916 default: 8917 goto next_sibling; 8918 } 8919 into_content: 8920 if ((cur->type == XML_ELEMENT_NODE) && 8921 (cur->children != NULL)) { 8922 /* 8923 * Process content of element-nodes only. 8924 */ 8925 cur = cur->children; 8926 continue; 8927 } 8928 next_sibling: 8929 if (cur == elem) 8930 break; 8931 if (cur->type == XML_ELEMENT_NODE) { 8932 if (XML_NSMAP_NOTEMPTY(nsMap)) { 8933 /* 8934 * Pop mappings. 8935 */ 8936 while ((nsMap->last != NULL) && 8937 (nsMap->last->depth >= depth)) 8938 { 8939 XML_NSMAP_POP(nsMap, mi) 8940 } 8941 /* 8942 * Unshadow. 8943 */ 8944 XML_NSMAP_FOREACH(nsMap, mi) { 8945 if (mi->shadowDepth >= depth) 8946 mi->shadowDepth = -1; 8947 } 8948 } 8949 depth--; 8950 } 8951 if (cur->next != NULL) 8952 cur = cur->next; 8953 else { 8954 if (cur->type == XML_ATTRIBUTE_NODE) { 8955 cur = cur->parent; 8956 goto into_content; 8957 } 8958 cur = cur->parent; 8959 goto next_sibling; 8960 } 8961 } while (cur != NULL); 8962 8963 ret = 0; 8964 goto exit; 8965 internal_error: 8966 ret = -1; 8967 exit: 8968 if (listRedund) { 8969 for (i = 0, j = 0; i < nbRedund; i++, j += 2) { 8970 xmlFreeNs(listRedund[j]); 8971 } 8972 xmlFree(listRedund); 8973 } 8974 if (nsMap != NULL) 8975 xmlDOMWrapNsMapFree(nsMap); 8976 return (ret); 8977 } 8978 8979 /* 8980 * xmlDOMWrapAdoptBranch: 8981 * @ctxt: the optional context for custom processing 8982 * @sourceDoc: the optional sourceDoc 8983 * @node: the element-node to start with 8984 * @destDoc: the destination doc for adoption 8985 * @destParent: the optional new parent of @node in @destDoc 8986 * @options: option flags 8987 * 8988 * Ensures that ns-references point to @destDoc: either to 8989 * elements->nsDef entries if @destParent is given, or to 8990 * @destDoc->oldNs otherwise. 8991 * If @destParent is given, it ensures that the tree is namespace 8992 * wellformed by creating additional ns-decls where needed. 8993 * Note that, since prefixes of already existent ns-decls can be 8994 * shadowed by this process, it could break QNames in attribute 8995 * values or element content. 8996 * 8997 * NOTE: This function was not intensively tested. 8998 * 8999 * Returns 0 if succeeded, -1 otherwise and on API/internal errors. 9000 */ 9001 static int 9002 xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt, 9003 xmlDocPtr sourceDoc, 9004 xmlNodePtr node, 9005 xmlDocPtr destDoc, 9006 xmlNodePtr destParent, 9007 int options ATTRIBUTE_UNUSED) 9008 { 9009 int ret = 0; 9010 xmlNodePtr cur, curElem = NULL; 9011 xmlNsMapPtr nsMap = NULL; 9012 xmlNsMapItemPtr mi; 9013 xmlNsPtr ns = NULL; 9014 int depth = -1, adoptStr = 1; 9015 /* gather @parent's ns-decls. */ 9016 int parnsdone; 9017 /* @ancestorsOnly should be set per option. */ 9018 int ancestorsOnly = 0; 9019 9020 /* 9021 * Optimize string adoption for equal or none dicts. 9022 */ 9023 if ((sourceDoc != NULL) && 9024 (sourceDoc->dict == destDoc->dict)) 9025 adoptStr = 0; 9026 else 9027 adoptStr = 1; 9028 9029 /* 9030 * Get the ns-map from the context if available. 9031 */ 9032 if (ctxt) 9033 nsMap = (xmlNsMapPtr) ctxt->namespaceMap; 9034 /* 9035 * Disable search for ns-decls in the parent-axis of the 9036 * desination element, if: 9037 * 1) there's no destination parent 9038 * 2) custom ns-reference handling is used 9039 */ 9040 if ((destParent == NULL) || 9041 (ctxt && ctxt->getNsForNodeFunc)) 9042 { 9043 parnsdone = 1; 9044 } else 9045 parnsdone = 0; 9046 9047 cur = node; 9048 if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL)) 9049 goto internal_error; 9050 9051 while (cur != NULL) { 9052 /* 9053 * Paranoid source-doc sanity check. 9054 */ 9055 if (cur->doc != sourceDoc) { 9056 /* 9057 * We'll assume XIncluded nodes if the doc differs. 9058 * TODO: Do we need to reconciliate XIncluded nodes? 9059 * This here skips XIncluded nodes and tries to handle 9060 * broken sequences. 9061 */ 9062 if (cur->next == NULL) 9063 goto leave_node; 9064 do { 9065 cur = cur->next; 9066 if ((cur->type == XML_XINCLUDE_END) || 9067 (cur->doc == node->doc)) 9068 break; 9069 } while (cur->next != NULL); 9070 9071 if (cur->doc != node->doc) 9072 goto leave_node; 9073 } 9074 cur->doc = destDoc; 9075 switch (cur->type) { 9076 case XML_XINCLUDE_START: 9077 case XML_XINCLUDE_END: 9078 /* 9079 * TODO 9080 */ 9081 return (-1); 9082 case XML_ELEMENT_NODE: 9083 curElem = cur; 9084 depth++; 9085 /* 9086 * Namespace declarations. 9087 * - ns->href and ns->prefix are never in the dict, so 9088 * we need not move the values over to the destination dict. 9089 * - Note that for custom handling of ns-references, 9090 * the ns-decls need not be stored in the ns-map, 9091 * since they won't be referenced by node->ns. 9092 */ 9093 if ((cur->nsDef) && 9094 ((ctxt == NULL) || (ctxt->getNsForNodeFunc == NULL))) 9095 { 9096 if (! parnsdone) { 9097 /* 9098 * Gather @parent's in-scope ns-decls. 9099 */ 9100 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, 9101 destParent) == -1) 9102 goto internal_error; 9103 parnsdone = 1; 9104 } 9105 for (ns = cur->nsDef; ns != NULL; ns = ns->next) { 9106 /* 9107 * NOTE: ns->prefix and ns->href are never in the dict. 9108 * XML_TREE_ADOPT_STR(ns->prefix) 9109 * XML_TREE_ADOPT_STR(ns->href) 9110 */ 9111 /* 9112 * Does it shadow any ns-decl? 9113 */ 9114 if (XML_NSMAP_NOTEMPTY(nsMap)) { 9115 XML_NSMAP_FOREACH(nsMap, mi) { 9116 if ((mi->depth >= XML_TREE_NSMAP_PARENT) && 9117 (mi->shadowDepth == -1) && 9118 ((ns->prefix == mi->newNs->prefix) || 9119 xmlStrEqual(ns->prefix, 9120 mi->newNs->prefix))) { 9121 9122 mi->shadowDepth = depth; 9123 } 9124 } 9125 } 9126 /* 9127 * Push mapping. 9128 */ 9129 if (xmlDOMWrapNsMapAddItem(&nsMap, -1, 9130 ns, ns, depth) == NULL) 9131 goto internal_error; 9132 } 9133 } 9134 /* Falls through. */ 9135 case XML_ATTRIBUTE_NODE: 9136 /* No namespace, no fun. */ 9137 if (cur->ns == NULL) 9138 goto ns_end; 9139 9140 if (! parnsdone) { 9141 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, 9142 destParent) == -1) 9143 goto internal_error; 9144 parnsdone = 1; 9145 } 9146 /* 9147 * Adopt ns-references. 9148 */ 9149 if (XML_NSMAP_NOTEMPTY(nsMap)) { 9150 /* 9151 * Search for a mapping. 9152 */ 9153 XML_NSMAP_FOREACH(nsMap, mi) { 9154 if ((mi->shadowDepth == -1) && 9155 (cur->ns == mi->oldNs)) { 9156 9157 cur->ns = mi->newNs; 9158 goto ns_end; 9159 } 9160 } 9161 } 9162 /* 9163 * No matching namespace in scope. We need a new one. 9164 */ 9165 if ((ctxt) && (ctxt->getNsForNodeFunc)) { 9166 /* 9167 * User-defined behaviour. 9168 */ 9169 ns = ctxt->getNsForNodeFunc(ctxt, cur, 9170 cur->ns->href, cur->ns->prefix); 9171 /* 9172 * Insert mapping if ns is available; it's the users fault 9173 * if not. 9174 */ 9175 if (xmlDOMWrapNsMapAddItem(&nsMap, -1, 9176 cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL) 9177 goto internal_error; 9178 cur->ns = ns; 9179 } else { 9180 /* 9181 * Aquire a normalized ns-decl and add it to the map. 9182 */ 9183 if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc, 9184 /* ns-decls on curElem or on destDoc->oldNs */ 9185 destParent ? curElem : NULL, 9186 cur->ns, &ns, 9187 &nsMap, depth, 9188 ancestorsOnly, 9189 /* ns-decls must be prefixed for attributes. */ 9190 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1) 9191 goto internal_error; 9192 cur->ns = ns; 9193 } 9194 ns_end: 9195 /* 9196 * Further node properties. 9197 * TODO: Is this all? 9198 */ 9199 XML_TREE_ADOPT_STR(cur->name) 9200 if (cur->type == XML_ELEMENT_NODE) { 9201 cur->psvi = NULL; 9202 cur->line = 0; 9203 cur->extra = 0; 9204 /* 9205 * Walk attributes. 9206 */ 9207 if (cur->properties != NULL) { 9208 /* 9209 * Process first attribute node. 9210 */ 9211 cur = (xmlNodePtr) cur->properties; 9212 continue; 9213 } 9214 } else { 9215 /* 9216 * Attributes. 9217 */ 9218 if ((sourceDoc != NULL) && 9219 (((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID)) 9220 { 9221 xmlRemoveID(sourceDoc, (xmlAttrPtr) cur); 9222 } 9223 ((xmlAttrPtr) cur)->atype = 0; 9224 ((xmlAttrPtr) cur)->psvi = NULL; 9225 } 9226 break; 9227 case XML_TEXT_NODE: 9228 case XML_CDATA_SECTION_NODE: 9229 /* 9230 * This puts the content in the dest dict, only if 9231 * it was previously in the source dict. 9232 */ 9233 XML_TREE_ADOPT_STR_2(cur->content) 9234 goto leave_node; 9235 case XML_ENTITY_REF_NODE: 9236 /* 9237 * Remove reference to the entitity-node. 9238 */ 9239 cur->content = NULL; 9240 cur->children = NULL; 9241 cur->last = NULL; 9242 if ((destDoc->intSubset) || (destDoc->extSubset)) { 9243 xmlEntityPtr ent; 9244 /* 9245 * Assign new entity-node if available. 9246 */ 9247 ent = xmlGetDocEntity(destDoc, cur->name); 9248 if (ent != NULL) { 9249 cur->content = ent->content; 9250 cur->children = (xmlNodePtr) ent; 9251 cur->last = (xmlNodePtr) ent; 9252 } 9253 } 9254 goto leave_node; 9255 case XML_PI_NODE: 9256 XML_TREE_ADOPT_STR(cur->name) 9257 XML_TREE_ADOPT_STR_2(cur->content) 9258 break; 9259 case XML_COMMENT_NODE: 9260 break; 9261 default: 9262 goto internal_error; 9263 } 9264 /* 9265 * Walk the tree. 9266 */ 9267 if (cur->children != NULL) { 9268 cur = cur->children; 9269 continue; 9270 } 9271 9272 leave_node: 9273 if (cur == node) 9274 break; 9275 if ((cur->type == XML_ELEMENT_NODE) || 9276 (cur->type == XML_XINCLUDE_START) || 9277 (cur->type == XML_XINCLUDE_END)) 9278 { 9279 /* 9280 * TODO: Do we expect nsDefs on XML_XINCLUDE_START? 9281 */ 9282 if (XML_NSMAP_NOTEMPTY(nsMap)) { 9283 /* 9284 * Pop mappings. 9285 */ 9286 while ((nsMap->last != NULL) && 9287 (nsMap->last->depth >= depth)) 9288 { 9289 XML_NSMAP_POP(nsMap, mi) 9290 } 9291 /* 9292 * Unshadow. 9293 */ 9294 XML_NSMAP_FOREACH(nsMap, mi) { 9295 if (mi->shadowDepth >= depth) 9296 mi->shadowDepth = -1; 9297 } 9298 } 9299 depth--; 9300 } 9301 if (cur->next != NULL) 9302 cur = cur->next; 9303 else if ((cur->type == XML_ATTRIBUTE_NODE) && 9304 (cur->parent->children != NULL)) 9305 { 9306 cur = cur->parent->children; 9307 } else { 9308 cur = cur->parent; 9309 goto leave_node; 9310 } 9311 } 9312 9313 goto exit; 9314 9315 internal_error: 9316 ret = -1; 9317 9318 exit: 9319 /* 9320 * Cleanup. 9321 */ 9322 if (nsMap != NULL) { 9323 if ((ctxt) && (ctxt->namespaceMap == nsMap)) { 9324 /* 9325 * Just cleanup the map but don't free. 9326 */ 9327 if (nsMap->first) { 9328 if (nsMap->pool) 9329 nsMap->last->next = nsMap->pool; 9330 nsMap->pool = nsMap->first; 9331 nsMap->first = NULL; 9332 } 9333 } else 9334 xmlDOMWrapNsMapFree(nsMap); 9335 } 9336 return(ret); 9337 } 9338 9339 /* 9340 * xmlDOMWrapCloneNode: 9341 * @ctxt: the optional context for custom processing 9342 * @sourceDoc: the optional sourceDoc 9343 * @node: the node to start with 9344 * @resNode: the clone of the given @node 9345 * @destDoc: the destination doc 9346 * @destParent: the optional new parent of @node in @destDoc 9347 * @deep: descend into child if set 9348 * @options: option flags 9349 * 9350 * References of out-of scope ns-decls are remapped to point to @destDoc: 9351 * 1) If @destParent is given, then nsDef entries on element-nodes are used 9352 * 2) If *no* @destParent is given, then @destDoc->oldNs entries are used. 9353 * This is the case when you don't know already where the cloned branch 9354 * will be added to. 9355 * 9356 * If @destParent is given, it ensures that the tree is namespace 9357 * wellformed by creating additional ns-decls where needed. 9358 * Note that, since prefixes of already existent ns-decls can be 9359 * shadowed by this process, it could break QNames in attribute 9360 * values or element content. 9361 * TODO: 9362 * 1) What to do with XInclude? Currently this returns an error for XInclude. 9363 * 9364 * Returns 0 if the operation succeeded, 9365 * 1 if a node of unsupported (or not yet supported) type was given, 9366 * -1 on API/internal errors. 9367 */ 9368 9369 int 9370 xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, 9371 xmlDocPtr sourceDoc, 9372 xmlNodePtr node, 9373 xmlNodePtr *resNode, 9374 xmlDocPtr destDoc, 9375 xmlNodePtr destParent, 9376 int deep, 9377 int options ATTRIBUTE_UNUSED) 9378 { 9379 int ret = 0; 9380 xmlNodePtr cur, curElem = NULL; 9381 xmlNsMapPtr nsMap = NULL; 9382 xmlNsMapItemPtr mi; 9383 xmlNsPtr ns; 9384 int depth = -1; 9385 /* int adoptStr = 1; */ 9386 /* gather @parent's ns-decls. */ 9387 int parnsdone = 0; 9388 /* 9389 * @ancestorsOnly: 9390 * TODO: @ancestorsOnly should be set per option. 9391 * 9392 */ 9393 int ancestorsOnly = 0; 9394 xmlNodePtr resultClone = NULL, clone = NULL, parentClone = NULL, prevClone = NULL; 9395 xmlNsPtr cloneNs = NULL, *cloneNsDefSlot = NULL; 9396 xmlDictPtr dict; /* The destination dict */ 9397 9398 if ((node == NULL) || (resNode == NULL) || (destDoc == NULL)) 9399 return(-1); 9400 /* 9401 * TODO: Initially we support only element-nodes. 9402 */ 9403 if (node->type != XML_ELEMENT_NODE) 9404 return(1); 9405 /* 9406 * Check node->doc sanity. 9407 */ 9408 if ((node->doc != NULL) && (sourceDoc != NULL) && 9409 (node->doc != sourceDoc)) { 9410 /* 9411 * Might be an XIncluded node. 9412 */ 9413 return (-1); 9414 } 9415 if (sourceDoc == NULL) 9416 sourceDoc = node->doc; 9417 if (sourceDoc == NULL) 9418 return (-1); 9419 9420 dict = destDoc->dict; 9421 /* 9422 * Reuse the namespace map of the context. 9423 */ 9424 if (ctxt) 9425 nsMap = (xmlNsMapPtr) ctxt->namespaceMap; 9426 9427 *resNode = NULL; 9428 9429 cur = node; 9430 if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL)) 9431 return(-1); 9432 9433 while (cur != NULL) { 9434 if (cur->doc != sourceDoc) { 9435 /* 9436 * We'll assume XIncluded nodes if the doc differs. 9437 * TODO: Do we need to reconciliate XIncluded nodes? 9438 * TODO: This here returns -1 in this case. 9439 */ 9440 goto internal_error; 9441 } 9442 /* 9443 * Create a new node. 9444 */ 9445 switch (cur->type) { 9446 case XML_XINCLUDE_START: 9447 case XML_XINCLUDE_END: 9448 /* 9449 * TODO: What to do with XInclude? 9450 */ 9451 goto internal_error; 9452 break; 9453 case XML_ELEMENT_NODE: 9454 case XML_TEXT_NODE: 9455 case XML_CDATA_SECTION_NODE: 9456 case XML_COMMENT_NODE: 9457 case XML_PI_NODE: 9458 case XML_DOCUMENT_FRAG_NODE: 9459 case XML_ENTITY_REF_NODE: 9460 case XML_ENTITY_NODE: 9461 /* 9462 * Nodes of xmlNode structure. 9463 */ 9464 clone = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); 9465 if (clone == NULL) { 9466 xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating a node"); 9467 goto internal_error; 9468 } 9469 memset(clone, 0, sizeof(xmlNode)); 9470 /* 9471 * Set hierachical links. 9472 */ 9473 if (resultClone != NULL) { 9474 clone->parent = parentClone; 9475 if (prevClone) { 9476 prevClone->next = clone; 9477 clone->prev = prevClone; 9478 } else 9479 parentClone->children = clone; 9480 } else 9481 resultClone = clone; 9482 9483 break; 9484 case XML_ATTRIBUTE_NODE: 9485 /* 9486 * Attributes (xmlAttr). 9487 */ 9488 clone = (xmlNodePtr) xmlMalloc(sizeof(xmlAttr)); 9489 if (clone == NULL) { 9490 xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating an attr-node"); 9491 goto internal_error; 9492 } 9493 memset(clone, 0, sizeof(xmlAttr)); 9494 /* 9495 * Set hierachical links. 9496 * TODO: Change this to add to the end of attributes. 9497 */ 9498 if (resultClone != NULL) { 9499 clone->parent = parentClone; 9500 if (prevClone) { 9501 prevClone->next = clone; 9502 clone->prev = prevClone; 9503 } else 9504 parentClone->properties = (xmlAttrPtr) clone; 9505 } else 9506 resultClone = clone; 9507 break; 9508 default: 9509 /* 9510 * TODO QUESTION: Any other nodes expected? 9511 */ 9512 goto internal_error; 9513 } 9514 9515 clone->type = cur->type; 9516 clone->doc = destDoc; 9517 9518 /* 9519 * Clone the name of the node if any. 9520 */ 9521 if (cur->name == xmlStringText) 9522 clone->name = xmlStringText; 9523 else if (cur->name == xmlStringTextNoenc) 9524 /* 9525 * NOTE: Although xmlStringTextNoenc is never assigned to a node 9526 * in tree.c, it might be set in Libxslt via 9527 * "xsl:disable-output-escaping". 9528 */ 9529 clone->name = xmlStringTextNoenc; 9530 else if (cur->name == xmlStringComment) 9531 clone->name = xmlStringComment; 9532 else if (cur->name != NULL) { 9533 DICT_CONST_COPY(cur->name, clone->name); 9534 } 9535 9536 switch (cur->type) { 9537 case XML_XINCLUDE_START: 9538 case XML_XINCLUDE_END: 9539 /* 9540 * TODO 9541 */ 9542 return (-1); 9543 case XML_ELEMENT_NODE: 9544 curElem = cur; 9545 depth++; 9546 /* 9547 * Namespace declarations. 9548 */ 9549 if (cur->nsDef != NULL) { 9550 if (! parnsdone) { 9551 if (destParent && (ctxt == NULL)) { 9552 /* 9553 * Gather @parent's in-scope ns-decls. 9554 */ 9555 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, 9556 destParent) == -1) 9557 goto internal_error; 9558 } 9559 parnsdone = 1; 9560 } 9561 /* 9562 * Clone namespace declarations. 9563 */ 9564 cloneNsDefSlot = &(clone->nsDef); 9565 for (ns = cur->nsDef; ns != NULL; ns = ns->next) { 9566 /* 9567 * Create a new xmlNs. 9568 */ 9569 cloneNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 9570 if (cloneNs == NULL) { 9571 xmlTreeErrMemory("xmlDOMWrapCloneNode(): " 9572 "allocating namespace"); 9573 return(-1); 9574 } 9575 memset(cloneNs, 0, sizeof(xmlNs)); 9576 cloneNs->type = XML_LOCAL_NAMESPACE; 9577 9578 if (ns->href != NULL) 9579 cloneNs->href = xmlStrdup(ns->href); 9580 if (ns->prefix != NULL) 9581 cloneNs->prefix = xmlStrdup(ns->prefix); 9582 9583 *cloneNsDefSlot = cloneNs; 9584 cloneNsDefSlot = &(cloneNs->next); 9585 9586 /* 9587 * Note that for custom handling of ns-references, 9588 * the ns-decls need not be stored in the ns-map, 9589 * since they won't be referenced by node->ns. 9590 */ 9591 if ((ctxt == NULL) || 9592 (ctxt->getNsForNodeFunc == NULL)) 9593 { 9594 /* 9595 * Does it shadow any ns-decl? 9596 */ 9597 if (XML_NSMAP_NOTEMPTY(nsMap)) { 9598 XML_NSMAP_FOREACH(nsMap, mi) { 9599 if ((mi->depth >= XML_TREE_NSMAP_PARENT) && 9600 (mi->shadowDepth == -1) && 9601 ((ns->prefix == mi->newNs->prefix) || 9602 xmlStrEqual(ns->prefix, 9603 mi->newNs->prefix))) { 9604 /* 9605 * Mark as shadowed at the current 9606 * depth. 9607 */ 9608 mi->shadowDepth = depth; 9609 } 9610 } 9611 } 9612 /* 9613 * Push mapping. 9614 */ 9615 if (xmlDOMWrapNsMapAddItem(&nsMap, -1, 9616 ns, cloneNs, depth) == NULL) 9617 goto internal_error; 9618 } 9619 } 9620 } 9621 /* cur->ns will be processed further down. */ 9622 break; 9623 case XML_ATTRIBUTE_NODE: 9624 /* IDs will be processed further down. */ 9625 /* cur->ns will be processed further down. */ 9626 break; 9627 case XML_TEXT_NODE: 9628 case XML_CDATA_SECTION_NODE: 9629 /* 9630 * Note that this will also cover the values of attributes. 9631 */ 9632 DICT_COPY(cur->content, clone->content); 9633 goto leave_node; 9634 case XML_ENTITY_NODE: 9635 /* TODO: What to do here? */ 9636 goto leave_node; 9637 case XML_ENTITY_REF_NODE: 9638 if (sourceDoc != destDoc) { 9639 if ((destDoc->intSubset) || (destDoc->extSubset)) { 9640 xmlEntityPtr ent; 9641 /* 9642 * Different doc: Assign new entity-node if available. 9643 */ 9644 ent = xmlGetDocEntity(destDoc, cur->name); 9645 if (ent != NULL) { 9646 clone->content = ent->content; 9647 clone->children = (xmlNodePtr) ent; 9648 clone->last = (xmlNodePtr) ent; 9649 } 9650 } 9651 } else { 9652 /* 9653 * Same doc: Use the current node's entity declaration 9654 * and value. 9655 */ 9656 clone->content = cur->content; 9657 clone->children = cur->children; 9658 clone->last = cur->last; 9659 } 9660 goto leave_node; 9661 case XML_PI_NODE: 9662 DICT_COPY(cur->content, clone->content); 9663 goto leave_node; 9664 case XML_COMMENT_NODE: 9665 DICT_COPY(cur->content, clone->content); 9666 goto leave_node; 9667 default: 9668 goto internal_error; 9669 } 9670 9671 if (cur->ns == NULL) 9672 goto end_ns_reference; 9673 9674 /* handle_ns_reference: */ 9675 /* 9676 ** The following will take care of references to ns-decls ******** 9677 ** and is intended only for element- and attribute-nodes. 9678 ** 9679 */ 9680 if (! parnsdone) { 9681 if (destParent && (ctxt == NULL)) { 9682 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, destParent) == -1) 9683 goto internal_error; 9684 } 9685 parnsdone = 1; 9686 } 9687 /* 9688 * Adopt ns-references. 9689 */ 9690 if (XML_NSMAP_NOTEMPTY(nsMap)) { 9691 /* 9692 * Search for a mapping. 9693 */ 9694 XML_NSMAP_FOREACH(nsMap, mi) { 9695 if ((mi->shadowDepth == -1) && 9696 (cur->ns == mi->oldNs)) { 9697 /* 9698 * This is the nice case: a mapping was found. 9699 */ 9700 clone->ns = mi->newNs; 9701 goto end_ns_reference; 9702 } 9703 } 9704 } 9705 /* 9706 * No matching namespace in scope. We need a new one. 9707 */ 9708 if ((ctxt != NULL) && (ctxt->getNsForNodeFunc != NULL)) { 9709 /* 9710 * User-defined behaviour. 9711 */ 9712 ns = ctxt->getNsForNodeFunc(ctxt, cur, 9713 cur->ns->href, cur->ns->prefix); 9714 /* 9715 * Add user's mapping. 9716 */ 9717 if (xmlDOMWrapNsMapAddItem(&nsMap, -1, 9718 cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL) 9719 goto internal_error; 9720 clone->ns = ns; 9721 } else { 9722 /* 9723 * Aquire a normalized ns-decl and add it to the map. 9724 */ 9725 if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc, 9726 /* ns-decls on curElem or on destDoc->oldNs */ 9727 destParent ? curElem : NULL, 9728 cur->ns, &ns, 9729 &nsMap, depth, 9730 /* if we need to search only in the ancestor-axis */ 9731 ancestorsOnly, 9732 /* ns-decls must be prefixed for attributes. */ 9733 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1) 9734 goto internal_error; 9735 clone->ns = ns; 9736 } 9737 9738 end_ns_reference: 9739 9740 /* 9741 * Some post-processing. 9742 * 9743 * Handle ID attributes. 9744 */ 9745 if ((clone->type == XML_ATTRIBUTE_NODE) && 9746 (clone->parent != NULL)) 9747 { 9748 if (xmlIsID(destDoc, clone->parent, (xmlAttrPtr) clone)) { 9749 9750 xmlChar *idVal; 9751 9752 idVal = xmlNodeListGetString(cur->doc, cur->children, 1); 9753 if (idVal != NULL) { 9754 if (xmlAddID(NULL, destDoc, idVal, (xmlAttrPtr) cur) == NULL) { 9755 /* TODO: error message. */ 9756 xmlFree(idVal); 9757 goto internal_error; 9758 } 9759 xmlFree(idVal); 9760 } 9761 } 9762 } 9763 /* 9764 ** 9765 ** The following will traverse the tree ************************** 9766 ** 9767 * 9768 * Walk the element's attributes before descending into child-nodes. 9769 */ 9770 if ((cur->type == XML_ELEMENT_NODE) && (cur->properties != NULL)) { 9771 prevClone = NULL; 9772 parentClone = clone; 9773 cur = (xmlNodePtr) cur->properties; 9774 continue; 9775 } 9776 into_content: 9777 /* 9778 * Descend into child-nodes. 9779 */ 9780 if (cur->children != NULL) { 9781 if (deep || (cur->type == XML_ATTRIBUTE_NODE)) { 9782 prevClone = NULL; 9783 parentClone = clone; 9784 cur = cur->children; 9785 continue; 9786 } 9787 } 9788 9789 leave_node: 9790 /* 9791 * At this point we are done with the node, its content 9792 * and an element-nodes's attribute-nodes. 9793 */ 9794 if (cur == node) 9795 break; 9796 if ((cur->type == XML_ELEMENT_NODE) || 9797 (cur->type == XML_XINCLUDE_START) || 9798 (cur->type == XML_XINCLUDE_END)) { 9799 /* 9800 * TODO: Do we expect nsDefs on XML_XINCLUDE_START? 9801 */ 9802 if (XML_NSMAP_NOTEMPTY(nsMap)) { 9803 /* 9804 * Pop mappings. 9805 */ 9806 while ((nsMap->last != NULL) && 9807 (nsMap->last->depth >= depth)) 9808 { 9809 XML_NSMAP_POP(nsMap, mi) 9810 } 9811 /* 9812 * Unshadow. 9813 */ 9814 XML_NSMAP_FOREACH(nsMap, mi) { 9815 if (mi->shadowDepth >= depth) 9816 mi->shadowDepth = -1; 9817 } 9818 } 9819 depth--; 9820 } 9821 if (cur->next != NULL) { 9822 prevClone = clone; 9823 cur = cur->next; 9824 } else if (cur->type != XML_ATTRIBUTE_NODE) { 9825 /* 9826 * Set clone->last. 9827 */ 9828 if (clone->parent != NULL) 9829 clone->parent->last = clone; 9830 clone = clone->parent; 9831 if (clone != NULL) 9832 parentClone = clone->parent; 9833 /* 9834 * Process parent --> next; 9835 */ 9836 cur = cur->parent; 9837 goto leave_node; 9838 } else { 9839 /* This is for attributes only. */ 9840 clone = clone->parent; 9841 parentClone = clone->parent; 9842 /* 9843 * Process parent-element --> children. 9844 */ 9845 cur = cur->parent; 9846 goto into_content; 9847 } 9848 } 9849 goto exit; 9850 9851 internal_error: 9852 ret = -1; 9853 9854 exit: 9855 /* 9856 * Cleanup. 9857 */ 9858 if (nsMap != NULL) { 9859 if ((ctxt) && (ctxt->namespaceMap == nsMap)) { 9860 /* 9861 * Just cleanup the map but don't free. 9862 */ 9863 if (nsMap->first) { 9864 if (nsMap->pool) 9865 nsMap->last->next = nsMap->pool; 9866 nsMap->pool = nsMap->first; 9867 nsMap->first = NULL; 9868 } 9869 } else 9870 xmlDOMWrapNsMapFree(nsMap); 9871 } 9872 /* 9873 * TODO: Should we try a cleanup of the cloned node in case of a 9874 * fatal error? 9875 */ 9876 *resNode = resultClone; 9877 return (ret); 9878 } 9879 9880 /* 9881 * xmlDOMWrapAdoptAttr: 9882 * @ctxt: the optional context for custom processing 9883 * @sourceDoc: the optional source document of attr 9884 * @attr: the attribute-node to be adopted 9885 * @destDoc: the destination doc for adoption 9886 * @destParent: the optional new parent of @attr in @destDoc 9887 * @options: option flags 9888 * 9889 * @attr is adopted by @destDoc. 9890 * Ensures that ns-references point to @destDoc: either to 9891 * elements->nsDef entries if @destParent is given, or to 9892 * @destDoc->oldNs otherwise. 9893 * 9894 * Returns 0 if succeeded, -1 otherwise and on API/internal errors. 9895 */ 9896 static int 9897 xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt, 9898 xmlDocPtr sourceDoc, 9899 xmlAttrPtr attr, 9900 xmlDocPtr destDoc, 9901 xmlNodePtr destParent, 9902 int options ATTRIBUTE_UNUSED) 9903 { 9904 xmlNodePtr cur; 9905 int adoptStr = 1; 9906 9907 if ((attr == NULL) || (destDoc == NULL)) 9908 return (-1); 9909 9910 attr->doc = destDoc; 9911 if (attr->ns != NULL) { 9912 xmlNsPtr ns = NULL; 9913 9914 if (ctxt != NULL) { 9915 /* TODO: User defined. */ 9916 } 9917 /* XML Namespace. */ 9918 if (IS_STR_XML(attr->ns->prefix)) { 9919 ns = xmlTreeEnsureXMLDecl(destDoc); 9920 } else if (destParent == NULL) { 9921 /* 9922 * Store in @destDoc->oldNs. 9923 */ 9924 ns = xmlDOMWrapStoreNs(destDoc, attr->ns->href, attr->ns->prefix); 9925 } else { 9926 /* 9927 * Declare on @destParent. 9928 */ 9929 if (xmlSearchNsByNamespaceStrict(destDoc, destParent, attr->ns->href, 9930 &ns, 1) == -1) 9931 goto internal_error; 9932 if (ns == NULL) { 9933 ns = xmlDOMWrapNSNormDeclareNsForced(destDoc, destParent, 9934 attr->ns->href, attr->ns->prefix, 1); 9935 } 9936 } 9937 if (ns == NULL) 9938 goto internal_error; 9939 attr->ns = ns; 9940 } 9941 9942 XML_TREE_ADOPT_STR(attr->name); 9943 attr->atype = 0; 9944 attr->psvi = NULL; 9945 /* 9946 * Walk content. 9947 */ 9948 if (attr->children == NULL) 9949 return (0); 9950 cur = attr->children; 9951 if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL)) 9952 goto internal_error; 9953 while (cur != NULL) { 9954 cur->doc = destDoc; 9955 switch (cur->type) { 9956 case XML_TEXT_NODE: 9957 case XML_CDATA_SECTION_NODE: 9958 XML_TREE_ADOPT_STR_2(cur->content) 9959 break; 9960 case XML_ENTITY_REF_NODE: 9961 /* 9962 * Remove reference to the entitity-node. 9963 */ 9964 cur->content = NULL; 9965 cur->children = NULL; 9966 cur->last = NULL; 9967 if ((destDoc->intSubset) || (destDoc->extSubset)) { 9968 xmlEntityPtr ent; 9969 /* 9970 * Assign new entity-node if available. 9971 */ 9972 ent = xmlGetDocEntity(destDoc, cur->name); 9973 if (ent != NULL) { 9974 cur->content = ent->content; 9975 cur->children = (xmlNodePtr) ent; 9976 cur->last = (xmlNodePtr) ent; 9977 } 9978 } 9979 break; 9980 default: 9981 break; 9982 } 9983 if (cur->children != NULL) { 9984 cur = cur->children; 9985 continue; 9986 } 9987 next_sibling: 9988 if (cur == (xmlNodePtr) attr) 9989 break; 9990 if (cur->next != NULL) 9991 cur = cur->next; 9992 else { 9993 cur = cur->parent; 9994 goto next_sibling; 9995 } 9996 } 9997 return (0); 9998 internal_error: 9999 return (-1); 10000 } 10001 10002 /* 10003 * xmlDOMWrapAdoptNode: 10004 * @ctxt: the optional context for custom processing 10005 * @sourceDoc: the optional sourceDoc 10006 * @node: the node to start with 10007 * @destDoc: the destination doc 10008 * @destParent: the optional new parent of @node in @destDoc 10009 * @options: option flags 10010 * 10011 * References of out-of scope ns-decls are remapped to point to @destDoc: 10012 * 1) If @destParent is given, then nsDef entries on element-nodes are used 10013 * 2) If *no* @destParent is given, then @destDoc->oldNs entries are used 10014 * This is the case when you have an unlinked node and just want to move it 10015 * to the context of 10016 * 10017 * If @destParent is given, it ensures that the tree is namespace 10018 * wellformed by creating additional ns-decls where needed. 10019 * Note that, since prefixes of already existent ns-decls can be 10020 * shadowed by this process, it could break QNames in attribute 10021 * values or element content. 10022 * NOTE: This function was not intensively tested. 10023 * 10024 * Returns 0 if the operation succeeded, 10025 * 1 if a node of unsupported type was given, 10026 * 2 if a node of not yet supported type was given and 10027 * -1 on API/internal errors. 10028 */ 10029 int 10030 xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt, 10031 xmlDocPtr sourceDoc, 10032 xmlNodePtr node, 10033 xmlDocPtr destDoc, 10034 xmlNodePtr destParent, 10035 int options) 10036 { 10037 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) || 10038 (destDoc == NULL) || 10039 ((destParent != NULL) && (destParent->doc != destDoc))) 10040 return(-1); 10041 /* 10042 * Check node->doc sanity. 10043 */ 10044 if ((node->doc != NULL) && (sourceDoc != NULL) && 10045 (node->doc != sourceDoc)) { 10046 /* 10047 * Might be an XIncluded node. 10048 */ 10049 return (-1); 10050 } 10051 if (sourceDoc == NULL) 10052 sourceDoc = node->doc; 10053 if (sourceDoc == destDoc) 10054 return (-1); 10055 switch (node->type) { 10056 case XML_ELEMENT_NODE: 10057 case XML_ATTRIBUTE_NODE: 10058 case XML_TEXT_NODE: 10059 case XML_CDATA_SECTION_NODE: 10060 case XML_ENTITY_REF_NODE: 10061 case XML_PI_NODE: 10062 case XML_COMMENT_NODE: 10063 break; 10064 case XML_DOCUMENT_FRAG_NODE: 10065 /* TODO: Support document-fragment-nodes. */ 10066 return (2); 10067 default: 10068 return (1); 10069 } 10070 /* 10071 * Unlink only if @node was not already added to @destParent. 10072 */ 10073 if ((node->parent != NULL) && (destParent != node->parent)) 10074 xmlUnlinkNode(node); 10075 10076 if (node->type == XML_ELEMENT_NODE) { 10077 return (xmlDOMWrapAdoptBranch(ctxt, sourceDoc, node, 10078 destDoc, destParent, options)); 10079 } else if (node->type == XML_ATTRIBUTE_NODE) { 10080 return (xmlDOMWrapAdoptAttr(ctxt, sourceDoc, 10081 (xmlAttrPtr) node, destDoc, destParent, options)); 10082 } else { 10083 xmlNodePtr cur = node; 10084 int adoptStr = 1; 10085 10086 cur->doc = destDoc; 10087 /* 10088 * Optimize string adoption. 10089 */ 10090 if ((sourceDoc != NULL) && 10091 (sourceDoc->dict == destDoc->dict)) 10092 adoptStr = 0; 10093 switch (node->type) { 10094 case XML_TEXT_NODE: 10095 case XML_CDATA_SECTION_NODE: 10096 XML_TREE_ADOPT_STR_2(node->content) 10097 break; 10098 case XML_ENTITY_REF_NODE: 10099 /* 10100 * Remove reference to the entitity-node. 10101 */ 10102 node->content = NULL; 10103 node->children = NULL; 10104 node->last = NULL; 10105 if ((destDoc->intSubset) || (destDoc->extSubset)) { 10106 xmlEntityPtr ent; 10107 /* 10108 * Assign new entity-node if available. 10109 */ 10110 ent = xmlGetDocEntity(destDoc, node->name); 10111 if (ent != NULL) { 10112 node->content = ent->content; 10113 node->children = (xmlNodePtr) ent; 10114 node->last = (xmlNodePtr) ent; 10115 } 10116 } 10117 XML_TREE_ADOPT_STR(node->name) 10118 break; 10119 case XML_PI_NODE: { 10120 XML_TREE_ADOPT_STR(node->name) 10121 XML_TREE_ADOPT_STR_2(node->content) 10122 break; 10123 } 10124 default: 10125 break; 10126 } 10127 } 10128 return (0); 10129 } 10130 10131 #define bottom_tree 10132 #include "elfgcchack.h" 10133