1 package org.apache.maven.doxia.module.xhtml; 2 3 /* 4 * Licensed to the Apache Software Foundation (ASF) under one 5 * or more contributor license agreements. See the NOTICE file 6 * distributed with this work for additional information 7 * regarding copyright ownership. The ASF licenses this file 8 * to you under the Apache License, Version 2.0 (the 9 * "License"); you may not use this file except in compliance 10 * with the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, 15 * software distributed under the License is distributed on an 16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 * KIND, either express or implied. See the License for the 18 * specific language governing permissions and limitations 19 * under the License. 20 */ 21 22 import java.io.Writer; 23 24 import javax.swing.text.MutableAttributeSet; 25 import javax.swing.text.html.HTML.Attribute; 26 27 import org.apache.maven.doxia.sink.XhtmlBaseSink; 28 import org.apache.maven.doxia.sink.SinkEventAttributeSet; 29 import org.apache.maven.doxia.util.HtmlTools; 30 31 import org.codehaus.plexus.util.StringUtils; 32 33 /** 34 * <a href="http://www.w3.org/TR/xhtml1/">Xhtml 1.0 Transitional</a> sink implementation. 35 * <br/> 36 * It uses the DTD/xhtml1-transitional <a href="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 37 * http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd</a>. 38 * 39 * @author Jason van Zyl 40 * @author ltheussl 41 * @version $Id: XhtmlSink.java 807186 2009-08-24 12:29:12Z vsiveton $ 42 * @since 1.0 43 */ 44 public class XhtmlSink 45 extends XhtmlBaseSink 46 implements XhtmlMarkup 47 { 48 // ---------------------------------------------------------------------- 49 // Instance fields 50 // ---------------------------------------------------------------------- 51 52 private String encoding; 53 54 private String languageId; 55 56 /** An indication on if we're inside a head title. */ 57 private boolean headTitleFlag; 58 59 // ---------------------------------------------------------------------- 60 // Constructors 61 // ---------------------------------------------------------------------- 62 63 /** 64 * Constructor, initialize the Writer. 65 * 66 * @param writer not null writer to write the result. 67 */ 68 protected XhtmlSink( Writer writer ) 69 { 70 super( writer ); 71 } 72 73 /** 74 * Constructor, initialize the Writer and tells which encoding is used. 75 * 76 * @param writer not null writer to write the result. 77 * @param encoding the encoding used, that should be written to the generated HTML content 78 * if not <code>null</code>. 79 */ 80 protected XhtmlSink( Writer writer, String encoding ) 81 { 82 super( writer ); 83 84 this.encoding = encoding; 85 } 86 87 /** 88 * Constructor, initialize the Writer and tells which encoding and languageId are used. 89 * 90 * @param writer not null writer to write the result. 91 * @param encoding the encoding used, that should be written to the generated HTML content 92 * if not <code>null</code>. 93 * @param languageId language identifier for the root element as defined by 94 * <a href="ftp://ftp.isi.edu/in-notes/bcp/bcp47.txt">IETF BCP 47</a>, Tags for the Identification of Languages; 95 * in addition, the empty string may be specified. 96 */ 97 protected XhtmlSink( Writer writer, String encoding, String languageId ) 98 { 99 this( writer, encoding ); 100 101 this.languageId = languageId; 102 } 103 104 /** {@inheritDoc} */ 105 public void head() 106 { 107 init(); 108 109 setHeadFlag( true ); 110 111 write( "<!DOCTYPE html PUBLIC \"" + XHTML_TRANSITIONAL_PUBLIC_ID + "\" \"" + XHTML_TRANSITIONAL_SYSTEM_ID 112 + "\">" ); 113 114 MutableAttributeSet atts = new SinkEventAttributeSet(); 115 atts.addAttribute( "xmlns", XHTML_NAMESPACE ); 116 117 if ( languageId != null ) 118 { 119 atts.addAttribute( Attribute.LANG.toString(), languageId ); 120 atts.addAttribute( "xml:lang", languageId ); 121 } 122 123 writeStartTag( HTML, atts ); 124 125 writeStartTag( HEAD ); 126 } 127 128 /** {@inheritDoc} */ 129 public void head_() 130 { 131 if ( !isHeadTitleFlag() ) 132 { 133 // The content of element type "head" must match 134 // "((script|style|meta|link|object|isindex)*, 135 // ((title,(script|style|meta|link|object|isindex)*, 136 // (base,(script|style|meta|link|object|isindex)*)?)|(base,(script|style|meta|link|object|isindex)*, 137 // (title,(script|style|meta|link|object|isindex)*))))" 138 writeStartTag( TITLE ); 139 writeEndTag( TITLE ); 140 } 141 142 setHeadFlag( false ); 143 setHeadTitleFlag( false ); 144 145 if ( encoding != null ) 146 { 147 write( "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=" + encoding + "\"/>" ); 148 } 149 150 writeEndTag( HEAD ); 151 } 152 153 /** 154 * {@inheritDoc} 155 * @see javax.swing.text.html.HTML.Tag#TITLE 156 */ 157 public void title() 158 { 159 setHeadTitleFlag( true ); 160 161 writeStartTag( TITLE ); 162 } 163 164 /** 165 * {@inheritDoc} 166 * @see javax.swing.text.html.HTML.Tag#TITLE 167 */ 168 public void title_() 169 { 170 content( getTextBuffer().toString() ); 171 172 writeEndTag( TITLE ); 173 174 resetTextBuffer(); 175 176 } 177 178 /** 179 * {@inheritDoc} 180 * @see javax.swing.text.html.HTML.Tag#META 181 */ 182 public void author_() 183 { 184 if ( getTextBuffer().length() > 0 ) 185 { 186 MutableAttributeSet att = new SinkEventAttributeSet(); 187 att.addAttribute( Attribute.NAME, "author" ); 188 String text = HtmlTools.escapeHTML( getTextBuffer().toString() ); 189 // hack: un-escape numerical entities that have been escaped above 190 // note that numerical entities should really be added as one unicode character in the first place 191 text = StringUtils.replace( text, "&#", "&#" ); 192 att.addAttribute( Attribute.CONTENT, text ); 193 194 writeSimpleTag( META, att ); 195 196 resetTextBuffer(); 197 } 198 } 199 200 /** 201 * {@inheritDoc} 202 * @see javax.swing.text.html.HTML.Tag#META 203 */ 204 public void date_() 205 { 206 if ( getTextBuffer().length() > 0 ) 207 { 208 MutableAttributeSet att = new SinkEventAttributeSet(); 209 att.addAttribute( Attribute.NAME, "date" ); 210 att.addAttribute( Attribute.CONTENT, getTextBuffer().toString() ); 211 212 writeSimpleTag( META, att ); 213 214 resetTextBuffer(); 215 } 216 } 217 218 /** 219 * {@inheritDoc} 220 * @see javax.swing.text.html.HTML.Tag#BODY 221 */ 222 public void body() 223 { 224 writeStartTag( BODY ); 225 } 226 227 /** 228 * {@inheritDoc} 229 * @see javax.swing.text.html.HTML.Tag#BODY 230 * @see javax.swing.text.html.HTML.Tag#HTML 231 */ 232 public void body_() 233 { 234 writeEndTag( BODY ); 235 236 writeEndTag( HTML ); 237 238 flush(); 239 240 init(); 241 } 242 243 // ---------------------------------------------------------------------- 244 // Public protected methods 245 // ---------------------------------------------------------------------- 246 247 /** 248 * <p>Setter for the field <code>headTitleFlag</code>.</p> 249 * 250 * @param headTitleFlag an header title flag. 251 * @since 1.1 252 */ 253 protected void setHeadTitleFlag( boolean headTitleFlag ) 254 { 255 this.headTitleFlag = headTitleFlag; 256 } 257 258 /** 259 * <p>isHeadTitleFlag.</p> 260 * 261 * @return the current headTitleFlag. 262 * @since 1.1 263 */ 264 protected boolean isHeadTitleFlag() 265 { 266 return this.headTitleFlag ; 267 } 268 }