#!/usr/bin/perl my %db2x_config = ( 'docbook2X-version' => q<0.8.8>, # Used by db2x_manxml and db2x_texixml only 'utf8trans-program' => q, 'utf8trans-map-roff' => q, 'utf8trans-map-texi' => q, 'iconv-program' => q, 'makeinfo-program' => q, # Used by docbook2X.pl only 'db2x_xsltproc-program' => q, 'db2x_manxml-program' => q, 'db2x_texixml-program' => q, # Used by db2x_xsltproc.pl only 'stylesheets-catalog' => q, 'xsltproc-program' => q, 'sgml2xml-isoent-program' => q, 'java-program' => q<>, 'resolver-jars' => q<>, 'saxon-jars' => q<>, 'xalan-jars' => q<>, 'xslt-processor' => q, ); # vim:sw=4 sta et showmatch # docbook2X.pl - script to invoke XSLT processor for docbook2X # (See docbook2X documentation for details) # # (C) 2003-2004 Steve Cheng # # See the COPYING file in the docbook2X distribution # for the copyright status of this software. # # Note: db2x_xsltproc.pl does not run by itself! # It must be configured by including a config.pl file # which is done when building docbook2X. use strict; use Getopt::Long; Getopt::Long::Configure('gnu_getopt'); my $options = { 'output' => '', 'xinclude' => '0', 'sgml' => '0', 'catalogs' => [], 'network' => '0', 'stylesheet' => '', 'param' => {}, 'string-param' => {}, 'debug' => 0, 'nesting-limit' => 0, 'profile' => 0, 'xslt-processor' => $db2x_config{'xslt-processor'}, }; # Hack, this allows us to easily test the docbook2X distribution # with different processors without re-running configure if(exists $ENV{DB2X_XSLT_PROCESSOR}) { $options->{'xslt-processor'} = $ENV{DB2X_XSLT_PROCESSOR}; } sub options_help { print "Usage: $0 [options] xml-document\n"; print <<'end'; XSLT processor invocation wrapper -v, --version display version information and exit -h, --help display this usage information -o, --output FILE send output to file instead of stdout -I, --xinclude do XInclude processing -S, --sgml input document is SGML rather than XML -C, --catalogs FILES use additional catalogs -N, --network allow fetching resources over network -s, --stylesheet FILE specify different stylesheet to use -p, --param NAME=VALUE add or modify a parameter to stylesheet VALUE is an XPath expression -g, --string-param NAME=VALUE same as -p, but VALUE is treated as a string -d, --debug display log of transformation -D, --nesting-limit change maximum nesting depth of templates -P, --profile display profiling information -X, --xslt-processor specify a XSLT processor to use; possible choices are: libxslt, saxon, xalan-j See the db2x_xsltproc(1) manual page and the docbook2X documentation for more details. end exit 0; } sub options_version { print "db2x_xsltproc (part of docbook2X " . $db2x_config{'docbook2X-version'} . ")\n"; print <<'end'; $Revision: 1.5 $ $Date: 2004/08/18 14:21:52 $ Copyright (C) 2004 Steve Cheng This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. end exit 0; } $SIG{__WARN__} = sub { print STDERR "$0: " . $_[0]; }; if(!GetOptions($options, 'output|o=s', 'xinclude|I', 'sgml|S', 'catalogs|C=s', 'network|N', 'stylesheet|s=s', 'param|p=s', 'string-param|stringparam|g=s', 'debug|d', 'nesting-limit|D=i', 'profile|P', 'xslt-processor|X=s', 'help', \&options_help, 'version', \&options_version)) { print STDERR "Try \"$0 --help\" for more information.\n"; exit 1; } $SIG{__WARN__} = undef; sub check_options { my ($options, @argv) = @_; if($options->{'stylesheet'} eq 'texi') { $options->{'stylesheet'} = "http://docbook2x.sf.net/latest/xslt/texi/docbook.xsl"; } elsif($options->{'stylesheet'} eq 'man') { $options->{'stylesheet'} = "http://docbook2x.sf.net/latest/xslt/man/docbook.xsl"; } if(scalar(@argv) != 1) { print STDERR "$0: you must specify exactly one source document\n"; exit 1; } } check_options($options, @ARGV); if($options->{'xslt-processor'} eq 'libxslt') { check_executable($db2x_config{'xsltproc-program'}); invoke_libxslt($options, @ARGV); } elsif($options->{'xslt-processor'} eq 'saxon') { check_executable($db2x_config{'java-program'}); check_jars($db2x_config{'saxon-jars'}, $db2x_config{'resolver-jars'}); invoke_saxon($options, @ARGV); } elsif($options->{'xslt-processor'} eq 'xalan-j') { check_executable($db2x_config{'java-program'}); check_jars($db2x_config{'xalan-jars'}, $db2x_config{'resolver-jars'}); invoke_xalan_j($options, @ARGV); } else { print STDERR "$0: XSLT processor \"" . $options->{'xslt-processor'} . "\" not supported\n"; exit 2; } sub check_executable { foreach my $exe (@_) { if($exe eq '') { print STDERR "$0: selected XSLT processor not installed\n"; print STDERR "$0: cannot use this XSLT processor --- try another one.\n"; exit 2; } if(!-x $exe) { print STDERR "$0: could not execute $exe\n"; print STDERR "$0: cannot use this XSLT processor --- try another one.\n"; exit 2; } } } sub check_jars { foreach my $jar_path (@_) { if($jar_path eq '') { print STDERR "$0: selected XSLT processor not installed\n"; print STDERR "$0: cannot use this XSLT processor --- try another one.\n"; exit 2; } if(0 < grep { $_ ne '' and !-r $_ } (split(/:/, $jar_path))) { print STDERR "$0: could not read JAR file $_\n"; print STDERR "$0: cannot use this XSLT processor --- try another one.\n"; exit 2; } } } sub invoke_libxslt { my ($options, @argv) = @_; my @args; push(@args, '--xinclude') if $options->{xinclude}; push(@args, '--nonet') if !$options->{network}; push(@args, '--debug') if $options->{debug}; push(@args, '--profile') if $options->{profile}; push(@args, '--maxdepth', $options->{'nesting-limit'}) if $options->{'nesting-limit'} > 0; push(@args, '--output', $options->{'output'}) if $options->{'output'} ne ''; foreach my $k (keys(%{$options->{param}})) { push(@args, '--param', $k, $options->{param}->{$k}); } foreach my $k (keys(%{$options->{'string-param'}})) { push(@args, '--stringparam', $k, $options->{'string-param'}->{$k}); } push(@args, $options->{'stylesheet'}); unshift(@args, $db2x_config{'xsltproc-program'}); if(exists $ENV{XML_CATALOG_FILES}) { $ENV{XML_CATALOG_FILES} =~ tr/:/ /; } else { $ENV{XML_CATALOG_FILES} = "/etc/xml/catalog"; } $ENV{XML_CATALOG_FILES} = join(' ', @{$options->{catalogs}}) . ' ' . $ENV{XML_CATALOG_FILES} . ' ' . $db2x_config{'stylesheets-catalog'}; if(!$options->{sgml}) { push(@args, @argv); print STDERR join(' ', @args) . "\n" if $options->{'debug'}; exec { $args[0] } (@args); } else { push(@args, '-'); exec shell_quote($db2x_config{'sgml2xml-isoent-program'}) . ' ' . shell_quote(@argv) . ' | ' . shell_quote(@args); } } sub setup_java_catalogs { my ($options) = @_; my $cat; if(exists $ENV{XML_CATALOG_FILES}) { $cat = $ENV{XML_CATALOG_FILES}; $cat =~ tr/:/;/; } else { $cat = '/etc/xml/catalog'; } $cat = join(';', @{$options->{catalogs}}) . ';' . $cat . ';' . $db2x_config{'stylesheets-catalog'}; return $cat; } sub invoke_saxon { my ($options, @argv) = @_; my @args; my $error = 0; if($options->{xinclude}) { print STDERR "$0: --xinclude not supported by SAXON processor\n"; exit 2; } if(keys(%{$options->{param}}) > 0) { print STDERR "$0: --param not supported by SAXON processor\n"; print STDERR "$0: (perhaps use --string-param instead?)\n"; exit 2; } foreach my $opt (qw(debug nesting-limit profile)) { print STDERR "$0: --$opt not supported by SAXON processor --- ignoring\n" if $options->{$opt}; } push(@args, '-classpath', join(':', $db2x_config{'resolver-jars'}, $db2x_config{'saxon-jars'})); push(@args, '-Dxml.catalog.files=' . setup_java_catalogs($options)); push(@args, qw(-Dxml.catalog.staticCatalog=yes -Dxml.catalog.verbosity=1 -Dxml.catalog.prefer=public)); push(@args, 'com.icl.saxon.StyleSheet'); push(@args, qw(-x org.apache.xml.resolver.tools.ResolvingXMLReader -y org.apache.xml.resolver.tools.ResolvingXMLReader -r org.apache.xml.resolver.tools.CatalogResolver -l -u)); push(@args, '-o', $options->{'output'}) if $options->{'output'} ne ''; my $xmldoc = $argv[0]; $xmldoc = '-' if $options->{sgml}; # Grr... SAXON barfs at '-' for reading from stdin $xmldoc = '/dev/stdin' if $xmldoc eq '-'; if($options->{'stylesheet'} ne '') { push(@args, $xmldoc); push(@args, $options->{'stylesheet'}); } else { push(@args, '-a'); push(@args, $xmldoc); } foreach my $k (keys(%{$options->{'string-param'}})) { push(@args, $k . '=' . $options->{'string-param'}->{$k}); } unshift(@args, $db2x_config{'java-program'}); if(!$options->{sgml}) { print STDERR join(' ', @args) . "\n" if $options->{'debug'}; exec { $args[0] } (@args); } else { exec shell_quote($db2x_config{'sgml2xml-isoent-program'}) . ' ' . shell_quote(@argv) . ' | ' . shell_quote(@args); } } sub invoke_xalan_j { my ($options, @argv) = @_; my @args; my $error = 0; if($options->{xinclude}) { print STDERR "$0: --xinclude not supported by Xalan-Java processor\n"; exit 2; } if(keys(%{$options->{param}}) > 0) { print STDERR "$0: --param not supported by Xalan-Java processor\n"; print STDERR "$0: (perhaps use --string-param instead?)\n"; exit 2; } foreach my $opt (qw(debug profile)) { print STDERR "$0: --$opt not supported by Xalan-Java processor --- ignoring\n" if $options->{$opt}; } # Workaround: see # http://sources.redhat.com/ml/docbook-apps/2004-q1/msg00065.html my $xalan_jar_dir = $db2x_config{'xalan-jars'}; $xalan_jar_dir =~ s/:.*//; $xalan_jar_dir =~ s/([^\/]+)$//; my $resolver_jar_dir = $db2x_config{'resolver-jars'}; $xalan_jar_dir =~ s/:.*//; $resolver_jar_dir =~ s/([^\/]+)$//; push(@args, "-Djava.endorsed.dirs=$xalan_jar_dir:$resolver_jar_dir"); push(@args, '-classpath', join(':', $db2x_config{'resolver-jars'}, $db2x_config{'xalan-jars'})); push(@args, '-Dxml.catalog.files=' . setup_java_catalogs($options)); push(@args, qw(-Dxml.catalog.staticCatalog=yes -Dxml.catalog.verbosity=1 -Dxml.catalog.prefer=public)); push(@args, 'org.apache.xalan.xslt.Process'); push(@args, qw(-EntityResolver org.apache.xml.resolver.tools.CatalogResolver -URIResolver org.apache.xml.resolver.tools.CatalogResolver -L)); push(@args, '-RL', $options->{'nesting-limit'}) if $options->{'nesting-limit'} > 0; push(@args, '-out', $options->{'output'}) if $options->{'output'} ne ''; push(@args, '-xsl', $options->{'stylesheet'}) if $options->{'stylesheet'} ne ''; foreach my $k (keys(%{$options->{'string-param'}})) { push(@args, '-param', $k, $options->{'string-param'}->{$k}); } unshift(@args, $db2x_config{'java-program'}); if(!$options->{sgml}) { push(@args, '-in', @argv); print STDERR join(' ', @args) . "\n" if $options->{'debug'} ; exec { $args[0] } (@args); } else { push(@args, qw(-in -)); exec shell_quote($db2x_config{'sgml2xml-isoent-program'}) . ' ' . shell_quote(@argv) . ' | ' . shell_quote(@args); } } sub shell_quote { join(' ', map { my $u = $_; $u =~ s#([\$`"\\\n])#\\$1#g; '"' . $u . '"' } @_); }