// Verbatim.java - Saxon extensions supporting DocBook verbatim environments package com.nwalsh.saxon; import java.util.Stack; import java.util.StringTokenizer; import org.xml.sax.*; import org.w3c.dom.*; import javax.xml.transform.TransformerException; import com.icl.saxon.Controller; import com.icl.saxon.expr.*; import com.icl.saxon.om.*; import com.icl.saxon.pattern.*; import com.icl.saxon.Context; import com.icl.saxon.tree.*; import com.icl.saxon.functions.Extensions; import com.nwalsh.saxon.NumberLinesEmitter; import com.nwalsh.saxon.CalloutEmitter; /** *
Saxon extensions supporting DocBook verbatim environments
* *$Id: Verbatim.java 7155 2007-07-26 21:34:48Z mzjn $
* *Copyright (C) 2000 Norman Walsh.
* *This class provides a * Saxon * implementation of two features that would be impractical to * implement directly in XSLT: line numbering and callouts.
* *Line Numbering
*The numberLines method takes a result tree * fragment (assumed to contain the contents of a formatted verbatim * element in DocBook: programlisting, screen, address, literallayout, * or synopsis) and returns a result tree fragment decorated with * line numbers.
* *Callouts
*The insertCallouts method takes an * areaspec and a result tree fragment * (assumed to contain the contents of a formatted verbatim * element in DocBook: programlisting, screen, address, literallayout, * or synopsis) and returns a result tree fragment decorated with * callouts.
* *Change Log:
*Initial release.
Constructor for Verbatim
* *All of the methods are static, so the constructor does nothing.
*/ public Verbatim() { } /** *Find the string value of a stylesheet variable or parameter
* *Returns the string value of varName
in the current
* context
. Returns the empty string if the variable is
* not defined.
Setup the parameters associated with line numbering
* *This method queries the stylesheet for the variables * associated with line numbering. It is called automatically before * lines are numbered. The context is used to retrieve the values, * this allows templates to redefine these variables.
* *The following variables are queried. If the variables do not * exist, builtin defaults will be used (but you may also get a bunch * of messages from the Java interpreter).
* *linenumbering.everyNth
linenumbering.width
linenumbering.separator
linenumbering.startinglinenumber
stylesheet.result.type
Number lines in a verbatim environment
* *The extension function expects the following variables to be * available in the calling context: $linenumbering.everyNth, * $linenumbering.width, $linenumbering.separator, and * $stylesheet.result.type.
* *This method adds line numbers to a result tree fragment. Each * newline that occurs in a text node is assumed to start a new line. * The first line is always numbered, every subsequent 'everyNth' line * is numbered (so if everyNth=5, lines 1, 5, 10, 15, etc. will be * numbered. If there are fewer than everyNth lines in the environment, * every line is numbered.
* *Every line number will be right justified in a string 'width' * characters long. If the line number of the last line in the * environment is too long to fit in the specified width, the width * is automatically increased to the smallest value that can hold the * number of the last line. (In other words, if you specify the value 2 * and attempt to enumerate the lines of an environment that is 100 lines * long, the value 3 will automatically be used for every line in the * environment.)
* *The 'separator' string is inserted between the line * number and the original program listing. Lines that aren't numbered * are preceded by a 'width' blank string and the separator.
* *If inline markup extends across line breaks, markup changes are * required. All the open elements are closed before the line break and * "reopened" afterwards. The reopened elements will have the same * attributes as the originals, except that 'name' and 'id' attributes * are not duplicated if the stylesheet.result.type is "html" and * 'id' attributes will not be duplicated if the result type is "fo".
* * @param context The current stylesheet context. * @param rtf_ns The result tree fragment of the verbatim environment. * * @return The modified result tree fragment. */ public static NodeSetValue numberLines (Context context, NodeSetValue rtf_ns) { FragmentValue rtf = (FragmentValue) rtf_ns; setupLineNumbering(context); try { LineCountEmitter lcEmitter = new LineCountEmitter(); rtf.replay(lcEmitter); int numLines = lcEmitter.lineCount(); int listingModulus = numLines < modulus ? 1 : modulus; double log10numLines = Math.log(numLines) / Math.log(10); int listingWidth = width < log10numLines+1 ? (int) Math.floor(log10numLines + 1) : width; Controller controller = context.getController(); NamePool namePool = controller.getNamePool(); NumberLinesEmitter nlEmitter = new NumberLinesEmitter(controller, namePool, startinglinenumber, listingModulus, listingWidth, separator, foStylesheet); rtf.replay(nlEmitter); return nlEmitter.getResultTreeFragment(); } catch (TransformerException e) { // This "can't" happen. System.out.println("Transformer Exception in numberLines"); return rtf; } } /** *Setup the parameters associated with callouts
* *This method queries the stylesheet for the variables * associated with line numbering. It is called automatically before * callouts are processed. The context is used to retrieve the values, * this allows templates to redefine these variables.
* *The following variables are queried. If the variables do not * exist, builtin defaults will be used (but you may also get a bunch * of messages from the Java interpreter).
* *callout.graphics
callout.graphics.path
callout.graphics.extension
callout.graphics.number.limit
callout.defaultcolumn
stylesheet.result.type
Insert text callouts into a verbatim environment.
* *This method examines the areaset and area elements * in the supplied areaspec and decorates the supplied * result tree fragment with appropriate callout markers.
* *If a label attribute is supplied on an area, * its content will be used for the label, otherwise the callout * number will be used, surrounded by parenthesis. Callout numbers may * also be represented as graphics. Callouts are * numbered in document order. All of the areas in an * areaset get the same number.
* *Only the linecolumn and linerange units are * supported. If no unit is specifed, linecolumn is assumed. * If only a line is specified, the callout decoration appears in * the defaultColumn. Lines will be padded with blanks to reach the * necessary column, but callouts that are located beyond the last * line of the verbatim environment will be ignored.
* *Callouts are inserted before the character at the line/column * where they are to occur.
* *If graphical callouts are used, and the callout number is less * than or equal to the $callout.graphics.number.limit, the following image * will be generated for HTML: * *
* <img src="$callout.graphics.path/999$callout.graphics.ext" * alt="conumber"> ** * If the $stylesheet.result.type is 'fo', the following image will * be generated: * *
* <fo:external-graphic src="$callout.graphics.path/999$callout.graphics.ext"/> ** *
If the callout number exceeds $callout.graphics.number.limit, * the callout will be the callout number surrounded by * parenthesis.
* * @param context The stylesheet context. * @param areaspecNodeList The source node set that contains the areaspec. * @param rtf_ns The result tree fragment of the verbatim environment. * * @return The modified result tree fragment. */ public static NodeSetValue insertCallouts (Context context, NodeList areaspecNodeList, NodeSetValue rtf_ns) { FragmentValue rtf = (FragmentValue) rtf_ns; setupCallouts(context); try { Controller controller = context.getController(); NamePool namePool = controller.getNamePool(); CalloutEmitter cEmitter = new CalloutEmitter(controller, namePool, defaultColumn, foStylesheet, fCallout); cEmitter.setupCallouts(areaspecNodeList); rtf.replay(cEmitter); return cEmitter.getResultTreeFragment(); } catch (TransformerException e) { // This "can't" happen. System.out.println("Transformer Exception in insertCallouts"); return rtf; } } }