001package com.hfg.html; 002 003import java.io.*; 004import java.nio.charset.Charset; 005 006import javax.servlet.http.HttpServletResponse; 007 008import com.hfg.util.StringBuilderPlus; 009import com.hfg.xml.XMLBasedDoc; 010import com.hfg.xml.Doctype; 011import com.hfg.util.mime.MimeType; 012import com.hfg.xml.XMLException; 013import com.hfg.xml.XMLNode; 014import com.hfg.xml.XMLTag; 015import com.hfg.xml.parser.SaxyParser; 016import com.hfg.xml.parser.XMLTagReader; 017 018//------------------------------------------------------------------------------ 019/** 020 Represents an HTML document. 021 022 @author J. Alex Taylor, hairyfatguy.com 023 */ 024//------------------------------------------------------------------------------ 025// com.hfg XML/HTML Coding Library 026// 027// This library is free software; you can redistribute it and/or 028// modify it under the terms of the GNU Lesser General Public 029// License as published by the Free Software Foundation; either 030// version 2.1 of the License, or (at your option) any later version. 031// 032// This library is distributed in the hope that it will be useful, 033// but WITHOUT ANY WARRANTY; without even the implied warranty of 034// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 035// Lesser General Public License for more details. 036// 037// You should have received a copy of the GNU Lesser General Public 038// License along with this library; if not, write to the Free Software 039// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 040// 041// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com 042// jataylor@hairyfatguy.com 043//------------------------------------------------------------------------------ 044 045 046public class HTMLDoc extends XMLBasedDoc<HTMLTag> 047{ 048 private Meta mContentTypeMetaTag; 049 050 private static Doctype DEFAULT_DOCTYPE = Doctype.HTML_5; 051 052 //########################################################################### 053 // CONSTRUCTORS 054 //########################################################################### 055 056 //--------------------------------------------------------------------------- 057 public HTMLDoc() 058 { 059 super(); 060 setRootNode(new HTML()); 061 init(); 062 } 063 064 //--------------------------------------------------------------------------- 065 public HTMLDoc(Doctype inDoctype) 066 { 067 this(); 068 setDoctype(inDoctype); 069 } 070 071 //--------------------------------------------------------------------------- 072 public HTMLDoc(HTML inRootTag) 073 { 074 super(inRootTag); 075// init(); 076 } 077 078 //--------------------------------------------------------------------------- 079 public HTMLDoc(File inFile) 080 throws XMLException, IOException 081 { 082 super(inFile); 083// init(); 084 } 085 086 //--------------------------------------------------------------------------- 087 public HTMLDoc(BufferedReader inReader) 088 { 089 super(inReader); 090 } 091 092 //--------------------------------------------------------------------------- 093 public HTMLDoc(BufferedInputStream inStream) 094 { 095 super(inStream); 096 } 097 098 //--------------------------------------------------------------------------- 099 private void init() 100 { 101 if (null == getDoctype()) 102 { 103 setDoctype(DEFAULT_DOCTYPE); 104 } 105 } 106 107 108 //########################################################################### 109 // PUBLIC METHODS 110 //########################################################################### 111 112 //-------------------------------------------------------------------------- 113 /** 114 Used by toXML() and toHTML() for content placed at the start of the document. 115 */ 116 @Override 117 public String getHeader() 118 { 119 String header = ""; 120 if (getDoctype() != null) 121 { 122 if (getDoctype().getMimeType() == MimeType.APPLICATION_XHTML) 123 { 124 header = super.getHeader(); // Adds XML header. ex: "<?xml version='1.0' standalone='yes' ?>" 125 } 126 else 127 { 128 header = getDoctype().toString() + NL; 129 } 130 } 131 132 return header; 133 } 134 135 //--------------------------------------------------------------------------- 136 @Override 137 public HTMLDoc setDoctype(Doctype inValue) 138 { 139 super.setDoctype(inValue); 140 return this; 141 } 142 143 //--------------------------------------------------------------------------- 144 @Override 145 public HTMLDoc setEncoding(Charset inValue) 146 { 147 super.setEncoding(inValue); 148 return this; 149 } 150 151 //--------------------------------------------------------------------------- 152 public String toHTML() 153 { 154 return toXML(); 155 } 156 157 //--------------------------------------------------------------------------- 158 public void toHTML(OutputStream inStream) 159 { 160 toXML(inStream); 161 } 162 163 //--------------------------------------------------------------------------- 164 public void toHTML(PrintWriter inWriter) 165 { 166 toXML(inWriter); 167 } 168 169 //--------------------------------------------------------------------------- 170 public void toHTML(File inFile) 171 { 172 toXML(inFile); 173 } 174 175 //--------------------------------------------------------------------------- 176 public void toHTML(HttpServletResponse inResponse) 177 { 178 if (getDoctype() != null) 179 { 180 inResponse.setContentType(generateContentTypeString()); 181 } 182 183 try 184 { 185 Writer writer = null; 186 try 187 { 188 writer = inResponse.getWriter(); 189 toXML(writer); 190 } 191 finally 192 { 193 if (writer != null) 194 { 195 writer.close(); 196 } 197 } 198 } 199 catch (IOException e) 200 { 201 throw new XMLException(e); 202 } 203 } 204 205 //-------------------------------------------------------------------------- 206 public String toIndentedHTML(int inInitialIndentLevel, int inIndentSize) 207 { 208 return toIndentedXML(inInitialIndentLevel, inIndentSize); 209 } 210 211 //-------------------------------------------------------------------------- 212 public void toIndentedHTML(OutputStream inOutputStream, int inInitialIndentLevel, int inIndentSize) 213 { 214 toIndentedXML(inOutputStream, inInitialIndentLevel, inIndentSize); 215 } 216 217 //-------------------------------------------------------------------------- 218 public void toIndentedHTML(PrintWriter inWriter, int inInitialIndentLevel, int inIndentSize) 219 { 220 toIndentedXML(inWriter, inInitialIndentLevel, inIndentSize); 221 } 222 223 224 //-------------------------------------------------------------------------- 225 public void toIndentedHTML(File inFile, int inInitialIndentLevel, int inIndentSize) 226 { 227 toIndentedXML(inFile, inInitialIndentLevel, inIndentSize); 228 } 229 230 //--------------------------------------------------------------------------- 231 public void setRootNode(HTML inValue) 232 { 233 super.setRootNode(inValue); 234 } 235 236 //--------------------------------------------------------------------------- 237 @Override 238 public HTML getRootNode() 239 { 240 XMLNode rootNode = super.getRootNode(); 241 if (!(rootNode instanceof HTML)) 242 { 243 rootNode = new HTML(rootNode); 244 setRootNode((HTML) rootNode); 245 } 246 247 return (HTML) rootNode; 248 } 249 250 //########################################################################### 251 // PROTECTED METHODS 252 //########################################################################### 253 254 //-------------------------------------------------------------------------- 255 protected void prepareForOutput() 256 { 257 // If we read in an HTML document we don't really want to alter its content. 258 // If however we constructed the document, let's be complete and set a meta tag for the content type. 259 if (isConstructedContent()) 260 { 261 setMetaContentTypeAndEncoding(); 262 } 263 } 264 265 //-------------------------------------------------------------------------- 266 protected XMLTagReader getTagReader() 267 { 268 XMLTagReader xmlTagReader = new XMLTagReader(); 269 if (xmlTagReader.getParser() instanceof SaxyParser) 270 { 271 ((SaxyParser) xmlTagReader.getParser()).setLenientHTMLParsing(true); 272 } 273 274 return xmlTagReader; 275 } 276 277 //########################################################################### 278 // PRIVATE METHODS 279 //########################################################################### 280 281 //--------------------------------------------------------------------------- 282 private void setMetaContentTypeAndEncoding() 283 { 284 if (getRootNode() != null) 285 { 286 if (null == mContentTypeMetaTag 287 && getRootNode().getHead() != null) 288 { 289 mContentTypeMetaTag = new Meta(); 290 getRootNode().getHead().addSubtag(mContentTypeMetaTag); 291 } 292 293 if (mContentTypeMetaTag != null) 294 { 295 mContentTypeMetaTag.setHttpEquiv("Content-Type") 296 .setContentAttribute(generateContentTypeString()); 297 } 298 } 299 } 300 301 //--------------------------------------------------------------------------- 302 private String generateContentTypeString() 303 { 304 StringBuilderPlus contentType = new StringBuilderPlus().setDelimiter("; "); 305 if (getDoctype() != null) 306 { 307 contentType.append(getDoctype().getMimeType()); 308 contentType.delimitedAppend("charset=" + getEncoding()); 309 } 310 311 return contentType.toString(); 312 } 313}