Coverage Report

Created: 2024-08-17 11:00

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