Source Code Cross Referenced for Verbatim.java in  » Search-Engine » snapper » 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 » Search Engine » snapper » 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.Attributes;
009:        import org.xml.sax.SAXException;
010:
011:        import org.w3c.dom.Attr;
012:        import org.w3c.dom.Document;
013:        import org.w3c.dom.DocumentFragment;
014:        import org.w3c.dom.NamedNodeMap;
015:        import org.w3c.dom.Node;
016:        import org.w3c.dom.Element;
017:        import org.w3c.dom.traversal.NodeIterator;
018:
019:        import org.apache.xpath.objects.XObject;
020:        import org.apache.xpath.XPath;
021:        import org.apache.xpath.XPathContext;
022:        import org.apache.xpath.NodeSet;
023:        import org.apache.xalan.extensions.XSLProcessorContext;
024:        import org.apache.xalan.extensions.ExpressionContext;
025:        import org.apache.xalan.transformer.TransformerImpl;
026:        import org.apache.xalan.templates.StylesheetRoot;
027:        import org.apache.xalan.templates.ElemExtensionCall;
028:        import org.apache.xalan.templates.OutputProperties;
029:        import org.apache.xalan.res.XSLTErrorResources;
030:        import org.apache.xml.utils.DOMBuilder;
031:        import org.apache.xml.utils.AttList;
032:        import org.apache.xml.utils.QName;
033:
034:        import javax.xml.transform.stream.StreamResult;
035:        import javax.xml.transform.TransformerException;
036:        import javax.xml.parsers.DocumentBuilder;
037:        import javax.xml.parsers.DocumentBuilderFactory;
038:        import javax.xml.parsers.ParserConfigurationException;
039:
040:        import com.nwalsh.xalan.Callout;
041:        import com.nwalsh.xalan.Params;
042:        import org.xml.sax.helpers.AttributesImpl;
043:
044:        /**
045:         * <p>Xalan extensions supporting DocBook verbatim environments</p>
046:         *
047:         * <p>$Id: Verbatim.java,v 1.1 2007-05-18 15:03:13 sinisa Exp $</p>
048:         *
049:         * <p>Copyright (C) 2001 Norman Walsh.</p>
050:         *
051:         * <p>This class provides a
052:         * <a href="http://xml.apache.org/xalan-j/">Xalan</a>
053:         * implementation of two features that would be impractical to
054:         * implement directly in XSLT: line numbering and callouts.</p>
055:         *
056:         * <p><b>Line Numbering</b></p>
057:         * <p>The <tt>numberLines</tt> family of functions takes a result tree
058:         * fragment (assumed to contain the contents of a formatted verbatim
059:         * element in DocBook: programlisting, screen, address, literallayout,
060:         * or synopsis) and returns a result tree fragment decorated with
061:         * line numbers.</p>
062:         *
063:         * <p><b>Callouts</b></p>
064:         * <p>The <tt>insertCallouts</tt> family of functions takes an
065:         * <tt>areaspec</tt> and a result tree fragment
066:         * (assumed to contain the contents of a formatted verbatim
067:         * element in DocBook: programlisting, screen, address, literallayout,
068:         * or synopsis) and returns a result tree fragment decorated with
069:         * callouts.</p>
070:         *
071:         * <p><b>Change Log:</b></p>
072:         * <dl>
073:         * <dt>1.0</dt>
074:         * <dd><p>Initial release.</p></dd>
075:         * </dl>
076:         *
077:         * @author Norman Walsh
078:         * <a href="mailto:ndw@nwalsh.com">ndw@nwalsh.com</a>
079:         *
080:         * @version $Id: Verbatim.java,v 1.1 2007-05-18 15:03:13 sinisa Exp $
081:         *
082:         */
083:        public class Verbatim {
084:            /** A stack to hold the open elements while walking through a RTF. */
085:            private Stack elementStack = null;
086:            /** A stack to hold the temporarily closed elements. */
087:            private Stack tempStack = null;
088:            /** The current line number. */
089:            private int lineNumber = 0;
090:            /** The current column number. */
091:            private int colNumber = 0;
092:            /** The modulus for line numbering (every 'modulus' line is numbered). */
093:            private int modulus = 0;
094:            /** The width (in characters) of line numbers (for padding). */
095:            private int width = 0;
096:            /** The separator between the line number and the verbatim text. */
097:            private String separator = "";
098:            /** The (sorted) array of callouts obtained from the areaspec. */
099:            private Callout callout[] = null;
100:            /** The number of callouts in the callout array. */
101:            private int calloutCount = 0;
102:            /** A pointer used to keep track of our position in the callout array. */
103:            private int calloutPos = 0;
104:            /** The path to use for graphical callout decorations. */
105:            private String graphicsPath = null;
106:            /** The extension to use for graphical callout decorations. */
107:            private String graphicsExt = null;
108:            /** The largest callout number that can be represented graphically. */
109:            private int graphicsMax = 10;
110:            /** Should graphic callouts use fo:external-graphics or imgs. */
111:            private boolean graphicsFO = false;
112:
113:            private static final String foURI = "http://www.w3.org/1999/XSL/Format";
114:            private static final String xhURI = "http://www.w3.org/1999/xhtml";
115:
116:            /**
117:             * <p>Constructor for Verbatim</p>
118:             *
119:             * <p>All of the methods are static, so the constructor does nothing.</p>
120:             */
121:            public Verbatim() {
122:            }
123:
124:            /**
125:             * <p>Number lines in a verbatim environment.</p>
126:             *
127:             * <p>This method adds line numbers to a result tree fragment. Each
128:             * newline that occurs in a text node is assumed to start a new line.
129:             * The first line is always numbered, every subsequent xalanMod line
130:             * is numbered (so if xalanMod=5, lines 1, 5, 10, 15, etc. will be
131:             * numbered. If there are fewer than xalanMod lines in the environment,
132:             * every line is numbered.</p>
133:             *
134:             * <p>xalanMod is taken from the $linenumbering.everyNth parameter.</p>
135:             *
136:             * <p>Every line number will be right justified in a string xalanWidth
137:             * characters long. If the line number of the last line in the
138:             * environment is too long to fit in the specified width, the width
139:             * is automatically increased to the smallest value that can hold the
140:             * number of the last line. (In other words, if you specify the value 2
141:             * and attempt to enumerate the lines of an environment that is 100 lines
142:             * long, the value 3 will automatically be used for every line in the
143:             * environment.)</p>
144:             *
145:             * <p>xalanWidth is taken from the $linenumbering.width parameter.</p>
146:             *
147:             * <p>The xalanSep string is inserted between the line
148:             * number and the original program listing. Lines that aren't numbered
149:             * are preceded by a xalanWidth blank string and the separator.</p>
150:             *
151:             * <p>xalanSep is taken from the $linenumbering.separator parameter.</p>
152:             *
153:             * <p>If inline markup extends across line breaks, markup changes are
154:             * required. All the open elements are closed before the line break and
155:             * "reopened" afterwards. The reopened elements will have the same
156:             * attributes as the originals, except that 'name' and 'id' attributes
157:             * are not duplicated.</p>
158:             *
159:             * @param context
160:             * @param xalanNI
161:             *
162:             * @return The modified result tree fragment.
163:             */
164:            public DocumentFragment numberLines(ExpressionContext context,
165:                    NodeIterator xalanNI) {
166:
167:                int xalanMod = Params.getInt(context, "linenumbering.everyNth");
168:                int xalanWidth = Params.getInt(context, "linenumbering.width");
169:                String xalanSep = Params.getString(context,
170:                        "linenumbering.separator");
171:
172:                DocumentFragment xalanRTF = (DocumentFragment) xalanNI
173:                        .nextNode();
174:                int numLines = countLineBreaks(xalanRTF) + 1;
175:
176:                DocumentBuilderFactory docFactory = DocumentBuilderFactory
177:                        .newInstance();
178:                DocumentBuilder docBuilder = null;
179:
180:                try {
181:                    docBuilder = docFactory.newDocumentBuilder();
182:                } catch (ParserConfigurationException e) {
183:                    System.out.println("PCE!");
184:                    return xalanRTF;
185:                }
186:                Document doc = docBuilder.newDocument();
187:                DocumentFragment df = doc.createDocumentFragment();
188:                DOMBuilder db = new DOMBuilder(doc, df);
189:
190:                elementStack = new Stack();
191:                lineNumber = 0;
192:                modulus = numLines < xalanMod ? 1 : xalanMod;
193:                width = xalanWidth;
194:                separator = xalanSep;
195:
196:                double log10numLines = Math.log(numLines) / Math.log(10);
197:
198:                if (width < log10numLines + 1) {
199:                    width = (int) Math.floor(log10numLines + 1);
200:                }
201:
202:                lineNumberFragment(db, xalanRTF);
203:                return df;
204:            }
205:
206:            /**
207:             * <p>Count the number of lines in a verbatim environment.</p>
208:             *
209:             * <p>This method walks over the nodes of a DocumentFragment and
210:             * returns the number of lines breaks that it contains.</p>
211:             *
212:             * @param node The root of the tree walk over.
213:             */
214:            private int countLineBreaks(Node node) {
215:                int numLines = 0;
216:
217:                if (node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE
218:                        || node.getNodeType() == Node.DOCUMENT_NODE
219:                        || node.getNodeType() == Node.ELEMENT_NODE) {
220:                    Node child = node.getFirstChild();
221:                    while (child != null) {
222:                        numLines += countLineBreaks(child);
223:                        child = child.getNextSibling();
224:                    }
225:                } else if (node.getNodeType() == Node.TEXT_NODE) {
226:                    String text = node.getNodeValue();
227:
228:                    // Walk through the text node looking for newlines
229:                    int pos = 0;
230:                    for (int count = 0; count < text.length(); count++) {
231:                        if (text.charAt(count) == '\n') {
232:                            numLines++;
233:                        }
234:                    }
235:                } else {
236:                    // nop
237:                }
238:
239:                return numLines;
240:            }
241:
242:            /**
243:             * <p>Build a DocumentFragment with numbered lines.</p>
244:             *
245:             * <p>This is the method that actually does the work of numbering
246:             * lines in a verbatim environment. It recursively walks through a
247:             * tree of nodes, copying the structure into the rtf. Text nodes
248:             * are examined for new lines and modified as requested by the
249:             * global line numbering parameters.</p>
250:             *
251:             * <p>When called, rtf should be an empty DocumentFragment and node
252:             * should be the first child of the result tree fragment that contains
253:             * the existing, formatted verbatim text.</p>
254:             *
255:             * @param rtf The resulting verbatim environment with numbered lines.
256:             * @param node The root of the tree to copy.
257:             */
258:            private void lineNumberFragment(DOMBuilder rtf, Node node) {
259:                try {
260:                    if (node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE
261:                            || node.getNodeType() == Node.DOCUMENT_NODE) {
262:                        Node child = node.getFirstChild();
263:                        while (child != null) {
264:                            lineNumberFragment(rtf, child);
265:                            child = child.getNextSibling();
266:                        }
267:                    } else if (node.getNodeType() == Node.ELEMENT_NODE) {
268:                        String ns = node.getNamespaceURI();
269:                        String localName = node.getLocalName();
270:                        String name = ((Element) node).getTagName();
271:
272:                        rtf.startElement(ns, localName, name,
273:                                copyAttributes((Element) node));
274:
275:                        elementStack.push(node);
276:
277:                        Node child = node.getFirstChild();
278:                        while (child != null) {
279:                            lineNumberFragment(rtf, child);
280:                            child = child.getNextSibling();
281:                        }
282:                    } else if (node.getNodeType() == Node.TEXT_NODE) {
283:                        String text = node.getNodeValue();
284:
285:                        if (lineNumber == 0) {
286:                            // The first line is always numbered
287:                            formatLineNumber(rtf, ++lineNumber);
288:                        }
289:
290:                        // Walk through the text node looking for newlines
291:                        char chars[] = text.toCharArray();
292:                        int pos = 0;
293:                        for (int count = 0; count < text.length(); count++) {
294:                            if (text.charAt(count) == '\n') {
295:                                // This is the tricky bit; if we find a newline, make sure
296:                                // it doesn't occur inside any markup.
297:
298:                                if (pos > 0) {
299:                                    rtf.characters(chars, 0, pos);
300:                                    pos = 0;
301:                                }
302:
303:                                closeOpenElements(rtf);
304:
305:                                // Copy the newline to the output
306:                                chars[pos++] = text.charAt(count);
307:                                rtf.characters(chars, 0, pos);
308:                                pos = 0;
309:
310:                                // Add the line number
311:                                formatLineNumber(rtf, ++lineNumber);
312:
313:                                openClosedElements(rtf);
314:                            } else {
315:                                chars[pos++] = text.charAt(count);
316:                            }
317:                        }
318:
319:                        if (pos > 0) {
320:                            rtf.characters(chars, 0, pos);
321:                        }
322:                    } else if (node.getNodeType() == Node.COMMENT_NODE) {
323:                        String text = node.getNodeValue();
324:                        char chars[] = text.toCharArray();
325:                        rtf.comment(chars, 0, text.length());
326:                    } else if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) {
327:                        rtf.processingInstruction(node.getNodeName(), node
328:                                .getNodeValue());
329:                    } else {
330:                        System.out
331:                                .println("Warning: unexpected node type in lineNumberFragment");
332:                    }
333:
334:                    if (node.getNodeType() == Node.ELEMENT_NODE) {
335:                        String ns = node.getNamespaceURI();
336:                        String localName = node.getLocalName();
337:                        String name = ((Element) node).getTagName();
338:                        rtf.endElement(ns, localName, name);
339:                        elementStack.pop();
340:                    }
341:                } catch (SAXException e) {
342:                    System.out.println("SAX Exception in lineNumberFragment");
343:                }
344:            }
345:
346:            /**
347:             * <p>Add a formatted line number to the result tree fragment.</p>
348:             *
349:             * <p>This method examines the global parameters that control line
350:             * number presentation (modulus, width, and separator) and adds
351:             * the appropriate text to the result tree fragment.</p>
352:             *
353:             * @param rtf The resulting verbatim environment with numbered lines.
354:             * @param lineNumber The number of the current line.
355:             */
356:            private void formatLineNumber(DOMBuilder rtf, int lineNumber) {
357:                char ch = 160;
358:                String lno = "";
359:                if (lineNumber == 1
360:                        || (modulus >= 1 && (lineNumber % modulus == 0))) {
361:                    lno = "" + lineNumber;
362:                }
363:
364:                while (lno.length() < width) {
365:                    lno = ch + lno;
366:                }
367:
368:                lno += separator;
369:
370:                char chars[] = lno.toCharArray();
371:                try {
372:                    rtf.characters(chars, 0, lno.length());
373:                } catch (SAXException e) {
374:                    System.out.println("SAX Exception in formatLineNumber");
375:                }
376:            }
377:
378:            /**
379:             * <p>Insert text callouts into a verbatim environment.</p>
380:             *
381:             * <p>This method examines the <tt>areaset</tt> and <tt>area</tt> elements
382:             * in the supplied <tt>areaspec</tt> and decorates the supplied
383:             * result tree fragment with appropriate callout markers.</p>
384:             *
385:             * <p>If a <tt>label</tt> attribute is supplied on an <tt>area</tt>,
386:             * its content will be used for the label, otherwise the callout
387:             * number will be used, surrounded by parenthesis. Callouts are
388:             * numbered in document order. All of the <tt>area</tt>s in an
389:             * <tt>areaset</tt> get the same number.</p>
390:             *
391:             * <p>Only the <tt>linecolumn</tt> and <tt>linerange</tt> units are
392:             * supported. If no unit is specifed, <tt>linecolumn</tt> is assumed.
393:             * If only a line is specified, the callout decoration appears in
394:             * the defaultColumn. Lines will be padded with blanks to reach the
395:             * necessary column, but callouts that are located beyond the last
396:             * line of the verbatim environment will be ignored.</p>
397:             *
398:             * <p>Callouts are inserted before the character at the line/column
399:             * where they are to occur.</p>
400:             *
401:             * @param areaspecNodeSet The source node set that contains the areaspec.
402:             * @param xalanRTF The result tree fragment of the verbatim environment.
403:             * @param defaultColumn The column for callouts that specify only a line.
404:             *
405:             * @return The modified result tree fragment.  */
406:
407:            /**
408:             * <p>Insert graphical callouts into a verbatim environment.</p>
409:             *
410:             * <p>This method examines the <tt>areaset</tt> and <tt>area</tt> elements
411:             * in the supplied <tt>areaspec</tt> and decorates the supplied
412:             * result tree fragment with appropriate callout markers.</p>
413:             *
414:             * <p>If a <tt>label</tt> attribute is supplied on an <tt>area</tt>,
415:             * its content will be used for the label, otherwise the callout
416:             * number will be used. Callouts are
417:             * numbered in document order. All of the <tt>area</tt>s in an
418:             * <tt>areaset</tt> get the same number.</p>
419:             *
420:             * <p>If the callout number is not greater than <tt>gMax</tt>, the
421:             * callout generated will be:</p>
422:             *
423:             * <pre>
424:             * &lt;img src="$gPath/conumber$gExt" alt="conumber">
425:             * </pre>
426:             *
427:             * <p>Otherwise, it will be the callout number surrounded by
428:             * parenthesis.</p>
429:             *
430:             * <p>Only the <tt>linecolumn</tt> and <tt>linerange</tt> units are
431:             * supported. If no unit is specifed, <tt>linecolumn</tt> is assumed.
432:             * If only a line is specified, the callout decoration appears in
433:             * the defaultColumn. Lines will be padded with blanks to reach the
434:             * necessary column, but callouts that are located beyond the last
435:             * line of the verbatim environment will be ignored.</p>
436:             *
437:             * <p>Callouts are inserted before the character at the line/column
438:             * where they are to occur.</p>
439:             *
440:             * @param context
441:             * @param areaspecNodeSet The source node set that contains the areaspec.
442:             * @param xalanNI
443:             *
444:             * @return The modified result tree fragment.
445:             */
446:            public DocumentFragment insertCallouts(ExpressionContext context,
447:                    NodeIterator areaspecNodeSet, NodeIterator xalanNI) {
448:                String type = Params.getString(context,
449:                        "stylesheet.result.type");
450:                boolean useFO = type.equals("fo");
451:                int defaultColumn = Params.getInt(context,
452:                        "callout.defaultcolumn");
453:
454:                if (Params.getBoolean(context, "callout.graphics")) {
455:                    String gPath = Params.getString(context,
456:                            "callout.graphics.path");
457:                    String gExt = Params.getString(context,
458:                            "callout.graphics.extension");
459:                    int gMax = Params.getInt(context,
460:                            "callout.graphics.number.limit");
461:                    return insertGraphicCallouts(areaspecNodeSet, xalanNI,
462:                            defaultColumn, gPath, gExt, gMax, useFO);
463:                } else if (Params.getBoolean(context, "callout.unicode")) {
464:                    int uStart = Params.getInt(context,
465:                            "callout.unicode.start.character");
466:                    int uMax = Params.getInt(context,
467:                            "callout.unicode.number.limit");
468:                    String uFont = Params.getString(context,
469:                            "callout.unicode.font");
470:                    return insertUnicodeCallouts(areaspecNodeSet, xalanNI,
471:                            defaultColumn, uFont, uStart, uMax, useFO);
472:                } else if (Params.getBoolean(context, "callout.dingbats")) {
473:                    int dMax = 10;
474:                    return insertDingbatCallouts(areaspecNodeSet, xalanNI,
475:                            defaultColumn, dMax, useFO);
476:                } else {
477:                    return insertTextCallouts(areaspecNodeSet, xalanNI,
478:                            defaultColumn, useFO);
479:                }
480:            }
481:
482:            public DocumentFragment insertGraphicCallouts(
483:                    NodeIterator areaspecNodeSet, NodeIterator xalanNI,
484:                    int defaultColumn, String gPath, String gExt, int gMax,
485:                    boolean useFO) {
486:                FormatGraphicCallout fgc = new FormatGraphicCallout(gPath,
487:                        gExt, gMax, useFO);
488:                return insertCallouts(areaspecNodeSet, xalanNI, defaultColumn,
489:                        fgc);
490:            }
491:
492:            public DocumentFragment insertUnicodeCallouts(
493:                    NodeIterator areaspecNodeSet, NodeIterator xalanNI,
494:                    int defaultColumn, String uFont, int uStart, int uMax,
495:                    boolean useFO) {
496:                FormatUnicodeCallout fuc = new FormatUnicodeCallout(uFont,
497:                        uStart, uMax, useFO);
498:                return insertCallouts(areaspecNodeSet, xalanNI, defaultColumn,
499:                        fuc);
500:            }
501:
502:            public DocumentFragment insertDingbatCallouts(
503:                    NodeIterator areaspecNodeSet, NodeIterator xalanNI,
504:                    int defaultColumn, int gMax, boolean useFO) {
505:                FormatDingbatCallout fdc = new FormatDingbatCallout(gMax, useFO);
506:                return insertCallouts(areaspecNodeSet, xalanNI, defaultColumn,
507:                        fdc);
508:            }
509:
510:            public DocumentFragment insertTextCallouts(
511:                    NodeIterator areaspecNodeSet, NodeIterator xalanNI,
512:                    int defaultColumn, boolean useFO) {
513:                FormatTextCallout ftc = new FormatTextCallout(useFO);
514:                return insertCallouts(areaspecNodeSet, xalanNI, defaultColumn,
515:                        ftc);
516:            }
517:
518:            public DocumentFragment insertCallouts(
519:                    NodeIterator areaspecNodeSet, NodeIterator xalanNI,
520:                    int defaultColumn, FormatCallout fCallout) {
521:
522:                DocumentFragment xalanRTF = (DocumentFragment) xalanNI
523:                        .nextNode();
524:
525:                callout = new Callout[10];
526:                calloutCount = 0;
527:                calloutPos = 0;
528:                lineNumber = 1;
529:                colNumber = 1;
530:
531:                // First we walk through the areaspec to calculate the position
532:                // of the callouts
533:                //  <areaspec>
534:                //  <areaset id="ex.plco.const" coords="">
535:                //    <area id="ex.plco.c1" coords="4"/>
536:                //    <area id="ex.plco.c2" coords="8"/>
537:                //  </areaset>
538:                //  <area id="ex.plco.ret" coords="12"/>
539:                //  <area id="ex.plco.dest" coords="12"/>
540:                //  </areaspec>
541:                int pos = 0;
542:                int coNum = 0;
543:                boolean inAreaSet = false;
544:                Node node = areaspecNodeSet.nextNode();
545:                node = node.getFirstChild();
546:                while (node != null) {
547:                    if (node.getNodeType() == Node.ELEMENT_NODE) {
548:                        if (node.getNodeName().equals("areaset")) {
549:                            coNum++;
550:                            Node area = node.getFirstChild();
551:                            while (area != null) {
552:                                if (area.getNodeType() == Node.ELEMENT_NODE) {
553:                                    if (area.getNodeName().equals("area")) {
554:                                        addCallout(coNum, area, defaultColumn);
555:                                    } else {
556:                                        System.out
557:                                                .println("Unexpected element in areaset: "
558:                                                        + area.getNodeName());
559:                                    }
560:                                }
561:                                area = area.getNextSibling();
562:                            }
563:                        } else if (node.getNodeName().equalsIgnoreCase("area")) {
564:                            coNum++;
565:                            addCallout(coNum, node, defaultColumn);
566:                        } else {
567:                            System.out
568:                                    .println("Unexpected element in areaspec: "
569:                                            + node.getNodeName());
570:                        }
571:                    }
572:
573:                    node = node.getNextSibling();
574:                }
575:
576:                // Now sort them
577:                java.util.Arrays.sort(callout, 0, calloutCount);
578:
579:                DocumentBuilderFactory docFactory = DocumentBuilderFactory
580:                        .newInstance();
581:                DocumentBuilder docBuilder = null;
582:
583:                try {
584:                    docBuilder = docFactory.newDocumentBuilder();
585:                } catch (ParserConfigurationException e) {
586:                    System.out.println("PCE 2!");
587:                    return xalanRTF;
588:                }
589:                Document doc = docBuilder.newDocument();
590:                DocumentFragment df = doc.createDocumentFragment();
591:                DOMBuilder db = new DOMBuilder(doc, df);
592:
593:                elementStack = new Stack();
594:                calloutFragment(db, xalanRTF, fCallout);
595:                return df;
596:            }
597:
598:            /**
599:             * <p>Build a FragmentValue with callout decorations.</p>
600:             *
601:             * <p>This is the method that actually does the work of adding
602:             * callouts to a verbatim environment. It recursively walks through a
603:             * tree of nodes, copying the structure into the rtf. Text nodes
604:             * are examined for the position of callouts as described by the
605:             * global callout parameters.</p>
606:             *
607:             * <p>When called, rtf should be an empty FragmentValue and node
608:             * should be the first child of the result tree fragment that contains
609:             * the existing, formatted verbatim text.</p>
610:             *
611:             * @param rtf The resulting verbatim environment with numbered lines.
612:             * @param node The root of the tree to copy.
613:             */
614:            private void calloutFragment(DOMBuilder rtf, Node node,
615:                    FormatCallout fCallout) {
616:                try {
617:                    if (node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE
618:                            || node.getNodeType() == Node.DOCUMENT_NODE) {
619:                        Node child = node.getFirstChild();
620:                        while (child != null) {
621:                            calloutFragment(rtf, child, fCallout);
622:                            child = child.getNextSibling();
623:                        }
624:                    } else if (node.getNodeType() == Node.ELEMENT_NODE) {
625:                        String ns = node.getNamespaceURI();
626:                        String localName = node.getLocalName();
627:                        String name = ((Element) node).getTagName();
628:
629:                        rtf.startElement(ns, localName, name,
630:                                copyAttributes((Element) node));
631:
632:                        elementStack.push(node);
633:
634:                        Node child = node.getFirstChild();
635:                        while (child != null) {
636:                            calloutFragment(rtf, child, fCallout);
637:                            child = child.getNextSibling();
638:                        }
639:                    } else if (node.getNodeType() == Node.TEXT_NODE) {
640:                        String text = node.getNodeValue();
641:
642:                        char chars[] = text.toCharArray();
643:                        int pos = 0;
644:                        for (int count = 0; count < text.length(); count++) {
645:                            if (calloutPos < calloutCount
646:                                    && callout[calloutPos].getLine() == lineNumber
647:                                    && callout[calloutPos].getColumn() == colNumber) {
648:
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 ("".equals(units) || 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.