View Javadoc

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, "&amp;#", "&#" );
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 }