733ddc705c2e239dd05c77dfd6611c745d994d5b
[platform/upstream/libxslt.git] / xsltproc / xsltproc.c
1 /*
2  * xsltproc.c: user program for the XSL Transformation 1.0 engine
3  *
4  * See Copyright for the status of this software.
5  *
6  * daniel@veillard.com
7  */
8
9 #include "libxslt/libxslt.h"
10 #include "libexslt/exslt.h"
11 #ifdef HAVE_STRING_H
12 #include <string.h>
13 #endif
14 #ifdef HAVE_SYS_TIME_H
15 #include <sys/time.h>
16 #endif
17 #ifdef HAVE_UNISTD_H
18 #include <unistd.h>
19 #endif
20 #ifdef HAVE_STDLIB_H
21 #include <stdlib.h>
22 #endif
23 #include <libxml/xmlmemory.h>
24 #include <libxml/debugXML.h>
25 #include <libxml/HTMLtree.h>
26 #include <libxml/xmlIO.h>
27 #ifdef LIBXML_DOCB_ENABLED
28 #include <libxml/DOCBparser.h>
29 #endif
30 #ifdef LIBXML_XINCLUDE_ENABLED
31 #include <libxml/xinclude.h>
32 #endif
33 #ifdef LIBXML_CATALOG_ENABLED
34 #include <libxml/catalog.h>
35 #endif
36 #include <libxml/parserInternals.h>
37
38 #include <libxslt/xslt.h>
39 #include <libxslt/xsltInternals.h>
40 #include <libxslt/transform.h>
41 #include <libxslt/xsltutils.h>
42 #include <libxslt/extensions.h>
43
44 #include <libexslt/exsltconfig.h>
45
46 #ifdef WIN32
47 #ifdef _MSC_VER
48 #include <winsock2.h>
49 #pragma comment(lib, "ws2_32.lib")
50 #define gettimeofday(p1,p2)
51 #endif /* _MS_VER */
52 #else /* WIN32 */
53 #include <sys/time.h>
54 #endif /* WIN32 */
55
56
57 static int debug = 0;
58 static int repeat = 0;
59 static int timing = 0;
60 static int novalid = 0;
61 static int noout = 0;
62 #ifdef LIBXML_DOCB_ENABLED
63 static int docbook = 0;
64 #endif
65 #ifdef LIBXML_HTML_ENABLED
66 static int html = 0;
67 #endif
68 #ifdef LIBXML_XINCLUDE_ENABLED
69 static int xinclude = 0;
70 #endif
71 static int profile = 0;
72 static int nonet;
73 static xmlExternalEntityLoader defaultLoader = NULL;
74
75 static struct timeval begin, end;
76 static const char *params[16 + 1];
77 static int nbparams = 0;
78 static const char *output = NULL;
79
80 static xmlParserInputPtr
81 xsltNoNetExternalEntityLoader(const char *URL, const char *ID,
82                                xmlParserCtxtPtr ctxt) {
83     if (URL != NULL) {
84         if ((!xmlStrncasecmp((const xmlChar *) URL,
85                             (const xmlChar *) "ftp://", 6)) ||
86             (!xmlStrncasecmp((const xmlChar *) URL,
87                             (const xmlChar *) "http://", 7))) {
88             fprintf(stderr, "Attempt to load network entity %s \n", URL);
89             if (nonet)
90                 return(NULL);
91         }
92     }
93     if (defaultLoader != NULL) {
94         return(defaultLoader(URL, ID, ctxt));
95     }
96     return(NULL);
97 }
98
99 static void
100 xsltProcess(xmlDocPtr doc, xsltStylesheetPtr cur, const char *filename) {
101     xmlDocPtr res;
102
103 #ifdef LIBXML_XINCLUDE_ENABLED
104     if (xinclude) {
105         if (timing)
106             gettimeofday(&begin, NULL);
107         xmlXIncludeProcess(doc);
108         if (timing) {
109             long msec;
110
111             gettimeofday(&end, NULL);
112             msec = end.tv_sec - begin.tv_sec;
113             msec *= 1000;
114             msec += (end.tv_usec - begin.tv_usec) / 1000;
115             fprintf(stderr, "XInclude processing %s took %ld ms\n",
116                     filename, msec);
117         }
118     }
119 #endif
120     if (timing)
121         gettimeofday(&begin, NULL);
122     if (output == NULL) {
123         if (repeat) {
124             int j;
125
126             for (j = 1; j < repeat; j++) {
127                 res = xsltApplyStylesheet(cur, doc, params);
128                 xmlFreeDoc(res);
129                 xmlFreeDoc(doc);
130 #ifdef LIBXML_HTML_ENABLED
131                 if (html)
132                     doc = htmlParseFile(filename, NULL);
133                 else
134 #endif
135 #ifdef LIBXML_DOCB_ENABLED
136                 if (docbook)
137                     doc = docbParseFile(filename, NULL);
138                 else
139 #endif
140                     doc = xmlParseFile(filename);
141             }
142         }
143         if (profile) {
144             res = xsltProfileStylesheet(cur, doc, params, stderr);
145         } else {
146             res = xsltApplyStylesheet(cur, doc, params);
147         }
148         if (timing) {
149             long msec;
150
151             gettimeofday(&end, NULL);
152             msec = end.tv_sec - begin.tv_sec;
153             msec *= 1000;
154             msec += (end.tv_usec - begin.tv_usec) / 1000;
155             if (repeat)
156                 fprintf(stderr,
157                         "Applying stylesheet %d times took %ld ms\n",
158                         repeat, msec);
159             else
160                 fprintf(stderr,
161                         "Applying stylesheet took %ld ms\n", msec);
162         }
163         xmlFreeDoc(doc);
164         if (res == NULL) {
165             fprintf(stderr, "no result for %s\n", filename);
166             return;
167         }
168         if (noout) {
169             xmlFreeDoc(res);
170             return;
171         }
172 #ifdef LIBXML_DEBUG_ENABLED
173         if (debug)
174             xmlDebugDumpDocument(stdout, res);
175         else {
176 #endif
177             if (cur->methodURI == NULL) {
178                 if (timing)
179                     gettimeofday(&begin, NULL);
180                 xsltSaveResultToFile(stdout, res, cur);
181                 if (timing) {
182                     long msec;
183
184                     gettimeofday(&end, NULL);
185                     msec = end.tv_sec - begin.tv_sec;
186                     msec *= 1000;
187                     msec += (end.tv_usec - begin.tv_usec) / 1000;
188                     fprintf(stderr, "Saving result took %ld ms\n",
189                             msec);
190                 }
191             } else {
192                 if (xmlStrEqual
193                     (cur->method, (const xmlChar *) "xhtml")) {
194                     fprintf(stderr, "non standard output xhtml\n");
195                     if (timing)
196                         gettimeofday(&begin, NULL);
197                     xsltSaveResultToFile(stdout, res, cur);
198                     if (timing) {
199                         long msec;
200
201                         gettimeofday(&end, NULL);
202                         msec = end.tv_sec - begin.tv_sec;
203                         msec *= 1000;
204                         msec +=
205                             (end.tv_usec - begin.tv_usec) / 1000;
206                         fprintf(stderr,
207                                 "Saving result took %ld ms\n",
208                                 msec);
209                     }
210                 } else {
211                     fprintf(stderr,
212                             "Unsupported non standard output %s\n",
213                             cur->method);
214                 }
215             }
216 #ifdef LIBXML_DEBUG_ENABLED
217         }
218 #endif
219
220         xmlFreeDoc(res);
221     } else {
222         xsltRunStylesheet(cur, doc, params, output, NULL, NULL);
223         if (timing) {
224             long msec;
225
226             gettimeofday(&end, NULL);
227             msec = end.tv_sec - begin.tv_sec;
228             msec *= 1000;
229             msec += (end.tv_usec - begin.tv_usec) / 1000;
230             fprintf(stderr,
231                 "Running stylesheet and saving result took %ld ms\n",
232                     msec);
233         }
234         xmlFreeDoc(doc);
235     }
236 }
237
238 static void usage(const char *name) {
239     printf("Usage: %s [options] stylesheet file [file ...]\n", name);
240     printf("   Options:\n");
241     printf("      --version or -V: show the version of libxml and libxslt used\n");
242     printf("      --verbose or -v: show logs of what's happening\n");
243     printf("      --output file or -o file: save to a given file\n");
244     printf("      --timing: display the time used\n");
245     printf("      --repeat: run the transformation 20 times\n");
246     printf("      --debug: dump the tree of the result instead\n");
247     printf("      --novalid: skip the Dtd loading phase\n");
248     printf("      --noout: do not dump the result\n");
249     printf("      --maxdepth val : increase the maximum depth\n");
250 #ifdef LIBXML_HTML_ENABLED
251     printf("      --html: the input document is(are) an HTML file(s)\n");
252 #endif
253 #ifdef LIBXML_DOCB_ENABLED
254     printf("      --docbook: the input document is SGML docbook\n");
255 #endif
256     printf("      --param name value : pass a (parameter,value) pair\n");
257     printf("      --nonet refuse to fetch DTDs or entities over network\n");
258     printf("      --warnnet warn against fetching over the network\n");
259 #ifdef LIBXML_CATALOG_ENABLED
260     printf("      --catalogs : use the catalogs from $SGML_CATALOG_FILES\n");
261 #endif
262 #ifdef LIBXML_XINCLUDE_ENABLED
263     printf("      --xinclude : do XInclude processing on document intput\n");
264 #endif
265     printf("      --profile or --norman : dump profiling informations \n");
266 }
267
268 int
269 main(int argc, char **argv)
270 {
271     int i;
272     xsltStylesheetPtr cur = NULL;
273     xmlDocPtr doc, style;
274
275     if (argc <= 1) {
276         usage(argv[0]);
277         return (1);
278     }
279
280     xmlInitMemory();
281
282     LIBXML_TEST_VERSION
283
284     defaultLoader = xmlGetExternalEntityLoader();
285     xmlLineNumbersDefault(1);
286
287     if (novalid == 0)
288         xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
289     else
290         xmlLoadExtDtdDefaultValue = 0;
291     for (i = 1; i < argc; i++) {
292         if (!strcmp(argv[i], "-"))
293             break;
294
295         if (argv[i][0] != '-')
296             continue;
297 #ifdef LIBXML_DEBUG_ENABLED
298         if ((!strcmp(argv[i], "-debug")) || (!strcmp(argv[i], "--debug"))) {
299             debug++;
300         } else
301 #endif
302         if ((!strcmp(argv[i], "-v")) ||
303                 (!strcmp(argv[i], "-verbose")) ||
304                 (!strcmp(argv[i], "--verbose"))) {
305             xsltSetGenericDebugFunc(stderr, NULL);
306         } else if ((!strcmp(argv[i], "-o")) ||
307                    (!strcmp(argv[i], "-output")) ||
308                    (!strcmp(argv[i], "--output"))) {
309             i++;
310             output = argv[i++];
311         } else if ((!strcmp(argv[i], "-V")) ||
312                    (!strcmp(argv[i], "-version")) ||
313                    (!strcmp(argv[i], "--version"))) {
314             printf("Using libxml %s, libxslt %s and libexslt %s\n",
315                    xmlParserVersion, xsltEngineVersion, exsltLibraryVersion);
316             printf
317     ("xsltproc was compiled against libxml %d, libxslt %d and libexslt %d\n",
318                  LIBXML_VERSION, LIBXSLT_VERSION, LIBEXSLT_VERSION);
319             printf("libxslt %d was compiled against libxml %d\n",
320                    xsltLibxsltVersion, xsltLibxmlVersion);
321             printf("libexslt %d was compiled against libxml %d\n",
322                    exsltLibexsltVersion, exsltLibxmlVersion);
323         } else if ((!strcmp(argv[i], "-repeat"))
324                    || (!strcmp(argv[i], "--repeat"))) {
325             if (repeat == 0)
326                 repeat = 20;
327             else
328                 repeat = 100;
329         } else if ((!strcmp(argv[i], "-novalid")) ||
330                    (!strcmp(argv[i], "--novalid"))) {
331             novalid++;
332         } else if ((!strcmp(argv[i], "-noout")) ||
333                    (!strcmp(argv[i], "--noout"))) {
334             noout++;
335 #ifdef LIBXML_DOCB_ENABLED
336         } else if ((!strcmp(argv[i], "-docbook")) ||
337                    (!strcmp(argv[i], "--docbook"))) {
338             docbook++;
339 #endif
340 #ifdef LIBXML_HTML_ENABLED
341         } else if ((!strcmp(argv[i], "-html")) ||
342                    (!strcmp(argv[i], "--html"))) {
343             html++;
344 #endif
345         } else if ((!strcmp(argv[i], "-timing")) ||
346                    (!strcmp(argv[i], "--timing"))) {
347             timing++;
348         } else if ((!strcmp(argv[i], "-profile")) ||
349                    (!strcmp(argv[i], "--profile"))) {
350             profile++;
351         } else if ((!strcmp(argv[i], "-norman")) ||
352                    (!strcmp(argv[i], "--norman"))) {
353             profile++;
354         } else if ((!strcmp(argv[i], "-warnnet")) ||
355                    (!strcmp(argv[i], "--warnnet"))) {
356             xmlSetExternalEntityLoader(xsltNoNetExternalEntityLoader);
357         } else if ((!strcmp(argv[i], "-nonet")) ||
358                    (!strcmp(argv[i], "--nonet"))) {
359             xmlSetExternalEntityLoader(xsltNoNetExternalEntityLoader);
360             nonet = 1;
361 #ifdef LIBXML_CATALOG_ENABLED
362         } else if ((!strcmp(argv[i], "-catalogs")) ||
363                    (!strcmp(argv[i], "--catalogs"))) {
364             const char *catalogs;
365
366             catalogs = getenv("SGML_CATALOG_FILES");
367             if (catalogs == NULL) {
368                 fprintf(stderr, "Variable $SGML_CATALOG_FILES not set\n");
369             } else {
370                 xmlLoadCatalogs(catalogs);
371             }
372 #endif
373 #ifdef LIBXML_XINCLUDE_ENABLED
374         } else if ((!strcmp(argv[i], "-xinclude")) ||
375                    (!strcmp(argv[i], "--xinclude"))) {
376             xinclude++;
377             xsltSetXIncludeDefault(1);
378 #endif
379         } else if ((!strcmp(argv[i], "-param")) ||
380                    (!strcmp(argv[i], "--param"))) {
381             i++;
382             params[nbparams++] = argv[i++];
383             params[nbparams++] = argv[i];
384             if (nbparams >= 16) {
385                 fprintf(stderr, "too many params\n");
386                 return (1);
387             }
388         } else if ((!strcmp(argv[i], "-maxdepth")) ||
389                    (!strcmp(argv[i], "--maxdepth"))) {
390             int value;
391
392             i++;
393             if (sscanf(argv[i], "%d", &value) == 1) {
394                 if (value > 0)
395                     xsltMaxDepth = value;
396             }
397         } else {
398             fprintf(stderr, "Unknown option %s\n", argv[i]);
399             usage(argv[0]);
400             return (1);
401         }
402     }
403     params[nbparams] = NULL;
404
405     /*
406      * Replace entities with their content.
407      */
408     xmlSubstituteEntitiesDefault(1);
409
410     /*
411      * Register the EXSLT extensions and the test module
412      */
413     exsltRegisterAll();
414     xsltRegisterTestModule();
415
416     for (i = 1; i < argc; i++) {
417         if ((!strcmp(argv[i], "-maxdepth")) ||
418             (!strcmp(argv[i], "--maxdepth"))) {
419             i++;
420             continue;
421         } else if ((!strcmp(argv[i], "-o")) ||
422                    (!strcmp(argv[i], "-output")) ||
423                    (!strcmp(argv[i], "--output"))) {
424             i++;
425             continue;
426         }
427         if ((!strcmp(argv[i], "-param")) || (!strcmp(argv[i], "--param"))) {
428             i += 2;
429             continue;
430         }
431         if ((argv[i][0] != '-') || (strcmp(argv[i], "-") == 0)) {
432             if (timing)
433                 gettimeofday(&begin, NULL);
434             style = xmlParseFile((const char *) argv[i]);
435             if (timing) {
436                 long msec;
437
438                 gettimeofday(&end, NULL);
439                 msec = end.tv_sec - begin.tv_sec;
440                 msec *= 1000;
441                 msec += (end.tv_usec - begin.tv_usec) / 1000;
442                 fprintf(stderr, "Parsing stylesheet %s took %ld ms\n",
443                         argv[i], msec);
444             }
445             if (style == NULL) {
446                 fprintf(stderr,  "cannot parse %s\n", argv[i]);
447                 cur = NULL;
448             } else {
449                 cur = xsltLoadStylesheetPI(style);
450                 if (cur != NULL) {
451                     /* it is an embedded stylesheet */
452                     xsltProcess(style, cur, argv[i]);
453                     xsltFreeStylesheet(cur);
454                     exit(0);
455                 }
456                 cur = xsltParseStylesheetDoc(style);
457                 if (cur != NULL) {
458                     if (cur->indent == 1)
459                         xmlIndentTreeOutput = 1;
460                     else
461                         xmlIndentTreeOutput = 0;
462                     i++;
463                 }
464             }
465             break;
466
467         }
468     }
469
470     /*
471      * disable CDATA from being built in the document tree
472      */
473     xmlDefaultSAXHandlerInit();
474     xmlDefaultSAXHandler.cdataBlock = NULL;
475
476     if ((cur != NULL) && (cur->errors == 0)) {
477         for (; i < argc; i++) {
478             doc = NULL;
479             if (timing)
480                 gettimeofday(&begin, NULL);
481 #ifdef LIBXML_HTML_ENABLED
482             if (html)
483                 doc = htmlParseFile(argv[i], NULL);
484             else
485 #endif
486 #ifdef LIBXML_DOCB_ENABLED
487             if (docbook)
488                 doc = docbParseFile(argv[i], NULL);
489             else
490 #endif
491                 doc = xmlParseFile(argv[i]);
492             if (doc == NULL) {
493                 fprintf(stderr, "unable to parse %s\n", argv[i]);
494                 continue;
495             }
496             if (timing) {
497                 long msec;
498
499                 gettimeofday(&end, NULL);
500                 msec = end.tv_sec - begin.tv_sec;
501                 msec *= 1000;
502                 msec += (end.tv_usec - begin.tv_usec) / 1000;
503                 fprintf(stderr, "Parsing document %s took %ld ms\n",
504                         argv[i], msec);
505             }
506             xsltProcess(doc, cur, argv[i]);
507         }
508         xsltFreeStylesheet(cur);
509     }
510     xsltCleanupGlobals();
511     xmlCleanupParser();
512     xmlMemoryDump();
513     return (0);
514 }
515