3 # @PACKAGE@ - apply an XSL stylesheet to an XML document
4 # Copyright (C) 2001, 2002, 2003 Tim Waugh <twaugh@redhat.com>
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, see <http://www.gnu.org/licenses/>.
19 # Utilities that we need that aren't everywhere
20 FIND=@FIND@ # This must be GNU find (need -maxdepth)
21 MKTEMP=@MKTEMP@ # See http://www.mktemp.org if missing on your system
22 BASH=@BASH@ # GNU bash, for running the format scripts
23 GETOPT=@GETOPT@ # a getopt that supports --longoptions
24 TAIL=@TAIL@ # a tail that supports -n (posix)
27 echo "@PACKAGE@ version @VERSION@"
32 usage: @PACKAGE@ [OPTION]... FORMAT XML
34 -v verbose output (-vv for very verbose)
35 -x stylesheet use the specified stylesheet instead of choosing one
36 -m fragment use the XSL fragment to customize the stylesheet
37 -o directory put output in the specified directory instead of
38 the current working directory
39 -p postprocopts pass option to postprocessor
40 --extensions turn on stylesheet extensions for this tool chain
41 --searchpath colon-separated list of fallback directories
43 do not attempt to validate the input before processing
44 --stringparam paramname=paramvalue
45 pass a named parameter to the stylesheet from the
47 --noclean temp files are not deleted automatically
48 (good for diagnostics)
49 --noautosize do not autodetect paper size via locales or paperconf
50 --with-fop use fop for formatting (if fop available)
51 --with-dblatex use dblatex for formatting (if dblatex available)
53 Available FORMATs depend on the type of the XML file (which is
54 determined automatically).
56 if [ -d "$FORMAT_DIR" ]
58 for source in $(${FIND} "$FORMAT_DIR" -maxdepth 1 -type d)
60 if [ "$source" = "$FORMAT_DIR" ]; then continue; fi
64 For documents of type "$(basename "$source")":
71 # make_temp [-d] filenametag varname [message upon failure]
73 # Wrapper for 'varname=$(mktemp /tmp/xmlto-$filenametag.XXXXXX)'.
74 # * Remembers the temporary file's name so it can be deleted on exit
75 # * If the failure message is empty or missing, exits on failure
77 local dirflag="" prefix="@PACKAGE@"
78 [ "$1" = "-d" ] && { dirflag="-d"; shift; }
79 [ -n "$1" ] && prefix="@PACKAGE@-$1"
81 if eval $2='$(${MKTEMP} $dirflag "${TMPDIR:-/tmp}/${prefix}.XXXXXX")'
83 eval 'CLEANFILES[$CLEANFILE_COUNT]="${'$2'}"'
84 CLEANFILE_COUNT=$(($CLEANFILE_COUNT + 1))
88 echo >&2 "mktemp failed!"
91 echo >&2 "mktemp failed. $3"
96 # Allow FORMAT_DIR to be over-ridden, so that we can be
97 # run from the build directory.
99 : ${FORMAT_DIR=@datarootdir@/@PACKAGE@/format}
100 # This can be over-ridden, but really we should detect the source
101 # document type without needing any help.
102 : ${SOURCE_FORMAT=docbook}
104 # Get absolute pathnames for FORMAT_DIR and OUTPUT_DIR.
106 if [ "x${FORMAT_DIR##/*}" != "x" ]
108 FORMAT_DIR="${PWD}/${FORMAT_DIR}"
112 # This is an array of XSL fragments specified by the user.
116 # List of files to remove after exit
117 declare -a CLEANFILES
119 trap -- 'cd /; [ -z "${CLEANFILES[*]}" ] || rm -rf "${CLEANFILES[@]}"' EXIT
123 PAPERCONF_PATH=@PAPER_CONF@
125 XMLLINT_PATH=@XMLLINT@
126 XSLTPROC_PATH=@XSLTPROC@
128 # Try to setup papersize using libpaper first ...
129 if [ -n "`type -t $PAPERCONF_PATH`" ]
131 papername=`"$PAPERCONF_PATH" -n`
132 paperheight=`"$PAPERCONF_PATH" -mh | sed 's/ //g'`
133 paperwidth=`"$PAPERCONF_PATH" -mw | sed 's/ //g'`
135 if [ -n "$paperheight" -a -n "$paperwidth" ]
137 make_temp xsl papersizemod "Using default paper type." &&
138 cat << EOF > "$papersizemod"
139 <?xml version='1.0'?>
140 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
142 <xsl:param name="page.height">$paperheight</xsl:param>
143 <xsl:param name="page.width">$paperwidth</xsl:param>
144 <xsl:template name="root.messages">
146 <xsl:text>Making </xsl:text>
147 <xsl:value-of select="\$page.orientation"/>
148 <xsl:text> pages on $papername paper (</xsl:text>
149 <xsl:value-of select="\$page.width"/>
150 <xsl:text>x</xsl:text>
151 <xsl:value-of select="\$page.height"/>
152 <xsl:text>)</xsl:text>
159 # ... or use magic paper size, based on LC_PAPER
160 elif [ -n "`type -t $LOCALE_PATH`" ]
162 # For paper sizes we know about, specify them.
163 h=$("$LOCALE_PATH" LC_PAPER 2>/dev/null | head -n 1)
169 if [ -n "$papertype" ]
171 make_temp xsl papersizemod "Using default paper type." &&
172 cat << EOF > "$papersizemod"
173 <?xml version='1.0'?>
174 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
176 <xsl:param name="paper.type" select="'$papertype'"/>
182 # Magic encoding, based on locale
183 if [ -n "`type -t $LOCALE_PATH`" ]
185 charmap=$("$LOCALE_PATH" charmap 2>/dev/null)
189 if make_temp xsl encodingmod "Using default output encoding."
191 cat << EOF > "$encodingmod"
192 <?xml version='1.0'?>
193 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
195 <xsl:param name="chunker.output.encoding" select="'$charmap'"/>
196 <xsl:param name="man.charmap.use.subset" select="'0'"/>
199 XSL_MODS[$XSL_MOD_COUNT]="$encodingmod"
200 XSL_MOD_COUNT=$(($XSL_MOD_COUNT + 1))
205 # Make verbosity level uniformly available to called scripts
209 # Disable network entities
210 XSLTOPTS="$XSLTOPTS --nonet"
212 # The names parameter for the XSLT stylesheet
216 XSLTOPTS="$XSLTOPTS --xinclude"
222 #actual possibilities DEFAULT(XSL-FO/passivetex), FOP and DBLATEX
223 USE_BACKEND=@BACKEND@
227 DBLATEX_PATH=@DBLATEX@
230 PDFXMLTEX_PATH=@PDFXMLTEX@
232 #check if we could use fop/dblatex backend as default(if not, use passivetex)
233 if [ x"$USE_BACKEND" = xFOP ] && [ -z "`type -t $FOP_PATH`" ]
235 echo >&2 "@PACKAGE@: Warning: fop not found or not executable."
236 echo >&2 "@PACKAGE@: Using default backend..."
239 if [ x"$USE_BACKEND" = xDBLATEX ] && \
240 [ -z "`type -t $DBLATEX_PATH`" ]
242 echo >&2 "@PACKAGE@: Warning: dblatex not found or not executable."
243 echo >&2 "@PACKAGE@: Using default backend..."
252 # Process any options
254 --longoptions=help,version,extensions,searchpath:,skip-validation,stringparam:,noclean,noautosize,with-fop,with-dblatex \
255 -n xmlto -- x:m:o:p:v "$@")
256 [ $? != 0 ] && { usage; exit 1; }
258 while [ "$#" -gt "0" ]; do
270 -) make_temp stdin-xsl TMP_STYLESHEET
271 cat /dev/stdin > ${TMP_STYLESHEET}
272 STYLESHEET=${TMP_STYLESHEET} ;;
273 /*) STYLESHEET="$2" ;;
274 *) STYLESHEET="$PWD/$2" ;;
280 /* | *:/*) XSL_MODS[$XSL_MOD_COUNT]="$2" ;;
281 *) XSL_MODS[$XSL_MOD_COUNT]="$PWD/$2" ;;
283 XSL_MOD_COUNT=$(($XSL_MOD_COUNT + 1))
288 /*) OUTPUT_DIR="$2" ;;
289 *) OUTPUT_DIR="$WD/$2" ;;
296 *) POSTPOSTARGS="$2" ;;
301 # Turn on extensions for whatever tools we are using.
302 # XSLTOPTS will be done later(once we will know which
303 # tool is used for processing)
305 XSLTOPTS="$XSLTOPTS --param use.extensions '1'"
310 VERBOSE=$((${VERBOSE}+1))
314 SEARCHPATH="$SEARCHPATH:$2"
315 SEARCHPATH="${SEARCHPATH#:}"
316 SEARCHPATH="${SEARCHPATH%:}"
325 XSLTPARAMS="$XSLTPARAMS --stringparam ${MYPARAM%=*}"
326 XSLTPARAMS="$XSLTPARAMS ${MYPARAM#*=}"
330 trap -- 'cd /; [ -z "${CLEANFILES[*]}" ] || echo "${CLEANFILES[@]}"' EXIT
338 ##use fop instead of passivetex where possible
339 if [ -z "`type -t $FOP_PATH`" ]
341 echo >&2 Warning: fop not found or not executable.
342 echo >&2 Using default backend...
349 ##use dblatex instead of passivetex where possible
350 if [ -z "`type -t $DBLATEX_PATH`" ]
352 echo >&2 Warning: dblatex not found or not executable.
353 echo >&2 Using default backend...
355 USE_BACKEND="DBLATEX"
366 ##here we would decide which extensions should be active
367 if [ "$EXTENSIONS" -eq 1 ]
369 case "$USE_BACKEND" in
371 #maybe fop1.extensions for latest fop, but keeping this one
372 XSLTOPTS="$XSLTOPTS --param fop.extensions '1'" ;;
376 XSLTOPTS="$XSLTOPTS --param passivetex.extensions '1'" ;;
388 /*) INPUT_FILE="$2" ;;
389 *) INPUT_FILE="$PWD/$2" ;;
392 if [ -z "$DEST_FORMAT" -o -z "$INPUT_FILE" ]
398 [ ! -e "$INPUT_FILE" ] && echo >&2 Input file "$INPUT_FILE" not found && \
401 # Since we know DEST_FORMAT, we know whether or not to use $papersizemod.
402 case "$DEST_FORMAT" in
404 if [ "$NO_AUTOSIZE" -eq 0 ] && [ -n "$papersizemod" ]
406 XSL_MODS[$XSL_MOD_COUNT]="$papersizemod"
407 XSL_MOD_COUNT=$(($XSL_MOD_COUNT + 1))
413 # Decide what source format this is. Default to DocBook.
414 #rootel=$(head -n 4 "$INPUT_FILE" | tr -d '\n' | \
415 # sed -e 's/^<?[^?>]*?>//g' -e 's/^<![^>]*>//g' -e 's/^<\([^ ]*\).*$/\1/')
417 # Seems reasonable fix the file command and teach it to identify the DTD/Schema but this is faster to write:
418 rootel=$(echo "xpath *" | "$XMLLINT_PATH" --shell "$INPUT_FILE" 2> /dev/null | head -n 3 |$TAIL -n 1 | cut -f 4 -d " " )
420 case $(echo $rootel) in
425 SOURCE_FORMAT="xhtml1"
429 [ "$VERBOSE" -ge 1 ] && \
430 echo >&2 "Source format: ${SOURCE_FORMAT} / root element: ${rootel} "
432 # If the destination format is an absolute pathname then it's a
433 # user-defined format script. Otherwise it's one of ours.
434 case "$DEST_FORMAT" in
435 /*) FORMAT="$DEST_FORMAT" ;;
436 *) FORMAT="${FORMAT_DIR}/${SOURCE_FORMAT}/${DEST_FORMAT}" ;;
439 [ "$VERBOSE" -ge 1 ] && echo >&2 "Format script: ${FORMAT}"
441 if [ ! -e "$FORMAT" ]
443 echo >&2 "I don't know how to convert ${SOURCE_FORMAT} into ${DEST_FORMAT}."
447 # Ask the format script what stylesheet to use.
448 XSLT_PROCESSOR="$XSLTPROC_PATH" # We only know about xsltproc right now.
449 export XSLT_PROCESSOR
457 export PDFXMLTEX_PATH
459 if [ -z "$STYLESHEET" ]
461 STYLESHEET="$(${BASH} "$FORMAT" stylesheet)" || exit 1
464 # We might need to create a temporary stylesheet if there are
465 # XSL fragments that need adding.
466 if [ "$XSL_MOD_COUNT" -gt "0" -a -n "$STYLESHEET" ]
468 REAL_STYLESHEET="$STYLESHEET"
469 [ "$VERBOSE" -ge 1 ] && echo >&2 "Real stylesheet: ${REAL_STYLESHEET}"
470 make_temp xsl STYLESHEET
471 cat << EOF > "$STYLESHEET"
472 <?xml version='1.0'?>
473 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
475 <xsl:import href="${REAL_STYLESHEET}"/>
479 while [ "$i" -lt "$XSL_MOD_COUNT" ]
481 cat << EOF >> "$STYLESHEET"
482 <xsl:include href="${XSL_MODS[$i]}"/>
487 cat << EOF >> "$STYLESHEET"
492 make_temp -d "" XSLT_PROCESSED_DIR
493 cd "$XSLT_PROCESSED_DIR"
496 if [ "$SKIP_VALIDATION" -eq 0 ] && [ "$SOURCE_FORMAT" != "fo" ]
498 #do we have xmllint validation tool?
499 if [ -z "`type -t $XMLLINT_PATH`" ]
501 echo >&2 "@PACKAGE@: xmllint validation tool not found or not executable."
502 echo >&2 "@PACKAGE@: Skipping validation... " \
503 "Please make sure xmllint is installed."
505 VALIDATION="${XSLT_PROCESSED_DIR}/validation-errors"
507 [ "$VERBOSE" -ge 1 ] && \
509 "$XMLLINT_PATH --noout --nonet --xinclude --postvalid --noent \"$INPUT_FILE\""
510 "$XMLLINT_PATH" --noout --nonet --xinclude --postvalid --noent "$INPUT_FILE" 2>"${VALIDATION}"
513 if [ $xmllint_status -ne 0 ]
515 echo >&2 "@PACKAGE@: $INPUT_FILE does not validate (status ${xmllint_status})"
516 echo >&2 "@PACKAGE@: Fix document syntax or use --skip-validation option"
517 cat >&2 "${VALIDATION}"
518 exit $(($xmllint_status + 10))
520 rm -f "${VALIDATION}"
524 if [ -z "${STYLESHEET}" ]
526 # No stylesheet: no XSL-T processing to do.
527 XSLT_PROCESSED="$INPUT_FILE"
530 #do we have xsltproc tool?
531 if [ -z "`type -t $XSLTPROC_PATH`" ]
533 echo >&2 "@PACKAGE@: Can't continue, xsltproc tool not found or not executable."
537 [ "$VERBOSE" -ge 1 ] && echo >&2 "Stylesheet: ${STYLESHEET}"
538 XSLT_PROCESSED="$XSLT_PROCESSED_DIR/$(basename "${INPUT_FILE%.*}").proc"
540 if [ "$VERBOSE" -gt 2 ]
542 XSLTOPTS="$XSLTOPTS -v"
545 if [ -n "$SEARCHPATH" ]
548 XSLTPATH=$(echo "$SEARCHPATH" | tr : ' ')
549 XSLTSHOWPATH="$XSLTWITHPATH \"$XSLTPATH\""
552 XSLTOPTS="$XSLTPARAMS $XSLTOPTS"
553 [ "$VERBOSE" -ge 1 ] && \
554 echo -e >&2 "$XSLTPROC_PATH ${XSLTOPTS} ${XSLTSHOWPATH}\\\\\n -o \"$XSLT_PROCESSED\" \\\\\n $STYLESHEET \\\\\n \"$INPUT_FILE\""
556 if [ -z "$XSLTWITHPATH" ]
558 "$XSLTPROC_PATH" $XSLTOPTS -o "$XSLT_PROCESSED" "$STYLESHEET" "$INPUT_FILE"
560 "$XSLTPROC_PATH" $XSLTOPTS $XSLTWITHPATH "$XSLTPATH" \
561 -o "$XSLT_PROCESSED" "$STYLESHEET" "$INPUT_FILE"
566 XSLTOPTS="${XSLTOPTS} --catalogs"
567 [ "$VERBOSE" -ge 1 ] && \
568 echo >&2 "No XML Catalogs? Trying again with --catalogs.."
569 "$XSLTPROC_PATH" $XSLTOPTS -o "$XSLT_PROCESSED" "$STYLESHEET" "$INPUT_FILE"
578 if [ ! -d "$OUTPUT_DIR" ]
580 [ "$VERBOSE" -ge 1 ] && echo >&2 "Creating output directory ${OUTPUT_DIR}"
581 mkdir -p "$OUTPUT_DIR"
584 # Run the format script in post-process mode to finish off.
588 export XSLT_PROCESSED
591 if [ "$VERBOSE" -gt 2 ]
596 ${BASH} "$FORMAT" post-process || exit 1