/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 | } |