source: trunk/third/libxslt/libxslt/namespaces.c @ 18543

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