1 23 24 package org.enhydra.xml.io; 25 26 import java.io.IOException ; 27 28 import org.enhydra.xml.dom.DOMAccess; 29 import org.w3c.dom.Attr ; 30 import org.w3c.dom.CDATASection ; 31 import org.w3c.dom.Document ; 32 import org.w3c.dom.DocumentFragment ; 33 import org.w3c.dom.DocumentType ; 34 import org.w3c.dom.Element ; 35 import org.w3c.dom.Node ; 36 import org.w3c.dom.ProcessingInstruction ; 37 import org.w3c.dom.Text ; 38 39 47 48 49 52 final class HTMLFormatter extends BaseDOMFormatter implements Formatter { 53 56 private static final String DEFAULT_XML_ENCODING = "ISO-8859-1"; 57 58 62 private static final boolean[] fEntityQuickCheck 63 = new boolean[MAX_ENTITY_QUICK_CHECK_CHAR+1]; 64 65 68 private final boolean fDropSpanIds; 69 70 74 private boolean fDropThisId; 75 76 80 private boolean fUseHTML4Entities; 81 82 88 private int fNoFormatNestCount; 89 90 93 private boolean fHandleText = false; 94 95 98 private boolean fNextSiblingText = false; 99 100 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 112 public HTMLFormatter(Node 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 125 static OutputOptions getDefaultOutputOptions() { 126 return new OutputOptions(); } 128 129 132 protected final String getCharacterEntity(char textChar) { 133 if (fUseHTML4Entities) { 134 return HTMLEntities.charToEntity4(textChar); 135 } else { 136 return HTMLEntities.charToEntity(textChar); 137 } 138 } 139 140 144 private boolean printableAttrValue(Attr attr) { 145 return (!(HTMLElements.isBooleanAttr(attr.getName()))); 146 } 147 148 151 private void outputDocType(Document document) throws IOException { 152 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 178 public void handleDocument(Document document) throws IOException { 179 if (!fOptions.getOmitDocType()) { 180 outputDocType(document); 181 } 182 fTraverser.processChildren(document); 183 } 184 185 189 public void handleDocumentType(DocumentType documentType) throws IOException { 190 throw new XMLIOError("Unexpected call to handleDocumentType"); 191 } 192 193 197 public void handleDocumentFragment(DocumentFragment documentFragment) { 198 fTraverser.processChildren(documentFragment); 199 } 200 201 205 public void handleAttr(Attr attr) throws IOException { 206 String 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 219 protected final void writeOpenTag(Element element, 220 String tagName, 221 boolean hasChildren) throws IOException { 222 String formattedTag = null; 223 if (fPrettyPrinting) { 224 if (fNextSiblingText) { 225 fOut.write('\n'); 226 } 227 fNextSiblingText = (element.getNextSibling() instanceof Text ); 228 } 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 )) { 238 printIndent(); 239 } 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 )) { 248 fOut.write('\n'); 249 } } 251 } 252 253 256 private void writeCloseTag(String tagName) throws IOException { 257 if (fHandleText) { 259 fHandleText = false; 260 } else { 261 printIndent(); 262 } 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 } } 273 274 284 public void handleElement(Element element) throws IOException { 285 String tagName = element.getTagName(); 286 287 Attr attr = DOMAccess.accessAttribute(fDocument, element, null, "visdom"); 295 if (attr != null && !(Boolean.valueOf(attr.getValue()).booleanValue())) return; 296 298 writeOpenTag(element, tagName, false); 300 301 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 317 public void handleProcessingInstruction(ProcessingInstruction pi) throws IOException { 318 throw new XMLIOError("Unexpected call to handleProcessingInstruction"); 319 } 320 321 326 public void handleCDATASection(CDATASection cdata) throws IOException { 327 fOut.write(cdata.getData()); 328 } 329 330 334 public final void handleText(Text text) throws IOException { 335 fHandleText = true; 336 if (fNoFormatNestCount > 0) { 337 fOut.write(text.getData()); 338 } else { 339 super.handleText(text); 340 } 341 } 342 } 343 | Popular Tags |