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@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 = BAD_CAST "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 }