From c4799bf461b2fc471255bb77d7b4404da05313be Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Tue, 28 Sep 2004 14:22:23 +0000 Subject: [PATCH] New tutorial from Panagiotis Louridas integrated the tutorial in the * doc/tutorial2/libxslt_pipes.*: New tutorial from Panagiotis Louridas * libxslt.spec.in doc/Makefile.am: integrated the tutorial in the distribution Daniel --- ChangeLog | 6 + doc/Makefile.am | 4 +- doc/libxslt-api.xml | 5 +- doc/libxslt-refs.xml | 14 + doc/tutorial2/libxslt_pipes.c | 148 ++++++++++ doc/tutorial2/libxslt_pipes.html | 592 ++++++++++++++++++++++++++++++++++++++ doc/tutorial2/libxslt_pipes.xml | 596 +++++++++++++++++++++++++++++++++++++++ libxslt.spec.in | 2 +- libxslt/xsltwin32config.h | 2 +- 9 files changed, 1365 insertions(+), 4 deletions(-) create mode 100644 doc/tutorial2/libxslt_pipes.c create mode 100644 doc/tutorial2/libxslt_pipes.html create mode 100644 doc/tutorial2/libxslt_pipes.xml diff --git a/ChangeLog b/ChangeLog index 0816d4c..5a0d344 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Tue Sep 28 16:20:48 CEST 2004 Daniel Veillard + + * doc/tutorial2/libxslt_pipes.*: New tutorial from Panagiotis Louridas + * libxslt.spec.in doc/Makefile.am: integrated the tutorial in the + distribution + Sat Sep 25 21:38:57 CEST 2004 Daniel Veillard * libxslt/preproc.c libxslt/variables.c: fixed 2 leaks with diff --git a/doc/Makefile.am b/doc/Makefile.am index 2356e94..4d8fb83 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -184,10 +184,12 @@ install-data-local: -@INSTALL@ -m 0644 $(srcdir)/EXSLT/*.html $(DESTDIR)$(TARGET_DIR)/EXSLT $(mkinstalldirs) $(DESTDIR)$(TARGET_DIR)/tutorial -@INSTALL@ -m 0644 $(srcdir)/tutorial/* $(DESTDIR)$(TARGET_DIR)/tutorial + $(mkinstalldirs) $(DESTDIR)$(TARGET_DIR)/tutorial2 + -@INSTALL@ -m 0644 $(srcdir)/tutorial2/* $(DESTDIR)$(TARGET_DIR)/tutorial2 dist-hook: (cd $(srcdir) ; tar cvf - *.1 *.html site.xsl news.xsl xsa.xsl \ - *.gif html/*.html html/*.png tutorial/libxslt*) | \ + *.gif html/*.html html/*.png tutorial*/libxslt*) | \ (cd $(distdir); tar xf -) .PHONY : html EXSLT EXSLT/html diff --git a/doc/libxslt-api.xml b/doc/libxslt-api.xml index 6561271..73ac2c9 100644 --- a/doc/libxslt-api.xml +++ b/doc/libxslt-api.xml @@ -681,6 +681,7 @@ + @@ -844,7 +845,9 @@ informations are stored'/> *'/> - + + diff --git a/doc/libxslt-refs.xml b/doc/libxslt-refs.xml index 0ffeee6..4b28a1f 100644 --- a/doc/libxslt-refs.xml +++ b/doc/libxslt-refs.xml @@ -2712,6 +2712,10 @@ + + + + @@ -3001,6 +3005,9 @@ + + + @@ -3523,7 +3530,9 @@ + + @@ -4051,6 +4060,7 @@ + @@ -4963,6 +4973,10 @@ + + + + diff --git a/doc/tutorial2/libxslt_pipes.c b/doc/tutorial2/libxslt_pipes.c new file mode 100644 index 0000000..ad331e6 --- /dev/null +++ b/doc/tutorial2/libxslt_pipes.c @@ -0,0 +1,148 @@ +/* + * libxslt_pipes.c: a program for performing a series of XSLT + * transformations + * + * Writen by Panos Louridas, based on libxslt_tutorial.c by John Fleck. + * + * Copyright (c) 2004 Panagiotis Louridas + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include +#include + +extern int xmlLoadExtDtdDefaultValue; + +static void usage(const char *name) { + printf("Usage: %s [options] stylesheet [stylesheet ...] file [file ...]\n", + name); + printf(" --out file: send output to file\n"); + printf(" --param name value: pass a (parameter,value) pair\n"); +} + +int main(int argc, char **argv) { + int arg_indx; + const char *params[16 + 1]; + int params_indx = 0; + int stylesheet_indx = 0; + int file_indx = 0; + int i, j, k; + FILE *output_file = stdout; + xsltStylesheetPtr *stylesheets = + (xsltStylesheetPtr *) calloc(argc, sizeof(xsltStylesheetPtr)); + xmlDocPtr *files = (xmlDocPtr *) calloc(argc, sizeof(xmlDocPtr)); + xmlDocPtr doc, res; + int return_value = 0; + + if (argc <= 1) { + usage(argv[0]); + return_value = 1; + goto finish; + } + + /* Collect arguments */ + for (arg_indx = 1; arg_indx < argc; arg_indx++) { + if (argv[arg_indx][0] != '-') + break; + if ((!strcmp(argv[arg_indx], "-param")) + || (!strcmp(argv[arg_indx], "--param"))) { + arg_indx++; + params[params_indx++] = argv[arg_indx++]; + params[params_indx++] = argv[arg_indx]; + if (params_indx >= 16) { + fprintf(stderr, "too many params\n"); + return_value = 1; + goto finish; + } + } else if ((!strcmp(argv[arg_indx], "-o")) + || (!strcmp(argv[arg_indx], "--out"))) { + arg_indx++; + output_file = fopen(argv[arg_indx], "w"); + } else { + fprintf(stderr, "Unknown option %s\n", argv[arg_indx]); + usage(argv[0]); + return_value = 1; + goto finish; + } + } + params[params_indx] = 0; + + /* Collect and parse stylesheets and files to be transformed */ + for (; arg_indx < argc; arg_indx++) { + char *argument = + (char *) malloc(sizeof(char) * (strlen(argv[arg_indx]) + 1)); + strcpy(argument, argv[arg_indx]); + if (strtok(argument, ".")) { + char *suffix = strtok(0, "."); + if (suffix && !strcmp(suffix, "xsl")) { + stylesheets[stylesheet_indx++] = + xsltParseStylesheetFile((const xmlChar *)argv[arg_indx]);; + } else { + files[file_indx++] = xmlParseFile(argv[arg_indx]); + } + } else { + files[file_indx++] = xmlParseFile(argv[arg_indx]); + } + free(argument); + } + + xmlSubstituteEntitiesDefault(1); + xmlLoadExtDtdDefaultValue = 1; + + /* Process files */ + for (i = 0; files[i]; i++) { + doc = files[i]; + res = doc; + for (j = 0; stylesheets[j]; j++) { + res = xsltApplyStylesheet(stylesheets[j], doc, params); + xmlFreeDoc(doc); + doc = res; + } + + if (stylesheets[0]) { + xsltSaveResultToFile(output_file, res, stylesheets[j-1]); + } else { + xmlDocDump(output_file, res); + } + xmlFreeDoc(res); + } + + fclose(output_file); + + for (k = 0; stylesheets[k]; k++) { + xsltFreeStylesheet(stylesheets[k]); + } + + xsltCleanupGlobals(); + xmlCleanupParser(); + + finish: + free(stylesheets); + free(files); + return(return_value); +} diff --git a/doc/tutorial2/libxslt_pipes.html b/doc/tutorial2/libxslt_pipes.html new file mode 100644 index 0000000..7965737 --- /dev/null +++ b/doc/tutorial2/libxslt_pipes.html @@ -0,0 +1,592 @@ +libxslt: An Extended Tutorial

