tree.c revision ab4e2e90f63db6b1cd8bb2e453cac899ef43d42b
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((xmlChar *)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 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity 5203 * references, but XML special chars need to be escaped first by using 5204 * xmlEncodeEntitiesReentrant() resp. xmlEncodeSpecialChars(). 5205 */ 5206void 5207xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) { 5208 if (cur == NULL) { 5209#ifdef DEBUG_TREE 5210 xmlGenericError(xmlGenericErrorContext, 5211 "xmlNodeSetContent : node == NULL\n"); 5212#endif 5213 return; 5214 } 5215 switch (cur->type) { 5216 case XML_DOCUMENT_FRAG_NODE: 5217 case XML_ELEMENT_NODE: 5218 case XML_ATTRIBUTE_NODE: 5219 if (cur->children != NULL) xmlFreeNodeList(cur->children); 5220 cur->children = xmlStringGetNodeList(cur->doc, content); 5221 UPDATE_LAST_CHILD_AND_PARENT(cur) 5222 break; 5223 case XML_TEXT_NODE: 5224 case XML_CDATA_SECTION_NODE: 5225 case XML_ENTITY_REF_NODE: 5226 case XML_ENTITY_NODE: 5227 case XML_PI_NODE: 5228 case XML_COMMENT_NODE: 5229 if ((cur->content != NULL) && 5230 (cur->content != (xmlChar *) &(cur->properties))) { 5231 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) && 5232 (xmlDictOwns(cur->doc->dict, cur->content)))) 5233 xmlFree(cur->content); 5234 } 5235 if (cur->children != NULL) xmlFreeNodeList(cur->children); 5236 cur->last = cur->children = NULL; 5237 if (content != NULL) { 5238 cur->content = xmlStrdup(content); 5239 } else 5240 cur->content = NULL; 5241 cur->properties = NULL; 5242 cur->nsDef = NULL; 5243 break; 5244 case XML_DOCUMENT_NODE: 5245 case XML_HTML_DOCUMENT_NODE: 5246 case XML_DOCUMENT_TYPE_NODE: 5247 case XML_XINCLUDE_START: 5248 case XML_XINCLUDE_END: 5249#ifdef LIBXML_DOCB_ENABLED 5250 case XML_DOCB_DOCUMENT_NODE: 5251#endif 5252 break; 5253 case XML_NOTATION_NODE: 5254 break; 5255 case XML_DTD_NODE: 5256 break; 5257 case XML_NAMESPACE_DECL: 5258 break; 5259 case XML_ELEMENT_DECL: 5260 /* TODO !!! */ 5261 break; 5262 case XML_ATTRIBUTE_DECL: 5263 /* TODO !!! */ 5264 break; 5265 case XML_ENTITY_DECL: 5266 /* TODO !!! */ 5267 break; 5268 } 5269} 5270 5271#ifdef LIBXML_TREE_ENABLED 5272/** 5273 * xmlNodeSetContentLen: 5274 * @cur: the node being modified 5275 * @content: the new value of the content 5276 * @len: the size of @content 5277 * 5278 * Replace the content of a node. 5279 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity 5280 * references, but XML special chars need to be escaped first by using 5281 * xmlEncodeEntitiesReentrant() resp. xmlEncodeSpecialChars(). 5282 */ 5283void 5284xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) { 5285 if (cur == NULL) { 5286#ifdef DEBUG_TREE 5287 xmlGenericError(xmlGenericErrorContext, 5288 "xmlNodeSetContentLen : node == NULL\n"); 5289#endif 5290 return; 5291 } 5292 switch (cur->type) { 5293 case XML_DOCUMENT_FRAG_NODE: 5294 case XML_ELEMENT_NODE: 5295 case XML_ATTRIBUTE_NODE: 5296 if (cur->children != NULL) xmlFreeNodeList(cur->children); 5297 cur->children = xmlStringLenGetNodeList(cur->doc, content, len); 5298 UPDATE_LAST_CHILD_AND_PARENT(cur) 5299 break; 5300 case XML_TEXT_NODE: 5301 case XML_CDATA_SECTION_NODE: 5302 case XML_ENTITY_REF_NODE: 5303 case XML_ENTITY_NODE: 5304 case XML_PI_NODE: 5305 case XML_COMMENT_NODE: 5306 case XML_NOTATION_NODE: 5307 if ((cur->content != NULL) && 5308 (cur->content != (xmlChar *) &(cur->properties))) { 5309 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) && 5310 (xmlDictOwns(cur->doc->dict, cur->content)))) 5311 xmlFree(cur->content); 5312 } 5313 if (cur->children != NULL) xmlFreeNodeList(cur->children); 5314 cur->children = cur->last = NULL; 5315 if (content != NULL) { 5316 cur->content = xmlStrndup(content, len); 5317 } else 5318 cur->content = NULL; 5319 cur->properties = NULL; 5320 cur->nsDef = NULL; 5321 break; 5322 case XML_DOCUMENT_NODE: 5323 case XML_DTD_NODE: 5324 case XML_HTML_DOCUMENT_NODE: 5325 case XML_DOCUMENT_TYPE_NODE: 5326 case XML_NAMESPACE_DECL: 5327 case XML_XINCLUDE_START: 5328 case XML_XINCLUDE_END: 5329#ifdef LIBXML_DOCB_ENABLED 5330 case XML_DOCB_DOCUMENT_NODE: 5331#endif 5332 break; 5333 case XML_ELEMENT_DECL: 5334 /* TODO !!! */ 5335 break; 5336 case XML_ATTRIBUTE_DECL: 5337 /* TODO !!! */ 5338 break; 5339 case XML_ENTITY_DECL: 5340 /* TODO !!! */ 5341 break; 5342 } 5343} 5344#endif /* LIBXML_TREE_ENABLED */ 5345 5346/** 5347 * xmlNodeAddContentLen: 5348 * @cur: the node being modified 5349 * @content: extra content 5350 * @len: the size of @content 5351 * 5352 * Append the extra substring to the node content. 5353 * NOTE: In contrast to xmlNodeSetContentLen(), @content is supposed to be 5354 * raw text, so unescaped XML special chars are allowed, entity 5355 * references are not supported. 5356 */ 5357void 5358xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) { 5359 if (cur == NULL) { 5360#ifdef DEBUG_TREE 5361 xmlGenericError(xmlGenericErrorContext, 5362 "xmlNodeAddContentLen : node == NULL\n"); 5363#endif 5364 return; 5365 } 5366 if (len <= 0) return; 5367 switch (cur->type) { 5368 case XML_DOCUMENT_FRAG_NODE: 5369 case XML_ELEMENT_NODE: { 5370 xmlNodePtr last, newNode, tmp; 5371 5372 last = cur->last; 5373 newNode = xmlNewTextLen(content, len); 5374 if (newNode != NULL) { 5375 tmp = xmlAddChild(cur, newNode); 5376 if (tmp != newNode) 5377 return; 5378 if ((last != NULL) && (last->next == newNode)) { 5379 xmlTextMerge(last, newNode); 5380 } 5381 } 5382 break; 5383 } 5384 case XML_ATTRIBUTE_NODE: 5385 break; 5386 case XML_TEXT_NODE: 5387 case XML_CDATA_SECTION_NODE: 5388 case XML_ENTITY_REF_NODE: 5389 case XML_ENTITY_NODE: 5390 case XML_PI_NODE: 5391 case XML_COMMENT_NODE: 5392 case XML_NOTATION_NODE: 5393 if (content != NULL) { 5394 if ((cur->content == (xmlChar *) &(cur->properties)) || 5395 ((cur->doc != NULL) && (cur->doc->dict != NULL) && 5396 xmlDictOwns(cur->doc->dict, cur->content))) { 5397 cur->content = xmlStrncatNew(cur->content, content, len); 5398 cur->properties = NULL; 5399 cur->nsDef = NULL; 5400 break; 5401 } 5402 cur->content = xmlStrncat(cur->content, content, len); 5403 } 5404 case XML_DOCUMENT_NODE: 5405 case XML_DTD_NODE: 5406 case XML_HTML_DOCUMENT_NODE: 5407 case XML_DOCUMENT_TYPE_NODE: 5408 case XML_NAMESPACE_DECL: 5409 case XML_XINCLUDE_START: 5410 case XML_XINCLUDE_END: 5411#ifdef LIBXML_DOCB_ENABLED 5412 case XML_DOCB_DOCUMENT_NODE: 5413#endif 5414 break; 5415 case XML_ELEMENT_DECL: 5416 case XML_ATTRIBUTE_DECL: 5417 case XML_ENTITY_DECL: 5418 break; 5419 } 5420} 5421 5422/** 5423 * xmlNodeAddContent: 5424 * @cur: the node being modified 5425 * @content: extra content 5426 * 5427 * Append the extra substring to the node content. 5428 * NOTE: In contrast to xmlNodeSetContent(), @content is supposed to be 5429 * raw text, so unescaped XML special chars are allowed, entity 5430 * references are not supported. 5431 */ 5432void 5433xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) { 5434 int len; 5435 5436 if (cur == NULL) { 5437#ifdef DEBUG_TREE 5438 xmlGenericError(xmlGenericErrorContext, 5439 "xmlNodeAddContent : node == NULL\n"); 5440#endif 5441 return; 5442 } 5443 if (content == NULL) return; 5444 len = xmlStrlen(content); 5445 xmlNodeAddContentLen(cur, content, len); 5446} 5447 5448/** 5449 * xmlTextMerge: 5450 * @first: the first text node 5451 * @second: the second text node being merged 5452 * 5453 * Merge two text nodes into one 5454 * Returns the first text node augmented 5455 */ 5456xmlNodePtr 5457xmlTextMerge(xmlNodePtr first, xmlNodePtr second) { 5458 if (first == NULL) return(second); 5459 if (second == NULL) return(first); 5460 if (first->type != XML_TEXT_NODE) return(first); 5461 if (second->type != XML_TEXT_NODE) return(first); 5462 if (second->name != first->name) 5463 return(first); 5464 xmlNodeAddContent(first, second->content); 5465 xmlUnlinkNode(second); 5466 xmlFreeNode(second); 5467 return(first); 5468} 5469 5470#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) 5471/** 5472 * xmlGetNsList: 5473 * @doc: the document 5474 * @node: the current node 5475 * 5476 * Search all the namespace applying to a given element. 5477 * Returns an NULL terminated array of all the #xmlNsPtr found 5478 * that need to be freed by the caller or NULL if no 5479 * namespace if defined 5480 */ 5481xmlNsPtr * 5482xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node) 5483{ 5484 xmlNsPtr cur; 5485 xmlNsPtr *ret = NULL; 5486 int nbns = 0; 5487 int maxns = 10; 5488 int i; 5489 5490 while (node != NULL) { 5491 if (node->type == XML_ELEMENT_NODE) { 5492 cur = node->nsDef; 5493 while (cur != NULL) { 5494 if (ret == NULL) { 5495 ret = 5496 (xmlNsPtr *) xmlMalloc((maxns + 1) * 5497 sizeof(xmlNsPtr)); 5498 if (ret == NULL) { 5499 xmlTreeErrMemory("getting namespace list"); 5500 return (NULL); 5501 } 5502 ret[nbns] = NULL; 5503 } 5504 for (i = 0; i < nbns; i++) { 5505 if ((cur->prefix == ret[i]->prefix) || 5506 (xmlStrEqual(cur->prefix, ret[i]->prefix))) 5507 break; 5508 } 5509 if (i >= nbns) { 5510 if (nbns >= maxns) { 5511 maxns *= 2; 5512 ret = (xmlNsPtr *) xmlRealloc(ret, 5513 (maxns + 5514 1) * 5515 sizeof(xmlNsPtr)); 5516 if (ret == NULL) { 5517 xmlTreeErrMemory("getting namespace list"); 5518 return (NULL); 5519 } 5520 } 5521 ret[nbns++] = cur; 5522 ret[nbns] = NULL; 5523 } 5524 5525 cur = cur->next; 5526 } 5527 } 5528 node = node->parent; 5529 } 5530 return (ret); 5531} 5532#endif /* LIBXML_TREE_ENABLED */ 5533 5534/* 5535* xmlTreeEnsureXMLDecl: 5536* @doc: the doc 5537* 5538* Ensures that there is an XML namespace declaration on the doc. 5539* 5540* Returns the XML ns-struct or NULL on API and internal errors. 5541*/ 5542static xmlNsPtr 5543xmlTreeEnsureXMLDecl(xmlDocPtr doc) 5544{ 5545 if (doc == NULL) 5546 return (NULL); 5547 if (doc->oldNs != NULL) 5548 return (doc->oldNs); 5549 { 5550 xmlNsPtr ns; 5551 ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 5552 if (ns == NULL) { 5553 xmlTreeErrMemory( 5554 "allocating the XML namespace"); 5555 return (NULL); 5556 } 5557 memset(ns, 0, sizeof(xmlNs)); 5558 ns->type = XML_LOCAL_NAMESPACE; 5559 ns->href = xmlStrdup(XML_XML_NAMESPACE); 5560 ns->prefix = xmlStrdup((const xmlChar *)"xml"); 5561 doc->oldNs = ns; 5562 return (ns); 5563 } 5564} 5565 5566/** 5567 * xmlSearchNs: 5568 * @doc: the document 5569 * @node: the current node 5570 * @nameSpace: the namespace prefix 5571 * 5572 * Search a Ns registered under a given name space for a document. 5573 * recurse on the parents until it finds the defined namespace 5574 * or return NULL otherwise. 5575 * @nameSpace can be NULL, this is a search for the default namespace. 5576 * We don't allow to cross entities boundaries. If you don't declare 5577 * the namespace within those you will be in troubles !!! A warning 5578 * is generated to cover this case. 5579 * 5580 * Returns the namespace pointer or NULL. 5581 */ 5582xmlNsPtr 5583xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) { 5584 5585 xmlNsPtr cur; 5586 xmlNodePtr orig = node; 5587 5588 if (node == NULL) return(NULL); 5589 if ((nameSpace != NULL) && 5590 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) { 5591 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) { 5592 /* 5593 * The XML-1.0 namespace is normally held on the root 5594 * element. In this case exceptionally create it on the 5595 * node element. 5596 */ 5597 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 5598 if (cur == NULL) { 5599 xmlTreeErrMemory("searching namespace"); 5600 return(NULL); 5601 } 5602 memset(cur, 0, sizeof(xmlNs)); 5603 cur->type = XML_LOCAL_NAMESPACE; 5604 cur->href = xmlStrdup(XML_XML_NAMESPACE); 5605 cur->prefix = xmlStrdup((const xmlChar *)"xml"); 5606 cur->next = node->nsDef; 5607 node->nsDef = cur; 5608 return(cur); 5609 } 5610 if (doc == NULL) { 5611 doc = node->doc; 5612 if (doc == NULL) 5613 return(NULL); 5614 } 5615 /* 5616 * Return the XML namespace declaration held by the doc. 5617 */ 5618 if (doc->oldNs == NULL) 5619 return(xmlTreeEnsureXMLDecl(doc)); 5620 else 5621 return(doc->oldNs); 5622 } 5623 while (node != NULL) { 5624 if ((node->type == XML_ENTITY_REF_NODE) || 5625 (node->type == XML_ENTITY_NODE) || 5626 (node->type == XML_ENTITY_DECL)) 5627 return(NULL); 5628 if (node->type == XML_ELEMENT_NODE) { 5629 cur = node->nsDef; 5630 while (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 cur = cur->next; 5639 } 5640 if (orig != node) { 5641 cur = node->ns; 5642 if (cur != NULL) { 5643 if ((cur->prefix == NULL) && (nameSpace == NULL) && 5644 (cur->href != NULL)) 5645 return(cur); 5646 if ((cur->prefix != NULL) && (nameSpace != NULL) && 5647 (cur->href != NULL) && 5648 (xmlStrEqual(cur->prefix, nameSpace))) 5649 return(cur); 5650 } 5651 } 5652 } 5653 node = node->parent; 5654 } 5655 return(NULL); 5656} 5657 5658/** 5659 * xmlNsInScope: 5660 * @doc: the document 5661 * @node: the current node 5662 * @ancestor: the ancestor carrying the namespace 5663 * @prefix: the namespace prefix 5664 * 5665 * Verify that the given namespace held on @ancestor is still in scope 5666 * on node. 5667 * 5668 * Returns 1 if true, 0 if false and -1 in case of error. 5669 */ 5670static int 5671xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node, 5672 xmlNodePtr ancestor, const xmlChar * prefix) 5673{ 5674 xmlNsPtr tst; 5675 5676 while ((node != NULL) && (node != ancestor)) { 5677 if ((node->type == XML_ENTITY_REF_NODE) || 5678 (node->type == XML_ENTITY_NODE) || 5679 (node->type == XML_ENTITY_DECL)) 5680 return (-1); 5681 if (node->type == XML_ELEMENT_NODE) { 5682 tst = node->nsDef; 5683 while (tst != NULL) { 5684 if ((tst->prefix == NULL) 5685 && (prefix == NULL)) 5686 return (0); 5687 if ((tst->prefix != NULL) 5688 && (prefix != NULL) 5689 && (xmlStrEqual(tst->prefix, prefix))) 5690 return (0); 5691 tst = tst->next; 5692 } 5693 } 5694 node = node->parent; 5695 } 5696 if (node != ancestor) 5697 return (-1); 5698 return (1); 5699} 5700 5701/** 5702 * xmlSearchNsByHref: 5703 * @doc: the document 5704 * @node: the current node 5705 * @href: the namespace value 5706 * 5707 * Search a Ns aliasing a given URI. Recurse on the parents until it finds 5708 * the defined namespace or return NULL otherwise. 5709 * Returns the namespace pointer or NULL. 5710 */ 5711xmlNsPtr 5712xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href) 5713{ 5714 xmlNsPtr cur; 5715 xmlNodePtr orig = node; 5716 int is_attr; 5717 5718 if ((node == NULL) || (href == NULL)) 5719 return (NULL); 5720 if (xmlStrEqual(href, XML_XML_NAMESPACE)) { 5721 /* 5722 * Only the document can hold the XML spec namespace. 5723 */ 5724 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) { 5725 /* 5726 * The XML-1.0 namespace is normally held on the root 5727 * element. In this case exceptionally create it on the 5728 * node element. 5729 */ 5730 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 5731 if (cur == NULL) { 5732 xmlTreeErrMemory("searching namespace"); 5733 return (NULL); 5734 } 5735 memset(cur, 0, sizeof(xmlNs)); 5736 cur->type = XML_LOCAL_NAMESPACE; 5737 cur->href = xmlStrdup(XML_XML_NAMESPACE); 5738 cur->prefix = xmlStrdup((const xmlChar *) "xml"); 5739 cur->next = node->nsDef; 5740 node->nsDef = cur; 5741 return (cur); 5742 } 5743 if (doc == NULL) { 5744 doc = node->doc; 5745 if (doc == NULL) 5746 return(NULL); 5747 } 5748 /* 5749 * Return the XML namespace declaration held by the doc. 5750 */ 5751 if (doc->oldNs == NULL) 5752 return(xmlTreeEnsureXMLDecl(doc)); 5753 else 5754 return(doc->oldNs); 5755 } 5756 is_attr = (node->type == XML_ATTRIBUTE_NODE); 5757 while (node != NULL) { 5758 if ((node->type == XML_ENTITY_REF_NODE) || 5759 (node->type == XML_ENTITY_NODE) || 5760 (node->type == XML_ENTITY_DECL)) 5761 return (NULL); 5762 if (node->type == XML_ELEMENT_NODE) { 5763 cur = node->nsDef; 5764 while (cur != NULL) { 5765 if ((cur->href != NULL) && (href != NULL) && 5766 (xmlStrEqual(cur->href, href))) { 5767 if (((!is_attr) || (cur->prefix != NULL)) && 5768 (xmlNsInScope(doc, orig, node, cur->prefix) == 1)) 5769 return (cur); 5770 } 5771 cur = cur->next; 5772 } 5773 if (orig != node) { 5774 cur = node->ns; 5775 if (cur != NULL) { 5776 if ((cur->href != NULL) && (href != NULL) && 5777 (xmlStrEqual(cur->href, href))) { 5778 if (((!is_attr) || (cur->prefix != NULL)) && 5779 (xmlNsInScope(doc, orig, node, cur->prefix) == 1)) 5780 return (cur); 5781 } 5782 } 5783 } 5784 } 5785 node = node->parent; 5786 } 5787 return (NULL); 5788} 5789 5790/** 5791 * xmlNewReconciliedNs: 5792 * @doc: the document 5793 * @tree: a node expected to hold the new namespace 5794 * @ns: the original namespace 5795 * 5796 * This function tries to locate a namespace definition in a tree 5797 * ancestors, or create a new namespace definition node similar to 5798 * @ns trying to reuse the same prefix. However if the given prefix is 5799 * null (default namespace) or reused within the subtree defined by 5800 * @tree or on one of its ancestors then a new prefix is generated. 5801 * Returns the (new) namespace definition or NULL in case of error 5802 */ 5803xmlNsPtr 5804xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) { 5805 xmlNsPtr def; 5806 xmlChar prefix[50]; 5807 int counter = 1; 5808 5809 if (tree == NULL) { 5810#ifdef DEBUG_TREE 5811 xmlGenericError(xmlGenericErrorContext, 5812 "xmlNewReconciliedNs : tree == NULL\n"); 5813#endif 5814 return(NULL); 5815 } 5816 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) { 5817#ifdef DEBUG_TREE 5818 xmlGenericError(xmlGenericErrorContext, 5819 "xmlNewReconciliedNs : ns == NULL\n"); 5820#endif 5821 return(NULL); 5822 } 5823 /* 5824 * Search an existing namespace definition inherited. 5825 */ 5826 def = xmlSearchNsByHref(doc, tree, ns->href); 5827 if (def != NULL) 5828 return(def); 5829 5830 /* 5831 * Find a close prefix which is not already in use. 5832 * Let's strip namespace prefixes longer than 20 chars ! 5833 */ 5834 if (ns->prefix == NULL) 5835 snprintf((char *) prefix, sizeof(prefix), "default"); 5836 else 5837 snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix); 5838 5839 def = xmlSearchNs(doc, tree, prefix); 5840 while (def != NULL) { 5841 if (counter > 1000) return(NULL); 5842 if (ns->prefix == NULL) 5843 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++); 5844 else 5845 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", 5846 (char *)ns->prefix, counter++); 5847 def = xmlSearchNs(doc, tree, prefix); 5848 } 5849 5850 /* 5851 * OK, now we are ready to create a new one. 5852 */ 5853 def = xmlNewNs(tree, ns->href, prefix); 5854 return(def); 5855} 5856 5857#ifdef LIBXML_TREE_ENABLED 5858/** 5859 * xmlReconciliateNs: 5860 * @doc: the document 5861 * @tree: a node defining the subtree to reconciliate 5862 * 5863 * This function checks that all the namespaces declared within the given 5864 * tree are properly declared. This is needed for example after Copy or Cut 5865 * and then paste operations. The subtree may still hold pointers to 5866 * namespace declarations outside the subtree or invalid/masked. As much 5867 * as possible the function try to reuse the existing namespaces found in 5868 * the new environment. If not possible the new namespaces are redeclared 5869 * on @tree at the top of the given subtree. 5870 * Returns the number of namespace declarations created or -1 in case of error. 5871 */ 5872int 5873xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) { 5874 xmlNsPtr *oldNs = NULL; 5875 xmlNsPtr *newNs = NULL; 5876 int sizeCache = 0; 5877 int nbCache = 0; 5878 5879 xmlNsPtr n; 5880 xmlNodePtr node = tree; 5881 xmlAttrPtr attr; 5882 int ret = 0, i; 5883 5884 if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1); 5885 if ((doc == NULL) || (doc->type != XML_DOCUMENT_NODE)) return(-1); 5886 if (node->doc != doc) return(-1); 5887 while (node != NULL) { 5888 /* 5889 * Reconciliate the node namespace 5890 */ 5891 if (node->ns != NULL) { 5892 /* 5893 * initialize the cache if needed 5894 */ 5895 if (sizeCache == 0) { 5896 sizeCache = 10; 5897 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache * 5898 sizeof(xmlNsPtr)); 5899 if (oldNs == NULL) { 5900 xmlTreeErrMemory("fixing namespaces"); 5901 return(-1); 5902 } 5903 newNs = (xmlNsPtr *) xmlMalloc(sizeCache * 5904 sizeof(xmlNsPtr)); 5905 if (newNs == NULL) { 5906 xmlTreeErrMemory("fixing namespaces"); 5907 xmlFree(oldNs); 5908 return(-1); 5909 } 5910 } 5911 for (i = 0;i < nbCache;i++) { 5912 if (oldNs[i] == node->ns) { 5913 node->ns = newNs[i]; 5914 break; 5915 } 5916 } 5917 if (i == nbCache) { 5918 /* 5919 * OK we need to recreate a new namespace definition 5920 */ 5921 n = xmlNewReconciliedNs(doc, tree, node->ns); 5922 if (n != NULL) { /* :-( what if else ??? */ 5923 /* 5924 * check if we need to grow the cache buffers. 5925 */ 5926 if (sizeCache <= nbCache) { 5927 sizeCache *= 2; 5928 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache * 5929 sizeof(xmlNsPtr)); 5930 if (oldNs == NULL) { 5931 xmlTreeErrMemory("fixing namespaces"); 5932 xmlFree(newNs); 5933 return(-1); 5934 } 5935 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache * 5936 sizeof(xmlNsPtr)); 5937 if (newNs == NULL) { 5938 xmlTreeErrMemory("fixing namespaces"); 5939 xmlFree(oldNs); 5940 return(-1); 5941 } 5942 } 5943 newNs[nbCache] = n; 5944 oldNs[nbCache++] = node->ns; 5945 node->ns = n; 5946 } 5947 } 5948 } 5949 /* 5950 * now check for namespace hold by attributes on the node. 5951 */ 5952 if (node->type == XML_ELEMENT_NODE) { 5953 attr = node->properties; 5954 while (attr != NULL) { 5955 if (attr->ns != NULL) { 5956 /* 5957 * initialize the cache if needed 5958 */ 5959 if (sizeCache == 0) { 5960 sizeCache = 10; 5961 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache * 5962 sizeof(xmlNsPtr)); 5963 if (oldNs == NULL) { 5964 xmlTreeErrMemory("fixing namespaces"); 5965 return(-1); 5966 } 5967 newNs = (xmlNsPtr *) xmlMalloc(sizeCache * 5968 sizeof(xmlNsPtr)); 5969 if (newNs == NULL) { 5970 xmlTreeErrMemory("fixing namespaces"); 5971 xmlFree(oldNs); 5972 return(-1); 5973 } 5974 } 5975 for (i = 0;i < nbCache;i++) { 5976 if (oldNs[i] == attr->ns) { 5977 attr->ns = newNs[i]; 5978 break; 5979 } 5980 } 5981 if (i == nbCache) { 5982 /* 5983 * OK we need to recreate a new namespace definition 5984 */ 5985 n = xmlNewReconciliedNs(doc, tree, attr->ns); 5986 if (n != NULL) { /* :-( what if else ??? */ 5987 /* 5988 * check if we need to grow the cache buffers. 5989 */ 5990 if (sizeCache <= nbCache) { 5991 sizeCache *= 2; 5992 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, 5993 sizeCache * sizeof(xmlNsPtr)); 5994 if (oldNs == NULL) { 5995 xmlTreeErrMemory("fixing namespaces"); 5996 xmlFree(newNs); 5997 return(-1); 5998 } 5999 newNs = (xmlNsPtr *) xmlRealloc(newNs, 6000 sizeCache * sizeof(xmlNsPtr)); 6001 if (newNs == NULL) { 6002 xmlTreeErrMemory("fixing namespaces"); 6003 xmlFree(oldNs); 6004 return(-1); 6005 } 6006 } 6007 newNs[nbCache] = n; 6008 oldNs[nbCache++] = attr->ns; 6009 attr->ns = n; 6010 } 6011 } 6012 } 6013 attr = attr->next; 6014 } 6015 } 6016 6017 /* 6018 * Browse the full subtree, deep first 6019 */ 6020 if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) { 6021 /* deep first */ 6022 node = node->children; 6023 } else if ((node != tree) && (node->next != NULL)) { 6024 /* then siblings */ 6025 node = node->next; 6026 } else if (node != tree) { 6027 /* go up to parents->next if needed */ 6028 while (node != tree) { 6029 if (node->parent != NULL) 6030 node = node->parent; 6031 if ((node != tree) && (node->next != NULL)) { 6032 node = node->next; 6033 break; 6034 } 6035 if (node->parent == NULL) { 6036 node = NULL; 6037 break; 6038 } 6039 } 6040 /* exit condition */ 6041 if (node == tree) 6042 node = NULL; 6043 } else 6044 break; 6045 } 6046 if (oldNs != NULL) 6047 xmlFree(oldNs); 6048 if (newNs != NULL) 6049 xmlFree(newNs); 6050 return(ret); 6051} 6052#endif /* LIBXML_TREE_ENABLED */ 6053 6054static xmlAttrPtr 6055xmlGetPropNodeInternal(xmlNodePtr node, const xmlChar *name, 6056 const xmlChar *nsName, int useDTD) 6057{ 6058 xmlAttrPtr prop; 6059 6060 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL)) 6061 return(NULL); 6062 6063 if (node->properties != NULL) { 6064 prop = node->properties; 6065 if (nsName == NULL) { 6066 /* 6067 * We want the attr to be in no namespace. 6068 */ 6069 do { 6070 if ((prop->ns == NULL) && xmlStrEqual(prop->name, name)) { 6071 return(prop); 6072 } 6073 prop = prop->next; 6074 } while (prop != NULL); 6075 } else { 6076 /* 6077 * We want the attr to be in the specified namespace. 6078 */ 6079 do { 6080 if ((prop->ns != NULL) && xmlStrEqual(prop->name, name) && 6081 ((prop->ns->href == nsName) || 6082 xmlStrEqual(prop->ns->href, nsName))) 6083 { 6084 return(prop); 6085 } 6086 prop = prop->next; 6087 } while (prop != NULL); 6088 } 6089 } 6090 6091#ifdef LIBXML_TREE_ENABLED 6092 if (! useDTD) 6093 return(NULL); 6094 /* 6095 * Check if there is a default/fixed attribute declaration in 6096 * the internal or external subset. 6097 */ 6098 if ((node->doc != NULL) && (node->doc->intSubset != NULL)) { 6099 xmlDocPtr doc = node->doc; 6100 xmlAttributePtr attrDecl = NULL; 6101 xmlChar *elemQName, *tmpstr = NULL; 6102 6103 /* 6104 * We need the QName of the element for the DTD-lookup. 6105 */ 6106 if ((node->ns != NULL) && (node->ns->prefix != NULL)) { 6107 tmpstr = xmlStrdup(node->ns->prefix); 6108 tmpstr = xmlStrcat(tmpstr, BAD_CAST ":"); 6109 tmpstr = xmlStrcat(tmpstr, node->name); 6110 if (tmpstr == NULL) 6111 return(NULL); 6112 elemQName = tmpstr; 6113 } else 6114 elemQName = (xmlChar *) node->name; 6115 if (nsName == NULL) { 6116 /* 6117 * The common and nice case: Attr in no namespace. 6118 */ 6119 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, 6120 elemQName, name, NULL); 6121 if ((attrDecl == NULL) && (doc->extSubset != NULL)) { 6122 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, 6123 elemQName, name, NULL); 6124 } 6125 } else { 6126 xmlNsPtr *nsList, *cur; 6127 6128 /* 6129 * The ugly case: Search using the prefixes of in-scope 6130 * ns-decls corresponding to @nsName. 6131 */ 6132 nsList = xmlGetNsList(node->doc, node); 6133 if (nsList == NULL) { 6134 if (tmpstr != NULL) 6135 xmlFree(tmpstr); 6136 return(NULL); 6137 } 6138 cur = nsList; 6139 while (*cur != NULL) { 6140 if (xmlStrEqual((*cur)->href, nsName)) { 6141 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elemQName, 6142 name, (*cur)->prefix); 6143 if (attrDecl) 6144 break; 6145 if (doc->extSubset != NULL) { 6146 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elemQName, 6147 name, (*cur)->prefix); 6148 if (attrDecl) 6149 break; 6150 } 6151 } 6152 cur++; 6153 } 6154 xmlFree(nsList); 6155 } 6156 if (tmpstr != NULL) 6157 xmlFree(tmpstr); 6158 /* 6159 * Only default/fixed attrs are relevant. 6160 */ 6161 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL)) 6162 return((xmlAttrPtr) attrDecl); 6163 } 6164#endif /* LIBXML_TREE_ENABLED */ 6165 return(NULL); 6166} 6167 6168static xmlChar* 6169xmlGetPropNodeValueInternal(xmlAttrPtr prop) 6170{ 6171 if (prop == NULL) 6172 return(NULL); 6173 if (prop->type == XML_ATTRIBUTE_NODE) { 6174 /* 6175 * Note that we return at least the empty string. 6176 * TODO: Do we really always want that? 6177 */ 6178 if (prop->children != NULL) { 6179 if ((prop->children->next == NULL) && 6180 ((prop->children->type == XML_TEXT_NODE) || 6181 (prop->children->type == XML_CDATA_SECTION_NODE))) 6182 { 6183 /* 6184 * Optimization for the common case: only 1 text node. 6185 */ 6186 return(xmlStrdup(prop->children->content)); 6187 } else { 6188 xmlChar *ret; 6189 6190 ret = xmlNodeListGetString(prop->doc, prop->children, 1); 6191 if (ret != NULL) 6192 return(ret); 6193 } 6194 } 6195 return(xmlStrdup((xmlChar *)"")); 6196 } else if (prop->type == XML_ATTRIBUTE_DECL) { 6197 return(xmlStrdup(((xmlAttributePtr)prop)->defaultValue)); 6198 } 6199 return(NULL); 6200} 6201 6202/** 6203 * xmlHasProp: 6204 * @node: the node 6205 * @name: the attribute name 6206 * 6207 * Search an attribute associated to a node 6208 * This function also looks in DTD attribute declaration for #FIXED or 6209 * default declaration values unless DTD use has been turned off. 6210 * 6211 * Returns the attribute or the attribute declaration or NULL if 6212 * neither was found. 6213 */ 6214xmlAttrPtr 6215xmlHasProp(xmlNodePtr node, const xmlChar *name) { 6216 xmlAttrPtr prop; 6217 xmlDocPtr doc; 6218 6219 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL)) 6220 return(NULL); 6221 /* 6222 * Check on the properties attached to the node 6223 */ 6224 prop = node->properties; 6225 while (prop != NULL) { 6226 if (xmlStrEqual(prop->name, name)) { 6227 return(prop); 6228 } 6229 prop = prop->next; 6230 } 6231 if (!xmlCheckDTD) return(NULL); 6232 6233 /* 6234 * Check if there is a default declaration in the internal 6235 * or external subsets 6236 */ 6237 doc = node->doc; 6238 if (doc != NULL) { 6239 xmlAttributePtr attrDecl; 6240 if (doc->intSubset != NULL) { 6241 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name); 6242 if ((attrDecl == NULL) && (doc->extSubset != NULL)) 6243 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name); 6244 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL)) 6245 /* return attribute declaration only if a default value is given 6246 (that includes #FIXED declarations) */ 6247 return((xmlAttrPtr) attrDecl); 6248 } 6249 } 6250 return(NULL); 6251} 6252 6253/** 6254 * xmlHasNsProp: 6255 * @node: the node 6256 * @name: the attribute name 6257 * @nameSpace: the URI of the namespace 6258 * 6259 * Search for an attribute associated to a node 6260 * This attribute has to be anchored in the namespace specified. 6261 * This does the entity substitution. 6262 * This function looks in DTD attribute declaration for #FIXED or 6263 * default declaration values unless DTD use has been turned off. 6264 * Note that a namespace of NULL indicates to use the default namespace. 6265 * 6266 * Returns the attribute or the attribute declaration or NULL 6267 * if neither was found. 6268 */ 6269xmlAttrPtr 6270xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) { 6271 6272 return(xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD)); 6273} 6274 6275/** 6276 * xmlGetProp: 6277 * @node: the node 6278 * @name: the attribute name 6279 * 6280 * Search and get the value of an attribute associated to a node 6281 * This does the entity substitution. 6282 * This function looks in DTD attribute declaration for #FIXED or 6283 * default declaration values unless DTD use has been turned off. 6284 * NOTE: this function acts independently of namespaces associated 6285 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp() 6286 * for namespace aware processing. 6287 * 6288 * Returns the attribute value or NULL if not found. 6289 * It's up to the caller to free the memory with xmlFree(). 6290 */ 6291xmlChar * 6292xmlGetProp(xmlNodePtr node, const xmlChar *name) { 6293 xmlAttrPtr prop; 6294 6295 prop = xmlHasProp(node, name); 6296 if (prop == NULL) 6297 return(NULL); 6298 return(xmlGetPropNodeValueInternal(prop)); 6299} 6300 6301/** 6302 * xmlGetNoNsProp: 6303 * @node: the node 6304 * @name: the attribute name 6305 * 6306 * Search and get the value of an attribute associated to a node 6307 * This does the entity substitution. 6308 * This function looks in DTD attribute declaration for #FIXED or 6309 * default declaration values unless DTD use has been turned off. 6310 * This function is similar to xmlGetProp except it will accept only 6311 * an attribute in no namespace. 6312 * 6313 * Returns the attribute value or NULL if not found. 6314 * It's up to the caller to free the memory with xmlFree(). 6315 */ 6316xmlChar * 6317xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) { 6318 xmlAttrPtr prop; 6319 6320 prop = xmlGetPropNodeInternal(node, name, NULL, xmlCheckDTD); 6321 if (prop == NULL) 6322 return(NULL); 6323 return(xmlGetPropNodeValueInternal(prop)); 6324} 6325 6326/** 6327 * xmlGetNsProp: 6328 * @node: the node 6329 * @name: the attribute name 6330 * @nameSpace: the URI of the namespace 6331 * 6332 * Search and get the value of an attribute associated to a node 6333 * This attribute has to be anchored in the namespace specified. 6334 * This does the entity substitution. 6335 * This function looks in DTD attribute declaration for #FIXED or 6336 * default declaration values unless DTD use has been turned off. 6337 * 6338 * Returns the attribute value or NULL if not found. 6339 * It's up to the caller to free the memory with xmlFree(). 6340 */ 6341xmlChar * 6342xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) { 6343 xmlAttrPtr prop; 6344 6345 prop = xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD); 6346 if (prop == NULL) 6347 return(NULL); 6348 return(xmlGetPropNodeValueInternal(prop)); 6349} 6350 6351#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) 6352/** 6353 * xmlUnsetProp: 6354 * @node: the node 6355 * @name: the attribute name 6356 * 6357 * Remove an attribute carried by a node. 6358 * This handles only attributes in no namespace. 6359 * Returns 0 if successful, -1 if not found 6360 */ 6361int 6362xmlUnsetProp(xmlNodePtr node, const xmlChar *name) { 6363 xmlAttrPtr prop; 6364 6365 prop = xmlGetPropNodeInternal(node, name, NULL, 0); 6366 if (prop == NULL) 6367 return(-1); 6368 xmlUnlinkNode((xmlNodePtr) prop); 6369 xmlFreeProp(prop); 6370 return(0); 6371} 6372 6373/** 6374 * xmlUnsetNsProp: 6375 * @node: the node 6376 * @ns: the namespace definition 6377 * @name: the attribute name 6378 * 6379 * Remove an attribute carried by a node. 6380 * Returns 0 if successful, -1 if not found 6381 */ 6382int 6383xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) { 6384 xmlAttrPtr prop; 6385 6386 prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0); 6387 if (prop == NULL) 6388 return(-1); 6389 xmlUnlinkNode((xmlNodePtr) prop); 6390 xmlFreeProp(prop); 6391 return(0); 6392} 6393#endif 6394 6395#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED) 6396/** 6397 * xmlSetProp: 6398 * @node: the node 6399 * @name: the attribute name (a QName) 6400 * @value: the attribute value 6401 * 6402 * Set (or reset) an attribute carried by a node. 6403 * If @name has a prefix, then the corresponding 6404 * namespace-binding will be used, if in scope; it is an 6405 * error it there's no such ns-binding for the prefix in 6406 * scope. 6407 * Returns the attribute pointer. 6408 * 6409 */ 6410xmlAttrPtr 6411xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) { 6412 int len; 6413 const xmlChar *nqname; 6414 6415 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE)) 6416 return(NULL); 6417 6418 /* 6419 * handle QNames 6420 */ 6421 nqname = xmlSplitQName3(name, &len); 6422 if (nqname != NULL) { 6423 xmlNsPtr ns; 6424 xmlChar *prefix = xmlStrndup(name, len); 6425 ns = xmlSearchNs(node->doc, node, prefix); 6426 if (prefix != NULL) 6427 xmlFree(prefix); 6428 if (ns != NULL) 6429 return(xmlSetNsProp(node, ns, nqname, value)); 6430 } 6431 return(xmlSetNsProp(node, NULL, name, value)); 6432} 6433 6434/** 6435 * xmlSetNsProp: 6436 * @node: the node 6437 * @ns: the namespace definition 6438 * @name: the attribute name 6439 * @value: the attribute value 6440 * 6441 * Set (or reset) an attribute carried by a node. 6442 * The ns structure must be in scope, this is not checked 6443 * 6444 * Returns the attribute pointer. 6445 */ 6446xmlAttrPtr 6447xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name, 6448 const xmlChar *value) 6449{ 6450 xmlAttrPtr prop; 6451 6452 if (ns && (ns->href == NULL)) 6453 return(NULL); 6454 prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0); 6455 if (prop != NULL) { 6456 /* 6457 * Modify the attribute's value. 6458 */ 6459 if (prop->atype == XML_ATTRIBUTE_ID) { 6460 xmlRemoveID(node->doc, prop); 6461 prop->atype = XML_ATTRIBUTE_ID; 6462 } 6463 if (prop->children != NULL) 6464 xmlFreeNodeList(prop->children); 6465 prop->children = NULL; 6466 prop->last = NULL; 6467 prop->ns = ns; 6468 if (value != NULL) { 6469 xmlChar *buffer; 6470 xmlNodePtr tmp; 6471 6472 buffer = xmlEncodeEntitiesReentrant(node->doc, value); 6473 prop->children = xmlStringGetNodeList(node->doc, buffer); 6474 prop->last = NULL; 6475 tmp = prop->children; 6476 while (tmp != NULL) { 6477 tmp->parent = (xmlNodePtr) prop; 6478 if (tmp->next == NULL) 6479 prop->last = tmp; 6480 tmp = tmp->next; 6481 } 6482 xmlFree(buffer); 6483 } 6484 if (prop->atype == XML_ATTRIBUTE_ID) 6485 xmlAddID(NULL, node->doc, value, prop); 6486 return(prop); 6487 } 6488 /* 6489 * No equal attr found; create a new one. 6490 */ 6491 return(xmlNewPropInternal(node, ns, name, value, 0)); 6492} 6493 6494#endif /* LIBXML_TREE_ENABLED */ 6495 6496/** 6497 * xmlNodeIsText: 6498 * @node: the node 6499 * 6500 * Is this node a Text node ? 6501 * Returns 1 yes, 0 no 6502 */ 6503int 6504xmlNodeIsText(xmlNodePtr node) { 6505 if (node == NULL) return(0); 6506 6507 if (node->type == XML_TEXT_NODE) return(1); 6508 return(0); 6509} 6510 6511/** 6512 * xmlIsBlankNode: 6513 * @node: the node 6514 * 6515 * Checks whether this node is an empty or whitespace only 6516 * (and possibly ignorable) text-node. 6517 * 6518 * Returns 1 yes, 0 no 6519 */ 6520int 6521xmlIsBlankNode(xmlNodePtr node) { 6522 const xmlChar *cur; 6523 if (node == NULL) return(0); 6524 6525 if ((node->type != XML_TEXT_NODE) && 6526 (node->type != XML_CDATA_SECTION_NODE)) 6527 return(0); 6528 if (node->content == NULL) return(1); 6529 cur = node->content; 6530 while (*cur != 0) { 6531 if (!IS_BLANK_CH(*cur)) return(0); 6532 cur++; 6533 } 6534 6535 return(1); 6536} 6537 6538/** 6539 * xmlTextConcat: 6540 * @node: the node 6541 * @content: the content 6542 * @len: @content length 6543 * 6544 * Concat the given string at the end of the existing node content 6545 * 6546 * Returns -1 in case of error, 0 otherwise 6547 */ 6548 6549int 6550xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) { 6551 if (node == NULL) return(-1); 6552 6553 if ((node->type != XML_TEXT_NODE) && 6554 (node->type != XML_CDATA_SECTION_NODE) && 6555 (node->type != XML_COMMENT_NODE) && 6556 (node->type != XML_PI_NODE)) { 6557#ifdef DEBUG_TREE 6558 xmlGenericError(xmlGenericErrorContext, 6559 "xmlTextConcat: node is not text nor CDATA\n"); 6560#endif 6561 return(-1); 6562 } 6563 /* need to check if content is currently in the dictionary */ 6564 if ((node->content == (xmlChar *) &(node->properties)) || 6565 ((node->doc != NULL) && (node->doc->dict != NULL) && 6566 xmlDictOwns(node->doc->dict, node->content))) { 6567 node->content = xmlStrncatNew(node->content, content, len); 6568 } else { 6569 node->content = xmlStrncat(node->content, content, len); 6570 } 6571 node->properties = NULL; 6572 if (node->content == NULL) 6573 return(-1); 6574 return(0); 6575} 6576 6577/************************************************************************ 6578 * * 6579 * Output : to a FILE or in memory * 6580 * * 6581 ************************************************************************/ 6582 6583/** 6584 * xmlBufferCreate: 6585 * 6586 * routine to create an XML buffer. 6587 * returns the new structure. 6588 */ 6589xmlBufferPtr 6590xmlBufferCreate(void) { 6591 xmlBufferPtr ret; 6592 6593 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer)); 6594 if (ret == NULL) { 6595 xmlTreeErrMemory("creating buffer"); 6596 return(NULL); 6597 } 6598 ret->use = 0; 6599 ret->size = xmlDefaultBufferSize; 6600 ret->alloc = xmlBufferAllocScheme; 6601 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar)); 6602 if (ret->content == NULL) { 6603 xmlTreeErrMemory("creating buffer"); 6604 xmlFree(ret); 6605 return(NULL); 6606 } 6607 ret->content[0] = 0; 6608 return(ret); 6609} 6610 6611/** 6612 * xmlBufferCreateSize: 6613 * @size: initial size of buffer 6614 * 6615 * routine to create an XML buffer. 6616 * returns the new structure. 6617 */ 6618xmlBufferPtr 6619xmlBufferCreateSize(size_t size) { 6620 xmlBufferPtr ret; 6621 6622 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer)); 6623 if (ret == NULL) { 6624 xmlTreeErrMemory("creating buffer"); 6625 return(NULL); 6626 } 6627 ret->use = 0; 6628 ret->alloc = xmlBufferAllocScheme; 6629 ret->size = (size ? size+2 : 0); /* +1 for ending null */ 6630 if (ret->size){ 6631 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar)); 6632 if (ret->content == NULL) { 6633 xmlTreeErrMemory("creating buffer"); 6634 xmlFree(ret); 6635 return(NULL); 6636 } 6637 ret->content[0] = 0; 6638 } else 6639 ret->content = NULL; 6640 return(ret); 6641} 6642 6643/** 6644 * xmlBufferCreateStatic: 6645 * @mem: the memory area 6646 * @size: the size in byte 6647 * 6648 * routine to create an XML buffer from an immutable memory area. 6649 * The area won't be modified nor copied, and is expected to be 6650 * present until the end of the buffer lifetime. 6651 * 6652 * returns the new structure. 6653 */ 6654xmlBufferPtr 6655xmlBufferCreateStatic(void *mem, size_t size) { 6656 xmlBufferPtr ret; 6657 6658 if ((mem == NULL) || (size == 0)) 6659 return(NULL); 6660 6661 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer)); 6662 if (ret == NULL) { 6663 xmlTreeErrMemory("creating buffer"); 6664 return(NULL); 6665 } 6666 ret->use = size; 6667 ret->size = size; 6668 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE; 6669 ret->content = (xmlChar *) mem; 6670 return(ret); 6671} 6672 6673/** 6674 * xmlBufferSetAllocationScheme: 6675 * @buf: the buffer to tune 6676 * @scheme: allocation scheme to use 6677 * 6678 * Sets the allocation scheme for this buffer 6679 */ 6680void 6681xmlBufferSetAllocationScheme(xmlBufferPtr buf, 6682 xmlBufferAllocationScheme scheme) { 6683 if (buf == NULL) { 6684#ifdef DEBUG_BUFFER 6685 xmlGenericError(xmlGenericErrorContext, 6686 "xmlBufferSetAllocationScheme: buf == NULL\n"); 6687#endif 6688 return; 6689 } 6690 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return; 6691 6692 buf->alloc = scheme; 6693} 6694 6695/** 6696 * xmlBufferFree: 6697 * @buf: the buffer to free 6698 * 6699 * Frees an XML buffer. It frees both the content and the structure which 6700 * encapsulate it. 6701 */ 6702void 6703xmlBufferFree(xmlBufferPtr buf) { 6704 if (buf == NULL) { 6705#ifdef DEBUG_BUFFER 6706 xmlGenericError(xmlGenericErrorContext, 6707 "xmlBufferFree: buf == NULL\n"); 6708#endif 6709 return; 6710 } 6711 6712 if ((buf->content != NULL) && 6713 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) { 6714 xmlFree(buf->content); 6715 } 6716 xmlFree(buf); 6717} 6718 6719/** 6720 * xmlBufferEmpty: 6721 * @buf: the buffer 6722 * 6723 * empty a buffer. 6724 */ 6725void 6726xmlBufferEmpty(xmlBufferPtr buf) { 6727 if (buf == NULL) return; 6728 if (buf->content == NULL) return; 6729 buf->use = 0; 6730 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) { 6731 buf->content = BAD_CAST ""; 6732 } else { 6733 memset(buf->content, 0, buf->size); 6734 } 6735} 6736 6737/** 6738 * xmlBufferShrink: 6739 * @buf: the buffer to dump 6740 * @len: the number of xmlChar to remove 6741 * 6742 * Remove the beginning of an XML buffer. 6743 * 6744 * Returns the number of #xmlChar removed, or -1 in case of failure. 6745 */ 6746int 6747xmlBufferShrink(xmlBufferPtr buf, unsigned int len) { 6748 if (buf == NULL) return(-1); 6749 if (len == 0) return(0); 6750 if (len > buf->use) return(-1); 6751 6752 buf->use -= len; 6753 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) { 6754 buf->content += len; 6755 } else { 6756 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar)); 6757 buf->content[buf->use] = 0; 6758 } 6759 return(len); 6760} 6761 6762/** 6763 * xmlBufferGrow: 6764 * @buf: the buffer 6765 * @len: the minimum free size to allocate 6766 * 6767 * Grow the available space of an XML buffer. 6768 * 6769 * Returns the new available space or -1 in case of error 6770 */ 6771int 6772xmlBufferGrow(xmlBufferPtr buf, unsigned int len) { 6773 int size; 6774 xmlChar *newbuf; 6775 6776 if (buf == NULL) return(-1); 6777 6778 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0); 6779 if (len + buf->use < buf->size) return(0); 6780 6781/* 6782 * Windows has a BIG problem on realloc timing, so we try to double 6783 * the buffer size (if that's enough) (bug 146697) 6784 */ 6785#ifdef WIN32 6786 if (buf->size > len) 6787 size = buf->size * 2; 6788 else 6789 size = buf->use + len + 100; 6790#else 6791 size = buf->use + len + 100; 6792#endif 6793 6794 newbuf = (xmlChar *) xmlRealloc(buf->content, size); 6795 if (newbuf == NULL) { 6796 xmlTreeErrMemory("growing buffer"); 6797 return(-1); 6798 } 6799 buf->content = newbuf; 6800 buf->size = size; 6801 return(buf->size - buf->use); 6802} 6803 6804/** 6805 * xmlBufferDump: 6806 * @file: the file output 6807 * @buf: the buffer to dump 6808 * 6809 * Dumps an XML buffer to a FILE *. 6810 * Returns the number of #xmlChar written 6811 */ 6812int 6813xmlBufferDump(FILE *file, xmlBufferPtr buf) { 6814 int ret; 6815 6816 if (buf == NULL) { 6817#ifdef DEBUG_BUFFER 6818 xmlGenericError(xmlGenericErrorContext, 6819 "xmlBufferDump: buf == NULL\n"); 6820#endif 6821 return(0); 6822 } 6823 if (buf->content == NULL) { 6824#ifdef DEBUG_BUFFER 6825 xmlGenericError(xmlGenericErrorContext, 6826 "xmlBufferDump: buf->content == NULL\n"); 6827#endif 6828 return(0); 6829 } 6830 if (file == NULL) 6831 file = stdout; 6832 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file); 6833 return(ret); 6834} 6835 6836/** 6837 * xmlBufferContent: 6838 * @buf: the buffer 6839 * 6840 * Function to extract the content of a buffer 6841 * 6842 * Returns the internal content 6843 */ 6844 6845const xmlChar * 6846xmlBufferContent(const xmlBufferPtr buf) 6847{ 6848 if(!buf) 6849 return NULL; 6850 6851 return buf->content; 6852} 6853 6854/** 6855 * xmlBufferLength: 6856 * @buf: the buffer 6857 * 6858 * Function to get the length of a buffer 6859 * 6860 * Returns the length of data in the internal content 6861 */ 6862 6863int 6864xmlBufferLength(const xmlBufferPtr buf) 6865{ 6866 if(!buf) 6867 return 0; 6868 6869 return buf->use; 6870} 6871 6872/** 6873 * xmlBufferResize: 6874 * @buf: the buffer to resize 6875 * @size: the desired size 6876 * 6877 * Resize a buffer to accommodate minimum size of @size. 6878 * 6879 * Returns 0 in case of problems, 1 otherwise 6880 */ 6881int 6882xmlBufferResize(xmlBufferPtr buf, unsigned int size) 6883{ 6884 unsigned int newSize; 6885 xmlChar* rebuf = NULL; 6886 6887 if (buf == NULL) 6888 return(0); 6889 6890 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0); 6891 6892 /* Don't resize if we don't have to */ 6893 if (size < buf->size) 6894 return 1; 6895 6896 /* figure out new size */ 6897 switch (buf->alloc){ 6898 case XML_BUFFER_ALLOC_DOUBLEIT: 6899 /*take care of empty case*/ 6900 newSize = (buf->size ? buf->size*2 : size + 10); 6901 while (size > newSize) newSize *= 2; 6902 break; 6903 case XML_BUFFER_ALLOC_EXACT: 6904 newSize = size+10; 6905 break; 6906 default: 6907 newSize = size+10; 6908 break; 6909 } 6910 6911 if (buf->content == NULL) 6912 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar)); 6913 else if (buf->size - buf->use < 100) { 6914 rebuf = (xmlChar *) xmlRealloc(buf->content, 6915 newSize * sizeof(xmlChar)); 6916 } else { 6917 /* 6918 * if we are reallocating a buffer far from being full, it's 6919 * better to make a new allocation and copy only the used range 6920 * and free the old one. 6921 */ 6922 rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar)); 6923 if (rebuf != NULL) { 6924 memcpy(rebuf, buf->content, buf->use); 6925 xmlFree(buf->content); 6926 rebuf[buf->use] = 0; 6927 } 6928 } 6929 if (rebuf == NULL) { 6930 xmlTreeErrMemory("growing buffer"); 6931 return 0; 6932 } 6933 buf->content = rebuf; 6934 buf->size = newSize; 6935 6936 return 1; 6937} 6938 6939/** 6940 * xmlBufferAdd: 6941 * @buf: the buffer to dump 6942 * @str: the #xmlChar string 6943 * @len: the number of #xmlChar to add 6944 * 6945 * Add a string range to an XML buffer. if len == -1, the length of 6946 * str is recomputed. 6947 * 6948 * Returns 0 successful, a positive error code number otherwise 6949 * and -1 in case of internal or API error. 6950 */ 6951int 6952xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) { 6953 unsigned int needSize; 6954 6955 if ((str == NULL) || (buf == NULL)) { 6956 return -1; 6957 } 6958 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1; 6959 if (len < -1) { 6960#ifdef DEBUG_BUFFER 6961 xmlGenericError(xmlGenericErrorContext, 6962 "xmlBufferAdd: len < 0\n"); 6963#endif 6964 return -1; 6965 } 6966 if (len == 0) return 0; 6967 6968 if (len < 0) 6969 len = xmlStrlen(str); 6970 6971 if (len < 0) return -1; 6972 if (len == 0) return 0; 6973 6974 needSize = buf->use + len + 2; 6975 if (needSize > buf->size){ 6976 if (!xmlBufferResize(buf, needSize)){ 6977 xmlTreeErrMemory("growing buffer"); 6978 return XML_ERR_NO_MEMORY; 6979 } 6980 } 6981 6982 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar)); 6983 buf->use += len; 6984 buf->content[buf->use] = 0; 6985 return 0; 6986} 6987 6988/** 6989 * xmlBufferAddHead: 6990 * @buf: the buffer 6991 * @str: the #xmlChar string 6992 * @len: the number of #xmlChar to add 6993 * 6994 * Add a string range to the beginning of an XML buffer. 6995 * if len == -1, the length of @str is recomputed. 6996 * 6997 * Returns 0 successful, a positive error code number otherwise 6998 * and -1 in case of internal or API error. 6999 */ 7000int 7001xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) { 7002 unsigned int needSize; 7003 7004 if (buf == NULL) 7005 return(-1); 7006 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1; 7007 if (str == NULL) { 7008#ifdef DEBUG_BUFFER 7009 xmlGenericError(xmlGenericErrorContext, 7010 "xmlBufferAddHead: str == NULL\n"); 7011#endif 7012 return -1; 7013 } 7014 if (len < -1) { 7015#ifdef DEBUG_BUFFER 7016 xmlGenericError(xmlGenericErrorContext, 7017 "xmlBufferAddHead: len < 0\n"); 7018#endif 7019 return -1; 7020 } 7021 if (len == 0) return 0; 7022 7023 if (len < 0) 7024 len = xmlStrlen(str); 7025 7026 if (len <= 0) return -1; 7027 7028 needSize = buf->use + len + 2; 7029 if (needSize > buf->size){ 7030 if (!xmlBufferResize(buf, needSize)){ 7031 xmlTreeErrMemory("growing buffer"); 7032 return XML_ERR_NO_MEMORY; 7033 } 7034 } 7035 7036 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar)); 7037 memmove(&buf->content[0], str, len * sizeof(xmlChar)); 7038 buf->use += len; 7039 buf->content[buf->use] = 0; 7040 return 0; 7041} 7042 7043/** 7044 * xmlBufferCat: 7045 * @buf: the buffer to add to 7046 * @str: the #xmlChar string 7047 * 7048 * Append a zero terminated string to an XML buffer. 7049 * 7050 * Returns 0 successful, a positive error code number otherwise 7051 * and -1 in case of internal or API error. 7052 */ 7053int 7054xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) { 7055 if (buf == NULL) 7056 return(-1); 7057 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1; 7058 if (str == NULL) return -1; 7059 return xmlBufferAdd(buf, str, -1); 7060} 7061 7062/** 7063 * xmlBufferCCat: 7064 * @buf: the buffer to dump 7065 * @str: the C char string 7066 * 7067 * Append a zero terminated C string to an XML buffer. 7068 * 7069 * Returns 0 successful, a positive error code number otherwise 7070 * and -1 in case of internal or API error. 7071 */ 7072int 7073xmlBufferCCat(xmlBufferPtr buf, const char *str) { 7074 const char *cur; 7075 7076 if (buf == NULL) 7077 return(-1); 7078 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1; 7079 if (str == NULL) { 7080#ifdef DEBUG_BUFFER 7081 xmlGenericError(xmlGenericErrorContext, 7082 "xmlBufferCCat: str == NULL\n"); 7083#endif 7084 return -1; 7085 } 7086 for (cur = str;*cur != 0;cur++) { 7087 if (buf->use + 10 >= buf->size) { 7088 if (!xmlBufferResize(buf, buf->use+10)){ 7089 xmlTreeErrMemory("growing buffer"); 7090 return XML_ERR_NO_MEMORY; 7091 } 7092 } 7093 buf->content[buf->use++] = *cur; 7094 } 7095 buf->content[buf->use] = 0; 7096 return 0; 7097} 7098 7099/** 7100 * xmlBufferWriteCHAR: 7101 * @buf: the XML buffer 7102 * @string: the string to add 7103 * 7104 * routine which manages and grows an output buffer. This one adds 7105 * xmlChars at the end of the buffer. 7106 */ 7107void 7108xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) { 7109 if (buf == NULL) 7110 return; 7111 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return; 7112 xmlBufferCat(buf, string); 7113} 7114 7115/** 7116 * xmlBufferWriteChar: 7117 * @buf: the XML buffer output 7118 * @string: the string to add 7119 * 7120 * routine which manage and grows an output buffer. This one add 7121 * C chars at the end of the array. 7122 */ 7123void 7124xmlBufferWriteChar(xmlBufferPtr buf, const char *string) { 7125 if (buf == NULL) 7126 return; 7127 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return; 7128 xmlBufferCCat(buf, string); 7129} 7130 7131 7132/** 7133 * xmlBufferWriteQuotedString: 7134 * @buf: the XML buffer output 7135 * @string: the string to add 7136 * 7137 * routine which manage and grows an output buffer. This one writes 7138 * a quoted or double quoted #xmlChar string, checking first if it holds 7139 * quote or double-quotes internally 7140 */ 7141void 7142xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) { 7143 const xmlChar *cur, *base; 7144 if (buf == NULL) 7145 return; 7146 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return; 7147 if (xmlStrchr(string, '\"')) { 7148 if (xmlStrchr(string, '\'')) { 7149#ifdef DEBUG_BUFFER 7150 xmlGenericError(xmlGenericErrorContext, 7151 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n"); 7152#endif 7153 xmlBufferCCat(buf, "\""); 7154 base = cur = string; 7155 while(*cur != 0){ 7156 if(*cur == '"'){ 7157 if (base != cur) 7158 xmlBufferAdd(buf, base, cur - base); 7159 xmlBufferAdd(buf, BAD_CAST """, 6); 7160 cur++; 7161 base = cur; 7162 } 7163 else { 7164 cur++; 7165 } 7166 } 7167 if (base != cur) 7168 xmlBufferAdd(buf, base, cur - base); 7169 xmlBufferCCat(buf, "\""); 7170 } 7171 else{ 7172 xmlBufferCCat(buf, "\'"); 7173 xmlBufferCat(buf, string); 7174 xmlBufferCCat(buf, "\'"); 7175 } 7176 } else { 7177 xmlBufferCCat(buf, "\""); 7178 xmlBufferCat(buf, string); 7179 xmlBufferCCat(buf, "\""); 7180 } 7181} 7182 7183 7184/** 7185 * xmlGetDocCompressMode: 7186 * @doc: the document 7187 * 7188 * get the compression ratio for a document, ZLIB based 7189 * Returns 0 (uncompressed) to 9 (max compression) 7190 */ 7191int 7192xmlGetDocCompressMode (xmlDocPtr doc) { 7193 if (doc == NULL) return(-1); 7194 return(doc->compression); 7195} 7196 7197/** 7198 * xmlSetDocCompressMode: 7199 * @doc: the document 7200 * @mode: the compression ratio 7201 * 7202 * set the compression ratio for a document, ZLIB based 7203 * Correct values: 0 (uncompressed) to 9 (max compression) 7204 */ 7205void 7206xmlSetDocCompressMode (xmlDocPtr doc, int mode) { 7207 if (doc == NULL) return; 7208 if (mode < 0) doc->compression = 0; 7209 else if (mode > 9) doc->compression = 9; 7210 else doc->compression = mode; 7211} 7212 7213/** 7214 * xmlGetCompressMode: 7215 * 7216 * get the default compression mode used, ZLIB based. 7217 * Returns 0 (uncompressed) to 9 (max compression) 7218 */ 7219int 7220xmlGetCompressMode(void) 7221{ 7222 return (xmlCompressMode); 7223} 7224 7225/** 7226 * xmlSetCompressMode: 7227 * @mode: the compression ratio 7228 * 7229 * set the default compression mode used, ZLIB based 7230 * Correct values: 0 (uncompressed) to 9 (max compression) 7231 */ 7232void 7233xmlSetCompressMode(int mode) { 7234 if (mode < 0) xmlCompressMode = 0; 7235 else if (mode > 9) xmlCompressMode = 9; 7236 else xmlCompressMode = mode; 7237} 7238 7239#define XML_TREE_NSMAP_PARENT -1 7240#define XML_TREE_NSMAP_XML -2 7241#define XML_TREE_NSMAP_DOC -3 7242#define XML_TREE_NSMAP_CUSTOM -4 7243 7244typedef struct xmlNsMapItem *xmlNsMapItemPtr; 7245struct xmlNsMapItem { 7246 xmlNsMapItemPtr next; 7247 xmlNsMapItemPtr prev; 7248 xmlNsPtr oldNs; /* old ns decl reference */ 7249 xmlNsPtr newNs; /* new ns decl reference */ 7250 int shadowDepth; /* Shadowed at this depth */ 7251 /* 7252 * depth: 7253 * >= 0 == @node's ns-decls 7254 * -1 == @parent's ns-decls 7255 * -2 == the doc->oldNs XML ns-decl 7256 * -3 == the doc->oldNs storage ns-decls 7257 * -4 == ns-decls provided via custom ns-handling 7258 */ 7259 int depth; 7260}; 7261 7262typedef struct xmlNsMap *xmlNsMapPtr; 7263struct xmlNsMap { 7264 xmlNsMapItemPtr first; 7265 xmlNsMapItemPtr last; 7266 xmlNsMapItemPtr pool; 7267}; 7268 7269#define XML_NSMAP_NOTEMPTY(m) (((m) != NULL) && ((m)->first != NULL)) 7270#define XML_NSMAP_FOREACH(m, i) for (i = (m)->first; i != NULL; i = (i)->next) 7271#define XML_NSMAP_POP(m, i) \ 7272 i = (m)->last; \ 7273 (m)->last = (i)->prev; \ 7274 if ((m)->last == NULL) \ 7275 (m)->first = NULL; \ 7276 else \ 7277 (m)->last->next = NULL; \ 7278 (i)->next = (m)->pool; \ 7279 (m)->pool = i; 7280 7281/* 7282* xmlDOMWrapNsMapFree: 7283* @map: the ns-map 7284* 7285* Frees the ns-map 7286*/ 7287static void 7288xmlDOMWrapNsMapFree(xmlNsMapPtr nsmap) 7289{ 7290 xmlNsMapItemPtr cur, tmp; 7291 7292 if (nsmap == NULL) 7293 return; 7294 cur = nsmap->pool; 7295 while (cur != NULL) { 7296 tmp = cur; 7297 cur = cur->next; 7298 xmlFree(tmp); 7299 } 7300 cur = nsmap->first; 7301 while (cur != NULL) { 7302 tmp = cur; 7303 cur = cur->next; 7304 xmlFree(tmp); 7305 } 7306 xmlFree(nsmap); 7307} 7308 7309/* 7310* xmlDOMWrapNsMapAddItem: 7311* @map: the ns-map 7312* @oldNs: the old ns-struct 7313* @newNs: the new ns-struct 7314* @depth: depth and ns-kind information 7315* 7316* Adds an ns-mapping item. 7317*/ 7318static xmlNsMapItemPtr 7319xmlDOMWrapNsMapAddItem(xmlNsMapPtr *nsmap, int position, 7320 xmlNsPtr oldNs, xmlNsPtr newNs, int depth) 7321{ 7322 xmlNsMapItemPtr ret; 7323 xmlNsMapPtr map; 7324 7325 if (nsmap == NULL) 7326 return(NULL); 7327 if ((position != -1) && (position != 0)) 7328 return(NULL); 7329 map = *nsmap; 7330 7331 if (map == NULL) { 7332 /* 7333 * Create the ns-map. 7334 */ 7335 map = (xmlNsMapPtr) xmlMalloc(sizeof(struct xmlNsMap)); 7336 if (map == NULL) { 7337 xmlTreeErrMemory("allocating namespace map"); 7338 return (NULL); 7339 } 7340 memset(map, 0, sizeof(struct xmlNsMap)); 7341 *nsmap = map; 7342 } 7343 7344 if (map->pool != NULL) { 7345 /* 7346 * Reuse an item from the pool. 7347 */ 7348 ret = map->pool; 7349 map->pool = ret->next; 7350 memset(ret, 0, sizeof(struct xmlNsMapItem)); 7351 } else { 7352 /* 7353 * Create a new item. 7354 */ 7355 ret = (xmlNsMapItemPtr) xmlMalloc(sizeof(struct xmlNsMapItem)); 7356 if (ret == NULL) { 7357 xmlTreeErrMemory("allocating namespace map item"); 7358 return (NULL); 7359 } 7360 memset(ret, 0, sizeof(struct xmlNsMapItem)); 7361 } 7362 7363 if (map->first == NULL) { 7364 /* 7365 * First ever. 7366 */ 7367 map->first = ret; 7368 map->last = ret; 7369 } else if (position == -1) { 7370 /* 7371 * Append. 7372 */ 7373 ret->prev = map->last; 7374 map->last->next = ret; 7375 map->last = ret; 7376 } else if (position == 0) { 7377 /* 7378 * Set on first position. 7379 */ 7380 map->first->prev = ret; 7381 ret->next = map->first; 7382 map->first = ret; 7383 } else 7384 return(NULL); 7385 7386 ret->oldNs = oldNs; 7387 ret->newNs = newNs; 7388 ret->shadowDepth = -1; 7389 ret->depth = depth; 7390 return (ret); 7391} 7392 7393/* 7394* xmlDOMWrapStoreNs: 7395* @doc: the doc 7396* @nsName: the namespace name 7397* @prefix: the prefix 7398* 7399* Creates or reuses an xmlNs struct on doc->oldNs with 7400* the given prefix and namespace name. 7401* 7402* Returns the aquired ns struct or NULL in case of an API 7403* or internal error. 7404*/ 7405static xmlNsPtr 7406xmlDOMWrapStoreNs(xmlDocPtr doc, 7407 const xmlChar *nsName, 7408 const xmlChar *prefix) 7409{ 7410 xmlNsPtr ns; 7411 7412 if (doc == NULL) 7413 return (NULL); 7414 ns = xmlTreeEnsureXMLDecl(doc); 7415 if (ns == NULL) 7416 return (NULL); 7417 if (ns->next != NULL) { 7418 /* Reuse. */ 7419 ns = ns->next; 7420 while (ns != NULL) { 7421 if (((ns->prefix == prefix) || 7422 xmlStrEqual(ns->prefix, prefix)) && 7423 xmlStrEqual(ns->href, nsName)) { 7424 return (ns); 7425 } 7426 if (ns->next == NULL) 7427 break; 7428 ns = ns->next; 7429 } 7430 } 7431 /* Create. */ 7432 ns->next = xmlNewNs(NULL, nsName, prefix); 7433 return (ns->next); 7434} 7435 7436/* 7437* xmlDOMWrapNewCtxt: 7438* 7439* Allocates and initializes a new DOM-wrapper context. 7440* 7441* Returns the xmlDOMWrapCtxtPtr or NULL in case of an internal errror. 7442*/ 7443xmlDOMWrapCtxtPtr 7444xmlDOMWrapNewCtxt(void) 7445{ 7446 xmlDOMWrapCtxtPtr ret; 7447 7448 ret = xmlMalloc(sizeof(xmlDOMWrapCtxt)); 7449 if (ret == NULL) { 7450 xmlTreeErrMemory("allocating DOM-wrapper context"); 7451 return (NULL); 7452 } 7453 memset(ret, 0, sizeof(xmlDOMWrapCtxt)); 7454 return (ret); 7455} 7456 7457/* 7458* xmlDOMWrapFreeCtxt: 7459* @ctxt: the DOM-wrapper context 7460* 7461* Frees the DOM-wrapper context. 7462*/ 7463void 7464xmlDOMWrapFreeCtxt(xmlDOMWrapCtxtPtr ctxt) 7465{ 7466 if (ctxt == NULL) 7467 return; 7468 if (ctxt->namespaceMap != NULL) 7469 xmlDOMWrapNsMapFree((xmlNsMapPtr) ctxt->namespaceMap); 7470 /* 7471 * TODO: Store the namespace map in the context. 7472 */ 7473 xmlFree(ctxt); 7474} 7475 7476/* 7477* xmlTreeLookupNsListByPrefix: 7478* @nsList: a list of ns-structs 7479* @prefix: the searched prefix 7480* 7481* Searches for a ns-decl with the given prefix in @nsList. 7482* 7483* Returns the ns-decl if found, NULL if not found and on 7484* API errors. 7485*/ 7486static xmlNsPtr 7487xmlTreeNSListLookupByPrefix(xmlNsPtr nsList, const xmlChar *prefix) 7488{ 7489 if (nsList == NULL) 7490 return (NULL); 7491 { 7492 xmlNsPtr ns; 7493 ns = nsList; 7494 do { 7495 if ((prefix == ns->prefix) || 7496 xmlStrEqual(prefix, ns->prefix)) { 7497 return (ns); 7498 } 7499 ns = ns->next; 7500 } while (ns != NULL); 7501 } 7502 return (NULL); 7503} 7504 7505/* 7506* 7507* xmlDOMWrapNSNormGatherInScopeNs: 7508* @map: the namespace map 7509* @node: the node to start with 7510* 7511* Puts in-scope namespaces into the ns-map. 7512* 7513* Returns 0 on success, -1 on API or internal errors. 7514*/ 7515static int 7516xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapPtr *map, 7517 xmlNodePtr node) 7518{ 7519 xmlNodePtr cur; 7520 xmlNsPtr ns; 7521 xmlNsMapItemPtr mi; 7522 int shadowed; 7523 7524 if ((map == NULL) || (*map != NULL)) 7525 return (-1); 7526 /* 7527 * Get in-scope ns-decls of @parent. 7528 */ 7529 cur = node; 7530 while ((cur != NULL) && (cur != (xmlNodePtr) cur->doc)) { 7531 if (cur->type == XML_ELEMENT_NODE) { 7532 if (cur->nsDef != NULL) { 7533 ns = cur->nsDef; 7534 do { 7535 shadowed = 0; 7536 if (XML_NSMAP_NOTEMPTY(*map)) { 7537 /* 7538 * Skip shadowed prefixes. 7539 */ 7540 XML_NSMAP_FOREACH(*map, mi) { 7541 if ((ns->prefix == mi->newNs->prefix) || 7542 xmlStrEqual(ns->prefix, mi->newNs->prefix)) { 7543 shadowed = 1; 7544 break; 7545 } 7546 } 7547 } 7548 /* 7549 * Insert mapping. 7550 */ 7551 mi = xmlDOMWrapNsMapAddItem(map, 0, NULL, 7552 ns, XML_TREE_NSMAP_PARENT); 7553 if (mi == NULL) 7554 return (-1); 7555 if (shadowed) 7556 mi->shadowDepth = 0; 7557 ns = ns->next; 7558 } while (ns != NULL); 7559 } 7560 } 7561 cur = cur->parent; 7562 } 7563 return (0); 7564} 7565 7566/* 7567* XML_TREE_ADOPT_STR: If we have a dest-dict, put @str in the dict; 7568* otherwise copy it, when it was in the source-dict. 7569*/ 7570#define XML_TREE_ADOPT_STR(str) \ 7571 if (adoptStr && (str != NULL)) { \ 7572 if (destDoc->dict) { \ 7573 const xmlChar *old = str; \ 7574 str = xmlDictLookup(destDoc->dict, str, -1); \ 7575 if ((sourceDoc == NULL) || (sourceDoc->dict == NULL) || \ 7576 (!xmlDictOwns(sourceDoc->dict, old))) \ 7577 xmlFree((char *)old); \ 7578 } else if ((sourceDoc) && (sourceDoc->dict) && \ 7579 xmlDictOwns(sourceDoc->dict, str)) { \ 7580 str = BAD_CAST xmlStrdup(str); \ 7581 } \ 7582 } 7583 7584/* 7585* XML_TREE_ADOPT_STR_2: If @str was in the source-dict, then 7586* put it in dest-dict or copy it. 7587*/ 7588#define XML_TREE_ADOPT_STR_2(str) \ 7589 if (adoptStr && (str != NULL) && (sourceDoc != NULL) && \ 7590 (sourceDoc->dict != NULL) && \ 7591 xmlDictOwns(sourceDoc->dict, cur->content)) { \ 7592 if (destDoc->dict) \ 7593 cur->content = (xmlChar *) \ 7594 xmlDictLookup(destDoc->dict, cur->content, -1); \ 7595 else \ 7596 cur->content = xmlStrdup(BAD_CAST cur->content); \ 7597 } 7598 7599/* 7600* xmlDOMWrapNSNormAddNsMapItem2: 7601* 7602* For internal use. Adds a ns-decl mapping. 7603* 7604* Returns 0 on success, -1 on internal errors. 7605*/ 7606static int 7607xmlDOMWrapNSNormAddNsMapItem2(xmlNsPtr **list, int *size, int *number, 7608 xmlNsPtr oldNs, xmlNsPtr newNs) 7609{ 7610 if (*list == NULL) { 7611 *list = (xmlNsPtr *) xmlMalloc(6 * sizeof(xmlNsPtr)); 7612 if (*list == NULL) { 7613 xmlTreeErrMemory("alloc ns map item"); 7614 return(-1); 7615 } 7616 *size = 3; 7617 *number = 0; 7618 } else if ((*number) >= (*size)) { 7619 *size *= 2; 7620 *list = (xmlNsPtr *) xmlRealloc(*list, 7621 (*size) * 2 * sizeof(xmlNsPtr)); 7622 if (*list == NULL) { 7623 xmlTreeErrMemory("realloc ns map item"); 7624 return(-1); 7625 } 7626 } 7627 (*list)[2 * (*number)] = oldNs; 7628 (*list)[2 * (*number) +1] = newNs; 7629 (*number)++; 7630 return (0); 7631} 7632 7633/* 7634* xmlDOMWrapRemoveNode: 7635* @ctxt: a DOM wrapper context 7636* @doc: the doc 7637* @node: the node to be removed. 7638* @options: set of options, unused at the moment 7639* 7640* Unlinks the given node from its owner. 7641* This will substitute ns-references to node->nsDef for 7642* ns-references to doc->oldNs, thus ensuring the removed 7643* branch to be autark wrt ns-references. 7644* 7645* NOTE: This function was not intensively tested. 7646* 7647* Returns 0 on success, 1 if the node is not supported, 7648* -1 on API and internal errors. 7649*/ 7650int 7651xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc, 7652 xmlNodePtr node, int options ATTRIBUTE_UNUSED) 7653{ 7654 xmlNsPtr *list = NULL; 7655 int sizeList, nbList, i, j; 7656 xmlNsPtr ns; 7657 7658 if ((node == NULL) || (doc == NULL) || (node->doc != doc)) 7659 return (-1); 7660 7661 /* TODO: 0 or -1 ? */ 7662 if (node->parent == NULL) 7663 return (0); 7664 7665 switch (node->type) { 7666 case XML_TEXT_NODE: 7667 case XML_CDATA_SECTION_NODE: 7668 case XML_ENTITY_REF_NODE: 7669 case XML_PI_NODE: 7670 case XML_COMMENT_NODE: 7671 xmlUnlinkNode(node); 7672 return (0); 7673 case XML_ELEMENT_NODE: 7674 case XML_ATTRIBUTE_NODE: 7675 break; 7676 default: 7677 return (1); 7678 } 7679 xmlUnlinkNode(node); 7680 /* 7681 * Save out-of-scope ns-references in doc->oldNs. 7682 */ 7683 do { 7684 switch (node->type) { 7685 case XML_ELEMENT_NODE: 7686 if ((ctxt == NULL) && (node->nsDef != NULL)) { 7687 ns = node->nsDef; 7688 do { 7689 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList, 7690 &nbList, ns, ns) == -1) 7691 goto internal_error; 7692 ns = ns->next; 7693 } while (ns != NULL); 7694 } 7695 /* No break on purpose. */ 7696 case XML_ATTRIBUTE_NODE: 7697 if (node->ns != NULL) { 7698 /* 7699 * Find a mapping. 7700 */ 7701 if (list != NULL) { 7702 for (i = 0, j = 0; i < nbList; i++, j += 2) { 7703 if (node->ns == list[j]) { 7704 node->ns = list[++j]; 7705 goto next_node; 7706 } 7707 } 7708 } 7709 ns = NULL; 7710 if (ctxt != NULL) { 7711 /* 7712 * User defined. 7713 */ 7714 } else { 7715 /* 7716 * Add to doc's oldNs. 7717 */ 7718 ns = xmlDOMWrapStoreNs(doc, node->ns->href, 7719 node->ns->prefix); 7720 if (ns == NULL) 7721 goto internal_error; 7722 } 7723 if (ns != NULL) { 7724 /* 7725 * Add mapping. 7726 */ 7727 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList, 7728 &nbList, node->ns, ns) == -1) 7729 goto internal_error; 7730 } 7731 node->ns = ns; 7732 } 7733 if ((node->type == XML_ELEMENT_NODE) && 7734 (node->properties != NULL)) { 7735 node = (xmlNodePtr) node->properties; 7736 continue; 7737 } 7738 break; 7739 default: 7740 goto next_sibling; 7741 } 7742next_node: 7743 if ((node->type == XML_ELEMENT_NODE) && 7744 (node->children != NULL)) { 7745 node = node->children; 7746 continue; 7747 } 7748next_sibling: 7749 if (node == NULL) 7750 break; 7751 if (node->next != NULL) 7752 node = node->next; 7753 else { 7754 node = node->parent; 7755 goto next_sibling; 7756 } 7757 } while (node != NULL); 7758 7759 if (list != NULL) 7760 xmlFree(list); 7761 return (0); 7762 7763internal_error: 7764 if (list != NULL) 7765 xmlFree(list); 7766 return (-1); 7767} 7768 7769/* 7770* xmlSearchNsByNamespaceStrict: 7771* @doc: the document 7772* @node: the start node 7773* @nsName: the searched namespace name 7774* @retNs: the resulting ns-decl 7775* @prefixed: if the found ns-decl must have a prefix (for attributes) 7776* 7777* Dynamically searches for a ns-declaration which matches 7778* the given @nsName in the ancestor-or-self axis of @node. 7779* 7780* Returns 1 if a ns-decl was found, 0 if not and -1 on API 7781* and internal errors. 7782*/ 7783static int 7784xmlSearchNsByNamespaceStrict(xmlDocPtr doc, xmlNodePtr node, 7785 const xmlChar* nsName, 7786 xmlNsPtr *retNs, int prefixed) 7787{ 7788 xmlNodePtr cur, prev = NULL, out = NULL; 7789 xmlNsPtr ns, prevns; 7790 7791 if ((doc == NULL) || (nsName == NULL) || (retNs == NULL)) 7792 return (-1); 7793 7794 *retNs = NULL; 7795 if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) { 7796 *retNs = xmlTreeEnsureXMLDecl(doc); 7797 if (*retNs == NULL) 7798 return (-1); 7799 return (1); 7800 } 7801 cur = node; 7802 do { 7803 if (cur->type == XML_ELEMENT_NODE) { 7804 if (cur->nsDef != NULL) { 7805 for (ns = cur->nsDef; ns != NULL; ns = ns->next) { 7806 if (prefixed && (ns->prefix == NULL)) 7807 continue; 7808 if (prev != NULL) { 7809 /* 7810 * Check the last level of ns-decls for a 7811 * shadowing prefix. 7812 */ 7813 prevns = prev->nsDef; 7814 do { 7815 if ((prevns->prefix == ns->prefix) || 7816 ((prevns->prefix != NULL) && 7817 (ns->prefix != NULL) && 7818 xmlStrEqual(prevns->prefix, ns->prefix))) { 7819 /* 7820 * Shadowed. 7821 */ 7822 break; 7823 } 7824 prevns = prevns->next; 7825 } while (prevns != NULL); 7826 if (prevns != NULL) 7827 continue; 7828 } 7829 /* 7830 * Ns-name comparison. 7831 */ 7832 if ((nsName == ns->href) || 7833 xmlStrEqual(nsName, ns->href)) { 7834 /* 7835 * At this point the prefix can only be shadowed, 7836 * if we are the the (at least) 3rd level of 7837 * ns-decls. 7838 */ 7839 if (out) { 7840 int ret; 7841 7842 ret = xmlNsInScope(doc, node, prev, ns->prefix); 7843 if (ret < 0) 7844 return (-1); 7845 /* 7846 * TODO: Should we try to find a matching ns-name 7847 * only once? This here keeps on searching. 7848 * I think we should try further since, there might 7849 * be an other matching ns-decl with an unshadowed 7850 * prefix. 7851 */ 7852 if (! ret) 7853 continue; 7854 } 7855 *retNs = ns; 7856 return (1); 7857 } 7858 } 7859 out = prev; 7860 prev = cur; 7861 } 7862 } else if ((cur->type == XML_ENTITY_NODE) || 7863 (cur->type == XML_ENTITY_DECL)) 7864 return (0); 7865 cur = cur->parent; 7866 } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur)); 7867 return (0); 7868} 7869 7870/* 7871* xmlSearchNsByPrefixStrict: 7872* @doc: the document 7873* @node: the start node 7874* @prefix: the searched namespace prefix 7875* @retNs: the resulting ns-decl 7876* 7877* Dynamically searches for a ns-declaration which matches 7878* the given @nsName in the ancestor-or-self axis of @node. 7879* 7880* Returns 1 if a ns-decl was found, 0 if not and -1 on API 7881* and internal errors. 7882*/ 7883static int 7884xmlSearchNsByPrefixStrict(xmlDocPtr doc, xmlNodePtr node, 7885 const xmlChar* prefix, 7886 xmlNsPtr *retNs) 7887{ 7888 xmlNodePtr cur; 7889 xmlNsPtr ns; 7890 7891 if ((doc == NULL) || (node == NULL)) 7892 return (-1); 7893 7894 if (retNs) 7895 *retNs = NULL; 7896 if (IS_STR_XML(prefix)) { 7897 if (retNs) { 7898 *retNs = xmlTreeEnsureXMLDecl(doc); 7899 if (*retNs == NULL) 7900 return (-1); 7901 } 7902 return (1); 7903 } 7904 cur = node; 7905 do { 7906 if (cur->type == XML_ELEMENT_NODE) { 7907 if (cur->nsDef != NULL) { 7908 ns = cur->nsDef; 7909 do { 7910 if ((prefix == ns->prefix) || 7911 xmlStrEqual(prefix, ns->prefix)) 7912 { 7913 /* 7914 * Disabled namespaces, e.g. xmlns:abc="". 7915 */ 7916 if (ns->href == NULL) 7917 return(0); 7918 if (retNs) 7919 *retNs = ns; 7920 return (1); 7921 } 7922 ns = ns->next; 7923 } while (ns != NULL); 7924 } 7925 } else if ((cur->type == XML_ENTITY_NODE) || 7926 (cur->type == XML_ENTITY_DECL)) 7927 return (0); 7928 cur = cur->parent; 7929 } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur)); 7930 return (0); 7931} 7932 7933/* 7934* xmlDOMWrapNSNormDeclareNsForced: 7935* @doc: the doc 7936* @elem: the element-node to declare on 7937* @nsName: the namespace-name of the ns-decl 7938* @prefix: the preferred prefix of the ns-decl 7939* @checkShadow: ensure that the new ns-decl doesn't shadow ancestor ns-decls 7940* 7941* Declares a new namespace on @elem. It tries to use the 7942* given @prefix; if a ns-decl with the given prefix is already existent 7943* on @elem, it will generate an other prefix. 7944* 7945* Returns 1 if a ns-decl was found, 0 if not and -1 on API 7946* and internal errors. 7947*/ 7948static xmlNsPtr 7949xmlDOMWrapNSNormDeclareNsForced(xmlDocPtr doc, 7950 xmlNodePtr elem, 7951 const xmlChar *nsName, 7952 const xmlChar *prefix, 7953 int checkShadow) 7954{ 7955 7956 xmlNsPtr ret; 7957 char buf[50]; 7958 const xmlChar *pref; 7959 int counter = 0; 7960 /* 7961 * Create a ns-decl on @anchor. 7962 */ 7963 pref = prefix; 7964 while (1) { 7965 /* 7966 * Lookup whether the prefix is unused in elem's ns-decls. 7967 */ 7968 if ((elem->nsDef != NULL) && 7969 (xmlTreeNSListLookupByPrefix(elem->nsDef, pref) != NULL)) 7970 goto ns_next_prefix; 7971 if (checkShadow && elem->parent && 7972 ((xmlNodePtr) elem->parent->doc != elem->parent)) { 7973 /* 7974 * Does it shadow ancestor ns-decls? 7975 */ 7976 if (xmlSearchNsByPrefixStrict(doc, elem->parent, pref, NULL) == 1) 7977 goto ns_next_prefix; 7978 } 7979 ret = xmlNewNs(NULL, nsName, pref); 7980 if (ret == NULL) 7981 return (NULL); 7982 if (elem->nsDef == NULL) 7983 elem->nsDef = ret; 7984 else { 7985 xmlNsPtr ns2 = elem->nsDef; 7986 while (ns2->next != NULL) 7987 ns2 = ns2->next; 7988 ns2->next = ret; 7989 } 7990 return (ret); 7991ns_next_prefix: 7992 counter++; 7993 if (counter > 1000) 7994 return (NULL); 7995 if (prefix == NULL) { 7996 snprintf((char *) buf, sizeof(buf), 7997 "ns_%d", counter); 7998 } else 7999 snprintf((char *) buf, sizeof(buf), 8000 "%.30s_%d", (char *)prefix, counter); 8001 pref = BAD_CAST buf; 8002 } 8003} 8004 8005/* 8006* xmlDOMWrapNSNormAquireNormalizedNs: 8007* @doc: the doc 8008* @elem: the element-node to declare namespaces on 8009* @ns: the ns-struct to use for the search 8010* @retNs: the found/created ns-struct 8011* @nsMap: the ns-map 8012* @depth: the current tree depth 8013* @ancestorsOnly: search in ancestor ns-decls only 8014* @prefixed: if the searched ns-decl must have a prefix (for attributes) 8015* 8016* Searches for a matching ns-name in the ns-decls of @nsMap, if not 8017* found it will either declare it on @elem, or store it in doc->oldNs. 8018* If a new ns-decl needs to be declared on @elem, it tries to use the 8019* @ns->prefix for it, if this prefix is already in use on @elem, it will 8020* change the prefix or the new ns-decl. 8021* 8022* Returns 0 if succeeded, -1 otherwise and on API/internal errors. 8023*/ 8024static int 8025xmlDOMWrapNSNormAquireNormalizedNs(xmlDocPtr doc, 8026 xmlNodePtr elem, 8027 xmlNsPtr ns, 8028 xmlNsPtr *retNs, 8029 xmlNsMapPtr *nsMap, 8030 8031 int depth, 8032 int ancestorsOnly, 8033 int prefixed) 8034{ 8035 xmlNsMapItemPtr mi; 8036 8037 if ((doc == NULL) || (ns == NULL) || (retNs == NULL) || 8038 (nsMap == NULL)) 8039 return (-1); 8040 8041 *retNs = NULL; 8042 /* 8043 * Handle XML namespace. 8044 */ 8045 if (IS_STR_XML(ns->prefix)) { 8046 /* 8047 * Insert XML namespace mapping. 8048 */ 8049 *retNs = xmlTreeEnsureXMLDecl(doc); 8050 if (*retNs == NULL) 8051 return (-1); 8052 return (0); 8053 } 8054 /* 8055 * If the search should be done in ancestors only and no 8056 * @elem (the first ancestor) was specified, then skip the search. 8057 */ 8058 if ((XML_NSMAP_NOTEMPTY(*nsMap)) && 8059 (! (ancestorsOnly && (elem == NULL)))) 8060 { 8061 /* 8062 * Try to find an equal ns-name in in-scope ns-decls. 8063 */ 8064 XML_NSMAP_FOREACH(*nsMap, mi) { 8065 if ((mi->depth >= XML_TREE_NSMAP_PARENT) && 8066 /* 8067 * ancestorsOnly: This should be turned on to gain speed, 8068 * if one knows that the branch itself was already 8069 * ns-wellformed and no stale references existed. 8070 * I.e. it searches in the ancestor axis only. 8071 */ 8072 ((! ancestorsOnly) || (mi->depth == XML_TREE_NSMAP_PARENT)) && 8073 /* Skip shadowed prefixes. */ 8074 (mi->shadowDepth == -1) && 8075 /* Skip xmlns="" or xmlns:foo="". */ 8076 ((mi->newNs->href != NULL) && 8077 (mi->newNs->href[0] != 0)) && 8078 /* Ensure a prefix if wanted. */ 8079 ((! prefixed) || (mi->newNs->prefix != NULL)) && 8080 /* Equal ns name */ 8081 ((mi->newNs->href == ns->href) || 8082 xmlStrEqual(mi->newNs->href, ns->href))) { 8083 /* Set the mapping. */ 8084 mi->oldNs = ns; 8085 *retNs = mi->newNs; 8086 return (0); 8087 } 8088 } 8089 } 8090 /* 8091 * No luck, the namespace is out of scope or shadowed. 8092 */ 8093 if (elem == NULL) { 8094 xmlNsPtr tmpns; 8095 8096 /* 8097 * Store ns-decls in "oldNs" of the document-node. 8098 */ 8099 tmpns = xmlDOMWrapStoreNs(doc, ns->href, ns->prefix); 8100 if (tmpns == NULL) 8101 return (-1); 8102 /* 8103 * Insert mapping. 8104 */ 8105 if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns, 8106 tmpns, XML_TREE_NSMAP_DOC) == NULL) { 8107 xmlFreeNs(tmpns); 8108 return (-1); 8109 } 8110 *retNs = tmpns; 8111 } else { 8112 xmlNsPtr tmpns; 8113 8114 tmpns = xmlDOMWrapNSNormDeclareNsForced(doc, elem, ns->href, 8115 ns->prefix, 0); 8116 if (tmpns == NULL) 8117 return (-1); 8118 8119 if (*nsMap != NULL) { 8120 /* 8121 * Does it shadow ancestor ns-decls? 8122 */ 8123 XML_NSMAP_FOREACH(*nsMap, mi) { 8124 if ((mi->depth < depth) && 8125 (mi->shadowDepth == -1) && 8126 ((ns->prefix == mi->newNs->prefix) || 8127 xmlStrEqual(ns->prefix, mi->newNs->prefix))) { 8128 /* 8129 * Shadows. 8130 */ 8131 mi->shadowDepth = depth; 8132 break; 8133 } 8134 } 8135 } 8136 if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns, tmpns, depth) == NULL) { 8137 xmlFreeNs(tmpns); 8138 return (-1); 8139 } 8140 *retNs = tmpns; 8141 } 8142 return (0); 8143} 8144 8145typedef enum { 8146 XML_DOM_RECONNS_REMOVEREDUND = 1<<0 8147} xmlDOMReconcileNSOptions; 8148 8149/* 8150* xmlDOMWrapReconcileNamespaces: 8151* @ctxt: DOM wrapper context, unused at the moment 8152* @elem: the element-node 8153* @options: option flags 8154* 8155* Ensures that ns-references point to ns-decls hold on element-nodes. 8156* Ensures that the tree is namespace wellformed by creating additional 8157* ns-decls where needed. Note that, since prefixes of already existent 8158* ns-decls can be shadowed by this process, it could break QNames in 8159* attribute values or element content. 8160* 8161* NOTE: This function was not intensively tested. 8162* 8163* Returns 0 if succeeded, -1 otherwise and on API/internal errors. 8164*/ 8165 8166int 8167xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED, 8168 xmlNodePtr elem, 8169 int options) 8170{ 8171 int depth = -1, adoptns = 0, parnsdone = 0; 8172 xmlNsPtr ns, prevns; 8173 xmlDocPtr doc; 8174 xmlNodePtr cur, curElem = NULL; 8175 xmlNsMapPtr nsMap = NULL; 8176 xmlNsMapItemPtr /* topmi = NULL, */ mi; 8177 /* @ancestorsOnly should be set by an option flag. */ 8178 int ancestorsOnly = 0; 8179 int optRemoveRedundantNS = 8180 ((xmlDOMReconcileNSOptions) options & XML_DOM_RECONNS_REMOVEREDUND) ? 1 : 0; 8181 xmlNsPtr *listRedund = NULL; 8182 int sizeRedund = 0, nbRedund = 0, ret, i, j; 8183 8184 if ((elem == NULL) || (elem->doc == NULL) || 8185 (elem->type != XML_ELEMENT_NODE)) 8186 return (-1); 8187 8188 doc = elem->doc; 8189 cur = elem; 8190 do { 8191 switch (cur->type) { 8192 case XML_ELEMENT_NODE: 8193 adoptns = 1; 8194 curElem = cur; 8195 depth++; 8196 /* 8197 * Namespace declarations. 8198 */ 8199 if (cur->nsDef != NULL) { 8200 prevns = NULL; 8201 ns = cur->nsDef; 8202 while (ns != NULL) { 8203 if (! parnsdone) { 8204 if ((elem->parent) && 8205 ((xmlNodePtr) elem->parent->doc != elem->parent)) { 8206 /* 8207 * Gather ancestor in-scope ns-decls. 8208 */ 8209 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, 8210 elem->parent) == -1) 8211 goto internal_error; 8212 } 8213 parnsdone = 1; 8214 } 8215 8216 /* 8217 * Lookup the ns ancestor-axis for equal ns-decls in scope. 8218 */ 8219 if (optRemoveRedundantNS && XML_NSMAP_NOTEMPTY(nsMap)) { 8220 XML_NSMAP_FOREACH(nsMap, mi) { 8221 if ((mi->depth >= XML_TREE_NSMAP_PARENT) && 8222 (mi->shadowDepth == -1) && 8223 ((ns->prefix == mi->newNs->prefix) || 8224 xmlStrEqual(ns->prefix, mi->newNs->prefix)) && 8225 ((ns->href == mi->newNs->href) || 8226 xmlStrEqual(ns->href, mi->newNs->href))) 8227 { 8228 /* 8229 * A redundant ns-decl was found. 8230 * Add it to the list of redundant ns-decls. 8231 */ 8232 if (xmlDOMWrapNSNormAddNsMapItem2(&listRedund, 8233 &sizeRedund, &nbRedund, ns, mi->newNs) == -1) 8234 goto internal_error; 8235 /* 8236 * Remove the ns-decl from the element-node. 8237 */ 8238 if (prevns) 8239 prevns->next = ns->next; 8240 else 8241 cur->nsDef = ns->next; 8242 goto next_ns_decl; 8243 } 8244 } 8245 } 8246 8247 /* 8248 * Skip ns-references handling if the referenced 8249 * ns-decl is declared on the same element. 8250 */ 8251 if ((cur->ns != NULL) && adoptns && (cur->ns == ns)) 8252 adoptns = 0; 8253 /* 8254 * Does it shadow any ns-decl? 8255 */ 8256 if (XML_NSMAP_NOTEMPTY(nsMap)) { 8257 XML_NSMAP_FOREACH(nsMap, mi) { 8258 if ((mi->depth >= XML_TREE_NSMAP_PARENT) && 8259 (mi->shadowDepth == -1) && 8260 ((ns->prefix == mi->newNs->prefix) || 8261 xmlStrEqual(ns->prefix, mi->newNs->prefix))) { 8262 8263 mi->shadowDepth = depth; 8264 } 8265 } 8266 } 8267 /* 8268 * Push mapping. 8269 */ 8270 if (xmlDOMWrapNsMapAddItem(&nsMap, -1, ns, ns, 8271 depth) == NULL) 8272 goto internal_error; 8273 8274 prevns = ns; 8275next_ns_decl: 8276 ns = ns->next; 8277 } 8278 } 8279 if (! adoptns) 8280 goto ns_end; 8281 /* No break on purpose. */ 8282 case XML_ATTRIBUTE_NODE: 8283 /* No ns, no fun. */ 8284 if (cur->ns == NULL) 8285 goto ns_end; 8286 8287 if (! parnsdone) { 8288 if ((elem->parent) && 8289 ((xmlNodePtr) elem->parent->doc != elem->parent)) { 8290 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, 8291 elem->parent) == -1) 8292 goto internal_error; 8293 } 8294 parnsdone = 1; 8295 } 8296 /* 8297 * Adjust the reference if this was a redundant ns-decl. 8298 */ 8299 if (listRedund) { 8300 for (i = 0, j = 0; i < nbRedund; i++, j += 2) { 8301 if (cur->ns == listRedund[j]) { 8302 cur->ns = listRedund[++j]; 8303 break; 8304 } 8305 } 8306 } 8307 /* 8308 * Adopt ns-references. 8309 */ 8310 if (XML_NSMAP_NOTEMPTY(nsMap)) { 8311 /* 8312 * Search for a mapping. 8313 */ 8314 XML_NSMAP_FOREACH(nsMap, mi) { 8315 if ((mi->shadowDepth == -1) && 8316 (cur->ns == mi->oldNs)) { 8317 8318 cur->ns = mi->newNs; 8319 goto ns_end; 8320 } 8321 } 8322 } 8323 /* 8324 * Aquire a normalized ns-decl and add it to the map. 8325 */ 8326 if (xmlDOMWrapNSNormAquireNormalizedNs(doc, curElem, 8327 cur->ns, &ns, 8328 &nsMap, depth, 8329 ancestorsOnly, 8330 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1) 8331 goto internal_error; 8332 cur->ns = ns; 8333 8334ns_end: 8335 if ((cur->type == XML_ELEMENT_NODE) && 8336 (cur->properties != NULL)) { 8337 /* 8338 * Process attributes. 8339 */ 8340 cur = (xmlNodePtr) cur->properties; 8341 continue; 8342 } 8343 break; 8344 default: 8345 goto next_sibling; 8346 } 8347into_content: 8348 if ((cur->type == XML_ELEMENT_NODE) && 8349 (cur->children != NULL)) { 8350 /* 8351 * Process content of element-nodes only. 8352 */ 8353 cur = cur->children; 8354 continue; 8355 } 8356next_sibling: 8357 if (cur == elem) 8358 break; 8359 if (cur->type == XML_ELEMENT_NODE) { 8360 if (XML_NSMAP_NOTEMPTY(nsMap)) { 8361 /* 8362 * Pop mappings. 8363 */ 8364 while ((nsMap->last != NULL) && 8365 (nsMap->last->depth >= depth)) 8366 { 8367 XML_NSMAP_POP(nsMap, mi) 8368 } 8369 /* 8370 * Unshadow. 8371 */ 8372 XML_NSMAP_FOREACH(nsMap, mi) { 8373 if (mi->shadowDepth >= depth) 8374 mi->shadowDepth = -1; 8375 } 8376 } 8377 depth--; 8378 } 8379 if (cur->next != NULL) 8380 cur = cur->next; 8381 else { 8382 if (cur->type == XML_ATTRIBUTE_NODE) { 8383 cur = cur->parent; 8384 goto into_content; 8385 } 8386 cur = cur->parent; 8387 goto next_sibling; 8388 } 8389 } while (cur != NULL); 8390 8391 ret = 0; 8392 goto exit; 8393internal_error: 8394 ret = -1; 8395exit: 8396 if (listRedund) { 8397 for (i = 0, j = 0; i < nbRedund; i++, j += 2) { 8398 xmlFreeNs(listRedund[j]); 8399 } 8400 xmlFree(listRedund); 8401 } 8402 if (nsMap != NULL) 8403 xmlDOMWrapNsMapFree(nsMap); 8404 return (ret); 8405} 8406 8407/* 8408* xmlDOMWrapAdoptBranch: 8409* @ctxt: the optional context for custom processing 8410* @sourceDoc: the optional sourceDoc 8411* @node: the element-node to start with 8412* @destDoc: the destination doc for adoption 8413* @destParent: the optional new parent of @node in @destDoc 8414* @options: option flags 8415* 8416* Ensures that ns-references point to @destDoc: either to 8417* elements->nsDef entries if @destParent is given, or to 8418* @destDoc->oldNs otherwise. 8419* If @destParent is given, it ensures that the tree is namespace 8420* wellformed by creating additional ns-decls where needed. 8421* Note that, since prefixes of already existent ns-decls can be 8422* shadowed by this process, it could break QNames in attribute 8423* values or element content. 8424* 8425* NOTE: This function was not intensively tested. 8426* 8427* Returns 0 if succeeded, -1 otherwise and on API/internal errors. 8428*/ 8429static int 8430xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt, 8431 xmlDocPtr sourceDoc, 8432 xmlNodePtr node, 8433 xmlDocPtr destDoc, 8434 xmlNodePtr destParent, 8435 int options ATTRIBUTE_UNUSED) 8436{ 8437 int ret = 0; 8438 xmlNodePtr cur, curElem = NULL; 8439 xmlNsMapPtr nsMap = NULL; 8440 xmlNsMapItemPtr mi; 8441 xmlNsPtr ns = NULL; 8442 int depth = -1, adoptStr = 1; 8443 /* gather @parent's ns-decls. */ 8444 int parnsdone; 8445 /* @ancestorsOnly should be set per option. */ 8446 int ancestorsOnly = 0; 8447 8448 /* 8449 * Optimize string adoption for equal or none dicts. 8450 */ 8451 if ((sourceDoc != NULL) && 8452 (sourceDoc->dict == destDoc->dict)) 8453 adoptStr = 0; 8454 else 8455 adoptStr = 1; 8456 8457 /* 8458 * Get the ns-map from the context if available. 8459 */ 8460 if (ctxt) 8461 nsMap = (xmlNsMapPtr) ctxt->namespaceMap; 8462 /* 8463 * Disable search for ns-decls in the parent-axis of the 8464 * desination element, if: 8465 * 1) there's no destination parent 8466 * 2) custom ns-reference handling is used 8467 */ 8468 if ((destParent == NULL) || 8469 (ctxt && ctxt->getNsForNodeFunc)) 8470 { 8471 parnsdone = 1; 8472 } else 8473 parnsdone = 0; 8474 8475 cur = node; 8476 while (cur != NULL) { 8477 /* 8478 * Paranoid source-doc sanity check. 8479 */ 8480 if (cur->doc != sourceDoc) { 8481 /* 8482 * We'll assume XIncluded nodes if the doc differs. 8483 * TODO: Do we need to reconciliate XIncluded nodes? 8484 * This here skips XIncluded nodes and tries to handle 8485 * broken sequences. 8486 */ 8487 if (cur->next == NULL) 8488 goto leave_node; 8489 do { 8490 cur = cur->next; 8491 if ((cur->type == XML_XINCLUDE_END) || 8492 (cur->doc == node->doc)) 8493 break; 8494 } while (cur->next != NULL); 8495 8496 if (cur->doc != node->doc) 8497 goto leave_node; 8498 } 8499 cur->doc = destDoc; 8500 switch (cur->type) { 8501 case XML_XINCLUDE_START: 8502 case XML_XINCLUDE_END: 8503 /* 8504 * TODO 8505 */ 8506 return (-1); 8507 case XML_ELEMENT_NODE: 8508 curElem = cur; 8509 depth++; 8510 /* 8511 * Namespace declarations. 8512 * - ns->href and ns->prefix are never in the dict, so 8513 * we need not move the values over to the destination dict. 8514 * - Note that for custom handling of ns-references, 8515 * the ns-decls need not be stored in the ns-map, 8516 * since they won't be referenced by node->ns. 8517 */ 8518 if ((cur->nsDef) && 8519 ((ctxt == NULL) || (ctxt->getNsForNodeFunc == NULL))) 8520 { 8521 if (! parnsdone) { 8522 /* 8523 * Gather @parent's in-scope ns-decls. 8524 */ 8525 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, 8526 destParent) == -1) 8527 goto internal_error; 8528 parnsdone = 1; 8529 } 8530 for (ns = cur->nsDef; ns != NULL; ns = ns->next) { 8531 /* 8532 * NOTE: ns->prefix and ns->href are never in the dict. 8533 * XML_TREE_ADOPT_STR(ns->prefix) 8534 * XML_TREE_ADOPT_STR(ns->href) 8535 */ 8536 /* 8537 * Does it shadow any ns-decl? 8538 */ 8539 if (XML_NSMAP_NOTEMPTY(nsMap)) { 8540 XML_NSMAP_FOREACH(nsMap, mi) { 8541 if ((mi->depth >= XML_TREE_NSMAP_PARENT) && 8542 (mi->shadowDepth == -1) && 8543 ((ns->prefix == mi->newNs->prefix) || 8544 xmlStrEqual(ns->prefix, 8545 mi->newNs->prefix))) { 8546 8547 mi->shadowDepth = depth; 8548 } 8549 } 8550 } 8551 /* 8552 * Push mapping. 8553 */ 8554 if (xmlDOMWrapNsMapAddItem(&nsMap, -1, 8555 ns, ns, depth) == NULL) 8556 goto internal_error; 8557 } 8558 } 8559 /* No break on purpose. */ 8560 case XML_ATTRIBUTE_NODE: 8561 /* No namespace, no fun. */ 8562 if (cur->ns == NULL) 8563 goto ns_end; 8564 8565 if (! parnsdone) { 8566 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, 8567 destParent) == -1) 8568 goto internal_error; 8569 parnsdone = 1; 8570 } 8571 /* 8572 * Adopt ns-references. 8573 */ 8574 if (XML_NSMAP_NOTEMPTY(nsMap)) { 8575 /* 8576 * Search for a mapping. 8577 */ 8578 XML_NSMAP_FOREACH(nsMap, mi) { 8579 if ((mi->shadowDepth == -1) && 8580 (cur->ns == mi->oldNs)) { 8581 8582 cur->ns = mi->newNs; 8583 goto ns_end; 8584 } 8585 } 8586 } 8587 /* 8588 * No matching namespace in scope. We need a new one. 8589 */ 8590 if ((ctxt) && (ctxt->getNsForNodeFunc)) { 8591 /* 8592 * User-defined behaviour. 8593 */ 8594 ns = ctxt->getNsForNodeFunc(ctxt, cur, 8595 cur->ns->href, cur->ns->prefix); 8596 /* 8597 * Insert mapping if ns is available; it's the users fault 8598 * if not. 8599 */ 8600 if (xmlDOMWrapNsMapAddItem(&nsMap, -1, 8601 cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL) 8602 goto internal_error; 8603 cur->ns = ns; 8604 } else { 8605 /* 8606 * Aquire a normalized ns-decl and add it to the map. 8607 */ 8608 if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc, 8609 /* ns-decls on curElem or on destDoc->oldNs */ 8610 destParent ? curElem : NULL, 8611 cur->ns, &ns, 8612 &nsMap, depth, 8613 ancestorsOnly, 8614 /* ns-decls must be prefixed for attributes. */ 8615 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1) 8616 goto internal_error; 8617 cur->ns = ns; 8618 } 8619ns_end: 8620 /* 8621 * Further node properties. 8622 * TODO: Is this all? 8623 */ 8624 XML_TREE_ADOPT_STR(cur->name) 8625 if (cur->type == XML_ELEMENT_NODE) { 8626 cur->psvi = NULL; 8627 cur->line = 0; 8628 cur->extra = 0; 8629 /* 8630 * Walk attributes. 8631 */ 8632 if (cur->properties != NULL) { 8633 /* 8634 * Process first attribute node. 8635 */ 8636 cur = (xmlNodePtr) cur->properties; 8637 continue; 8638 } 8639 } else { 8640 /* 8641 * Attributes. 8642 */ 8643 if ((sourceDoc != NULL) && 8644 (((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID)) 8645 { 8646 xmlRemoveID(sourceDoc, (xmlAttrPtr) cur); 8647 } 8648 ((xmlAttrPtr) cur)->atype = 0; 8649 ((xmlAttrPtr) cur)->psvi = NULL; 8650 } 8651 break; 8652 case XML_TEXT_NODE: 8653 case XML_CDATA_SECTION_NODE: 8654 /* 8655 * This puts the content in the dest dict, only if 8656 * it was previously in the source dict. 8657 */ 8658 XML_TREE_ADOPT_STR_2(cur->content) 8659 goto leave_node; 8660 case XML_ENTITY_REF_NODE: 8661 /* 8662 * Remove reference to the entitity-node. 8663 */ 8664 cur->content = NULL; 8665 cur->children = NULL; 8666 cur->last = NULL; 8667 if ((destDoc->intSubset) || (destDoc->extSubset)) { 8668 xmlEntityPtr ent; 8669 /* 8670 * Assign new entity-node if available. 8671 */ 8672 ent = xmlGetDocEntity(destDoc, cur->name); 8673 if (ent != NULL) { 8674 cur->content = ent->content; 8675 cur->children = (xmlNodePtr) ent; 8676 cur->last = (xmlNodePtr) ent; 8677 } 8678 } 8679 goto leave_node; 8680 case XML_PI_NODE: 8681 XML_TREE_ADOPT_STR(cur->name) 8682 XML_TREE_ADOPT_STR_2(cur->content) 8683 break; 8684 case XML_COMMENT_NODE: 8685 break; 8686 default: 8687 goto internal_error; 8688 } 8689 /* 8690 * Walk the tree. 8691 */ 8692 if (cur->children != NULL) { 8693 cur = cur->children; 8694 continue; 8695 } 8696 8697leave_node: 8698 if (cur == node) 8699 break; 8700 if ((cur->type == XML_ELEMENT_NODE) || 8701 (cur->type == XML_XINCLUDE_START) || 8702 (cur->type == XML_XINCLUDE_END)) 8703 { 8704 /* 8705 * TODO: Do we expect nsDefs on XML_XINCLUDE_START? 8706 */ 8707 if (XML_NSMAP_NOTEMPTY(nsMap)) { 8708 /* 8709 * Pop mappings. 8710 */ 8711 while ((nsMap->last != NULL) && 8712 (nsMap->last->depth >= depth)) 8713 { 8714 XML_NSMAP_POP(nsMap, mi) 8715 } 8716 /* 8717 * Unshadow. 8718 */ 8719 XML_NSMAP_FOREACH(nsMap, mi) { 8720 if (mi->shadowDepth >= depth) 8721 mi->shadowDepth = -1; 8722 } 8723 } 8724 depth--; 8725 } 8726 if (cur->next != NULL) 8727 cur = cur->next; 8728 else if ((cur->type == XML_ATTRIBUTE_NODE) && 8729 (cur->parent->children != NULL)) 8730 { 8731 cur = cur->parent->children; 8732 } else { 8733 cur = cur->parent; 8734 goto leave_node; 8735 } 8736 } 8737 8738 goto exit; 8739 8740internal_error: 8741 ret = -1; 8742 8743exit: 8744 /* 8745 * Cleanup. 8746 */ 8747 if (nsMap != NULL) { 8748 if ((ctxt) && (ctxt->namespaceMap == nsMap)) { 8749 /* 8750 * Just cleanup the map but don't free. 8751 */ 8752 if (nsMap->first) { 8753 if (nsMap->pool) 8754 nsMap->last->next = nsMap->pool; 8755 nsMap->pool = nsMap->first; 8756 nsMap->first = NULL; 8757 } 8758 } else 8759 xmlDOMWrapNsMapFree(nsMap); 8760 } 8761 return(ret); 8762} 8763 8764/* 8765* xmlDOMWrapCloneNode: 8766* @ctxt: the optional context for custom processing 8767* @sourceDoc: the optional sourceDoc 8768* @node: the node to start with 8769* @resNode: the clone of the given @node 8770* @destDoc: the destination doc 8771* @destParent: the optional new parent of @node in @destDoc 8772* @deep: descend into child if set 8773* @options: option flags 8774* 8775* References of out-of scope ns-decls are remapped to point to @destDoc: 8776* 1) If @destParent is given, then nsDef entries on element-nodes are used 8777* 2) If *no* @destParent is given, then @destDoc->oldNs entries are used. 8778* This is the case when you don't know already where the cloned branch 8779* will be added to. 8780* 8781* If @destParent is given, it ensures that the tree is namespace 8782* wellformed by creating additional ns-decls where needed. 8783* Note that, since prefixes of already existent ns-decls can be 8784* shadowed by this process, it could break QNames in attribute 8785* values or element content. 8786* TODO: 8787* 1) What to do with XInclude? Currently this returns an error for XInclude. 8788* 8789* Returns 0 if the operation succeeded, 8790* 1 if a node of unsupported (or not yet supported) type was given, 8791* -1 on API/internal errors. 8792*/ 8793 8794int 8795xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, 8796 xmlDocPtr sourceDoc, 8797 xmlNodePtr node, 8798 xmlNodePtr *resNode, 8799 xmlDocPtr destDoc, 8800 xmlNodePtr destParent, 8801 int deep, 8802 int options ATTRIBUTE_UNUSED) 8803{ 8804 int ret = 0; 8805 xmlNodePtr cur, curElem = NULL; 8806 xmlNsMapPtr nsMap = NULL; 8807 xmlNsMapItemPtr mi; 8808 xmlNsPtr ns; 8809 int depth = -1; 8810 /* int adoptStr = 1; */ 8811 /* gather @parent's ns-decls. */ 8812 int parnsdone = 0; 8813 /* 8814 * @ancestorsOnly: 8815 * TODO: @ancestorsOnly should be set per option. 8816 * 8817 */ 8818 int ancestorsOnly = 0; 8819 xmlNodePtr resultClone = NULL, clone = NULL, parentClone = NULL, prevClone = NULL; 8820 xmlNsPtr cloneNs = NULL, *cloneNsDefSlot = NULL; 8821 xmlDictPtr dict; /* The destination dict */ 8822 8823 if ((node == NULL) || (resNode == NULL) || (destDoc == NULL)) 8824 return(-1); 8825 /* 8826 * TODO: Initially we support only element-nodes. 8827 */ 8828 if (node->type != XML_ELEMENT_NODE) 8829 return(1); 8830 /* 8831 * Check node->doc sanity. 8832 */ 8833 if ((node->doc != NULL) && (sourceDoc != NULL) && 8834 (node->doc != sourceDoc)) { 8835 /* 8836 * Might be an XIncluded node. 8837 */ 8838 return (-1); 8839 } 8840 if (sourceDoc == NULL) 8841 sourceDoc = node->doc; 8842 if (sourceDoc == NULL) 8843 return (-1); 8844 8845 dict = destDoc->dict; 8846 /* 8847 * Reuse the namespace map of the context. 8848 */ 8849 if (ctxt) 8850 nsMap = (xmlNsMapPtr) ctxt->namespaceMap; 8851 8852 *resNode = NULL; 8853 8854 cur = node; 8855 while (cur != NULL) { 8856 if (cur->doc != sourceDoc) { 8857 /* 8858 * We'll assume XIncluded nodes if the doc differs. 8859 * TODO: Do we need to reconciliate XIncluded nodes? 8860 * TODO: This here returns -1 in this case. 8861 */ 8862 goto internal_error; 8863 } 8864 /* 8865 * Create a new node. 8866 */ 8867 switch (cur->type) { 8868 case XML_XINCLUDE_START: 8869 case XML_XINCLUDE_END: 8870 /* 8871 * TODO: What to do with XInclude? 8872 */ 8873 goto internal_error; 8874 break; 8875 case XML_ELEMENT_NODE: 8876 case XML_TEXT_NODE: 8877 case XML_CDATA_SECTION_NODE: 8878 case XML_COMMENT_NODE: 8879 case XML_PI_NODE: 8880 case XML_DOCUMENT_FRAG_NODE: 8881 case XML_ENTITY_REF_NODE: 8882 case XML_ENTITY_NODE: 8883 /* 8884 * Nodes of xmlNode structure. 8885 */ 8886 clone = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); 8887 if (clone == NULL) { 8888 xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating a node"); 8889 goto internal_error; 8890 } 8891 memset(clone, 0, sizeof(xmlNode)); 8892 /* 8893 * Set hierachical links. 8894 */ 8895 if (resultClone != NULL) { 8896 clone->parent = parentClone; 8897 if (prevClone) { 8898 prevClone->next = clone; 8899 clone->prev = prevClone; 8900 } else 8901 parentClone->children = clone; 8902 } else 8903 resultClone = clone; 8904 8905 break; 8906 case XML_ATTRIBUTE_NODE: 8907 /* 8908 * Attributes (xmlAttr). 8909 */ 8910 clone = (xmlNodePtr) xmlMalloc(sizeof(xmlAttr)); 8911 if (clone == NULL) { 8912 xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating an attr-node"); 8913 goto internal_error; 8914 } 8915 memset(clone, 0, sizeof(xmlAttr)); 8916 /* 8917 * Set hierachical links. 8918 * TODO: Change this to add to the end of attributes. 8919 */ 8920 if (resultClone != NULL) { 8921 clone->parent = parentClone; 8922 if (prevClone) { 8923 prevClone->next = clone; 8924 clone->prev = prevClone; 8925 } else 8926 parentClone->properties = (xmlAttrPtr) clone; 8927 } else 8928 resultClone = clone; 8929 break; 8930 default: 8931 /* 8932 * TODO QUESTION: Any other nodes expected? 8933 */ 8934 goto internal_error; 8935 } 8936 8937 clone->type = cur->type; 8938 clone->doc = destDoc; 8939 8940 /* 8941 * Clone the name of the node if any. 8942 */ 8943 if (cur->name == xmlStringText) 8944 clone->name = xmlStringText; 8945 else if (cur->name == xmlStringTextNoenc) 8946 /* 8947 * NOTE: Although xmlStringTextNoenc is never assigned to a node 8948 * in tree.c, it might be set in Libxslt via 8949 * "xsl:disable-output-escaping". 8950 */ 8951 clone->name = xmlStringTextNoenc; 8952 else if (cur->name == xmlStringComment) 8953 clone->name = xmlStringComment; 8954 else if (cur->name != NULL) { 8955 DICT_CONST_COPY(cur->name, clone->name); 8956 } 8957 8958 switch (cur->type) { 8959 case XML_XINCLUDE_START: 8960 case XML_XINCLUDE_END: 8961 /* 8962 * TODO 8963 */ 8964 return (-1); 8965 case XML_ELEMENT_NODE: 8966 curElem = cur; 8967 depth++; 8968 /* 8969 * Namespace declarations. 8970 */ 8971 if (cur->nsDef != NULL) { 8972 if (! parnsdone) { 8973 if (destParent && (ctxt == NULL)) { 8974 /* 8975 * Gather @parent's in-scope ns-decls. 8976 */ 8977 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, 8978 destParent) == -1) 8979 goto internal_error; 8980 } 8981 parnsdone = 1; 8982 } 8983 /* 8984 * Clone namespace declarations. 8985 */ 8986 cloneNsDefSlot = &(clone->nsDef); 8987 for (ns = cur->nsDef; ns != NULL; ns = ns->next) { 8988 /* 8989 * Create a new xmlNs. 8990 */ 8991 cloneNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 8992 if (cloneNs == NULL) { 8993 xmlTreeErrMemory("xmlDOMWrapCloneNode(): " 8994 "allocating namespace"); 8995 return(-1); 8996 } 8997 memset(cloneNs, 0, sizeof(xmlNs)); 8998 cloneNs->type = XML_LOCAL_NAMESPACE; 8999 9000 if (ns->href != NULL) 9001 cloneNs->href = xmlStrdup(ns->href); 9002 if (ns->prefix != NULL) 9003 cloneNs->prefix = xmlStrdup(ns->prefix); 9004 9005 *cloneNsDefSlot = cloneNs; 9006 cloneNsDefSlot = &(cloneNs->next); 9007 9008 /* 9009 * Note that for custom handling of ns-references, 9010 * the ns-decls need not be stored in the ns-map, 9011 * since they won't be referenced by node->ns. 9012 */ 9013 if ((ctxt == NULL) || 9014 (ctxt->getNsForNodeFunc == NULL)) 9015 { 9016 /* 9017 * Does it shadow any ns-decl? 9018 */ 9019 if (XML_NSMAP_NOTEMPTY(nsMap)) { 9020 XML_NSMAP_FOREACH(nsMap, mi) { 9021 if ((mi->depth >= XML_TREE_NSMAP_PARENT) && 9022 (mi->shadowDepth == -1) && 9023 ((ns->prefix == mi->newNs->prefix) || 9024 xmlStrEqual(ns->prefix, 9025 mi->newNs->prefix))) { 9026 /* 9027 * Mark as shadowed at the current 9028 * depth. 9029 */ 9030 mi->shadowDepth = depth; 9031 } 9032 } 9033 } 9034 /* 9035 * Push mapping. 9036 */ 9037 if (xmlDOMWrapNsMapAddItem(&nsMap, -1, 9038 ns, cloneNs, depth) == NULL) 9039 goto internal_error; 9040 } 9041 } 9042 } 9043 /* cur->ns will be processed further down. */ 9044 break; 9045 case XML_ATTRIBUTE_NODE: 9046 /* IDs will be processed further down. */ 9047 /* cur->ns will be processed further down. */ 9048 break; 9049 case XML_TEXT_NODE: 9050 case XML_CDATA_SECTION_NODE: 9051 /* 9052 * Note that this will also cover the values of attributes. 9053 */ 9054 DICT_COPY(cur->content, clone->content); 9055 goto leave_node; 9056 case XML_ENTITY_NODE: 9057 /* TODO: What to do here? */ 9058 goto leave_node; 9059 case XML_ENTITY_REF_NODE: 9060 if (sourceDoc != destDoc) { 9061 if ((destDoc->intSubset) || (destDoc->extSubset)) { 9062 xmlEntityPtr ent; 9063 /* 9064 * Different doc: Assign new entity-node if available. 9065 */ 9066 ent = xmlGetDocEntity(destDoc, cur->name); 9067 if (ent != NULL) { 9068 clone->content = ent->content; 9069 clone->children = (xmlNodePtr) ent; 9070 clone->last = (xmlNodePtr) ent; 9071 } 9072 } 9073 } else { 9074 /* 9075 * Same doc: Use the current node's entity declaration 9076 * and value. 9077 */ 9078 clone->content = cur->content; 9079 clone->children = cur->children; 9080 clone->last = cur->last; 9081 } 9082 goto leave_node; 9083 case XML_PI_NODE: 9084 DICT_COPY(cur->content, clone->content); 9085 goto leave_node; 9086 case XML_COMMENT_NODE: 9087 DICT_COPY(cur->content, clone->content); 9088 goto leave_node; 9089 default: 9090 goto internal_error; 9091 } 9092 9093 if (cur->ns == NULL) 9094 goto end_ns_reference; 9095 9096/* handle_ns_reference: */ 9097 /* 9098 ** The following will take care of references to ns-decls ******** 9099 ** and is intended only for element- and attribute-nodes. 9100 ** 9101 */ 9102 if (! parnsdone) { 9103 if (destParent && (ctxt == NULL)) { 9104 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, destParent) == -1) 9105 goto internal_error; 9106 } 9107 parnsdone = 1; 9108 } 9109 /* 9110 * Adopt ns-references. 9111 */ 9112 if (XML_NSMAP_NOTEMPTY(nsMap)) { 9113 /* 9114 * Search for a mapping. 9115 */ 9116 XML_NSMAP_FOREACH(nsMap, mi) { 9117 if ((mi->shadowDepth == -1) && 9118 (cur->ns == mi->oldNs)) { 9119 /* 9120 * This is the nice case: a mapping was found. 9121 */ 9122 clone->ns = mi->newNs; 9123 goto end_ns_reference; 9124 } 9125 } 9126 } 9127 /* 9128 * No matching namespace in scope. We need a new one. 9129 */ 9130 if ((ctxt != NULL) && (ctxt->getNsForNodeFunc != NULL)) { 9131 /* 9132 * User-defined behaviour. 9133 */ 9134 ns = ctxt->getNsForNodeFunc(ctxt, cur, 9135 cur->ns->href, cur->ns->prefix); 9136 /* 9137 * Add user's mapping. 9138 */ 9139 if (xmlDOMWrapNsMapAddItem(&nsMap, -1, 9140 cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL) 9141 goto internal_error; 9142 clone->ns = ns; 9143 } else { 9144 /* 9145 * Aquire a normalized ns-decl and add it to the map. 9146 */ 9147 if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc, 9148 /* ns-decls on curElem or on destDoc->oldNs */ 9149 destParent ? curElem : NULL, 9150 cur->ns, &ns, 9151 &nsMap, depth, 9152 /* if we need to search only in the ancestor-axis */ 9153 ancestorsOnly, 9154 /* ns-decls must be prefixed for attributes. */ 9155 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1) 9156 goto internal_error; 9157 clone->ns = ns; 9158 } 9159 9160end_ns_reference: 9161 9162 /* 9163 * Some post-processing. 9164 * 9165 * Handle ID attributes. 9166 */ 9167 if ((clone->type == XML_ATTRIBUTE_NODE) && 9168 (clone->parent != NULL)) 9169 { 9170 if (xmlIsID(destDoc, clone->parent, (xmlAttrPtr) clone)) { 9171 9172 xmlChar *idVal; 9173 9174 idVal = xmlNodeListGetString(cur->doc, cur->children, 1); 9175 if (idVal != NULL) { 9176 if (xmlAddID(NULL, destDoc, idVal, (xmlAttrPtr) cur) == NULL) { 9177 /* TODO: error message. */ 9178 xmlFree(idVal); 9179 goto internal_error; 9180 } 9181 xmlFree(idVal); 9182 } 9183 } 9184 } 9185 /* 9186 ** 9187 ** The following will traverse the tree ************************** 9188 ** 9189 * 9190 * Walk the element's attributes before descending into child-nodes. 9191 */ 9192 if ((cur->type == XML_ELEMENT_NODE) && (cur->properties != NULL)) { 9193 prevClone = NULL; 9194 parentClone = clone; 9195 cur = (xmlNodePtr) cur->properties; 9196 continue; 9197 } 9198into_content: 9199 /* 9200 * Descend into child-nodes. 9201 */ 9202 if (cur->children != NULL) { 9203 if (deep || (cur->type == XML_ATTRIBUTE_NODE)) { 9204 prevClone = NULL; 9205 parentClone = clone; 9206 cur = cur->children; 9207 continue; 9208 } 9209 } 9210 9211leave_node: 9212 /* 9213 * At this point we are done with the node, its content 9214 * and an element-nodes's attribute-nodes. 9215 */ 9216 if (cur == node) 9217 break; 9218 if ((cur->type == XML_ELEMENT_NODE) || 9219 (cur->type == XML_XINCLUDE_START) || 9220 (cur->type == XML_XINCLUDE_END)) { 9221 /* 9222 * TODO: Do we expect nsDefs on XML_XINCLUDE_START? 9223 */ 9224 if (XML_NSMAP_NOTEMPTY(nsMap)) { 9225 /* 9226 * Pop mappings. 9227 */ 9228 while ((nsMap->last != NULL) && 9229 (nsMap->last->depth >= depth)) 9230 { 9231 XML_NSMAP_POP(nsMap, mi) 9232 } 9233 /* 9234 * Unshadow. 9235 */ 9236 XML_NSMAP_FOREACH(nsMap, mi) { 9237 if (mi->shadowDepth >= depth) 9238 mi->shadowDepth = -1; 9239 } 9240 } 9241 depth--; 9242 } 9243 if (cur->next != NULL) { 9244 prevClone = clone; 9245 cur = cur->next; 9246 } else if (cur->type != XML_ATTRIBUTE_NODE) { 9247 /* 9248 * Set clone->last. 9249 */ 9250 if (clone->parent != NULL) 9251 clone->parent->last = clone; 9252 clone = clone->parent; 9253 parentClone = clone->parent; 9254 /* 9255 * Process parent --> next; 9256 */ 9257 cur = cur->parent; 9258 goto leave_node; 9259 } else { 9260 /* This is for attributes only. */ 9261 clone = clone->parent; 9262 parentClone = clone->parent; 9263 /* 9264 * Process parent-element --> children. 9265 */ 9266 cur = cur->parent; 9267 goto into_content; 9268 } 9269 } 9270 goto exit; 9271 9272internal_error: 9273 ret = -1; 9274 9275exit: 9276 /* 9277 * Cleanup. 9278 */ 9279 if (nsMap != NULL) { 9280 if ((ctxt) && (ctxt->namespaceMap == nsMap)) { 9281 /* 9282 * Just cleanup the map but don't free. 9283 */ 9284 if (nsMap->first) { 9285 if (nsMap->pool) 9286 nsMap->last->next = nsMap->pool; 9287 nsMap->pool = nsMap->first; 9288 nsMap->first = NULL; 9289 } 9290 } else 9291 xmlDOMWrapNsMapFree(nsMap); 9292 } 9293 /* 9294 * TODO: Should we try a cleanup of the cloned node in case of a 9295 * fatal error? 9296 */ 9297 *resNode = resultClone; 9298 return (ret); 9299} 9300 9301/* 9302* xmlDOMWrapAdoptAttr: 9303* @ctxt: the optional context for custom processing 9304* @sourceDoc: the optional source document of attr 9305* @attr: the attribute-node to be adopted 9306* @destDoc: the destination doc for adoption 9307* @destParent: the optional new parent of @attr in @destDoc 9308* @options: option flags 9309* 9310* @attr is adopted by @destDoc. 9311* Ensures that ns-references point to @destDoc: either to 9312* elements->nsDef entries if @destParent is given, or to 9313* @destDoc->oldNs otherwise. 9314* 9315* Returns 0 if succeeded, -1 otherwise and on API/internal errors. 9316*/ 9317static int 9318xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt, 9319 xmlDocPtr sourceDoc, 9320 xmlAttrPtr attr, 9321 xmlDocPtr destDoc, 9322 xmlNodePtr destParent, 9323 int options ATTRIBUTE_UNUSED) 9324{ 9325 xmlNodePtr cur; 9326 int adoptStr = 1; 9327 9328 if ((attr == NULL) || (destDoc == NULL)) 9329 return (-1); 9330 9331 attr->doc = destDoc; 9332 if (attr->ns != NULL) { 9333 xmlNsPtr ns = NULL; 9334 9335 if (ctxt != NULL) { 9336 /* TODO: User defined. */ 9337 } 9338 /* XML Namespace. */ 9339 if (IS_STR_XML(attr->ns->prefix)) { 9340 ns = xmlTreeEnsureXMLDecl(destDoc); 9341 } else if (destParent == NULL) { 9342 /* 9343 * Store in @destDoc->oldNs. 9344 */ 9345 ns = xmlDOMWrapStoreNs(destDoc, attr->ns->href, attr->ns->prefix); 9346 } else { 9347 /* 9348 * Declare on @destParent. 9349 */ 9350 if (xmlSearchNsByNamespaceStrict(destDoc, destParent, attr->ns->href, 9351 &ns, 1) == -1) 9352 goto internal_error; 9353 if (ns == NULL) { 9354 ns = xmlDOMWrapNSNormDeclareNsForced(destDoc, destParent, 9355 attr->ns->href, attr->ns->prefix, 1); 9356 } 9357 } 9358 if (ns == NULL) 9359 goto internal_error; 9360 attr->ns = ns; 9361 } 9362 9363 XML_TREE_ADOPT_STR(attr->name); 9364 attr->atype = 0; 9365 attr->psvi = NULL; 9366 /* 9367 * Walk content. 9368 */ 9369 if (attr->children == NULL) 9370 return (0); 9371 cur = attr->children; 9372 while (cur != NULL) { 9373 cur->doc = destDoc; 9374 switch (cur->type) { 9375 case XML_TEXT_NODE: 9376 case XML_CDATA_SECTION_NODE: 9377 XML_TREE_ADOPT_STR_2(cur->content) 9378 break; 9379 case XML_ENTITY_REF_NODE: 9380 /* 9381 * Remove reference to the entitity-node. 9382 */ 9383 cur->content = NULL; 9384 cur->children = NULL; 9385 cur->last = NULL; 9386 if ((destDoc->intSubset) || (destDoc->extSubset)) { 9387 xmlEntityPtr ent; 9388 /* 9389 * Assign new entity-node if available. 9390 */ 9391 ent = xmlGetDocEntity(destDoc, cur->name); 9392 if (ent != NULL) { 9393 cur->content = ent->content; 9394 cur->children = (xmlNodePtr) ent; 9395 cur->last = (xmlNodePtr) ent; 9396 } 9397 } 9398 break; 9399 default: 9400 break; 9401 } 9402 if (cur->children != NULL) { 9403 cur = cur->children; 9404 continue; 9405 } 9406next_sibling: 9407 if (cur == (xmlNodePtr) attr) 9408 break; 9409 if (cur->next != NULL) 9410 cur = cur->next; 9411 else { 9412 cur = cur->parent; 9413 goto next_sibling; 9414 } 9415 } 9416 return (0); 9417internal_error: 9418 return (-1); 9419} 9420 9421/* 9422* xmlDOMWrapAdoptNode: 9423* @ctxt: the optional context for custom processing 9424* @sourceDoc: the optional sourceDoc 9425* @node: the node to start with 9426* @destDoc: the destination doc 9427* @destParent: the optional new parent of @node in @destDoc 9428* @options: option flags 9429* 9430* References of out-of scope ns-decls are remapped to point to @destDoc: 9431* 1) If @destParent is given, then nsDef entries on element-nodes are used 9432* 2) If *no* @destParent is given, then @destDoc->oldNs entries are used 9433* This is the case when you have an unliked node and just want to move it 9434* to the context of 9435* 9436* If @destParent is given, it ensures that the tree is namespace 9437* wellformed by creating additional ns-decls where needed. 9438* Note that, since prefixes of already existent ns-decls can be 9439* shadowed by this process, it could break QNames in attribute 9440* values or element content. 9441* NOTE: This function was not intensively tested. 9442* 9443* Returns 0 if the operation succeeded, 9444* 1 if a node of unsupported type was given, 9445* 2 if a node of not yet supported type was given and 9446* -1 on API/internal errors. 9447*/ 9448int 9449xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt, 9450 xmlDocPtr sourceDoc, 9451 xmlNodePtr node, 9452 xmlDocPtr destDoc, 9453 xmlNodePtr destParent, 9454 int options) 9455{ 9456 if ((node == NULL) || (destDoc == NULL) || 9457 ((destParent != NULL) && (destParent->doc != destDoc))) 9458 return(-1); 9459 /* 9460 * Check node->doc sanity. 9461 */ 9462 if ((node->doc != NULL) && (sourceDoc != NULL) && 9463 (node->doc != sourceDoc)) { 9464 /* 9465 * Might be an XIncluded node. 9466 */ 9467 return (-1); 9468 } 9469 if (sourceDoc == NULL) 9470 sourceDoc = node->doc; 9471 if (sourceDoc == destDoc) 9472 return (-1); 9473 switch (node->type) { 9474 case XML_ELEMENT_NODE: 9475 case XML_ATTRIBUTE_NODE: 9476 case XML_TEXT_NODE: 9477 case XML_CDATA_SECTION_NODE: 9478 case XML_ENTITY_REF_NODE: 9479 case XML_PI_NODE: 9480 case XML_COMMENT_NODE: 9481 break; 9482 case XML_DOCUMENT_FRAG_NODE: 9483 /* TODO: Support document-fragment-nodes. */ 9484 return (2); 9485 default: 9486 return (1); 9487 } 9488 /* 9489 * Unlink only if @node was not already added to @destParent. 9490 */ 9491 if ((node->parent != NULL) && (destParent != node->parent)) 9492 xmlUnlinkNode(node); 9493 9494 if (node->type == XML_ELEMENT_NODE) { 9495 return (xmlDOMWrapAdoptBranch(ctxt, sourceDoc, node, 9496 destDoc, destParent, options)); 9497 } else if (node->type == XML_ATTRIBUTE_NODE) { 9498 return (xmlDOMWrapAdoptAttr(ctxt, sourceDoc, 9499 (xmlAttrPtr) node, destDoc, destParent, options)); 9500 } else { 9501 xmlNodePtr cur = node; 9502 int adoptStr = 1; 9503 9504 cur->doc = destDoc; 9505 /* 9506 * Optimize string adoption. 9507 */ 9508 if ((sourceDoc != NULL) && 9509 (sourceDoc->dict == destDoc->dict)) 9510 adoptStr = 0; 9511 switch (node->type) { 9512 case XML_TEXT_NODE: 9513 case XML_CDATA_SECTION_NODE: 9514 XML_TREE_ADOPT_STR_2(node->content) 9515 break; 9516 case XML_ENTITY_REF_NODE: 9517 /* 9518 * Remove reference to the entitity-node. 9519 */ 9520 node->content = NULL; 9521 node->children = NULL; 9522 node->last = NULL; 9523 if ((destDoc->intSubset) || (destDoc->extSubset)) { 9524 xmlEntityPtr ent; 9525 /* 9526 * Assign new entity-node if available. 9527 */ 9528 ent = xmlGetDocEntity(destDoc, node->name); 9529 if (ent != NULL) { 9530 node->content = ent->content; 9531 node->children = (xmlNodePtr) ent; 9532 node->last = (xmlNodePtr) ent; 9533 } 9534 } 9535 XML_TREE_ADOPT_STR(node->name) 9536 break; 9537 case XML_PI_NODE: { 9538 XML_TREE_ADOPT_STR(node->name) 9539 XML_TREE_ADOPT_STR_2(node->content) 9540 break; 9541 } 9542 default: 9543 break; 9544 } 9545 } 9546 return (0); 9547} 9548 9549#define bottom_tree 9550#include "elfgcchack.h" 9551