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