📄 verbatim.java
字号:
// Verbatim.java - Xalan extensions supporting DocBook verbatim environmentspackage com.nwalsh.xalan;import java.util.Stack;import java.util.StringTokenizer;import org.xml.sax.*;import org.xml.sax.helpers.AttributesImpl;import org.w3c.dom.*;import org.w3c.dom.traversal.NodeIterator;import org.apache.xerces.dom.*;import org.apache.xpath.objects.XObject;import org.apache.xpath.XPath;import org.apache.xpath.XPathContext;import org.apache.xpath.NodeSet;import org.apache.xpath.DOMHelper;import org.apache.xalan.extensions.XSLProcessorContext;import org.apache.xalan.extensions.ExpressionContext;import org.apache.xalan.transformer.TransformerImpl;import org.apache.xalan.templates.StylesheetRoot;import org.apache.xalan.templates.ElemExtensionCall;import org.apache.xalan.templates.OutputProperties;import org.apache.xalan.res.XSLTErrorResources;import org.apache.xml.utils.DOMBuilder;import org.apache.xml.utils.AttList;import org.apache.xml.utils.QName;import javax.xml.transform.stream.StreamResult;import javax.xml.transform.TransformerException;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import javax.xml.parsers.ParserConfigurationException;import com.nwalsh.xalan.Callout;import com.nwalsh.xalan.Params;/** * <p>Xalan extensions supporting DocBook verbatim environments</p> * * <p>$Id: Verbatim.java,v 1.4 2001/07/15 20:07:49 nwalsh Exp $</p> * * <p>Copyright (C) 2001 Norman Walsh.</p> * * <p>This class provides a * <a href="http://xml.apache.org/xalan">Xalan</a> * implementation of two features that would be impractical to * implement directly in XSLT: line numbering and callouts.</p> * * <p><b>Line Numbering</b></p> * <p>The <tt>numberLines</tt> family of functions 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.</p> * * <p><b>Callouts</b></p> * <p>The <tt>insertCallouts</tt> family of functions takes an * <tt>areaspec</tt> 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.</p> * * <p><b>Change Log:</b></p> * <dl> * <dt>1.0</dt> * <dd><p>Initial release.</p></dd> * </dl> * * @author Norman Walsh * <a href="mailto:ndw@nwalsh.com">ndw@nwalsh.com</a> * * @version $Id: Verbatim.java,v 1.4 2001/07/15 20:07:49 nwalsh Exp $ * */public class Verbatim { /** A stack to hold the open elements while walking through a RTF. */ private Stack elementStack = null; /** A stack to hold the temporarily closed elements. */ private Stack tempStack = null; /** The current line number. */ private int lineNumber = 0; /** The current column number. */ private int colNumber = 0; /** The modulus for line numbering (every 'modulus' line is numbered). */ private int modulus = 0; /** The width (in characters) of line numbers (for padding). */ private int width = 0; /** The separator between the line number and the verbatim text. */ private String separator = ""; /** The (sorted) array of callouts obtained from the areaspec. */ private Callout callout[] = null; /** The number of callouts in the callout array. */ private int calloutCount = 0; /** A pointer used to keep track of our position in the callout array. */ private int calloutPos = 0; /** The path to use for graphical callout decorations. */ private String graphicsPath = null; /** The extension to use for graphical callout decorations. */ private String graphicsExt = null; /** The largest callout number that can be represented graphically. */ private int graphicsMax = 10; /** Should graphic callouts use fo:external-graphics or imgs. */ private boolean graphicsFO = false; private static final String foURI = "http://www.w3.org/1999/XSL/Format"; private static final String xhURI = "http://www.w3.org/1999/xhtml"; /** * <p>Constructor for Verbatim</p> * * <p>All of the methods are static, so the constructor does nothing.</p> */ public Verbatim() { } /** * <p>Number lines in a verbatim environment.</p> * * <p>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 xalanMod line * is numbered (so if xalanMod=5, lines 1, 5, 10, 15, etc. will be * numbered. If there are fewer than xalanMod lines in the environment, * every line is numbered.</p> * * <p>xalanMod is taken from the $linenumbering.everyNth parameter.</p> * * <p>Every line number will be right justified in a string xalanWidth * 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.)</p> * * <p>xalanWidth is taken from the $linenumbering.width parameter.</p> * * <p>The xalanSep string is inserted between the line * number and the original program listing. Lines that aren't numbered * are preceded by a xalanWidth blank string and the separator.</p> * * <p>xalanSep is taken from the $linenumbering.separator parameter.</p> * * <p>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.</p> * * @param xalanRTF The result tree fragment of the verbatim environment. * * @return The modified result tree fragment. */ public DocumentFragment numberLines (ExpressionContext context, NodeIterator xalanNI) { int xalanMod = Params.getInt(context, "linenumbering.everyNth"); int xalanWidth = Params.getInt(context, "linenumbering.width"); String xalanSep = Params.getString(context, "linenumbering.separator"); DocumentFragment xalanRTF = (DocumentFragment) xalanNI.nextNode(); int numLines = countLineBreaks(xalanRTF) + 1; DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder = null; try { docBuilder = docFactory.newDocumentBuilder(); } catch (ParserConfigurationException e) { System.out.println("PCE!"); return xalanRTF; } Document doc = docBuilder.newDocument(); DocumentFragment df = doc.createDocumentFragment(); DOMBuilder db = new DOMBuilder(doc, df); elementStack = new Stack(); lineNumber = 0; modulus = numLines < xalanMod ? 1 : xalanMod; width = xalanWidth; separator = xalanSep; double log10numLines = Math.log(numLines) / Math.log(10); if (width < log10numLines + 1) { width = (int) Math.floor(log10numLines + 1); } lineNumberFragment(db, xalanRTF); return df; } /** * <p>Count the number of lines in a verbatim environment.</p> * * <p>This method walks over the nodes of a DocumentFragment and * returns the number of lines breaks that it contains.</p> * * @param node The root of the tree walk over. */ private int countLineBreaks(Node node) { int numLines = 0; if (node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE || node.getNodeType() == Node.DOCUMENT_NODE || node.getNodeType() == Node.ELEMENT_NODE) { Node child = node.getFirstChild(); while (child != null) { numLines += countLineBreaks(child); child = child.getNextSibling(); } } else if (node.getNodeType() == Node.TEXT_NODE) { String text = node.getNodeValue(); // Walk through the text node looking for newlines int pos = 0; for (int count = 0; count < text.length(); count++) { if (text.charAt(count) == '\n') { numLines++; } } } else { // nop } return numLines; } /** * <p>Build a DocumentFragment with numbered lines.</p> * * <p>This is the method that actually does the work of numbering * lines in a verbatim environment. It recursively walks through a * tree of nodes, copying the structure into the rtf. Text nodes * are examined for new lines and modified as requested by the * global line numbering parameters.</p> * * <p>When called, rtf should be an empty DocumentFragment and node * should be the first child of the result tree fragment that contains * the existing, formatted verbatim text.</p> * * @param rtf The resulting verbatim environment with numbered lines. * @param node The root of the tree to copy. */ private void lineNumberFragment(DOMBuilder rtf, Node node) { try { if (node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE || node.getNodeType() == Node.DOCUMENT_NODE) { Node child = node.getFirstChild(); while (child != null) { lineNumberFragment(rtf, child); child = child.getNextSibling(); } } else if (node.getNodeType() == Node.ELEMENT_NODE) { String ns = node.getNamespaceURI(); String localName = node.getLocalName(); String name = ((Element) node).getTagName(); rtf.startElement(ns, localName, name, copyAttributes((Element) node)); elementStack.push(node); Node child = node.getFirstChild(); while (child != null) { lineNumberFragment(rtf, child); child = child.getNextSibling(); } } else if (node.getNodeType() == Node.TEXT_NODE) { String text = node.getNodeValue(); if (lineNumber == 0) { // The first line is always numbered formatLineNumber(rtf, ++lineNumber); } // Walk through the text node looking for newlines char chars[] = text.toCharArray(); int pos = 0; for (int count = 0; count < text.length(); count++) { if (text.charAt(count) == '\n') { // This is the tricky bit; if we find a newline, make sure // it doesn't occur inside any markup. if (pos > 0) { rtf.characters(chars, 0, pos); pos = 0; } closeOpenElements(rtf); // Copy the newline to the output chars[pos++] = text.charAt(count); rtf.characters(chars, 0, pos); pos = 0; // Add the line number formatLineNumber(rtf, ++lineNumber); openClosedElements(rtf); } else { chars[pos++] = text.charAt(count); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -