KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > enhydra > xml > io > HTMLFormatter


1 /*
2  * Enhydra Java Application Server Project
3  *
4  * The contents of this file are subject to the Enhydra Public License
5  * Version 1.1 (the "License"); you may not use this file except in
6  * compliance with the License. You may obtain a copy of the License on
7  * the Enhydra web site ( http://www.enhydra.org/ ).
8  *
9  * Software distributed under the License is distributed on an "AS IS"
10  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
11  * the License for the specific terms governing rights and limitations
12  * under the License.
13  *
14  * The Initial Developer of the Enhydra Application Server is Lutris
15  * Technologies, Inc. The Enhydra Application Server and portions created
16  * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
17  * All Rights Reserved.
18  *
19  * Contributor(s):
20  *
21  * $Id: HTMLFormatter.java,v 1.7 2005/01/26 08:29:24 jkjome Exp $
22  */

23
24 package org.enhydra.xml.io;
25
26 import java.io.IOException JavaDoc;
27
28 import org.enhydra.xml.dom.DOMAccess;
29 import org.w3c.dom.Attr JavaDoc;
30 import org.w3c.dom.CDATASection JavaDoc;
31 import org.w3c.dom.Document JavaDoc;
32 import org.w3c.dom.DocumentFragment JavaDoc;
33 import org.w3c.dom.DocumentType JavaDoc;
34 import org.w3c.dom.Element JavaDoc;
35 import org.w3c.dom.Node JavaDoc;
36 import org.w3c.dom.ProcessingInstruction JavaDoc;
37 import org.w3c.dom.Text JavaDoc;
38
39 /*
40  * FIXME:
41  * - Need to check for optional attributes.
42  * - Give control over newline in OutputOptions or maybe use a PrintWriter???
43  * - Need option to include HTML 4.0 entity references.
44  * - script and style child special handling.
45  * - Need to output HTML header.
46  */

47
48
49 /**
50  * Formatter for outputting a HTML DOM as a HTML text document.
51  */

