ee35b933594aaf5952759c9c5b063758197944da
[platform/upstream/libxslt.git] / libxslt / namespaces.c
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 #include "libxslt.h"
13
14 #include <string.h>
15
16 #ifdef HAVE_SYS_TYPES_H
17 #include <sys/types.h>
18 #endif
19 #ifdef HAVE_MATH_H
20 #include <math.h>
21 #endif
22 #ifdef HAVE_FLOAT_H
23 #include <float.h>
24 #endif
25 #ifdef HAVE_IEEEFP_H
26 #include <ieeefp.h>
27 #endif
28 #ifdef HAVE_NAN_H
29 #include <nan.h>
30 #endif
31 #ifdef HAVE_CTYPE_H
32 #include <ctype.h>
33 #endif
34
35 #include <libxml/xmlmemory.h>
36 #include <libxml/tree.h>
37 #include <libxml/hash.h>
38 #include <libxml/xmlerror.h>
39 #include <libxml/uri.h>
40 #include "xslt.h"
41 #include "xsltInternals.h"
42 #include "xsltutils.h"
43 #include "namespaces.h"
44 #include "imports.h"
45
46
47
48 /************************************************************************
49  *                                                                      *
50  *                      Module interfaces                               *
51  *                                                                      *
52  ************************************************************************/
53
54 /**
55  * xsltNamespaceAlias:
56  * @style:  the XSLT stylesheet
57  * @node:  the xsl:namespace-alias node
58  *
59  * Read the stylesheet-prefix and result-prefix attributes, register
60  * them as well as the corresponding namespace.
61  */
62 void
63 xsltNamespaceAlias(xsltStylesheetPtr style, xmlNodePtr node) {
64     xmlChar *sprefix;
65     xmlNsPtr sNs;
66     xmlChar *rprefix;
67     xmlNsPtr rNs;
68
69     sprefix = xsltGetNsProp(node, (const xmlChar *)"stylesheet-prefix",
70                            XSLT_NAMESPACE);
71     if (sprefix == NULL) {
72         xsltPrintErrorContext(NULL, style, node);
73         xsltGenericError(xsltGenericErrorContext,
74             "namespace-alias: stylesheet-prefix attribute missing\n");
75         return;
76     }
77     rprefix = xsltGetNsProp(node, (const xmlChar *)"result-prefix",
78                            XSLT_NAMESPACE);
79     if (rprefix == NULL) {
80         xsltPrintErrorContext(NULL, style, node);
81         xsltGenericError(xsltGenericErrorContext,
82             "namespace-alias: result-prefix attribute missing\n");
83         goto error;
84     }
85     if (xmlStrEqual(sprefix, (const xmlChar *)"#default")) {
86         sNs = xmlSearchNs(node->doc, node, NULL);
87     } else {
88         sNs = xmlSearchNs(node->doc, node, sprefix);
89     }
90     if ((sNs == NULL) || (sNs->href == NULL)) {
91         xsltPrintErrorContext(NULL, style, node);
92         xsltGenericError(xsltGenericErrorContext,
93             "namespace-alias: prefix %s not bound to any namespace\n",
94                          sprefix);
95         goto error;
96     }
97     if (xmlStrEqual(rprefix, (const xmlChar *)"#default")) {
98         rNs = xmlSearchNs(node->doc, node, NULL);
99     } else {
100         rNs = xmlSearchNs(node->doc, node, rprefix);
101     }
102     if ((rNs == NULL) || (rNs->href == NULL)) {
103         xsltPrintErrorContext(NULL, style, node);
104         xsltGenericError(xsltGenericErrorContext,
105             "namespace-alias: prefix %s not bound to any namespace\n",
106                          rprefix);
107         goto error;
108     }
109     if (style->nsAliases == NULL)
110         style->nsAliases = xmlHashCreate(10);
111     if (style->nsAliases == NULL) {
112         xsltPrintErrorContext(NULL, style, node);
113         xsltGenericError(xsltGenericErrorContext,
114             "namespace-alias: cannot create hash table\n");
115         goto error;
116     }
117     xmlHashAddEntry((xmlHashTablePtr) style->nsAliases,
118                     sNs->href, (void *) rNs->href);
119
120 error:
121     if (sprefix != NULL)
122         xmlFree(sprefix);
123     if (rprefix != NULL)
124         xmlFree(rprefix);
125 }
126
127 /**
128  * xsltGetSpecialNamespace:
129  * @ctxt:  a transformation context
130  * @cur:  the input node
131  * @URI:  the namespace URI
132  * @prefix:  the suggested prefix
133  * @out:  the output node (or its parent)
134  *
135  * Find the right namespace value for this URI, if needed create
136  * and add a new namespace decalaration on the node
137  *
138  * Returns the namespace node to use or NULL
139  */
140 xmlNsPtr
141 xsltGetSpecialNamespace(xsltTransformContextPtr ctxt, xmlNodePtr cur,
142                 const xmlChar *URI, const xmlChar *prefix, xmlNodePtr out) {
143     xmlNsPtr ret;
144     static int prefixno = 1;
145     char nprefix[10];
146
147     if ((ctxt == NULL) || (cur == NULL) || (out == NULL) || (URI == NULL))
148         return(NULL);
149
150     if ((out->parent != NULL) &&
151         (out->parent->type == XML_ELEMENT_NODE) &&
152         (out->parent->ns != NULL) &&
153         (xmlStrEqual(out->parent->ns->href, URI)))
154         ret = out->parent->ns;
155     else
156         ret = xmlSearchNsByHref(out->doc, out, URI);
157
158     if (ret == NULL) {
159         if (prefix == NULL) {
160             do {
161                 sprintf(nprefix, "ns%d", prefixno++);
162                 ret = xmlSearchNs(out->doc, out, (xmlChar *)nprefix);
163             } while (ret != NULL);
164             prefix = (const xmlChar *) &nprefix[0];
165         }
166         if (out->type == XML_ELEMENT_NODE)
167             ret = xmlNewNs(out, URI, prefix);
168     }
169     return(ret);
170 }
171
172 /**
173  * xsltGetNamespace:
174  * @ctxt:  a transformation context
175  * @cur:  the input node
176  * @ns:  the namespace
177  * @out:  the output node (or its parent)
178  *
179  * Find the right namespace value for this prefix, if needed create
180  * and add a new namespace decalaration on the node
181  * Handle namespace aliases
182  *
183  * Returns the namespace node to use or NULL
184  */
185 xmlNsPtr
186 xsltGetNamespace(xsltTransformContextPtr ctxt, xmlNodePtr cur, xmlNsPtr ns,
187                  xmlNodePtr out) {
188     xsltStylesheetPtr style;
189     xmlNsPtr ret;
190     const xmlChar *URI = NULL; /* the replacement URI */
191
192     if ((ctxt == NULL) || (cur == NULL) || (out == NULL) || (ns == NULL))
193         return(NULL);
194
195     style = ctxt->style;
196     while (style != NULL) {
197         if (style->nsAliases != NULL)
198             URI = (const xmlChar *) 
199                 xmlHashLookup(ctxt->style->nsAliases, ns->href);
200         if (URI != NULL)
201             break;
202
203         style = xsltNextImport(style);
204     }
205
206     if (URI == NULL)
207         URI = ns->href;
208
209     if ((out->parent != NULL) &&
210         (out->parent->type == XML_ELEMENT_NODE) &&
211         (out->parent->ns != NULL) &&
212         (xmlStrEqual(out->parent->ns->href, URI)))
213         ret = out->parent->ns;
214     else
215         ret = xmlSearchNsByHref(out->doc, out, URI);
216
217     if (ret == NULL) {
218         if (out->type == XML_ELEMENT_NODE)
219             ret = xmlNewNs(out, URI, ns->prefix);
220     }
221     return(ret);
222 }
223
224 /**
225  * xsltCopyNamespaceList:
226  * @ctxt:  a transformation context
227  * @node:  the target node
228  * @cur:  the first namespace
229  *
230  * Do a copy of an namespace list. If @node is non-NULL the
231  * new namespaces are added automatically. This handles namespaces
232  * aliases
233  *
234  * Returns: a new xmlNsPtr, or NULL in case of error.
235  */
236 xmlNsPtr
237 xsltCopyNamespaceList(xsltTransformContextPtr ctxt, xmlNodePtr node,
238                       xmlNsPtr cur) {
239     xmlNsPtr ret = NULL;
240     xmlNsPtr p = NULL,q;
241     const xmlChar *URI;
242
243     if (cur == NULL)
244         return(NULL);
245     if (cur->type != XML_NAMESPACE_DECL)
246         return(NULL);
247
248     /*
249      * One can add namespaces only on element nodes
250      */
251     if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
252         node = NULL;
253
254     while (cur != NULL) {
255         if (cur->type != XML_NAMESPACE_DECL)
256             break;
257         if (!xmlStrEqual(cur->href, XSLT_NAMESPACE)) {
258             /* TODO apply cascading */
259             URI = (const xmlChar *) xmlHashLookup(ctxt->style->nsAliases,
260                                                   cur->href);
261             if (URI != NULL) {
262                 q = xmlNewNs(node, URI, cur->prefix);
263             } else {
264                 q = xmlNewNs(node, cur->href, cur->prefix);
265             }
266             if (p == NULL) {
267                 ret = p = q;
268             } else {
269                 p->next = q;
270                 p = q;
271             }
272         }
273         cur = cur->next;
274     }
275     return(ret);
276 }
277
278 /**
279  * xsltCopyNamespace:
280  * @ctxt:  a transformation context
281  * @node:  the target node
282  * @cur:  the namespace node
283  *
284  * Do a copy of an namespace node. If @node is non-NULL the
285  * new namespaces are added automatically. This handles namespaces
286  * aliases
287  *
288  * Returns: a new xmlNsPtr, or NULL in case of error.
289  */
290 xmlNsPtr
291 xsltCopyNamespace(xsltTransformContextPtr ctxt, xmlNodePtr node,
292                   xmlNsPtr cur) {
293     xmlNsPtr ret = NULL;
294     const xmlChar *URI;
295
296     if (cur == NULL)
297         return(NULL);
298     if (cur->type != XML_NAMESPACE_DECL)
299         return(NULL);
300
301     /*
302      * One can add namespaces only on element nodes
303      */
304     if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
305         node = NULL;
306
307     if (!xmlStrEqual(cur->href, XSLT_NAMESPACE)) {
308         URI = (const xmlChar *) xmlHashLookup(ctxt->style->nsAliases,
309                                               cur->href);
310         if (URI != NULL) {
311             ret = xmlNewNs(node, URI, cur->prefix);
312         } else {
313             ret = xmlNewNs(node, cur->href, cur->prefix);
314         }
315     }
316     return(ret);
317 }
318
319
320 /**
321  * xsltFreeNamespaceAliasHashes:
322  * @style: an XSLT stylesheet
323  *
324  * Free up the memory used by namespaces aliases
325  */
326 void
327 xsltFreeNamespaceAliasHashes(xsltStylesheetPtr style) {
328     if (style->nsAliases != NULL)
329         xmlHashFree((xmlHashTablePtr) style->nsAliases, NULL);
330     style->nsAliases = NULL;
331 }