libxslt: An Extended Tutorial

Panos Louridas

Permission is hereby granted, free of charge, to + any person obtaining a copy of this software and associated + documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, + copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software + is furnished to do so, subject to the following conditions: +

The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. +

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


Introduction

The Extensible Stylesheet Language Transformations (XSLT) +specification defines an XML template language for transforming XML +documents. An XSLT engine reads an XSLT file and an XML document and +transforms the document accordingly.

We want to perform a series of XSLT transformations to a series +of documents. An obvious solution is to use the operating system's +pipe mechanism and start a series of transformation processes, each +one taking as input the output of the previous transformation. It +would be interesting, though, and perhaps more efficient if we could +do our job within a single process.

libxslt is a library for doing XSLT transformations. It is built +on libxml, which is a library for handling XML documents. libxml and +libxslt are used by the GNOME project. Although developed in the +*NIX world, both libxml and libxslt have been +ported to the MS-Windows platform. In principle an application using +libxslt should be easily portable between the two systems. In +practice, however, there arise various wrinkles. These do not have +anything to do with libxml or libxslt per se, but rather with the +different compilation and linking procedures of each system.

The presented solution is an extension of John +Fleck's libxslt tutorial, but the present tutorial tries to be +self-contained. It develops a minimal libxslt application +(libxslt_pipes) that can perform a series of transformations to a +series of files in a pipe-like manner. An invocation might be:

+ + libxslt_pipes --out results.xml foo.xsl bar.xsl doc1.xml doc2.xml + +

The foo.xsl stylesheet will be applied to + doc1.xml and the bar.xsl +stylesheet will be applied to the resulting document; then the two +stylesheets will be applied in the same sequence to +bar.xsl. The results are sent to +results.xml (if no output is specified they are +sent to standard output).

The application is compiled in both *NIX +systems and MS-Windows, where by *NIX systems we +mean Linux, BSD, and other members of the +family. The gcc suite is used in the *NIX platform +and the Microsoft compiler and linker are used in the +MS-Windows platform.

Setting the Scene

+We need to include the necessary libraries: + +

+  
+  #include <stdio.h>
+  #include <string.h>
+  #include <stdlib.h>
+  #include <malloc.h>
+  
+  #include <libxslt/transform.h>
+  #include <libxslt/xsltutils.h>
+  
+

+

The first group of include directives includes general C +libraries. The libraries we need to make libxslt work are in the +second group. The transform.h header file +declares the API that does the bulk of the actual processing. The +xsltutils.h header file declares the API for some +generic utility functions of the XSLT engine; among other things, +saving to a file, which is what we need it for.

+If our input files contain entities through external subsets, we need +to tell libxslt to load them. The global variable +xmlLoadExtDtdDefaultValue, defined in +libxml/globals.h, is responsible for that. As the +variable is defined outside our program we must specify external +linkage: +

+    extern int xmlLoadExtDtdDefaultValue;
+  

+

+The program is called from the command line. We anticipate that the +user may not call it the right way, so we define a function for +describing its usage: +

+  static void usage(const char *name) {
+      printf("Usage: %s [options] stylesheet [stylesheet ...] file [file ...]\n",
+          name);
+      printf("      --out file: send output to file\n");
+      printf("      --param name value: pass a (parameter,value) pair\n");
+  }
+

+

Program Start

We need to define a few variables that are used throughout the +program: +