52 final class HTMLFormatter extends BaseDOMFormatter implements Formatter {
53     /**
54      * Default XML encoding.
55      */

56     private static final String JavaDoc DEFAULT_XML_ENCODING = "ISO-8859-1";
57
58     /**
59      * Table use to optimized checking for characters that should be
60      * represented as entity references.
61      */

62     private static final boolean[] fEntityQuickCheck
63         = new boolean[MAX_ENTITY_QUICK_CHECK_CHAR+1];
64
65     /**
66      * Should SPAN ID attributes be dropped?
67      */

68     private final boolean fDropSpanIds;
69
70     /**
71      * Flag that indicates the ID attribute should be dropped for the current
72      * element.
73      */

74     private boolean fDropThisId;
75     
76     /**
77      * Flag that indicates wether to use all named entites for all HTML 4.0 character
78      * entities or not.
79      */

80     private boolean fUseHTML4Entities;
81
82     /**
83      * Nesting count for elements that don't have their content formatted.
84      * This is done for script and style elements. The contents of these
85      * elements are outputted as-is. Its not legal for them to nest, but a
86      * count is used to keep code from being confused by a broken DOM.
87      */

88     private int fNoFormatNestCount;
89
90     /**
91      * Indicates then a text has just been handled
92      */

93     private boolean fHandleText = false;
94
95     /**
96      * Indicates the next Sibling is a Text node
97      */

98     private boolean fNextSiblingText = false;
99
100     /**
101      * Static constructor.
102      */

103     static {
104         for (char ch = 0; ch <= MAX_ENTITY_QUICK_CHECK_CHAR; ch++) {
105             fEntityQuickCheck[ch] = (HTMLEntities.charToEntity(ch) != null);
106         }
107     }
108
109     /**
110      * Constructor.
111      */

112     public HTMLFormatter(Node JavaDoc node,
113                          OutputOptions outputOptions,
114                          boolean forPreFormatting) {
115         super(node, outputOptions, forPreFormatting, DEFAULT_XML_ENCODING, fEntityQuickCheck);
116         fDropSpanIds = fOptions.getDropHtmlSpanIds();
117         fUseHTML4Entities = fOptions.getUseHTML4Entities();
118     }
119
120     /**
121      * Get the default OutputOptions for a document formatter with this
122      * formatter. The encoding will not be set, which signals to use the
123      * default encoding.
124      */

125     static OutputOptions getDefaultOutputOptions() {
126         return new OutputOptions(); // Nothing special
127
}
128
129     /**
130      * @see BaseDOMFormatter#getCharacterEntity
131      */

132     protected final String JavaDoc getCharacterEntity(char textChar) {
133         if (fUseHTML4Entities) {
134             return HTMLEntities.charToEntity4(textChar);
135         } else {
136             return HTMLEntities.charToEntity(textChar);
137         }
138     }
139
140     /**
141      * Determine if an attribute's value should be printer. Those that don't
142      * normally have values only get them if one was explictly supplied.
143      */

144     private boolean printableAttrValue(Attr JavaDoc attr) {
145         return (!(HTMLElements.isBooleanAttr(attr.getName())));
146     }
147
148     /**
149      * Output the DOCTYPE declaration, if the information is available.
150      */

151     private void outputDocType(Document JavaDoc document) throws IOException JavaDoc {
152         //FIXME: Don't currently have a way of getting doctype from the parser
153
//to here, the only way is via the outputOptions override.
154
if ((fPublicId != null) || (fSystemId != null)) {
155             fOut.write("<!DOCTYPE html");
156             if (fPublicId != null) {
157                 fOut.write(" PUBLIC \"");
158                 fOut.write(fPublicId);
159                 fOut.write("\"");
160             }
161             if (fSystemId != null) {
162                 if (fPublicId == null) {
163                     fOut.write(" SYSTEM");
164                 }
165                 fOut.write(" \"");
166                 fOut.write(fSystemId);
167                 fOut.write("\"");
168             }
169             fOut.write('>');
170             writeln();
171         }
172     }
173
174     /**
175      * Handler called for Document nodes.
176      * @see org.enhydra.xml.dom.DOMTraversal.Handler#handleDocument
177      */

178     public void handleDocument(Document JavaDoc document) throws IOException JavaDoc {
179         if (!fOptions.getOmitDocType()) {
180             outputDocType(document);
181         }
182         fTraverser.processChildren(document);
183     }
184
185     /**
186      * Handler called for Document nodes; should never be called.
187      * @see org.enhydra.xml.dom.DOMTraversal.Handler#handleDocumentType
188      */

189     public void handleDocumentType(DocumentType JavaDoc documentType) throws IOException JavaDoc {
190         throw new XMLIOError("Unexpected call to handleDocumentType");
191     }
192
193     /**
194      * Handler called for DocumentFragment nodes; just process children.
195      * @see org.enhydra.xml.dom.DOMTraversal.Handler#handleDocumentFragment
196      */

197     public void handleDocumentFragment(DocumentFragment JavaDoc documentFragment) {
198         fTraverser.processChildren(documentFragment);
199     }
200
201     /**
202      * Handler called for Attr nodes.
203      * @see org.enhydra.xml.dom.DOMTraversal.Handler#handleAttr
204      */

205     public void handleAttr(Attr JavaDoc attr) throws IOException JavaDoc {
206         String JavaDoc name = attr.getName();
207         if (!(fDropThisId && name.equals("id"))) {
208             fOut.write(' ');
209             fOut.write(name);
210             if (printableAttrValue(attr)) {
211                 writeAttributeValue(attr);
212             }
213         }
214     }
215
216     /**
217      * Write an element open tag. The hasChildren option is ignored.
218      */

219     protected final void writeOpenTag(Element JavaDoc element,
220                                       String JavaDoc tagName,
221                                       boolean hasChildren) throws IOException JavaDoc {
222         String JavaDoc formattedTag = null;
223         if (fPrettyPrinting) {
224             if (fNextSiblingText) {
225                 fOut.write('\n');
226             }
227             fNextSiblingText = (element.getNextSibling() instanceof Text JavaDoc);
228         } // end of if ()
229

230         if (fUsePreFormattedElements && (element instanceof PreFormattedText)) {
231             formattedTag = ((PreFormattedText)element).getPreFormattedText();
232         }
233         if (formattedTag != null) {
234             fOut.write(formattedTag);
235             fPreFormattedElementCount++;
236         } else {
237             if (fPrettyPrinting && !(element.getPreviousSibling() instanceof Text JavaDoc)) {
238                 printIndent();
239             } // end of if ()
240

241             fDropThisId = fDropSpanIds && tagName.equals("SPAN");
242             fOut.write('<');
243             fOut.write(tagName);
244             fTraverser.processAttributes(element);
245             fOut.write('>');
246             fDynamicFormattedElementCount++;
247             if (fPrettyPrinting && !(element.getFirstChild() instanceof Text JavaDoc)) {
248                 fOut.write('\n');
249             } // end of if ()
250
}
251     }
252
253     /**
254      * Write an element close tag.
255      */

256     private void writeCloseTag(String JavaDoc tagName) throws IOException JavaDoc {
257         // Output end tag when legal.
258
if (fHandleText) {
259             fHandleText = false;
260         } else {
261             printIndent();
262         } // end of else
263

264         if (HTMLElements.hasCloseTag(tagName)) {
265             fOut.write("</");
266             fOut.write(tagName);
267             fOut.write('>');
268         }
269         if (fPrettyPrinting && !fNextSiblingText) {
270             fOut.write('\n');
271         } // end of if ()
272
}
273
274     /**
275      * Handler called for Element nodes.
276      * <p>
277      * This optionally corrects problem cases for browsers:
278      * <UL>
279      * <LI> ID attributes are dropped from SPAN tags. This cause Internet
280      * Explorer 4.0 to get confused on keep-alive connections.
281      * </UL>
282      * @see org.enhydra.xml.dom.DOMTraversal.Handler#handleElement
283      */

284     public void handleElement(Element JavaDoc element) throws IOException JavaDoc {
285         String JavaDoc tagName = element.getTagName();
286
287         // Start Barracuda Kludge ======
288
// check the element to see if it contains a
289
// attribute "visdom".
290
// (org.enhydra.barracuda.core.comp.BComponent.VISIBILITY_MARKER)
291
// This controls DOM visibility. If this value exists and does not
292
// match to true, don't print this particular node.
293
// Note: This should be made generic, but for now...
294
Attr JavaDoc attr = DOMAccess.accessAttribute(fDocument, element, null, "visdom");
295         if (attr != null && !(Boolean.valueOf(attr.getValue()).booleanValue())) return;
296         // End Barracuda Kludge ======
297

298         // HTML version doesn't care if it has childrne.
299
writeOpenTag(element, tagName, false);
300
301         // Output childern and close
302
boolean isScriptStyle = HTMLElements.isScriptStyle(element);
303         if (isScriptStyle) {
304             fNoFormatNestCount++;
305         }
306         fTraverser.processChildren(element);
307         if (isScriptStyle) {
308             fNoFormatNestCount--;
309         }
310         writeCloseTag(tagName);
311     }
312
313     /**
314      * Handler called for ProcessingInstruction nodes.
315      * @see org.enhydra.xml.dom.DOMTraversal.Handler#handleProcessingInstruction
316      */

317     public void handleProcessingInstruction(ProcessingInstruction JavaDoc pi) throws IOException JavaDoc {
318         throw new XMLIOError("Unexpected call to handleProcessingInstruction");
319     }
320
321     /**
322      * Handler called for CDATASection nodes.
323      * Non-standard extension: outputs data as-is.
324      * @see org.enhydra.xml.dom.DOMTraversal.Handler#handleCDATASection
325      */

326     public void handleCDATASection(CDATASection JavaDoc cdata) throws IOException JavaDoc {
327         fOut.write(cdata.getData());
328     }
329
330     /**
331      * Handler called for Text nodes.
332      * @see org.enhydra.xml.dom.DOMTraversal.Handler#handleText
333      */

334     public final void handleText(Text JavaDoc text) throws IOException JavaDoc {
335         fHandleText = true;
336         if (fNoFormatNestCount > 0) {
337             fOut.write(text.getData());
338         } else {
339             super.handleText(text);
340         }
341     }
342 }
343
Popular Tags