Source Code Cross Referenced for Verbatim.java in  » J2EE » enhydra » com » nwalsh » xalan » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » J2EE » enhydra » com.nwalsh.xalan 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        // Verbatim.java - Xalan extensions supporting DocBook verbatim environments
002:
003:        package com.nwalsh.xalan;
004:
005:        import java.util.Stack;
006:        import java.util.StringTokenizer;
007:
008:        import org.xml.sax.*;
009:        import org.xml.sax.helpers.AttributesImpl;
010:        import org.w3c.dom.*;
011:        import org.w3c.dom.traversal.NodeIterator;
012:        import org.apache.xerces.dom.*;
013:
014:        import org.apache.xpath.objects.XObject;
015:        import org.apache.xpath.XPath;
016:        import org.apache.xpath.XPathContext;
017:        import org.apache.xpath.NodeSet;
018:        import org.apache.xpath.DOMHelper;
019:        import org.apache.xalan.extensions.XSLProcessorContext;
020:        import org.apache.xalan.extensions.ExpressionContext;
021:        import org.apache.xalan.transformer.TransformerImpl;
022:        import org.apache.xalan.templates.StylesheetRoot;
023:        import org.apache.xalan.templates.ElemExtensionCall;
024:        import org.apache.xalan.templates.OutputProperties;
025:        import org.apache.xalan.res.XSLTErrorResources;
026:        import org.apache.xml.utils.DOMBuilder;
027:        import org.apache.xml.utils.AttList;
028:        import org.apache.xml.utils.QName;
029:
030:        import javax.xml.transform.stream.StreamResult;
031:        import javax.xml.transform.TransformerException;
032:        import javax.xml.parsers.DocumentBuilder;
033:        import javax.xml.parsers.DocumentBuilderFactory;
034:        import javax.xml.parsers.ParserConfigurationException;
035:
036:        import com.nwalsh.xalan.Callout;
037:        import com.nwalsh.xalan.Params;
038:
039:        /**
040:         * <p>Xalan extensions supporting DocBook verbatim environments</p>
041:         *
042:         * <p>$Id: Verbatim.java,v 1.4 2005-08-30 08:14:58 draganr Exp $</p>
043:         *
044:         * <p>Copyright (C) 2001 Norman Walsh.</p>
045:         *
046:         * <p>This class provides a
047:         * <a href="http://xml.apache.org/xalan">Xalan</a>
048:         * implementation of two features that would be impractical to
049:         * implement directly in XSLT: line numbering and callouts.</p>
050:         *
051:         * <p><b>Line Numbering</b></p>
052:         * <p>The <tt>numberLines</tt> family of functions takes a result tree
053:         * fragment (assumed to contain the contents of a formatted verbatim
054:         * element in DocBook: programlisting, screen, address, literallayout,
055:         * or synopsis) and returns a result tree fragment decorated with
056:         * line numbers.</p>
057:         *
058:         * <p><b>Callouts</b></p>
059:         * <p>The <tt>insertCallouts</tt> family of functions takes an
060:         * <tt>areaspec</tt> and a result tree fragment
061:         * (assumed to contain the contents of a formatted verbatim
062:         * element in DocBook: programlisting, screen, address, literallayout,
063:         * or synopsis) and returns a result tree fragment decorated with
064:         * callouts.</p>
065:         *
066:         * <p><b>Change Log:</b></p>
067:         * <dl>
068:         * <dt>1.0</dt>
069:         * <dd><p>Initial release.</p></dd>
070:         * </dl>
071:         *
072:         * @author Norman Walsh
073:         * <a href="mailto:ndw@nwalsh.com">ndw@nwalsh.com</a>
074:         *
075:         * @version $Id: Verbatim.java,v 1.4 2005-08-30 08:14:58 draganr Exp $
076:         *
077:         */
078:        public class Verbatim {
079:            /** A stack to hold the open elements while walking through a RTF. */
080:            private Stack elementStack = null;
081:            /** A stack to hold the temporarily closed elements. */
082:            private Stack tempStack = null;
083:            /** The current line number. */
084:            private int lineNumber = 0;
085:            /** The current column number. */
086:            private int colNumber = 0;
087:            /** The modulus for line numbering (every 'modulus' line is numbered). */
088:            private int modulus = 0;
089:            /** The width (in characters) of line numbers (for padding). */
090:            private int width = 0;
091:            /** The separator between the line number and the verbatim text. */
092:            private String separator = "";
093:            /** The (sorted) array of callouts obtained from the areaspec. */
094:            private Callout callout[] = null;
095:            /** The number of callouts in the callout array. */
096:            private int calloutCount = 0;
097:            /** A pointer used to keep track of our position in the callout array. */
098:            private int calloutPos = 0;
099:            /** The path to use for graphical callout decorations. */
100:            private String graphicsPath = null;
101:            /** The extension to use for graphical callout decorations. */
102:            private String graphicsExt = null;
103:            /** The largest callout number that can be represented graphically. */
104:            private int graphicsMax = 10;
105:            /** Should graphic callouts use fo:external-graphics or imgs. */
106:            private boolean graphicsFO = false;
107:
108:            private static final String foURI = "http://www.w3.org/1999/XSL/Format";
109:            private static final String xhURI = "http://www.w3.org/1999/xhtml";
110:
111:            /**
112:             * <p>Constructor for Verbatim</p>
113:             *
114:             * <p>All of the methods are static, so the constructor does nothing.</p>
115:             */
116:            public Verbatim() {
117:            }
118:
119:            /**
120:             * <p>Number lines in a verbatim environment.</p>
121:             *
122:             * <p>This method adds line numbers to a result tree fragment. Each
123:             * newline that occurs in a text node is assumed to start a new line.
124:             * The first line is always numbered, every subsequent xalanMod line
125:             * is numbered (so if xalanMod=5, lines 1, 5, 10, 15, etc. will be
126:             * numbered. If there are fewer than xalanMod lines in the environment,
127:             * every line is numbered.</p>
128:             *
129:             * <p>xalanMod is taken from the $linenumbering.everyNth parameter.</p>
130:             *
131:             * <p>Every line number will be right justified in a string xalanWidth
132:             * characters long. If the line number of the last line in the
133:             * environment is too long to fit in the specified width, the width
134:             * is automatically increased to the smallest value that can hold the
135:             * number of the last line. (In other words, if you specify the value 2
136:             * and attempt to enumerate the lines of an environment that is 100 lines
137:             * long, the value 3 will automatically be used for every line in the
138:             * environment.)</p>
139:             *
140:             * <p>xalanWidth is taken from the $linenumbering.width parameter.</p>
141:             *
142:             * <p>The xalanSep string is inserted between the line
143:             * number and the original program listing. Lines that aren't numbered
144:             * are preceded by a xalanWidth blank string and the separator.</p>
145:             *
146:             * <p>xalanSep is taken from the $linenumbering.separator parameter.</p>
147:             *
148:             * <p>If inline markup extends across line breaks, markup changes are
149:             * required. All the open elements are closed before the line break and
150:             * "reopened" afterwards. The reopened elements will have the same
151:             * attributes as the originals, except that 'name' and 'id' attributes
152:             * are not duplicated.</p>
153:             *
154:             * @param xalanRTF The result tree fragment of the verbatim environment.
155:             *
156:             * @return The modified result tree fragment.
157:             */
158:            public DocumentFragment numberLines(ExpressionContext context,
159:                    NodeIterator xalanNI) {
160:
161:                int xalanMod = Params.getInt(context, "linenumbering.everyNth");
162:                int xalanWidth = Params.getInt(context, "linenumbering.width");
163:                String xalanSep = Params.getString(context,
164:                        "linenumbering.separator");
165:
166:                DocumentFragment xalanRTF = (DocumentFragment) xalanNI
167:                        .nextNode();
168:                int numLines = countLineBreaks(xalanRTF) + 1;
169:
170:                DocumentBuilderFactory docFactory = DocumentBuilderFactory
171:                        .newInstance();
172:                DocumentBuilder docBuilder = null;
173:
174:                try {
175:                    docBuilder = docFactory.newDocumentBuilder();
176:                } catch (ParserConfigurationException e) {
177:                    System.out.println("PCE!");
178:                    return xalanRTF;
179:                }
180:                Document doc = docBuilder.newDocument();
181:                DocumentFragment df = doc.createDocumentFragment();
182:                DOMBuilder db = new DOMBuilder(doc, df);
183:
184:                elementStack = new Stack();
185:                lineNumber = 0;
186:                modulus = numLines < xalanMod ? 1 : xalanMod;
187:                width = xalanWidth;
188:                separator = xalanSep;
189:
190:                double log10numLines = Math.log(numLines) / Math.log(10);
191:
192:                if (width < log10numLines + 1) {
193:                    width = (int) Math.floor(log10numLines + 1);
194:                }
195:
196:                lineNumberFragment(db, xalanRTF);
197:                return df;
198:            }
199:
200:            /**
201:             * <p>Count the number of lines in a verbatim environment.</p>
202:             *
203:             * <p>This method walks over the nodes of a DocumentFragment and
204:             * returns the number of lines breaks that it contains.</p>
205:             *
206:             * @param node The root of the tree walk over.
207:             */
208:            private int countLineBreaks(Node node) {
209:                int numLines = 0;
210:
211:                if (node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE
212:                        || node.getNodeType() == Node.DOCUMENT_NODE
213:                        || node.getNodeType() == Node.ELEMENT_NODE) {
214:                    Node child = node.getFirstChild();
215:                    while (child != null) {
216:                        numLines += countLineBreaks(child);
217:                        child = child.getNextSibling();
218:                    }
219:                } else if (node.getNodeType() == Node.TEXT_NODE) {
220:                    String text = node.getNodeValue();
221:
222:                    // Walk through the text node looking for newlines
223:                    int pos = 0;
224:                    for (int count = 0; count < text.length(); count++) {
225:                        if (text.charAt(count) == '\n') {
226:                            numLines++;
227:                        }
228:                    }
229:                } else {
230:                    // nop
231:                }
232:
233:                return numLines;
234:            }
235:
236:            /**
237:             * <p>Build a DocumentFragment with numbered lines.</p>
238:             *
239:             * <p>This is the method that actually does the work of numbering
240:             * lines in a verbatim environment. It recursively walks through a
241:             * tree of nodes, copying the structure into the rtf. Text nodes
242:             * are examined for new lines and modified as requested by the
243:             * global line numbering parameters.</p>
244:             *
245:             * <p>When called, rtf should be an empty DocumentFragment and node
246:             * should be the first child of the result tree fragment that contains
247:             * the existing, formatted verbatim text.</p>
248:             *
249:             * @param rtf The resulting verbatim environment with numbered lines.
250:             * @param node The root of the tree to copy.
251:             */
252:            private void lineNumberFragment(DOMBuilder rtf, Node node) {
253:                try {
254:                    if (node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE
255:                            || node.getNodeType() == Node.DOCUMENT_NODE) {
256:                        Node child = node.getFirstChild();
257:                        while (child != null) {
258:                            lineNumberFragment(rtf, child);
259:                            child = child.getNextSibling();
260:                        }
261:                    } else if (node.getNodeType() == Node.ELEMENT_NODE) {
262:                        String ns = node.getNamespaceURI();
263:                        String localName = node.getLocalName();
264:                        String name = ((Element) node).getTagName();
265:
266:                        rtf.startElement(ns, localName, name,
267:                                copyAttributes((Element) node));
268:
269:                        elementStack.push(node);
270:
271:                        Node child = node.getFirstChild();
272:                        while (child != null) {
273:                            lineNumberFragment(rtf, child);
274:                            child = child.getNextSibling();
275:                        }
276:                    } else if (node.getNodeType() == Node.TEXT_NODE) {
277:                        String text = node.getNodeValue();
278:
279:                        if (lineNumber == 0) {
280:                            // The first line is always numbered
281:                            formatLineNumber(rtf, ++lineNumber);
282:                        }
283:
284:                        // Walk through the text node looking for newlines
285:                        char chars[] = text.toCharArray();
286:                        int pos = 0;
287:                        for (int count = 0; count < text.length(); count++) {
288:                            if (text.charAt(count) == '\n') {
289:                                // This is the tricky bit; if we find a newline, make sure
290:                                // it doesn't occur inside any markup.
291:
292:                                if (pos > 0) {
293:                                    rtf.characters(chars, 0, pos);
294:                                    pos = 0;
295:                                }
296:
297:                                closeOpenElements(rtf);
298:
299:                                // Copy the newline to the output
300:                                chars[pos++] = text.charAt(count);
301:                                rtf.characters(chars, 0, pos);
302:                                pos = 0;
303:
304:                                // Add the line number
305:                                formatLineNumber(rtf, ++lineNumber);
306:
307:                                openClosedElements(rtf);
308:                            } else {
309:                                chars[pos++] = text.charAt(count);
310:                            }
311:                        }
312:
313:                        if (pos > 0) {
314:                            rtf.characters(chars, 0, pos);
315:                        }
316:                    } else if (node.getNodeType() == Node.COMMENT_NODE) {
317:                        String text = node.getNodeValue();
318:                        char chars[] = text.toCharArray();
319:                        rtf.comment(chars, 0, text.length());
320:                    } else if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) {
321:                        rtf.processingInstruction(node.getNodeName(), node
322:                                .getNodeValue());
323:                    } else {
324:                        System.out
325:                                .println("Warning: unexpected node type in lineNumberFragment");
326:                    }
327:
328:                    if (node.getNodeType() == Node.ELEMENT_NODE) {
329:                        String ns = node.getNamespaceURI();
330:                        String localName = node.getLocalName();
331:                        String name = ((Element) node).getTagName();
332:                        rtf.endElement(ns, localName, name);
333:                        elementStack.pop();
334:                    }
335:                } catch (SAXException e) {
336:                    System.out.println("SAX Exception in lineNumberFragment");
337:                }
338:            }
339:
340:            /**
341:             * <p>Add a formatted line number to the result tree fragment.</p>
342:             *
343:             * <p>This method examines the global parameters that control line
344:             * number presentation (modulus, width, and separator) and adds
345:             * the appropriate text to the result tree fragment.</p>
346:             *
347:             * @param rtf The resulting verbatim environment with numbered lines.
348:             * @param lineNumber The number of the current line.
349:             */
350:            private void formatLineNumber(DOMBuilder rtf, int lineNumber) {
351:                char ch = 160;
352:                String lno = "";
353:                if (lineNumber == 1
354:                        || (modulus >= 1 && (lineNumber % modulus == 0))) {
355:                    lno = "" + lineNumber;
356:                }
357:
358:                while (lno.length() < width) {
359:                    lno = ch + lno;
360:                }
361:
362:                lno += separator;
363:
364:                char chars[] = lno.toCharArray();
365:                try {
366:                    rtf.characters(chars, 0, lno.length());
367:                } catch (SAXException e) {
368:                    System.out.println("SAX Exception in formatLineNumber");
369:                }
370:            }
371:
372:            /**
373:             * <p>Insert text callouts into a verbatim environment.</p>
374:             *
375:             * <p>This method examines the <tt>areaset</tt> and <tt>area</tt> elements
376:             * in the supplied <tt>areaspec</tt> and decorates the supplied
377:             * result tree fragment with appropriate callout markers.</p>
378:             *
379:             * <p>If a <tt>label</tt> attribute is supplied on an <tt>area</tt>,
380:             * its content will be used for the label, otherwise the callout
381:             * number will be used, surrounded by parenthesis. Callouts are
382:             * numbered in document order. All of the <tt>area</tt>s in an
383:             * <tt>areaset</tt> get the same number.</p>
384:             *
385:             * <p>Only the <tt>linecolumn</tt> and <tt>linerange</tt> units are
386:             * supported. If no unit is specifed, <tt>linecolumn</tt> is assumed.
387:             * If only a line is specified, the callout decoration appears in
388:             * the defaultColumn. Lines will be padded with blanks to reach the
389:             * necessary column, but callouts that are located beyond the last
390:             * line of the verbatim environment will be ignored.</p>
391:             *
392:             * <p>Callouts are inserted before the character at the line/column
393:             * where they are to occur.</p>
394:             *
395:             * @param areaspecNodeSet The source node set that contains the areaspec.
396:             * @param xalanRTF The result tree fragment of the verbatim environment.
397:             * @param defaultColumn The column for callouts that specify only a line.
398:             *
399:             * @return The modified result tree fragment.  */
400:
401:            /**
402:             * <p>Insert graphical callouts into a verbatim environment.</p>
403:             *
404:             * <p>This method examines the <tt>areaset</tt> and <tt>area</tt> elements
405:             * in the supplied <tt>areaspec</tt> and decorates the supplied
406:             * result tree fragment with appropriate callout markers.</p>
407:             *
408:             * <p>If a <tt>label</tt> attribute is supplied on an <tt>area</tt>,
409:             * its content will be used for the label, otherwise the callout
410:             * number will be used. Callouts are
411:             * numbered in document order. All of the <tt>area</tt>s in an
412:             * <tt>areaset</tt> get the same number.</p>
413:             *
414:             * <p>If the callout number is not greater than <tt>gMax</tt>, the
415:             * callout generated will be:</p>
416:             *
417:             * <pre>
418:             * &lt;img src="$gPath/conumber$gExt" alt="conumber">
419:             * </pre>
420:             *
421:             * <p>Otherwise, it will be the callout number surrounded by
422:             * parenthesis.</p>
423:             *
424:             * <p>Only the <tt>linecolumn</tt> and <tt>linerange</tt> units are
425:             * supported. If no unit is specifed, <tt>linecolumn</tt> is assumed.
426:             * If only a line is specified, the callout decoration appears in
427:             * the defaultColumn. Lines will be padded with blanks to reach the
428:             * necessary column, but callouts that are located beyond the last
429:             * line of the verbatim environment will be ignored.</p>
430:             *
431:             * <p>Callouts are inserted before the character at the line/column
432:             * where they are to occur.</p>
433:             *
434:             * @param areaspecNodeSet The source node set that contains the areaspec.
435:             * @param xalanRTF The result tree fragment of the verbatim environment.
436:             * @param defaultColumn The column for callouts that specify only a line.
437:             * @param gPath The path to use for callout graphics.
438:             * @param gExt The extension to use for callout graphics.
439:             * @param gMax The largest number that can be represented as a graphic.
440:             * @param useFO Should fo:external-graphics be produced, as opposed to
441:             * HTML imgs. This is bogus, the extension should figure it out, but I
442:             * haven't figured out how to do that yet.
443:             *
444:             * @return The modified result tree fragment.
445:             */
446:
447:            public DocumentFragment insertCallouts(ExpressionContext context,
448:                    NodeIterator areaspecNodeSet, NodeIterator xalanNI) {
449:                String type = Params.getString(context,
450:                        "stylesheet.result.type");
451:                boolean useFO = type.equals("fo");
452:                int defaultColumn = Params.getInt(context,
453:                        "callout.defaultcolumn");
454:
455:                if (Params.getBoolean(context, "callout.graphics")) {
456:                    String gPath = Params.getString(context,
457:                            "callout.graphics.path");
458:                    String gExt = Params.getString(context,
459:                            "callout.graphics.extension");
460:                    int gMax = Params.getInt(context,
461:                            "callout.graphics.number.limit");
462:                    return insertGraphicCallouts(areaspecNodeSet, xalanNI,
463:                            defaultColumn, gPath, gExt, gMax, useFO);
464:                } else if (Params.getBoolean(context, "callout.unicode")) {
465:                    int uStart = Params.getInt(context,
466:                            "callout.unicode.start.character");
467:                    int uMax = Params.getInt(context,
468:                            "callout.unicode.number.limit");
469:                    String uFont = Params.getString(context,
470:                            "callout.unicode.font");
471:                    return insertUnicodeCallouts(areaspecNodeSet, xalanNI,
472:                            defaultColumn, uFont, uStart, uMax, useFO);
473:                } else if (Params.getBoolean(context, "callout.dingbats")) {
474:                    int dMax = 10;
475:                    return insertDingbatCallouts(areaspecNodeSet, xalanNI,
476:                            defaultColumn, dMax, useFO);
477:                } else {
478:                    return insertTextCallouts(areaspecNodeSet, xalanNI,
479:                            defaultColumn, useFO);
480:                }
481:            }
482:
483:            public DocumentFragment insertGraphicCallouts(
484:                    NodeIterator areaspecNodeSet, NodeIterator xalanNI,
485:                    int defaultColumn, String gPath, String gExt, int gMax,
486:                    boolean useFO) {
487:                FormatGraphicCallout fgc = new FormatGraphicCallout(gPath,
488:                        gExt, gMax, useFO);
489:                return insertCallouts(areaspecNodeSet, xalanNI, defaultColumn,
490:                        fgc);
491:            }
492:
493:            public DocumentFragment insertUnicodeCallouts(
494:                    NodeIterator areaspecNodeSet, NodeIterator xalanNI,
495:                    int defaultColumn, String uFont, int uStart, int uMax,
496:                    boolean useFO) {
497:                FormatUnicodeCallout fuc = new FormatUnicodeCallout(uFont,
498:                        uStart, uMax, useFO);
499:                return insertCallouts(areaspecNodeSet, xalanNI, defaultColumn,
500:                        fuc);
501:            }
502:
503:            public DocumentFragment insertDingbatCallouts(
504:                    NodeIterator areaspecNodeSet, NodeIterator xalanNI,
505:                    int defaultColumn, int gMax, boolean useFO) {
506:                FormatDingbatCallout fdc = new FormatDingbatCallout(gMax, useFO);
507:                return insertCallouts(areaspecNodeSet, xalanNI, defaultColumn,
508:                        fdc);
509:            }
510:
511:            public DocumentFragment insertTextCallouts(
512:                    NodeIterator areaspecNodeSet, NodeIterator xalanNI,
513:                    int defaultColumn, boolean useFO) {
514:                FormatTextCallout ftc = new FormatTextCallout(useFO);
515:                return insertCallouts(areaspecNodeSet, xalanNI, defaultColumn,
516:                        ftc);
517:            }
518:
519:            public DocumentFragment insertCallouts(
520:                    NodeIterator areaspecNodeSet, NodeIterator xalanNI,
521:                    int defaultColumn, FormatCallout fCallout) {
522:
523:                DocumentFragment xalanRTF = (DocumentFragment) xalanNI
524:                        .nextNode();
525:
526:                callout = new Callout[10];
527:                calloutCount = 0;
528:                calloutPos = 0;
529:                lineNumber = 1;
530:                colNumber = 1;
531:
532:                // First we walk through the areaspec to calculate the position
533:                // of the callouts
534:                //  <areaspec>
535:                //  <areaset id="ex.plco.const" coords="">
536:                //    <area id="ex.plco.c1" coords="4"/>
537:                //    <area id="ex.plco.c2" coords="8"/>
538:                //  </areaset>
539:                //  <area id="ex.plco.ret" coords="12"/>
540:                //  <area id="ex.plco.dest" coords="12"/>
541:                //  </areaspec>
542:                int pos = 0;
543:                int coNum = 0;
544:                boolean inAreaSet = false;
545:                Node node = areaspecNodeSet.nextNode();
546:                node = node.getFirstChild();
547:                while (node != null) {
548:                    if (node.getNodeType() == Node.ELEMENT_NODE) {
549:                        if (node.getNodeName().equals("areaset")) {
550:                            coNum++;
551:                            Node area = node.getFirstChild();
552:                            while (area != null) {
553:                                if (area.getNodeType() == Node.ELEMENT_NODE) {
554:                                    if (area.getNodeName().equals("area")) {
555:                                        addCallout(coNum, area, defaultColumn);
556:                                    } else {
557:                                        System.out
558:                                                .println("Unexpected element in areaset: "
559:                                                        + area.getNodeName());
560:                                    }
561:                                }
562:                                area = area.getNextSibling();
563:                            }
564:                        } else if (node.getNodeName().equalsIgnoreCase("area")) {
565:                            coNum++;
566:                            addCallout(coNum, node, defaultColumn);
567:                        } else {
568:                            System.out
569:                                    .println("Unexpected element in areaspec: "
570:                                            + node.getNodeName());
571:                        }
572:                    }
573:
574:                    node = node.getNextSibling();
575:                }
576:
577:                // Now sort them
578:                java.util.Arrays.sort(callout, 0, calloutCount);
579:
580:                DocumentBuilderFactory docFactory = DocumentBuilderFactory
581:                        .newInstance();
582:                DocumentBuilder docBuilder = null;
583:
584:                try {
585:                    docBuilder = docFactory.newDocumentBuilder();
586:                } catch (ParserConfigurationException e) {
587:                    System.out.println("PCE 2!");
588:                    return xalanRTF;
589:                }
590:                Document doc = docBuilder.newDocument();
591:                DocumentFragment df = doc.createDocumentFragment();
592:                DOMBuilder db = new DOMBuilder(doc, df);
593:
594:                elementStack = new Stack();
595:                calloutFragment(db, xalanRTF, fCallout);
596:                return df;
597:            }
598:
599:            /**
600:             * <p>Build a FragmentValue with callout decorations.</p>
601:             *
602:             * <p>This is the method that actually does the work of adding
603:             * callouts to a verbatim environment. It recursively walks through a
604:             * tree of nodes, copying the structure into the rtf. Text nodes
605:             * are examined for the position of callouts as described by the
606:             * global callout parameters.</p>
607:             *
608:             * <p>When called, rtf should be an empty FragmentValue and node
609:             * should be the first child of the result tree fragment that contains
610:             * the existing, formatted verbatim text.</p>
611:             *
612:             * @param rtf The resulting verbatim environment with numbered lines.
613:             * @param node The root of the tree to copy.
614:             */
615:            private void calloutFragment(DOMBuilder rtf, Node node,
616:                    FormatCallout fCallout) {
617:                try {
618:                    if (node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE
619:                            || node.getNodeType() == Node.DOCUMENT_NODE) {
620:                        Node child = node.getFirstChild();
621:                        while (child != null) {
622:                            calloutFragment(rtf, child, fCallout);
623:                            child = child.getNextSibling();
624:                        }
625:                    } else if (node.getNodeType() == Node.ELEMENT_NODE) {
626:                        String ns = node.getNamespaceURI();
627:                        String localName = node.getLocalName();
628:                        String name = ((Element) node).getTagName();
629:
630:                        rtf.startElement(ns, localName, name,
631:                                copyAttributes((Element) node));
632:
633:                        elementStack.push(node);
634:
635:                        Node child = node.getFirstChild();
636:                        while (child != null) {
637:                            calloutFragment(rtf, child, fCallout);
638:                            child = child.getNextSibling();
639:                        }
640:                    } else if (node.getNodeType() == Node.TEXT_NODE) {
641:                        String text = node.getNodeValue();
642:
643:                        char chars[] = text.toCharArray();
644:                        int pos = 0;
645:                        for (int count = 0; count < text.length(); count++) {
646:                            if (calloutPos < calloutCount
647:                                    && callout[calloutPos].getLine() == lineNumber
648:                                    && callout[calloutPos].getColumn() == colNumber) {
649:                                if (pos > 0) {
650:                                    rtf.characters(chars, 0, pos);
651:                                    pos = 0;
652:                                }
653:
654:                                closeOpenElements(rtf);
655:
656:                                while (calloutPos < calloutCount
657:                                        && callout[calloutPos].getLine() == lineNumber
658:                                        && callout[calloutPos].getColumn() == colNumber) {
659:                                    fCallout.formatCallout(rtf,
660:                                            callout[calloutPos]);
661:                                    calloutPos++;
662:                                }
663:
664:                                openClosedElements(rtf);
665:                            }
666:
667:                            if (text.charAt(count) == '\n') {
668:                                // What if we need to pad this line?
669:                                if (calloutPos < calloutCount
670:                                        && callout[calloutPos].getLine() == lineNumber
671:                                        && callout[calloutPos].getColumn() > colNumber) {
672:
673:                                    if (pos > 0) {
674:                                        rtf.characters(chars, 0, pos);
675:                                        pos = 0;
676:                                    }
677:
678:                                    closeOpenElements(rtf);
679:
680:                                    while (calloutPos < calloutCount
681:                                            && callout[calloutPos].getLine() == lineNumber
682:                                            && callout[calloutPos].getColumn() > colNumber) {
683:                                        formatPad(rtf, callout[calloutPos]
684:                                                .getColumn()
685:                                                - colNumber);
686:                                        colNumber = callout[calloutPos]
687:                                                .getColumn();
688:                                        while (calloutPos < calloutCount
689:                                                && callout[calloutPos]
690:                                                        .getLine() == lineNumber
691:                                                && callout[calloutPos]
692:                                                        .getColumn() == colNumber) {
693:                                            fCallout.formatCallout(rtf,
694:                                                    callout[calloutPos]);
695:                                            calloutPos++;
696:                                        }
697:                                    }
698:
699:                                    openClosedElements(rtf);
700:                                }
701:
702:                                lineNumber++;
703:                                colNumber = 1;
704:                            } else {
705:                                colNumber++;
706:                            }
707:                            chars[pos++] = text.charAt(count);
708:                        }
709:
710:                        if (pos > 0) {
711:                            rtf.characters(chars, 0, pos);
712:                        }
713:                    } else if (node.getNodeType() == Node.COMMENT_NODE) {
714:                        String text = node.getNodeValue();
715:                        char chars[] = text.toCharArray();
716:                        rtf.comment(chars, 0, text.length());
717:                    } else if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) {
718:                        rtf.processingInstruction(node.getNodeName(), node
719:                                .getNodeValue());
720:                    } else {
721:                        System.out
722:                                .println("Warning: unexpected node type in calloutFragment: "
723:                                        + node.getNodeType()
724:                                        + ": "
725:                                        + node.getNodeName());
726:                    }
727:
728:                    if (node.getNodeType() == Node.ELEMENT_NODE) {
729:                        String ns = node.getNamespaceURI();
730:                        String localName = node.getLocalName();
731:                        String name = ((Element) node).getTagName();
732:                        rtf.endElement(ns, localName, name);
733:                        elementStack.pop();
734:                    } else {
735:                        // nop
736:                    }
737:                } catch (SAXException e) {
738:                    System.out.println("SAX Exception in calloutFragment");
739:                }
740:            }
741:
742:            /**
743:             * <p>Add a callout to the global callout array</p>
744:             *
745:             * <p>This method examines a callout <tt>area</tt> and adds it to
746:             * the global callout array if it can be interpreted.</p>
747:             *
748:             * <p>Only the <tt>linecolumn</tt> and <tt>linerange</tt> units are
749:             * supported. If no unit is specifed, <tt>linecolumn</tt> is assumed.
750:             * If only a line is specified, the callout decoration appears in
751:             * the <tt>defaultColumn</tt>.</p>
752:             *
753:             * @param coNum The callout number.
754:             * @param node The <tt>area</tt>.
755:             * @param defaultColumn The default column for callouts.
756:             */
757:            private void addCallout(int coNum, Node node, int defaultColumn) {
758:                Element area = (Element) node;
759:
760:                String units = area.getAttribute("units");
761:                String otherUnits = area.getAttribute("otherunits");
762:                String coords = area.getAttribute("coords");
763:                int type = 0;
764:                String otherType = null;
765:
766:                if (units == null || units.equals("linecolumn")) {
767:                    type = Callout.LINE_COLUMN; // the default
768:                } else if (units.equals("linerange")) {
769:                    type = Callout.LINE_RANGE;
770:                } else if (units.equals("linecolumnpair")) {
771:                    type = Callout.LINE_COLUMN_PAIR;
772:                } else if (units.equals("calspair")) {
773:                    type = Callout.CALS_PAIR;
774:                } else {
775:                    type = Callout.OTHER;
776:                    otherType = otherUnits;
777:                }
778:
779:                if (type != Callout.LINE_COLUMN && type != Callout.LINE_RANGE) {
780:                    System.out
781:                            .println("Only linecolumn and linerange units are supported");
782:                    return;
783:                }
784:
785:                if (coords == null) {
786:                    System.out.println("Coords must be specified");
787:                    return;
788:                }
789:
790:                // Now let's see if we can interpret the coordinates...
791:                StringTokenizer st = new StringTokenizer(coords);
792:                int tokenCount = 0;
793:                int c1 = 0;
794:                int c2 = 0;
795:                while (st.hasMoreTokens()) {
796:                    tokenCount++;
797:                    if (tokenCount > 2) {
798:                        System.out.println("Unparseable coordinates");
799:                        return;
800:                    }
801:                    try {
802:                        String token = st.nextToken();
803:                        int coord = Integer.parseInt(token);
804:                        c2 = coord;
805:                        if (tokenCount == 1) {
806:                            c1 = coord;
807:                        }
808:                    } catch (NumberFormatException e) {
809:                        System.out.println("Unparseable coordinate");
810:                        return;
811:                    }
812:                }
813:
814:                // Make sure we aren't going to blow past the end of our array
815:                if (calloutCount == callout.length) {
816:                    Callout bigger[] = new Callout[calloutCount + 10];
817:                    for (int count = 0; count < callout.length; count++) {
818:                        bigger[count] = callout[count];
819:                    }
820:                    callout = bigger;
821:                }
822:
823:                // Ok, add the callout
824:                if (tokenCount == 2) {
825:                    if (type == Callout.LINE_RANGE) {
826:                        for (int count = c1; count <= c2; count++) {
827:                            callout[calloutCount++] = new Callout(coNum, area,
828:                                    count, defaultColumn, type);
829:                        }
830:                    } else {
831:                        // assume linecolumn
832:                        callout[calloutCount++] = new Callout(coNum, area, c1,
833:                                c2, type);
834:                    }
835:                } else {
836:                    // if there's only one number, assume it's the line
837:                    callout[calloutCount++] = new Callout(coNum, area, c1,
838:                            defaultColumn, type);
839:                }
840:            }
841:
842:            /**
843:             * <p>Add blanks to the result tree fragment.</p>
844:             *
845:             * <p>This method adds <tt>numBlanks</tt> to the result tree fragment.
846:             * It's used to pad lines when callouts occur after the last existing
847:             * characater in a line.</p>
848:             *
849:             * @param rtf The resulting verbatim environment with numbered lines.
850:             * @param numBlanks The number of blanks to add.
851:             */
852:            private void formatPad(DOMBuilder rtf, int numBlanks) {
853:                char chars[] = new char[numBlanks];
854:                for (int count = 0; count < numBlanks; count++) {
855:                    chars[count] = ' ';
856:                }
857:
858:                try {
859:                    rtf.characters(chars, 0, numBlanks);
860:                } catch (SAXException e) {
861:                    System.out.println("SAX Exception in formatCallout");
862:                }
863:            }
864:
865:            private void closeOpenElements(DOMBuilder rtf) throws SAXException {
866:                // Close all the open elements...
867:                tempStack = new Stack();
868:                while (!elementStack.empty()) {
869:                    Node elem = (Node) elementStack.pop();
870:
871:                    String ns = elem.getNamespaceURI();
872:                    String localName = elem.getLocalName();
873:                    String name = ((Element) elem).getTagName();
874:
875:                    // If this is the bottom of the stack and it's an fo:block
876:                    // or an HTML pre or div, don't duplicate it...
877:                    if (elementStack.empty()
878:                            && (((ns != null) && ns.equals(foURI) && localName
879:                                    .equals("block"))
880:                                    || (((ns == null) && localName
881:                                            .equalsIgnoreCase("pre")) || ((ns != null)
882:                                            && ns.equals(xhURI) && localName
883:                                            .equals("pre"))) || (((ns == null) && localName
884:                                    .equalsIgnoreCase("div")) || ((ns != null)
885:                                    && ns.equals(xhURI) && localName
886:                                    .equals("div"))))) {
887:                        elementStack.push(elem);
888:                        break;
889:                    } else {
890:                        rtf.endElement(ns, localName, name);
891:                        tempStack.push(elem);
892:                    }
893:                }
894:            }
895:
896:            private void openClosedElements(DOMBuilder rtf) throws SAXException {
897:                // Now "reopen" the elements that we closed...
898:                while (!tempStack.empty()) {
899:                    Node elem = (Node) tempStack.pop();
900:
901:                    String ns = elem.getNamespaceURI();
902:                    String localName = elem.getLocalName();
903:                    String name = ((Element) elem).getTagName();
904:                    NamedNodeMap domAttr = elem.getAttributes();
905:
906:                    AttributesImpl attr = new AttributesImpl();
907:                    for (int acount = 0; acount < domAttr.getLength(); acount++) {
908:                        Node a = domAttr.item(acount);
909:
910:                        if (((ns == null || ns == "http://www.w3.org/1999/xhtml") && localName
911:                                .equalsIgnoreCase("a"))
912:                                || (a.getLocalName().equalsIgnoreCase("id"))) {
913:                            // skip this attribute
914:                        } else {
915:                            attr.addAttribute(a.getNamespaceURI(), a
916:                                    .getLocalName(), a.getNodeName(), "CDATA",
917:                                    a.getNodeValue());
918:                        }
919:                    }
920:
921:                    rtf.startElement(ns, localName, name, attr);
922:                    elementStack.push(elem);
923:                }
924:
925:                tempStack = null;
926:            }
927:
928:            private Attributes copyAttributes(Element node) {
929:                AttributesImpl attrs = new AttributesImpl();
930:                NamedNodeMap nnm = node.getAttributes();
931:                for (int count = 0; count < nnm.getLength(); count++) {
932:                    Attr attr = (Attr) nnm.item(count);
933:                    String name = attr.getName();
934:                    if (name.startsWith("xmlns:") || name.equals("xmlns")) {
935:                        // Skip it; (don't ya just love it!!)
936:                    } else {
937:                        attrs.addAttribute(attr.getNamespaceURI(), attr
938:                                .getName(), attr.getName(), "CDATA", attr
939:                                .getValue());
940:                    }
941:                }
942:                return attrs;
943:            }
944:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.