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