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