2 * extra.c: Implementation of non-standard features
5 * Michael Kay "XSLT Programmer's Reference" pp 637-643
6 * The node-set() extension function
8 * See Copyright for the status of this software.
24 #include <libxml/xmlmemory.h>
25 #include <libxml/tree.h>
26 #include <libxml/hash.h>
27 #include <libxml/xmlerror.h>
28 #include <libxml/parserInternals.h>
30 #include "xsltInternals.h"
31 #include "xsltutils.h"
32 #include "extensions.h"
33 #include "variables.h"
34 #include "transform.h"
38 #ifdef WITH_XSLT_DEBUG
39 #define WITH_XSLT_DEBUG_EXTRA
42 /************************************************************************
44 * Handling of XSLT debugging *
46 ************************************************************************/
50 * @ctxt: an XSLT processing context
51 * @node: The current node
52 * @inst: the instruction in the stylesheet
53 * @comp: precomputed informations
55 * Process an debug node
58 xsltDebug(xsltTransformContextPtr ctxt
, xmlNodePtr node ATTRIBUTE_UNUSED
,
59 xmlNodePtr inst ATTRIBUTE_UNUSED
,
60 xsltStylePreCompPtr comp ATTRIBUTE_UNUSED
)
64 xsltGenericError(xsltGenericErrorContext
, "Templates:\n");
65 for (i
= 0, j
= ctxt
->templNr
- 1; ((i
< 15) && (j
>= 0)); i
++, j
--) {
66 xsltGenericError(xsltGenericErrorContext
, "#%d ", i
);
67 if (ctxt
->templTab
[j
]->name
!= NULL
)
68 xsltGenericError(xsltGenericErrorContext
, "name %s ",
69 ctxt
->templTab
[j
]->name
);
70 if (ctxt
->templTab
[j
]->match
!= NULL
)
71 xsltGenericError(xsltGenericErrorContext
, "name %s ",
72 ctxt
->templTab
[j
]->match
);
73 if (ctxt
->templTab
[j
]->mode
!= NULL
)
74 xsltGenericError(xsltGenericErrorContext
, "name %s ",
75 ctxt
->templTab
[j
]->mode
);
76 xsltGenericError(xsltGenericErrorContext
, "\n");
78 xsltGenericError(xsltGenericErrorContext
, "Variables:\n");
79 for (i
= 0, j
= ctxt
->varsNr
- 1; ((i
< 15) && (j
>= 0)); i
++, j
--) {
82 if (ctxt
->varsTab
[j
] == NULL
)
84 xsltGenericError(xsltGenericErrorContext
, "#%d\n", i
);
85 cur
= ctxt
->varsTab
[j
];
87 if (cur
->comp
== NULL
) {
88 xsltGenericError(xsltGenericErrorContext
,
90 } else if (cur
->comp
->type
== XSLT_FUNC_PARAM
) {
91 xsltGenericError(xsltGenericErrorContext
, "param ");
92 } else if (cur
->comp
->type
== XSLT_FUNC_VARIABLE
) {
93 xsltGenericError(xsltGenericErrorContext
, "var ");
95 if (cur
->name
!= NULL
)
96 xsltGenericError(xsltGenericErrorContext
, "%s ",
99 xsltGenericError(xsltGenericErrorContext
, "noname !!!!");
100 #ifdef LIBXML_DEBUG_ENABLED
101 if (cur
->value
!= NULL
) {
102 xmlXPathDebugDumpObject(stdout
, cur
->value
, 1);
104 xsltGenericError(xsltGenericErrorContext
, "NULL !!!!");
107 xsltGenericError(xsltGenericErrorContext
, "\n");
114 /************************************************************************
116 * Classic extensions as described by M. Kay *
118 ************************************************************************/
121 * xsltFunctionNodeSet:
122 * @ctxt: the XPath Parser context
123 * @nargs: the number of arguments
125 * Implement the node-set() XSLT function
126 * node-set node-set(result-tree)
128 * This function is available in libxslt, saxon or xt namespace.
131 xsltFunctionNodeSet(xmlXPathParserContextPtr ctxt
, int nargs
){
133 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
134 "node-set() : expects one result-tree arg\n");
135 ctxt
->error
= XPATH_INVALID_ARITY
;
138 if ((ctxt
->value
== NULL
) ||
139 ((ctxt
->value
->type
!= XPATH_XSLT_TREE
) &&
140 (ctxt
->value
->type
!= XPATH_NODESET
))) {
141 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
142 "node-set() invalid arg expecting a result tree\n");
143 ctxt
->error
= XPATH_INVALID_TYPE
;
146 if (ctxt
->value
->type
== XPATH_XSLT_TREE
) {
147 ctxt
->value
->type
= XPATH_NODESET
;
153 * Okay the following really seems unportable and since it's not
154 * part of any standard I'm not too ashamed to do this
156 #if defined(linux) || defined(__sun)
157 #if defined(HAVE_MKTIME) && defined(HAVE_LOCALTIME) && defined(HAVE_ASCTIME)
158 #define WITH_LOCALTIME
161 * xsltFunctionLocalTime:
162 * @ctxt: the XPath Parser context
163 * @nargs: the number of arguments
165 * Implement the localTime XSLT function used by NORM
166 * string localTime(???)
168 * This function is available in Norm's extension namespace
169 * Code (and comments) contributed by Norm
172 xsltFunctionLocalTime(xmlXPathParserContextPtr ctxt
, int nargs
) {
173 xmlXPathObjectPtr obj
;
183 xsltTransformError(xsltXPathGetTransformContext(ctxt
), NULL
, NULL
,
184 "localTime() : invalid number of args %d\n", nargs
);
185 ctxt
->error
= XPATH_INVALID_ARITY
;
189 obj
= valuePop(ctxt
);
191 if (obj
->type
!= XPATH_STRING
) {
192 obj
= xmlXPathConvertString(obj
);
195 valuePush(ctxt
, xmlXPathNewString((const xmlChar
*)""));
199 str
= (char *) obj
->stringval
;
202 memset(digits
, 0, sizeof(digits
));
203 strncpy(digits
, str
+7, 4);
204 field
= strtol(digits
, NULL
, 10);
205 gmt_tm
.tm_year
= field
- 1900;
207 memset(digits
, 0, sizeof(digits
));
208 strncpy(digits
, str
+12, 2);
209 field
= strtol(digits
, NULL
, 10);
210 gmt_tm
.tm_mon
= field
- 1;
212 memset(digits
, 0, sizeof(digits
));
213 strncpy(digits
, str
+15, 2);
214 field
= strtol(digits
, NULL
, 10);
215 gmt_tm
.tm_mday
= field
;
217 memset(digits
, 0, sizeof(digits
));
218 strncpy(digits
, str
+18, 2);
219 field
= strtol(digits
, NULL
, 10);
220 gmt_tm
.tm_hour
= field
;
222 memset(digits
, 0, sizeof(digits
));
223 strncpy(digits
, str
+21, 2);
224 field
= strtol(digits
, NULL
, 10);
225 gmt_tm
.tm_min
= field
;
227 memset(digits
, 0, sizeof(digits
));
228 strncpy(digits
, str
+24, 2);
229 field
= strtol(digits
, NULL
, 10);
230 gmt_tm
.tm_sec
= field
;
232 /* Now turn gmt_tm into a time. */
233 gmt
= mktime(&gmt_tm
);
237 * FIXME: it's been too long since I did manual memory management.
238 * (I swore never to do it again.) Does this introduce a memory leak?
240 local_tm
= localtime(&gmt
);
243 * Calling localtime() has the side-effect of setting timezone.
244 * After we know the timezone, we can adjust for it
246 lmt
= gmt
- timezone
;
249 * FIXME: it's been too long since I did manual memory management.
250 * (I swore never to do it again.) Does this introduce a memory leak?
252 local_tm
= localtime(&lmt
);
255 * Now convert local_tm back into a string. This doesn't introduce
256 * a memory leak, so says asctime(3).
259 str
= asctime(local_tm
); /* "Tue Jun 26 05:02:16 2001" */
260 /* 0123456789 123456789 123 */
262 memset(result
, 0, sizeof(result
)); /* "Thu, 26 Jun 2001" */
263 /* 0123456789 12345 */
265 strncpy(result
, str
, 20);
266 strcpy(result
+20, "???"); /* tzname doesn't work, fake it */
267 strncpy(result
+23, str
+19, 5);
269 /* Ok, now result contains the string I want to send back. */
270 valuePush(ctxt
, xmlXPathNewString((xmlChar
*)result
));
273 #endif /* linux or sun */
277 * xsltRegisterExtras:
278 * @ctxt: a XSLT process context
280 * Registers the built-in extensions. This function is deprecated, use
281 * xsltRegisterAllExtras instead.
284 xsltRegisterExtras(xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED
) {
285 xsltRegisterAllExtras();
289 * xsltRegisterAllExtras:
291 * Registers the built-in extensions
294 xsltRegisterAllExtras (void) {
295 xsltRegisterExtModuleFunction((const xmlChar
*) "node-set",
296 XSLT_LIBXSLT_NAMESPACE
,
297 xsltFunctionNodeSet
);
298 xsltRegisterExtModuleFunction((const xmlChar
*) "node-set",
299 XSLT_SAXON_NAMESPACE
,
300 xsltFunctionNodeSet
);
301 xsltRegisterExtModuleFunction((const xmlChar
*) "node-set",
303 xsltFunctionNodeSet
);
304 #ifdef WITH_LOCALTIME
305 xsltRegisterExtModuleFunction((const xmlChar
*) "localTime",
306 XSLT_NORM_SAXON_NAMESPACE
,
307 xsltFunctionLocalTime
);
309 xsltRegisterExtModuleElement((const xmlChar
*) "debug",
310 XSLT_LIBXSLT_NAMESPACE
,
312 (xsltTransformFunction
) xsltDebug
);
313 xsltRegisterExtModuleElement((const xmlChar
*) "output",
314 XSLT_SAXON_NAMESPACE
,
316 (xsltTransformFunction
) xsltDocumentElem
);
317 xsltRegisterExtModuleElement((const xmlChar
*) "write",
318 XSLT_XALAN_NAMESPACE
,
320 (xsltTransformFunction
) xsltDocumentElem
);
321 xsltRegisterExtModuleElement((const xmlChar
*) "document",
324 (xsltTransformFunction
) xsltDocumentElem
);
325 xsltRegisterExtModuleElement((const xmlChar
*) "document",
328 (xsltTransformFunction
) xsltDocumentElem
);