1 /* 2 * namespaces.c: Implementation of the XSLT namespaces handling 3 * 4 * Reference: 5 * http://www.w3.org/TR/1999/REC-xslt-19991116 6 * 7 * See Copyright for the status of this software. 8 * 9 * daniel (at) veillard.com 10 */ 11 12 #define IN_LIBXSLT 13 #include "libxslt.h" 14 15 #include <string.h> 16 17 #ifdef HAVE_SYS_TYPES_H 18 #include <sys/types.h> 19 #endif 20 #ifdef HAVE_MATH_H 21 #include <math.h> 22 #endif 23 #ifdef HAVE_FLOAT_H 24 #include <float.h> 25 #endif 26 #ifdef HAVE_IEEEFP_H 27 #include <ieeefp.h> 28 #endif 29 #ifdef HAVE_NAN_H 30 #include <nan.h> 31 #endif 32 #ifdef HAVE_CTYPE_H 33 #include <ctype.h> 34 #endif 35 #ifndef XSLT_NEED_TRIO 36 #include <stdio.h> 37 #else 38 #include <trio.h> 39 #endif 40 41 #include <libxml/xmlmemory.h> 42 #include <libxml/tree.h> 43 #include <libxml/hash.h> 44 #include <libxml/xmlerror.h> 45 #include <libxml/uri.h> 46 #include "xslt.h" 47 #include "xsltInternals.h" 48 #include "xsltutils.h" 49 #include "namespaces.h" 50 #include "imports.h" 51 52 /************************************************************************ 53 * * 54 * Module interfaces * 55 * * 56 ************************************************************************/ 57 58 #ifdef XSLT_REFACTORED 59 static xsltNsAliasPtr 60 xsltNewNsAlias(xsltCompilerCtxtPtr cctxt) 61 { 62 xsltNsAliasPtr ret; 63 64 if (cctxt == NULL) 65 return(NULL); 66 67 ret = (xsltNsAliasPtr) xmlMalloc(sizeof(xsltNsAlias)); 68 if (ret == NULL) { 69 xsltTransformError(NULL, cctxt->style, NULL, 70 "Internal error in xsltNewNsAlias(): Memory allocation failed.\n"); 71 cctxt->style->errors++; 72 return(NULL); 73 } 74 memset(ret, 0, sizeof(xsltNsAlias)); 75 /* 76 * TODO: Store the item at current stylesheet-level. 77 */ 78 ret->next = cctxt->nsAliases; 79 cctxt->nsAliases = ret; 80 81 return(ret); 82 } 83 #endif /* XSLT_REFACTORED */ 84 /** 85 * xsltNamespaceAlias: 86 * @style: the XSLT stylesheet 87 * @node: the xsl:namespace-alias node 88 * 89 * Read the stylesheet-prefix and result-prefix attributes, register 90 * them as well as the corresponding namespace. 91 */ 92 void 93 xsltNamespaceAlias(xsltStylesheetPtr style, xmlNodePtr node) 94 { 95 xmlChar *resultPrefix = NULL; 96 xmlChar *stylePrefix = NULL; 97 xmlNsPtr literalNs = NULL; 98 xmlNsPtr targetNs = NULL; 99 100 #ifdef XSLT_REFACTORED 101 xsltNsAliasPtr alias; 102 103 if ((style == NULL) || (node == NULL)) 104 return; 105 106 /* 107 * SPEC XSLT 1.0: 108 * "If a namespace URI is declared to be an alias for multiple 109 * different namespace URIs, then the declaration with the highest 110 * import precedence is used. It is an error if there is more than 111 * one such declaration. An XSLT processor may signal the error; 112 * if it does not signal the error, it must recover by choosing, 113 * from amongst the declarations with the highest import precedence, 114 * the one that occurs last in the stylesheet." 115 * 116 * SPEC TODO: Check for the errors mentioned above. 117 */ 118 /* 119 * NOTE that the XSLT 2.0 also *does* use the NULL namespace if 120 * "#default" is used and there's no default namespace is scope. 121 * I.e., this is *not* an error. 122 * Most XSLT 1.0 implementations work this way. 123 * The XSLT 1.0 spec has nothing to say on the subject. 124 */ 125 /* 126 * Attribute "stylesheet-prefix". 127 */ 128 stylePrefix = xmlGetNsProp(node, (const xmlChar *)"stylesheet-prefix", NULL); 129 if (stylePrefix == NULL) { 130 xsltTransformError(NULL, style, node, 131 "The attribute 'stylesheet-prefix' is missing.\n"); 132 return; 133 } 134 if (xmlStrEqual(stylePrefix, (const xmlChar *)"#default")) 135 literalNs = xmlSearchNs(node->doc, node, NULL); 136 else { 137 literalNs = xmlSearchNs(node->doc, node, stylePrefix); 138 if (literalNs == NULL) { 139 xsltTransformError(NULL, style, node, 140 "Attribute 'stylesheet-prefix': There's no namespace " 141 "declaration in scope for the prefix '%s'.\n", 142 stylePrefix); 143 goto error; 144 } 145 } 146 /* 147 * Attribute "result-prefix". 148 */ 149 resultPrefix = xmlGetNsProp(node, (const xmlChar *)"result-prefix", NULL); 150 if (resultPrefix == NULL) { 151 xsltTransformError(NULL, style, node, 152 "The attribute 'result-prefix' is missing.\n"); 153 goto error; 154 } 155 if (xmlStrEqual(resultPrefix, (const xmlChar *)"#default")) 156 targetNs = xmlSearchNs(node->doc, node, NULL); 157 else { 158 targetNs = xmlSearchNs(node->doc, node, resultPrefix); 159 160 if (targetNs == NULL) { 161 xsltTransformError(NULL, style, node, 162 "Attribute 'result-prefix': There's no namespace " 163 "declaration in scope for the prefix '%s'.\n", 164 stylePrefix); 165 goto error; 166 } 167 } 168 /* 169 * 170 * Same alias for multiple different target namespace URIs: 171 * TODO: The one with the highest import precedence is used. 172 * Example: 173 * <xsl:namespace-alias stylesheet-prefix="foo" 174 * result-prefix="bar"/> 175 * 176 * <xsl:namespace-alias stylesheet-prefix="foo" 177 * result-prefix="zar"/> 178 * 179 * Same target namespace URI for multiple different aliases: 180 * All alias-definitions will be used. 181 * Example: 182 * <xsl:namespace-alias stylesheet-prefix="bar" 183 * result-prefix="foo"/> 184 * 185 * <xsl:namespace-alias stylesheet-prefix="zar" 186 * result-prefix="foo"/> 187 * Cases using #default: 188 * <xsl:namespace-alias stylesheet-prefix="#default" 189 * result-prefix="#default"/> 190 * TODO: Has this an effect at all? 191 * 192 * <xsl:namespace-alias stylesheet-prefix="foo" 193 * result-prefix="#default"/> 194 * From namespace to no namespace. 195 * 196 * <xsl:namespace-alias stylesheet-prefix="#default" 197 * result-prefix="foo"/> 198 * From no namespace to namespace. 199 */ 200 201 202 /* 203 * Store the ns-node in the alias-object. 204 */ 205 alias = xsltNewNsAlias(XSLT_CCTXT(style)); 206 if (alias == NULL) 207 return; 208 alias->literalNs = literalNs; 209 alias->targetNs = targetNs; 210 XSLT_CCTXT(style)->hasNsAliases = 1; 211 212 213 #else /* XSLT_REFACTORED */ 214 const xmlChar *literalNsName; 215 const xmlChar *targetNsName; 216 217 218 if ((style == NULL) || (node == NULL)) 219 return; 220 221 stylePrefix = xmlGetNsProp(node, (const xmlChar *)"stylesheet-prefix", NULL); 222 if (stylePrefix == NULL) { 223 xsltTransformError(NULL, style, node, 224 "namespace-alias: stylesheet-prefix attribute missing\n"); 225 return; 226 } 227 resultPrefix = xmlGetNsProp(node, (const xmlChar *)"result-prefix", NULL); 228 if (resultPrefix == NULL) { 229 xsltTransformError(NULL, style, node, 230 "namespace-alias: result-prefix attribute missing\n"); 231 goto error; 232 } 233 234 if (xmlStrEqual(stylePrefix, (const xmlChar *)"#default")) { 235 literalNs = xmlSearchNs(node->doc, node, NULL); 236 if (literalNs == NULL) { 237 literalNsName = NULL; 238 } else 239 literalNsName = literalNs->href; /* Yes - set for nsAlias table */ 240 } else { 241 literalNs = xmlSearchNs(node->doc, node, stylePrefix); 242 243 if ((literalNs == NULL) || (literalNs->href == NULL)) { 244 xsltTransformError(NULL, style, node, 245 "namespace-alias: prefix %s not bound to any namespace\n", 246 stylePrefix); 247 goto error; 248 } else 249 literalNsName = literalNs->href; 250 } 251 252 /* 253 * When "#default" is used for result, if a default namespace has not 254 * been explicitly declared the special value UNDEFINED_DEFAULT_NS is 255 * put into the nsAliases table 256 */ 257 if (xmlStrEqual(resultPrefix, (const xmlChar *)"#default")) { 258 targetNs = xmlSearchNs(node->doc, node, NULL); 259 if (targetNs == NULL) { 260 targetNsName = UNDEFINED_DEFAULT_NS; 261 } else 262 targetNsName = targetNs->href; 263 } else { 264 targetNs = xmlSearchNs(node->doc, node, resultPrefix); 265 266 if ((targetNs == NULL) || (targetNs->href == NULL)) { 267 xsltTransformError(NULL, style, node, 268 "namespace-alias: prefix %s not bound to any namespace\n", 269 resultPrefix); 270 goto error; 271 } else 272 targetNsName = targetNs->href; 273 } 274 /* 275 * Special case: if #default is used for 276 * the stylesheet-prefix (literal namespace) and there's no default 277 * namespace in scope, we'll use style->defaultAlias for this. 278 */ 279 if (literalNsName == NULL) { 280 if (targetNs != NULL) { 281 /* 282 * BUG TODO: Is it not sufficient to have only 1 field for 283 * this, since subsequently alias declarations will 284 * overwrite this. 285 * Example: 286 * <xsl:namespace-alias result-prefix="foo" 287 * stylesheet-prefix="#default"/> 288 * <xsl:namespace-alias result-prefix="bar" 289 * stylesheet-prefix="#default"/> 290 * The mapping for "foo" won't be visible anymore. 291 */ 292 style->defaultAlias = targetNs->href; 293 } 294 } else { 295 if (style->nsAliases == NULL) 296 style->nsAliases = xmlHashCreate(10); 297 if (style->nsAliases == NULL) { 298 xsltTransformError(NULL, style, node, 299 "namespace-alias: cannot create hash table\n"); 300 goto error; 301 } 302 xmlHashAddEntry((xmlHashTablePtr) style->nsAliases, 303 literalNsName, (void *) targetNsName); 304 } 305 #endif /* else of XSLT_REFACTORED */ 306 307 error: 308 if (stylePrefix != NULL) 309 xmlFree(stylePrefix); 310 if (resultPrefix != NULL) 311 xmlFree(resultPrefix); 312 } 313 314 /** 315 * xsltGetSpecialNamespace: 316 * @ctxt: the transformation context 317 * @invocNode: the invoking node; e.g. a literal result element/attr; 318 * only used for error reports 319 * @nsName: the namespace name (or NULL) 320 * @nsPrefix: the suggested namespace prefix (or NULL) 321 * @target: the result element on which to anchor a namespace 322 * 323 * Find a matching (prefix and ns-name) ns-declaration 324 * for the requested @nsName and @nsPrefix in the result tree. 325 * If none is found then a new ns-declaration will be 326 * added to @resultElem. If, in this case, the given prefix is 327 * already in use, then a ns-declaration with a modified ns-prefix 328 * be we created. Note that this function's priority is to 329 * preserve ns-prefixes; it will only change a prefix if there's 330 * a namespace clash. 331 * If both @nsName and @nsPrefix are NULL, then this will try to 332 * "undeclare" a default namespace by declaring an xmlns="". 333 * 334 * Returns a namespace declaration or NULL. 335 */ 336 xmlNsPtr 337 xsltGetSpecialNamespace(xsltTransformContextPtr ctxt, xmlNodePtr invocNode, 338 const xmlChar *nsName, const xmlChar *nsPrefix, 339 xmlNodePtr target) 340 { 341 xmlNsPtr ns; 342 int prefixOccupied = 0; 343 344 if ((ctxt == NULL) || (target == NULL) || 345 (target->type != XML_ELEMENT_NODE)) 346 return(NULL); 347 348 /* 349 * NOTE: Namespace exclusion and ns-aliasing is performed at 350 * compilation-time in the refactored code; so this need not be done 351 * here (it was in the old code). 352 * NOTE: @invocNode was named @cur in the old code and was documented to 353 * be an input node; since it was only used to anchor an error report 354 * somewhere, we can safely change this to @invocNode, which now 355 * will be the XSLT instruction (also a literal result element/attribute), 356 * which was responsible for this call. 357 */ 358 /* 359 * OPTIMIZE TODO: This all could be optimized by keeping track of 360 * the ns-decls currently in-scope via a specialized context. 361 */ 362 if ((nsPrefix == NULL) && ((nsName == NULL) || (nsName[0] == 0))) { 363 /* 364 * NOTE: the "undeclaration" of the default namespace was 365 * part of the logic of the old xsltGetSpecialNamespace() code, 366 * so we'll keep that mechanism. 367 * Related to the old code: bug #302020: 368 */ 369 /* 370 * OPTIMIZE TODO: This all could be optimized by keeping track of 371 * the ns-decls currently in-scope via a specialized context. 372 */ 373 /* 374 * Search on the result element itself. 375 */ 376 if (target->nsDef != NULL) { 377 ns = target->nsDef; 378 do { 379 if (ns->prefix == NULL) { 380 if ((ns->href != NULL) && (ns->href[0] != 0)) { 381 /* 382 * Raise a namespace normalization error. 383 */ 384 xsltTransformError(ctxt, NULL, invocNode, 385 "Namespace normalization error: Cannot undeclare " 386 "the default namespace, since the default namespace " 387 "'%s' is already declared on the result element " 388 "'%s'.\n", ns->href, target->name); 389 return(NULL); 390 } else { 391 /* 392 * The default namespace was undeclared on the 393 * result element. 394 */ 395 return(NULL); 396 } 397 break; 398 } 399 ns = ns->next; 400 } while (ns != NULL); 401 } 402 if ((target->parent != NULL) && 403 (target->parent->type == XML_ELEMENT_NODE)) 404 { 405 /* 406 * The parent element is in no namespace, so assume 407 * that there is no default namespace in scope. 408 */ 409 if (target->parent->ns == NULL) 410 return(NULL); 411 412 ns = xmlSearchNs(target->doc, target->parent, 413 NULL); 414 /* 415 * Fine if there's no default ns is scope, or if the 416 * default ns was undeclared. 417 */ 418 if ((ns == NULL) || (ns->href == NULL) || (ns->href[0] == 0)) 419 return(NULL); 420 421 /* 422 * Undeclare the default namespace. 423 */ 424 xmlNewNs(target, BAD_CAST "", NULL); 425 /* TODO: Check result */ 426 return(NULL); 427 } 428 return(NULL); 429 } 430 /* 431 * Handle the XML namespace. 432 * QUESTION: Is this faster than using xmlStrEqual() anyway? 433 */ 434 if ((nsPrefix != NULL) && 435 (nsPrefix[0] == 'x') && (nsPrefix[1] == 'm') && 436 (nsPrefix[2] == 'l') && (nsPrefix[3] == 0)) 437 { 438 return(xmlSearchNs(target->doc, target, nsPrefix)); 439 } 440 /* 441 * First: search on the result element itself. 442 */ 443 if (target->nsDef != NULL) { 444 ns = target->nsDef; 445 do { 446 if ((ns->prefix == NULL) == (nsPrefix == NULL)) { 447 if (ns->prefix == nsPrefix) { 448 if (xmlStrEqual(ns->href, nsName)) 449 return(ns); 450 prefixOccupied = 1; 451 break; 452 } else if (xmlStrEqual(ns->prefix, nsPrefix)) { 453 if (xmlStrEqual(ns->href, nsName)) 454 return(ns); 455 prefixOccupied = 1; 456 break; 457 } 458 } 459 ns = ns->next; 460 } while (ns != NULL); 461 } 462 if (prefixOccupied) { 463 /* 464 * If the ns-prefix is occupied by an other ns-decl on the 465 * result element, then this means: 466 * 1) The desired prefix is shadowed 467 * 2) There's no way around changing the prefix 468 * 469 * Try a desperate search for an in-scope ns-decl 470 * with a matching ns-name before we use the last option, 471 * which is to recreate the ns-decl with a modified prefix. 472 */ 473 ns = xmlSearchNsByHref(target->doc, target, nsName); 474 if (ns != NULL) 475 return(ns); 476 477 /* 478 * Fallback to changing the prefix. 479 */ 480 } else if ((target->parent != NULL) && 481 (target->parent->type == XML_ELEMENT_NODE)) 482 { 483 /* 484 * Try to find a matching ns-decl in the ancestor-axis. 485 * 486 * Check the common case: The parent element of the current 487 * result element is in the same namespace (with an equal ns-prefix). 488 */ 489 if ((target->parent->ns != NULL) && 490 ((target->parent->ns->prefix != NULL) == (nsPrefix != NULL))) 491 { 492 ns = target->parent->ns; 493 494 if (nsPrefix == NULL) { 495 if (xmlStrEqual(ns->href, nsName)) 496 return(ns); 497 } else if (xmlStrEqual(ns->prefix, nsPrefix) && 498 xmlStrEqual(ns->href, nsName)) 499 { 500 return(ns); 501 } 502 } 503 /* 504 * Lookup the remaining in-scope namespaces. 505 */ 506 ns = xmlSearchNs(target->doc, target->parent, nsPrefix); 507 if (ns != NULL) { 508 if (xmlStrEqual(ns->href, nsName)) 509 return(ns); 510 /* 511 * Now check for a nasty case: We need to ensure that the new 512 * ns-decl won't shadow a prefix in-use by an existing attribute. 513 * <foo xmlns:a="urn:test:a"> 514 * <bar a:a="val-a"> 515 * <xsl:attribute xmlns:a="urn:test:b" name="a:b"> 516 * val-b</xsl:attribute> 517 * </bar> 518 * </foo> 519 */ 520 if (target->properties) { 521 xmlAttrPtr attr = target->properties; 522 do { 523 if ((attr->ns) && 524 xmlStrEqual(attr->ns->prefix, nsPrefix)) 525 { 526 /* 527 * Bad, this prefix is already in use. 528 * Since we'll change the prefix anyway, try 529 * a search for a matching ns-decl based on the 530 * namespace name. 531 */ 532 ns = xmlSearchNsByHref(target->doc, target, nsName); 533 if (ns != NULL) 534 return(ns); 535 goto declare_new_prefix; 536 } 537 attr = attr->next; 538 } while (attr != NULL); 539 } 540 } else { 541 /* 542 * Either no matching ns-prefix was found or the namespace is 543 * shadowed. 544 * Create a new ns-decl on the current result element. 545 * 546 * Hmm, we could also try to reuse an in-scope 547 * namespace with a matching ns-name but a different 548 * ns-prefix. 549 * What has higher priority? 550 * 1) If keeping the prefix: create a new ns-decl. 551 * 2) If reusal: first lookup ns-names; then fallback 552 * to creation of a new ns-decl. 553 * REVISIT: this currently uses case 1) although 554 * the old way was use xmlSearchNsByHref() and to let change 555 * the prefix. 556 */ 557 #if 0 558 ns = xmlSearchNsByHref(target->doc, target, nsName); 559 if (ns != NULL) 560 return(ns); 561 #endif 562 } 563 /* 564 * Create the ns-decl on the current result element. 565 */ 566 ns = xmlNewNs(target, nsName, nsPrefix); 567 /* TODO: check errors */ 568 return(ns); 569 } else { 570 /* 571 * This is either the root of the tree or something weird is going on. 572 */ 573 ns = xmlNewNs(target, nsName, nsPrefix); 574 /* TODO: Check result */ 575 return(ns); 576 } 577 578 declare_new_prefix: 579 /* 580 * Fallback: we need to generate a new prefix and declare the namespace 581 * on the result element. 582 */ 583 { 584 xmlChar pref[30]; 585 int counter = 1; 586 587 if (nsPrefix == NULL) { 588 nsPrefix = "ns"; 589 } 590 591 do { 592 snprintf((char *) pref, 30, "%s_%d", nsPrefix, counter++); 593 ns = xmlSearchNs(target->doc, target, BAD_CAST pref); 594 if (counter > 1000) { 595 xsltTransformError(ctxt, NULL, invocNode, 596 "Internal error in xsltAcquireResultInScopeNs(): " 597 "Failed to compute a unique ns-prefix for the " 598 "generated element"); 599 return(NULL); 600 } 601 } while (ns != NULL); 602 ns = xmlNewNs(target, nsName, BAD_CAST pref); 603 /* TODO: Check result */ 604 return(ns); 605 } 606 return(NULL); 607 } 608 609 /** 610 * xsltGetNamespace: 611 * @ctxt: a transformation context 612 * @cur: the input node 613 * @ns: the namespace 614 * @out: the output node (or its parent) 615 * 616 * Find a matching (prefix and ns-name) ns-declaration 617 * for the requested @ns->prefix and @ns->href in the result tree. 618 * If none is found then a new ns-declaration will be 619 * added to @resultElem. If, in this case, the given prefix is 620 * already in use, then a ns-declaration with a modified ns-prefix 621 * be we created. 622 * 623 * Called by: 624 * - xsltCopyPropList() (*not* anymore) 625 * - xsltShallowCopyElement() 626 * - xsltCopyTreeInternal() (*not* anymore) 627 * - xsltApplySequenceConstructor() (*not* in the refactored code), 628 * - xsltElement() (*not* anymore) 629 * 630 * Returns a namespace declaration or NULL in case of 631 * namespace fixup failures or API or internal errors. 632 */ 633 xmlNsPtr 634 xsltGetNamespace(xsltTransformContextPtr ctxt, xmlNodePtr cur, xmlNsPtr ns, 635 xmlNodePtr out) 636 { 637 638 if (ns == NULL) 639 return(NULL); 640 641 #ifdef XSLT_REFACTORED 642 /* 643 * Namespace exclusion and ns-aliasing is performed at 644 * compilation-time in the refactored code. 645 * Additionally, aliasing is not intended for non Literal 646 * Result Elements. 647 */ 648 return(xsltGetSpecialNamespace(ctxt, cur, ns->href, ns->prefix, out)); 649 #else 650 { 651 xsltStylesheetPtr style; 652 const xmlChar *URI = NULL; /* the replacement URI */ 653 654 if ((ctxt == NULL) || (cur == NULL) || (out == NULL)) 655 return(NULL); 656 657 style = ctxt->style; 658 while (style != NULL) { 659 if (style->nsAliases != NULL) 660 URI = (const xmlChar *) 661 xmlHashLookup(style->nsAliases, ns->href); 662 if (URI != NULL) 663 break; 664 665 style = xsltNextImport(style); 666 } 667 668 669 if (URI == UNDEFINED_DEFAULT_NS) { 670 return(xsltGetSpecialNamespace(ctxt, cur, NULL, NULL, out)); 671 #if 0 672 /* 673 * TODO: Removed, since wrong. If there was no default 674 * namespace in the stylesheet then this must resolve to 675 * the NULL namespace. 676 */ 677 xmlNsPtr dflt; 678 dflt = xmlSearchNs(cur->doc, cur, NULL); 679 if (dflt != NULL) 680 URI = dflt->href; 681 else 682 return NULL; 683 #endif 684 } else if (URI == NULL) 685 URI = ns->href; 686 687 return(xsltGetSpecialNamespace(ctxt, cur, URI, ns->prefix, out)); 688 } 689 #endif 690 } 691 692 /** 693 * xsltGetPlainNamespace: 694 * @ctxt: a transformation context 695 * @cur: the input node 696 * @ns: the namespace 697 * @out: the result element 698 * 699 * Obsolete. 700 * *Not* called by any Libxslt/Libexslt function. 701 * Exaclty the same as xsltGetNamespace(). 702 * 703 * Returns a namespace declaration or NULL in case of 704 * namespace fixup failures or API or internal errors. 705 */ 706 xmlNsPtr 707 xsltGetPlainNamespace(xsltTransformContextPtr ctxt, xmlNodePtr cur, 708 xmlNsPtr ns, xmlNodePtr out) 709 { 710 return(xsltGetNamespace(ctxt, cur, ns, out)); 711 } 712 713 /** 714 * xsltCopyNamespaceList: 715 * @ctxt: a transformation context 716 * @node: the target node 717 * @cur: the first namespace 718 * 719 * Do a copy of an namespace list. If @node is non-NULL the 720 * new namespaces are added automatically. This handles namespaces 721 * aliases. 722 * This function is intended only for *internal* use at 723 * transformation-time for copying ns-declarations of Literal 724 * Result Elements. 725 * 726 * Called by: 727 * xsltCopyTreeInternal() (transform.c) 728 * xsltShallowCopyElem() (transform.c) 729 * 730 * REVISIT: This function won't be used in the refactored code. 731 * 732 * Returns: a new xmlNsPtr, or NULL in case of error. 733 */ 734 xmlNsPtr 735 xsltCopyNamespaceList(xsltTransformContextPtr ctxt, xmlNodePtr node, 736 xmlNsPtr cur) { 737 xmlNsPtr ret = NULL, tmp; 738 xmlNsPtr p = NULL,q; 739 740 if (cur == NULL) 741 return(NULL); 742 if (cur->type != XML_NAMESPACE_DECL) 743 return(NULL); 744 745 /* 746 * One can add namespaces only on element nodes 747 */ 748 if ((node != NULL) && (node->type != XML_ELEMENT_NODE)) 749 node = NULL; 750 751 while (cur != NULL) { 752 if (cur->type != XML_NAMESPACE_DECL) 753 break; 754 755 /* 756 * Avoid duplicating namespace declarations in the tree if 757 * a matching declaration is in scope. 758 */ 759 if (node != NULL) { 760 if ((node->ns != NULL) && 761 (xmlStrEqual(node->ns->prefix, cur->prefix)) && 762 (xmlStrEqual(node->ns->href, cur->href))) { 763 cur = cur->next; 764 continue; 765 } 766 tmp = xmlSearchNs(node->doc, node, cur->prefix); 767 if ((tmp != NULL) && (xmlStrEqual(tmp->href, cur->href))) { 768 cur = cur->next; 769 continue; 770 } 771 } 772 #ifdef XSLT_REFACTORED 773 /* 774 * Namespace exclusion and ns-aliasing is performed at 775 * compilation-time in the refactored code. 776 */ 777 q = xmlNewNs(node, cur->href, cur->prefix); 778 if (p == NULL) { 779 ret = p = q; 780 } else { 781 p->next = q; 782 p = q; 783 } 784 #else 785 /* 786 * TODO: Remove this if the refactored code gets enabled. 787 */ 788 if (!xmlStrEqual(cur->href, XSLT_NAMESPACE)) { 789 const xmlChar *URI; 790 /* TODO apply cascading */ 791 URI = (const xmlChar *) xmlHashLookup(ctxt->style->nsAliases, 792 cur->href); 793 if (URI == UNDEFINED_DEFAULT_NS) 794 continue; 795 if (URI != NULL) { 796 q = xmlNewNs(node, URI, cur->prefix); 797 } else { 798 q = xmlNewNs(node, cur->href, cur->prefix); 799 } 800 if (p == NULL) { 801 ret = p = q; 802 } else { 803 p->next = q; 804 p = q; 805 } 806 } 807 #endif 808 cur = cur->next; 809 } 810 return(ret); 811 } 812 813 /** 814 * xsltCopyNamespace: 815 * @ctxt: a transformation context 816 * @elem: the target element node 817 * @ns: the namespace node 818 * 819 * Copies a namespace node (declaration). If @elem is not NULL, 820 * then the new namespace will be declared on @elem. 821 * 822 * Returns: a new xmlNsPtr, or NULL in case of an error. 823 */ 824 xmlNsPtr 825 xsltCopyNamespace(xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, 826 xmlNodePtr elem, xmlNsPtr ns) 827 { 828 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 829 return(NULL); 830 /* 831 * One can add namespaces only on element nodes 832 */ 833 if ((elem != NULL) && (elem->type != XML_ELEMENT_NODE)) 834 return(xmlNewNs(NULL, ns->href, ns->prefix)); 835 else 836 return(xmlNewNs(elem, ns->href, ns->prefix)); 837 } 838 839 840 /** 841 * xsltFreeNamespaceAliasHashes: 842 * @style: an XSLT stylesheet 843 * 844 * Free up the memory used by namespaces aliases 845 */ 846 void 847 xsltFreeNamespaceAliasHashes(xsltStylesheetPtr style) { 848 if (style->nsAliases != NULL) 849 xmlHashFree((xmlHashTablePtr) style->nsAliases, NULL); 850 style->nsAliases = NULL; 851 } 852