+    int main(int argc, char **argv) {
+        int arg_indx;
+	const char *params[16 + 1];
+	int params_indx = 0;
+	int stylesheet_indx = 0;
+	int file_indx = 0;
+	int i, j, k;
+	FILE *output_file = stdout;
+	xsltStylesheetPtr *stylesheets = 
+	    (xsltStylesheetPtr *) calloc(argc, sizeof(xsltStylesheetPtr));
+	    xmlDocPtr *files = (xmlDocPtr *) calloc(argc, sizeof(xmlDocPtr));
+	int return_value = 0;
+

+

The arg_indx integer is an index used to +iterate over the program arguments. The params +string array is used to collect the XSLT parameters. In XSLT, +additional information may be passed to the processor via +parameters. The user of the program specifies these in key-value pairs +in the command line following the --param +command line argument. We accept up to 8 such key-value pairs, which +we track with the params_indx integer. libxslt +expects the parameters array to be null-terminated, so we have to +allocate one extra place (16 + 1) for it. The +file_indx is an index to iterate over the files to +be processed. The i, j, +k integers are additional indices for iteration +purposes, and return_value is the value the program +returns to the operating system. We expect the result of the +transformation to be the standard output in most cases, but the user +may wish otherwise via the --out command line +option, so we need to keep track of the situation with the +output_file file pointer.

In libxslt, XSLT stylesheets are internally stored in +xsltStylesheet structures; similarly, in +libxml XML documents are stored in xmlDoc +structures. xsltStylesheetPtr and xmlDocPtr +are simply typedefs of pointers to them. The user may specify any +number of stylesheets that will be applied to the documents one after +the other. To save time we parse the stylesheets and the documents as +we read them from the command line and keep the parsed representation +of them. The parsed results are kept in arrays. These are dynamically +allocated and sized to the number of arguments; this wastes some +space, but not much (the size of xmlStyleSheetPtr and +xmlDocPtr is the size of a pointer) and simplifies code +later on. The array memory is allocated with +calloc to ensure contents are initialised to +zero. +

Arguments Collection

If the program gets no arguments at all, we print the usage +description, set the program return value to 1 and exit. Instead of +returning directly we go to (literally) to the end of the program text +where some housekeeping takes place.

+

+  
+    if (argc <= 1) {
+        usage(argv[0]);
+        return_value = 1;
+        goto finish;
+    }
+        
+    /* Collect arguments */
+    for (arg_indx = 1; arg_indx < argc; arg_indx++) {
+        if (argv[arg_indx][0] != '-')
+            break;
+        if ((!strcmp(argv[arg_indx], "-param"))
+                || (!strcmp(argv[arg_indx], "--param"))) {
+            arg_indx++;
+            params[params_indx++] = argv[arg_indx++];
+            params[params_indx++] = argv[arg_indx];
+            if (params_indx >= 16) {
+                fprintf(stderr, "too many params\n");
+                return_value = 1;
+                goto finish;
+            }
+        }  else if ((!strcmp(argv[arg_indx], "-o"))
+                || (!strcmp(argv[arg_indx], "--out"))) {
+            arg_indx++;
+            output_file = fopen(argv[arg_indx], "w");
+        } else {
+            fprintf(stderr, "Unknown option %s\n", argv[arg_indx]);
+            usage(argv[0]);
+            return_value = 1;
+            goto finish;
+        }
+    }
+    params[params_indx] = 0;
+    
+

+

If the user passes arguments we have to collect them. This is a +matter of iterating over the program argument list while we encounter +arguments starting with a dash. The XSLT parameters are put into the +params array and the output_file +is set to the user request, if any. After processing all the parameter +key-value pairs we set the last element of the params +array to null. +

Parsing

The rest of the argument list is taken to be stylesheets and +files to be transformed. Stylesheets are identified by their suffix, +which is expected to be xsl (case sensitive). All other files are +assumed to be XML documents, regardless of suffix.

+

+  
+    /* Collect and parse stylesheets and files to be transformed */
+    for (; arg_indx < argc; arg_indx++) {
+        char *argument =
+            (char *) malloc(sizeof(char) * (strlen(argv[arg_indx]) + 1));
+        strcpy(argument, argv[arg_indx]);
+        if (strtok(argument, ".")) {
+            char *suffix = strtok(0, ".");
+            if (suffix && !strcmp(suffix, "xsl")) {
+                stylesheets[stylesheet_indx++] =
+                    xsltParseStylesheetFile((const xmlChar *)argv[arg_indx]);;
+            } else {
+                files[file_indx++] = xmlParseFile(argv[arg_indx]);
+            }
+        } else {
+            files[file_indx++] = xmlParseFile(argv[arg_indx]);
+        }
+        free(argument);
+    }
+  
+

+

Stylesheets are parsed using the +xsltParseStylesheetFile +function. xsltParseStylesheetFile takes as +argument a pointer to an xmlChar, a typedef of an +unsigned char; in effect, the filename of the stylesheet. The +resulting xsltStylesheetPtr is placed in the +stylesheets array. In the same vein, XML files are +parsed using the xmlParseFile function that takes +as argument the file's name; the resulting xmlDocPtr is +placed in the files array. +

File Processing

All stylesheets are applied to each file one after the +other. Stylesheets are applied with the +xsltApplyStylesheet function that takes as +argument the stylesheet to be applied, the file to be transformed and +any parameters we have collected. The in-memory representation of an +XML document takes space, which we free using the +xmlFreeDoc function. The file is then saved to the +specified output.

+

+  
+    /* Process files */
+    for (i = 0; files[i]; i++) {
+        doc = files[i];
+        res = doc;
+        for (j = 0; stylesheets[j]; j++) {
+            res = xsltApplyStylesheet(stylesheets[j], doc, params);
+            xmlFreeDoc(doc);
+            doc = res;
+        }
+
+        if (stylesheets[0]) {
+            xsltSaveResultToFile(output_file, res, stylesheets[j-1]);
+        } else {
+            xmlDocDump(output_file, res);
+        }
+        xmlFreeDoc(res);
+    }
+
+    fclose(output_file);
+
+    for (k = 0; stylesheets[k]; k++) {
+        xsltFreeStylesheet(stylesheets[k]);
+    }
+
+    xsltCleanupGlobals();
+    xmlCleanupParser();
+
+ finish:
+    free(stylesheets);
+    free(files);
+    return(return_value);
+    
+

+

To output an XML document we have in memory we use the +xlstSaveResultToFile function, where we specify +the destination, the document and the stylesheet that has been applied +to it. The stylesheet is required so that output-related information +contained in the stylesheet, such as the encoding to be used, is used +in output. If no transformation has taken place, which will happen +when the user specifies no stylesheets at all in the command line, we +use the xmlDocDump libxml function that saves the +source document to the file without further ado.

As parsed stylesheets take up space in memory, we take care to +free that memory after use with a call to +xmlFreeStyleSheet. When all work is done, we +clean up all global variables used by the XSLT library using +xsltCleanupGlobals. Likewise, all global memory +allocated for the XML parser is reclaimed by a call to +xmlCleanupParser. Before returning we deallocate +the memory allocated for the holding the pointers to the XML documents +and stylesheets.

*NIX Compiling and Linking

Compiling and linking in a *NIX environment +is easy, as the required libraries are almost certain to be already in +place (remember that libxml and libxslt are used by the GNOME project, +so they are present in most installations). The program can be +dynamically linked so that its footprint is minimized, or statically +linked, so that it stands by itself, carrying all required code. For +dynamic linking the following one liner will do:

+gcc -o libxslt_pipes -Wall -I/usr/include/libxml2 -lxslt -lxml2 -L/usr/lib +libxslt_pipes.c +

We assume that the necessary header files are in /usr/include/libxml2 and that the +required libraries (libxslt.so, +libxsml2.so) are in /usr/lib.

For static linking we must list more libraries in the command +line, as the libraries on which the libxsl and libxslt libraries +depend are also needed. Still, an one-liner will do:

+ +gcc -o libxslt_pipes -Wall -I/usr/include/libxml2 libxslt_pipes.c +-static -lxslt -lxml2 -lpthread -lz -lm + +

If we get warnings to the effect that some function in +statically linked applications requires at runtime the shared +libraries used from the glibc version used for linking, that means +that the binary is not completely static. Although we statically +linked against the GNU C runtime library glibc, glibc uses external +libraries to perform some of its functions. Same version libraries +must be present on the system we want the application to run. One way +to avoid this it to use an alternative C runtime, for example uClibc, which requires obtaining +and building a uClibc toolchain first (if the reason for trying to get +a statically linked version of the program is to embed it somewhere, +using uClibc might be a good idea anyway). +

MS-Windows Compiling and Linking

Compiling and linking in MS-Windows requires +some attention. First, the MS-Windows ports must be +downloaded and installed in the programming workstation. The ports are +available in Igor +Zlatković's site. We need the ports for iconv, zlib, libxml, +and libxslt. In contrast to *NIX environments, we +cannot assume that the libraries needed will be present in other +computers where the program will be used. One solution is to +distribute the program along with the necessary dynamic +libraries. Another solution is to statically link the program so that +only a single executable file will have to be distributed.

We assume that we have decompressed the downloaded ports and +have placed the required contents of their include directories in an include directory in our file system. The +required contents include everything apart from the libexslt directory of the libxslt port, +as we are not using EXLST (an initiative to provide extensions to +XSLT) in this project. In order to compile the program we have to make +sure that all necessary header files are included. When using the +Microsoft compiler this translates to adding the required +/I switches in the command line. If using a Visual +Studio product the same effect is attained by specifying additional +include directories in the compilation options. In the end, if the +headers have been copied in C:\include the command line must contain +/I"C:\include" /I"C:\include\libslt" +/I"C:\include\libxml".

This being a C program, it needs to be compiled against an +implementation of the C libraries. Microsoft provides various +implementations. The ports, however, have been compiled against the +msvcrt.dll implementation, so it is wise to use +the same runtime in our project, lest we wish to come against +unexpected runtime crashes. The msvcrt.dll is a +multi-threaded implementation and is specified by giving +/MD as a compiler option. Unfortunately, the +correspondence between the /MD switch and +msvcrt.dll breaks after version 6 of the +Microsoft compiler. In version 7 and later (i.e., Visual Studio .NET), +/MD links against a different DLL; in version 7.1 +this is msvcrt71.dll. The end result of this bit +of esoterica is that if you try to dynamically link your application +with a compiler whose version is greater than 6, your program is +likely to crash unexpectedly. Alternatively, you may wish to compile +all iconv, zlib, libxml and libxslt yourself, using the new runtime +library. This is not a tall order, and some details are given +below.

There are three kinds of libraries in MS-Windows. Dynamically +Linked Libraries (DLLs), like msvcrt.dll we met +above, are used for dynamic linking; an application links to them at +runtime, so the application does not include the code contained in +them. Static libraries are used for static linking; an application +adds the libraries' code to its own code at link time. Import +libraries are used when building an application that uses DLLs. For +the application to be built, the linker must somehow find the +definitions of the functions that will be provided in runtime by the +DLLs, otherwise it will complain about unresolved references. Import +libraries contain function stubs that, for each DLL function we want +to call, know where to look for it in the DLL. In essence, in order to +use a DLL we must link against its corresponding import library. DLLs +have a .dll suffix; static and import libraries +both have a .lib suffix. In the MS-Windows ports +of libxml and libxslt static libraries are distinguished by their name +ending in _a.lib, while in the zlib port the +import library is zdll.lib and the static library +is zlib.lib. In what follows we assume we have a +lib directory in our filesystem +where we place the libraries we need for linking.

If we want to link dynamically we must make sure the lib directory contains +iconv.lib, libxslt.lib, +libxml2.lib, and +zdll.lib. When using the Microsoft linker this +translates to adding the required /LIBPATH +switch and the necessary libraries in the command line. In Visual +Studio we must specify an additional library directory for lib and put the necessary libraries in +the additional dependencies. In the end, the command line must include +/LIBPATH:"C:\lib" "lib\iconv.lib" "lib\libxslt.lib" +"lib\libxml2.lib" "lib\zdll.lib", provided the libraries' +directory is C:\lib. In order +for the resulting executable to run, the ports DLLs must be present; +one way is to place all DLLs contained in the ports in the home +directory of our application, and make sure they are distributed +together.

If we want to link statically we must make sure the lib directory contains +iconv_a.lib, libxslt_a.lib, +libxml2_a.lib, and +zlib.lib. Adding lib as a library directory and putting +the necessary libraries in the additional dependencies, we get a +command line that should include /LIBPATH:"C:\lib" +"lib\iconv_a.lib" "lib\libxslt_a.lib" "lib\libxml2_a.lib" +"lib\zlib.lib". The resulting executable is much bigger +than if we linked dynamically; it is, however, self-contained and can +be distributed more easily, in theory at least. In practice, however, +the executable is not completely static. We saw that the ports are +compiled against msvcrt.dll, so the program does +require that DLL at runtime. Moreover, since when using a version of +Microsoft developer tools with a version number greater than 6, we are +no longer using msvcrt.dll, but another runtime +like msvcrt71.dll, and we then need that DLL. In +contrast to msvcrt.dll it may not be present on +the target computer, so we may have to copy it along.

Building the Ports in +MS-Windows

The source code of the ports is readily available on the web, +one has to check the ports sites. Each port can be built without +problems in an MS-Windows environment using Microsoft development +tools. The necessary command line tools (compiler, linker, +nmake) must be available. This means running a +batch file called vcvars32.bat that comes with +Visual Studio (its exact location in the directory tree may vary +depending on the version of Visual Studio, but a file search will find +it anyway). Makefiles for the Microsoft tools are found in all +ports. They are distinguished by their suffix, e.g., +Makefile.msvc or +Makefile.msc. To build zlib it suffices to run +nmake against Makefile.msc +(i.e., with the /F option); similarly, to build +iconv it suffices to run nmake +against Makefile.msvc. Building libxml and +libxslt requires an extra configuration step; we must run the +configure.js configuration script with the +cscript command. configure.js +is found in the win32 directory +in the distributions. It is written in JScript, Microsoft's +implementation of the ECMA 262 language specification (ECMAScript +Edition 3), a JavaScript offspring. The configuration string takes a +number of parameters detailing our environment and needs; +cscript configure.js help documents +them.

It is wise to read all documentation files in the source +distributions before starting; moreover, pay attention to the +dependencies between the ports. If we configure libxml and libxslt to +use iconv and zlib we must build these two first and make sure their +headers and libraries can be found by the compiler and the +linker when building libxml and libxslt.

The Complete Program

+The complete program listing is given below. The program is also +available online. +

+

+/*
+ * libxslt_pipes.c: a program for performing a series of XSLT
+ * transformations
+ *
+ * Writen by Panos Louridas, based on libxslt_tutorial.c by John Fleck.
+ *
+ * Copyright (c) 2004 Panagiotis Louridas
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions: </para>
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */ 
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <stdarg.h>
+
+#include <libxslt/transform.h>
+#include <libxslt/xsltutils.h>
+
+extern int xmlLoadExtDtdDefaultValue;
+
+static void usage(const char *name) {
+    printf("Usage: %s [options] stylesheet [stylesheet ...] file [file ...]\n",
+            name);
+    printf("      --out file: send output to file\n");
+    printf("      --param name value: pass a (parameter,value) pair\n");
+}
+
+int main(int argc, char **argv) {
+    int arg_indx;
+    const char *params[16 + 1];
+    int params_indx = 0;
+    int stylesheet_indx = 0;
+    int file_indx = 0;
+    int i, j, k;
+    FILE *output_file = stdout;
+    xsltStylesheetPtr *stylesheets = 
+        (xsltStylesheetPtr *) calloc(argc, sizeof(xsltStylesheetPtr));
+    xmlDocPtr *files = (xmlDocPtr *) calloc(argc, sizeof(xmlDocPtr));
+    xmlDocPtr doc, res;
+    int return_value = 0;
+        
+    if (argc <= 1) {
+        usage(argv[0]);
+        return_value = 1;
+        goto finish;
+    }
+        
+    /* Collect arguments */
+    for (arg_indx = 1; arg_indx < argc; arg_indx++) {
+        if (argv[arg_indx][0] != '-')
+            break;
+        if ((!strcmp(argv[arg_indx], "-param"))
+                || (!strcmp(argv[arg_indx], "--param"))) {
+            arg_indx++;
+            params[params_indx++] = argv[arg_indx++];
+            params[params_indx++] = argv[arg_indx];
+            if (params_indx >= 16) {
+                fprintf(stderr, "too many params\n");
+                return_value = 1;
+                goto finish;
+            }
+        }  else if ((!strcmp(argv[arg_indx], "-o"))
+                || (!strcmp(argv[arg_indx], "--out"))) {
+            arg_indx++;
+            output_file = fopen(argv[arg_indx], "w");
+        } else {
+            fprintf(stderr, "Unknown option %s\n", argv[arg_indx]);
+            usage(argv[0]);
+            return_value = 1;
+            goto finish;
+        }
+    }
+    params[params_indx] = 0;
+
+    /* Collect and parse stylesheets and files to be transformed */
+    for (; arg_indx < argc; arg_indx++) {
+        char *argument =
+            (char *) malloc(sizeof(char) * (strlen(argv[arg_indx]) + 1));
+        strcpy(argument, argv[arg_indx]);
+        if (strtok(argument, ".")) {
+            char *suffix = strtok(0, ".");
+            if (suffix && !strcmp(suffix, "xsl")) {
+                stylesheets[stylesheet_indx++] =
+                    xsltParseStylesheetFile((const xmlChar *)argv[arg_indx]);;
+            } else {
+                files[file_indx++] = xmlParseFile(argv[arg_indx]);
+            }
+        } else {
+            files[file_indx++] = xmlParseFile(argv[arg_indx]);
+        }
+        free(argument);
+    }
+
+    xmlSubstituteEntitiesDefault(1);
+    xmlLoadExtDtdDefaultValue = 1;
+
+    /* Process files */
+    for (i = 0; files[i]; i++) {
+        doc = files[i];
+        res = doc;
+        for (j = 0; stylesheets[j]; j++) {
+            res = xsltApplyStylesheet(stylesheets[j], doc, params);
+            xmlFreeDoc(doc);
+            doc = res;
+        }
+
+        if (stylesheets[0]) {
+            xsltSaveResultToFile(output_file, res, stylesheets[j-1]);
+        } else {
+            xmlDocDump(output_file, res);
+        }
+        xmlFreeDoc(res);
+    }
+
+    fclose(output_file);
+
+    for (k = 0; stylesheets[k]; k++) {
+        xsltFreeStylesheet(stylesheets[k]);
+    }
+
+    xsltCleanupGlobals();
+    xmlCleanupParser();
+
+ finish:
+    free(stylesheets);
+    free(files);
+    return(return_value);
+}
+
+

+

diff --git a/doc/tutorial2/libxslt_pipes.xml b/doc/tutorial2/libxslt_pipes.xml new file mode 100644 index 0000000..188aa29 --- /dev/null +++ b/doc/tutorial2/libxslt_pipes.xml @@ -0,0 +1,596 @@ + + + +
+ + PanosLouridas + + 2004 + Panagiotis Louridas + + + Permission is hereby granted, free of charge, to + any person obtaining a copy of this software and associated + documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, + copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software + is furnished to do so, subject to the following conditions: + + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + + +libxslt: An Extended Tutorial + +Introduction + +The Extensible Stylesheet Language Transformations (XSLT) +specification defines an XML template language for transforming XML +documents. An XSLT engine reads an XSLT file and an XML document and +transforms the document accordingly. + +We want to perform a series of XSLT transformations to a series +of documents. An obvious solution is to use the operating system's +pipe mechanism and start a series of transformation processes, each +one taking as input the output of the previous transformation. It +would be interesting, though, and perhaps more efficient if we could +do our job within a single process. + +libxslt is a library for doing XSLT transformations. It is built +on libxml, which is a library for handling XML documents. libxml and +libxslt are used by the GNOME project. Although developed in the +*NIX world, both libxml and libxslt have been +ported to the MS-Windows platform. In principle an application using +libxslt should be easily portable between the two systems. In +practice, however, there arise various wrinkles. These do not have +anything to do with libxml or libxslt per se, but rather with the +different compilation and linking procedures of each system. + +The presented solution is an extension of John +Fleck's libxslt tutorial, but the present tutorial tries to be +self-contained. It develops a minimal libxslt application +(libxslt_pipes) that can perform a series of transformations to a +series of files in a pipe-like manner. An invocation might be: + + + + libxslt_pipes --out results.xml foo.xsl bar.xsl doc1.xml doc2.xml + + + +The foo.xsl stylesheet will be applied to + doc1.xml and the bar.xsl +stylesheet will be applied to the resulting document; then the two +stylesheets will be applied in the same sequence to +bar.xsl. The results are sent to +results.xml (if no output is specified they are +sent to standard output). + +The application is compiled in both *NIX +systems and MS-Windows, where by *NIX systems we +mean Linux, BSD, and other members of the +family. The gcc suite is used in the *NIX platform +and the Microsoft compiler and linker are used in the +MS-Windows platform. + + + +Setting the Scene + + +We need to include the necessary libraries: + + + + #include + #include + #include + + #include + #include + ]]> + + + +The first group of include directives includes general C +libraries. The libraries we need to make libxslt work are in the +second group. The transform.h header file +declares the API that does the bulk of the actual processing. The +xsltutils.h header file declares the API for some +generic utility functions of the XSLT engine; among other things, +saving to a file, which is what we need it for. + + +If our input files contain entities through external subsets, we need +to tell libxslt to load them. The global variable +xmlLoadExtDtdDefaultValue, defined in +libxml/globals.h, is responsible for that. As the +variable is defined outside our program we must specify external +linkage: + + extern int xmlLoadExtDtdDefaultValue; + + + + +The program is called from the command line. We anticipate that the +user may not call it the right way, so we define a function for +describing its usage: + + static void usage(const char *name) { + printf("Usage: %s [options] stylesheet [stylesheet ...] file [file ...]\n", + name); + printf(" --out file: send output to file\n"); + printf(" --param name value: pass a (parameter,value) pair\n"); + } + + + + +Program Start + +We need to define a few variables that are used throughout the +program: + + int main(int argc, char **argv) { + int arg_indx; + const char *params[16 + 1]; + int params_indx = 0; + int stylesheet_indx = 0; + int file_indx = 0; + int i, j, k; + FILE *output_file = stdout; + xsltStylesheetPtr *stylesheets = + (xsltStylesheetPtr *) calloc(argc, sizeof(xsltStylesheetPtr)); + xmlDocPtr *files = (xmlDocPtr *) calloc(argc, sizeof(xmlDocPtr)); + int return_value = 0; + + + +The arg_indx integer is an index used to +iterate over the program arguments. The params +string array is used to collect the XSLT parameters. In XSLT, +additional information may be passed to the processor via +parameters. The user of the program specifies these in key-value pairs +in the command line following the --param +command line argument. We accept up to 8 such key-value pairs, which +we track with the params_indx integer. libxslt +expects the parameters array to be null-terminated, so we have to +allocate one extra place (16 + 1) for it. The +file_indx is an index to iterate over the files to +be processed. The i, j, +k integers are additional indices for iteration +purposes, and return_value is the value the program +returns to the operating system. We expect the result of the +transformation to be the standard output in most cases, but the user +may wish otherwise via the command line +option, so we need to keep track of the situation with the +output_file file pointer. + +In libxslt, XSLT stylesheets are internally stored in +xsltStylesheet structures; similarly, in +libxml XML documents are stored in xmlDoc +structures. xsltStylesheetPtr and xmlDocPtr +are simply typedefs of pointers to them. The user may specify any +number of stylesheets that will be applied to the documents one after +the other. To save time we parse the stylesheets and the documents as +we read them from the command line and keep the parsed representation +of them. The parsed results are kept in arrays. These are dynamically +allocated and sized to the number of arguments; this wastes some +space, but not much (the size of xmlStyleSheetPtr and +xmlDocPtr is the size of a pointer) and simplifies code +later on. The array memory is allocated with +calloc to ensure contents are initialised to +zero. + + + + +Arguments Collection + +If the program gets no arguments at all, we print the usage +description, set the program return value to 1 and exit. Instead of +returning directly we go to (literally) to the end of the program text +where some housekeeping takes place. + + + + = 16) { + fprintf(stderr, "too many params\n"); + return_value = 1; + goto finish; + } + } else if ((!strcmp(argv[arg_indx], "-o")) + || (!strcmp(argv[arg_indx], "--out"))) { + arg_indx++; + output_file = fopen(argv[arg_indx], "w"); + } else { + fprintf(stderr, "Unknown option %s\n", argv[arg_indx]); + usage(argv[0]); + return_value = 1; + goto finish; + } + } + params[params_indx] = 0; + ]]> + + + +If the user passes arguments we have to collect them. This is a +matter of iterating over the program argument list while we encounter +arguments starting with a dash. The XSLT parameters are put into the +params array and the output_file +is set to the user request, if any. After processing all the parameter +key-value pairs we set the last element of the params +array to null. + + + +Parsing + +The rest of the argument list is taken to be stylesheets and +files to be transformed. Stylesheets are identified by their suffix, +which is expected to be xsl (case sensitive). All other files are +assumed to be XML documents, regardless of suffix. + + + + + + + +Stylesheets are parsed using the +xsltParseStylesheetFile +function. xsltParseStylesheetFile takes as +argument a pointer to an xmlChar, a typedef of an +unsigned char; in effect, the filename of the stylesheet. The +resulting xsltStylesheetPtr is placed in the +stylesheets array. In the same vein, XML files are +parsed using the xmlParseFile function that takes +as argument the file's name; the resulting xmlDocPtr is +placed in the files array. + + + + +File Processing + +All stylesheets are applied to each file one after the +other. Stylesheets are applied with the +xsltApplyStylesheet function that takes as +argument the stylesheet to be applied, the file to be transformed and +any parameters we have collected. The in-memory representation of an +XML document takes space, which we free using the +xmlFreeDoc function. The file is then saved to the +specified output. + + + + + + + +To output an XML document we have in memory we use the +xlstSaveResultToFile function, where we specify +the destination, the document and the stylesheet that has been applied +to it. The stylesheet is required so that output-related information +contained in the stylesheet, such as the encoding to be used, is used +in output. If no transformation has taken place, which will happen +when the user specifies no stylesheets at all in the command line, we +use the xmlDocDump libxml function that saves the +source document to the file without further ado. + +As parsed stylesheets take up space in memory, we take care to +free that memory after use with a call to +xmlFreeStyleSheet. When all work is done, we +clean up all global variables used by the XSLT library using +xsltCleanupGlobals. Likewise, all global memory +allocated for the XML parser is reclaimed by a call to +xmlCleanupParser. Before returning we deallocate +the memory allocated for the holding the pointers to the XML documents +and stylesheets. + + + +*NIX Compiling and Linking + +Compiling and linking in a *NIX environment +is easy, as the required libraries are almost certain to be already in +place (remember that libxml and libxslt are used by the GNOME project, +so they are present in most installations). The program can be +dynamically linked so that its footprint is minimized, or statically +linked, so that it stands by itself, carrying all required code. For +dynamic linking the following one liner will do: + + +gcc -o libxslt_pipes -Wall -I/usr/include/libxml2 -lxslt -lxml2 -L/usr/lib +libxslt_pipes.c + + +We assume that the necessary header files are in /usr/include/libxml2 and that the +required libraries (libxslt.so, +libxsml2.so) are in /usr/lib. + +For static linking we must list more libraries in the command +line, as the libraries on which the libxsl and libxslt libraries +depend are also needed. Still, an one-liner will do: + + + +gcc -o libxslt_pipes -Wall -I/usr/include/libxml2 libxslt_pipes.c +-static -lxslt -lxml2 -lpthread -lz -lm + + + +If we get warnings to the effect that some function in +statically linked applications requires at runtime the shared +libraries used from the glibc version used for linking, that means +that the binary is not completely static. Although we statically +linked against the GNU C runtime library glibc, glibc uses external +libraries to perform some of its functions. Same version libraries +must be present on the system we want the application to run. One way +to avoid this it to use an alternative C runtime, for example uClibc, which requires obtaining +and building a uClibc toolchain first (if the reason for trying to get +a statically linked version of the program is to embed it somewhere, +using uClibc might be a good idea anyway). + + + + +MS-Windows Compiling and Linking + +Compiling and linking in MS-Windows requires +some attention. First, the MS-Windows ports must be +downloaded and installed in the programming workstation. The ports are +available in Igor +Zlatkoviæ's site. We need the ports for iconv, zlib, libxml, +and libxslt. In contrast to *NIX environments, we +cannot assume that the libraries needed will be present in other +computers where the program will be used. One solution is to +distribute the program along with the necessary dynamic +libraries. Another solution is to statically link the program so that +only a single executable file will have to be distributed. + +We assume that we have decompressed the downloaded ports and +have placed the required contents of their include directories in an include directory in our file system. The +required contents include everything apart from the libexslt directory of the libxslt port, +as we are not using EXLST (an initiative to provide extensions to +XSLT) in this project. In order to compile the program we have to make +sure that all necessary header files are included. When using the +Microsoft compiler this translates to adding the required + switches in the command line. If using a Visual +Studio product the same effect is attained by specifying additional +include directories in the compilation options. In the end, if the +headers have been copied in C:\include the command line must contain +. + +This being a C program, it needs to be compiled against an +implementation of the C libraries. Microsoft provides various +implementations. The ports, however, have been compiled against the +msvcrt.dll implementation, so it is wise to use +the same runtime in our project, lest we wish to come against +unexpected runtime crashes. The msvcrt.dll is a +multi-threaded implementation and is specified by giving + as a compiler option. Unfortunately, the +correspondence between the switch and +msvcrt.dll breaks after version 6 of the +Microsoft compiler. In version 7 and later (i.e., Visual Studio .NET), + links against a different DLL; in version 7.1 +this is msvcrt71.dll. The end result of this bit +of esoterica is that if you try to dynamically link your application +with a compiler whose version is greater than 6, your program is +likely to crash unexpectedly. Alternatively, you may wish to compile +all iconv, zlib, libxml and libxslt yourself, using the new runtime +library. This is not a tall order, and some details are given +below. + +There are three kinds of libraries in MS-Windows. Dynamically +Linked Libraries (DLLs), like msvcrt.dll we met +above, are used for dynamic linking; an application links to them at +runtime, so the application does not include the code contained in +them. Static libraries are used for static linking; an application +adds the libraries' code to its own code at link time. Import +libraries are used when building an application that uses DLLs. For +the application to be built, the linker must somehow find the +definitions of the functions that will be provided in runtime by the +DLLs, otherwise it will complain about unresolved references. Import +libraries contain function stubs that, for each DLL function we want +to call, know where to look for it in the DLL. In essence, in order to +use a DLL we must link against its corresponding import library. DLLs +have a .dll suffix; static and import libraries +both have a .lib suffix. In the MS-Windows ports +of libxml and libxslt static libraries are distinguished by their name +ending in _a.lib, while in the zlib port the +import library is zdll.lib and the static library +is zlib.lib. In what follows we assume we have a +lib directory in our filesystem +where we place the libraries we need for linking. + +If we want to link dynamically we must make sure the lib directory contains +iconv.lib, libxslt.lib, +libxml2.lib, and +zdll.lib. When using the Microsoft linker this +translates to adding the required +switch and the necessary libraries in the command line. In Visual +Studio we must specify an additional library directory for lib and put the necessary libraries in +the additional dependencies. In the end, the command line must include +, provided the libraries' +directory is C:\lib. In order +for the resulting executable to run, the ports DLLs must be present; +one way is to place all DLLs contained in the ports in the home +directory of our application, and make sure they are distributed +together. + +If we want to link statically we must make sure the lib directory contains +iconv_a.lib, libxslt_a.lib, +libxml2_a.lib, and +zlib.lib. Adding lib as a library directory and putting +the necessary libraries in the additional dependencies, we get a +command line that should include . The resulting executable is much bigger +than if we linked dynamically; it is, however, self-contained and can +be distributed more easily, in theory at least. In practice, however, +the executable is not completely static. We saw that the ports are +compiled against msvcrt.dll, so the program does +require that DLL at runtime. Moreover, since when using a version of +Microsoft developer tools with a version number greater than 6, we are +no longer using msvcrt.dll, but another runtime +like msvcrt71.dll, and we then need that DLL. In +contrast to msvcrt.dll it may not be present on +the target computer, so we may have to copy it along. + +Building the Ports in +MS-Windows + +The source code of the ports is readily available on the web, +one has to check the ports sites. Each port can be built without +problems in an MS-Windows environment using Microsoft development +tools. The necessary command line tools (compiler, linker, +nmake) must be available. This means running a +batch file called vcvars32.bat that comes with +Visual Studio (its exact location in the directory tree may vary +depending on the version of Visual Studio, but a file search will find +it anyway). Makefiles for the Microsoft tools are found in all +ports. They are distinguished by their suffix, e.g., +Makefile.msvc or +Makefile.msc. To build zlib it suffices to run +nmake against Makefile.msc +(i.e., with the option); similarly, to build +iconv it suffices to run nmake +against Makefile.msvc. Building libxml and +libxslt requires an extra configuration step; we must run the +configure.js configuration script with the +cscript command. configure.js +is found in the win32 directory +in the distributions. It is written in JScript, Microsoft's +implementation of the ECMA 262 language specification (ECMAScript +Edition 3), a JavaScript offspring. The configuration string takes a +number of parameters detailing our environment and needs; +cscript configure.js help documents +them. + +It is wise to read all documentation files in the source +distributions before starting; moreover, pay attention to the +dependencies between the ports. If we configure libxml and libxslt to +use iconv and zlib we must build these two first and make sure their +headers and libraries can be found by the compiler and the +linker when building libxml and libxslt. + + + + + +The Complete Program + + +The complete program listing is given below. The program is also +available online. + + + + + + + + + + +
diff --git a/libxslt.spec.in b/libxslt.spec.in index 9f1c994..60c7ad7 100644 --- a/libxslt.spec.in +++ b/libxslt.spec.in @@ -76,7 +76,7 @@ rm -fr %{buildroot} %defattr(-, root, root) %doc AUTHORS ChangeLog.gz NEWS README Copyright TODO FEATURES -%doc doc/*.html doc/html doc/tutorial doc/*.gif +%doc doc/*.html doc/html doc/tutorial doc/tutorial2 doc/*.gif %doc %{_mandir}/man1/xsltproc.1* %{_libdir}/lib*.so.* %{prefix}/bin/xsltproc diff --git a/libxslt/xsltwin32config.h b/libxslt/xsltwin32config.h index e0a0a0c..dcc2bd4 100644 --- a/libxslt/xsltwin32config.h +++ b/libxslt/xsltwin32config.h @@ -44,7 +44,7 @@ extern "C" { * * extra version information, used to show a CVS compilation */ -#define LIBXML_VERSION_EXTRA "-CVS940" +#define LIBXML_VERSION_EXTRA "-CVS949" /** * WITH_XSLT_DEBUG: -- 2.7.4