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

Revision 19102, 8.8 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r19101, 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 ((prefix == NULL) && (URI[0] == 0)) {
147        ret = xmlSearchNs(out->doc, out, NULL);
148        if (ret != NULL) {
149            ret = xmlNewNs(out, URI, prefix);
150            return(ret);
151        }
152        return(NULL);
153    }
154
155    if ((out->parent != NULL) &&
156        (out->parent->type == XML_ELEMENT_NODE) &&
157        (out->parent->ns != NULL) &&
158        (xmlStrEqual(out->parent->ns->href, URI)))
159        ret = out->parent->ns;
160    else
161        ret = xmlSearchNsByHref(out->doc, out, URI);
162
163    if ((ret == NULL) || (ret->prefix == NULL)) {
164        if (prefix == NULL) {
165            do {
166                sprintf(nprefix, "ns%d", prefixno++);
167                ret = xmlSearchNs(out->doc, out, (xmlChar *)nprefix);
168            } while (ret != NULL);
169            prefix = (const xmlChar *) &nprefix[0];
170        }
171        if (out->type == XML_ELEMENT_NODE)
172            ret = xmlNewNs(out, URI, prefix);
173    }
174    return(ret);
175}
176
177/**
178 * xsltGetNamespace:
179 * @ctxt:  a transformation context
180 * @cur:  the input node
181 * @ns:  the namespace
182 * @out:  the output node (or its parent)
183 *
184 * Find the right namespace value for this prefix, if needed create
185 * and add a new namespace decalaration on the node
186 * Handle namespace aliases
187 *
188 * Returns the namespace node to use or NULL
189 */
190xmlNsPtr
191xsltGetNamespace(xsltTransformContextPtr ctxt, xmlNodePtr cur, xmlNsPtr ns,
192                 xmlNodePtr out) {
193    xsltStylesheetPtr style;
194    xmlNsPtr ret;
195    const xmlChar *URI = NULL; /* the replacement URI */
196
197    if ((ctxt == NULL) || (cur == NULL) || (out == NULL) || (ns == NULL))
198        return(NULL);
199
200    style = ctxt->style;
201    while (style != NULL) {
202        if (style->nsAliases != NULL)
203            URI = (const xmlChar *)
204                xmlHashLookup(style->nsAliases, ns->href);
205        if (URI != NULL)
206            break;
207
208        style = xsltNextImport(style);
209    }
210
211    if (URI == NULL)
212        URI = ns->href;
213
214    if ((out->parent != NULL) &&
215        (out->parent->type == XML_ELEMENT_NODE) &&
216        (out->parent->ns != NULL) &&
217        (xmlStrEqual(out->parent->ns->href, URI)))
218        ret = out->parent->ns;
219    else {
220        if (ns->prefix != NULL) {
221            ret = xmlSearchNs(out->doc, out, ns->prefix);
222            if ((ret == NULL) || (!xmlStrEqual(ns->href, URI))) {
223                ret = xmlSearchNsByHref(out->doc, out, URI);
224            }
225        } else {
226            ret = xmlSearchNsByHref(out->doc, out, URI);
227        }
228    }
229
230    if (ret == NULL) {
231        if (out->type == XML_ELEMENT_NODE)
232            ret = xmlNewNs(out, URI, ns->prefix);
233    }
234    return(ret);
235}
236
237/**
238 * xsltCopyNamespaceList:
239 * @ctxt:  a transformation context
240 * @node:  the target node
241 * @cur:  the first namespace
242 *
243 * Do a copy of an namespace list. If @node is non-NULL the
244 * new namespaces are added automatically. This handles namespaces
245 * aliases
246 *
247 * Returns: a new xmlNsPtr, or NULL in case of error.
248 */
249xmlNsPtr
250xsltCopyNamespaceList(xsltTransformContextPtr ctxt, xmlNodePtr node,
251                      xmlNsPtr cur) {
252    xmlNsPtr ret = NULL, tmp;
253    xmlNsPtr p = NULL,q;
254    const xmlChar *URI;
255
256    if (cur == NULL)
257        return(NULL);
258    if (cur->type != XML_NAMESPACE_DECL)
259        return(NULL);
260
261    /*
262     * One can add namespaces only on element nodes
263     */
264    if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
265        node = NULL;
266
267    while (cur != NULL) {
268        if (cur->type != XML_NAMESPACE_DECL)
269            break;
270
271        /*
272         * Avoid duplicating namespace declrations on the tree
273         */
274        if ((node != NULL) && (node->ns != NULL) &&
275            (xmlStrEqual(node->ns->href, cur->href)) &&
276            (xmlStrEqual(node->ns->prefix, cur->prefix))) {
277            cur = cur->next;
278            continue;
279        }
280        tmp = xmlSearchNs(node->doc, node, cur->prefix);
281        if ((tmp != NULL) && (xmlStrEqual(tmp->href, cur->href))) {
282            cur = cur->next;
283            continue;
284        }
285       
286        if (!xmlStrEqual(cur->href, XSLT_NAMESPACE)) {
287            /* TODO apply cascading */
288            URI = (const xmlChar *) xmlHashLookup(ctxt->style->nsAliases,
289                                                  cur->href);
290            if (URI != NULL) {
291                q = xmlNewNs(node, URI, cur->prefix);
292            } else {
293                q = xmlNewNs(node, cur->href, cur->prefix);
294            }
295            if (p == NULL) {
296                ret = p = q;
297            } else {
298                p->next = q;
299                p = q;
300            }
301        }
302        cur = cur->next;
303    }
304    return(ret);
305}
306
307/**
308 * xsltCopyNamespace:
309 * @ctxt:  a transformation context
310 * @node:  the target node
311 * @cur:  the namespace node
312 *
313 * Do a copy of an namespace node. If @node is non-NULL the
314 * new namespaces are added automatically. This handles namespaces
315 * aliases
316 *
317 * Returns: a new xmlNsPtr, or NULL in case of error.
318 */
319xmlNsPtr
320xsltCopyNamespace(xsltTransformContextPtr ctxt, xmlNodePtr node,
321                  xmlNsPtr cur) {
322    xmlNsPtr ret = NULL;
323    const xmlChar *URI;
324
325    if (cur == NULL)
326        return(NULL);
327    if (cur->type != XML_NAMESPACE_DECL)
328        return(NULL);
329
330    /*
331     * One can add namespaces only on element nodes
332     */
333    if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
334        node = NULL;
335
336    if (!xmlStrEqual(cur->href, XSLT_NAMESPACE)) {
337        URI = (const xmlChar *) xmlHashLookup(ctxt->style->nsAliases,
338                                              cur->href);
339        if (URI != NULL) {
340            ret = xmlNewNs(node, URI, cur->prefix);
341        } else {
342            ret = xmlNewNs(node, cur->href, cur->prefix);
343        }
344    }
345    return(ret);
346}
347
348
349/**
350 * xsltFreeNamespaceAliasHashes:
351 * @style: an XSLT stylesheet
352 *
353 * Free up the memory used by namespaces aliases
354 */
355void
356xsltFreeNamespaceAliasHashes(xsltStylesheetPtr style) {
357    if (style->nsAliases != NULL)
358        xmlHashFree((xmlHashTablePtr) style->nsAliases, NULL);
359    style->nsAliases = NULL;
360}
Note: See TracBrowser for help on using the repository browser.