001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.components.serializers;
018:
019: import org.apache.avalon.framework.configuration.Configuration;
020: import org.apache.avalon.framework.configuration.ConfigurationException;
021: import org.apache.cocoon.components.serializers.encoding.XHTMLEncoder;
022: import org.apache.cocoon.components.serializers.util.DocType;
023: import org.xml.sax.SAXException;
024:
025: /**
026: * <p>A pedantinc XHTML serializer encoding all recognized entities with their
027: * proper HTML names.</p>
028: *
029: * <p>For configuration options of this serializer, please look at the
030: * {@link EncodingSerializer}, in addition to those, this serializer also
031: * support the specification of a default doctype. This default will be used
032: * if no document type is received in the SAX events, and can be configured
033: * in the following way:</p>
034: *
035: * <pre>
036: * <serializer class="org.apache.cocoon.components.serializers..." ... >
037: * <doctype-default>mytype</doctype-default>
038: * </serializer>
039: * </pre>
040: *
041: * <p>The value <i>mytype</i> can be one of:</p>
042: *
043: * <dl>
044: * <dt>"<code>none</code>"</dt>
045: * <dd>Not to emit any dococument type declaration.</dd>
046: * <dt>"<code>strict</code>"</dt>
047: * <dd>The XHTML 1.0 Strict document type.</dd>
048: * <dt>"<code>loose</code>"</dt>
049: * <dd>The XHTML 1.0 Transitional document type.</dd>
050: * <dt>"<code>frameset</code>"</dt>
051: * <dd>The XHTML 1.0 Frameset document type.</dd>
052: * </dl>
053: *
054: * @version CVS $Id: XHTMLSerializer.java 433543 2006-08-22 06:22:54Z crossley $
055: */
056: public class XHTMLSerializer extends XMLSerializer {
057:
058: /** The namespace URI for XHTML 1.0. */
059: public static final String XHTML1_NAMESPACE = "http://www.w3.org/1999/xhtml";
060:
061: /** A representation of the XHTML 1.0 strict document type. */
062: public static final DocType XHTML1_DOCTYPE_STRICT = new DocType(
063: "html", "-//W3C//DTD XHTML 1.0 Strict//EN",
064: "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd");
065:
066: /** A representation of the XHTML 1.0 transitional document type. */
067: public static final DocType XHTML1_DOCTYPE_TRANSITIONAL = new DocType(
068: "html", "-//W3C//DTD XHTML 1.0 Transitional//EN",
069: "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd");
070:
071: /** A representation of the XHTML 1.0 frameset document type. */
072: public static final DocType XHTML1_DOCTYPE_FRAMESET = new DocType(
073: "html", "-//W3C//DTD XHTML 1.0 Frameset//EN",
074: "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd");
075:
076: /* ====================================================================== */
077:
078: private static final XHTMLEncoder XHTML_ENCODER = new XHTMLEncoder();
079:
080: /* ====================================================================== */
081:
082: /** The <code>DocType</code> instance representing the document. */
083: protected DocType doctype_default = null;
084:
085: /** Define whether to put XML declaration in the head of the document. */
086: private String omitXmlDeclaration = null;
087:
088: /* ====================================================================== */
089:
090: /**
091: * Create a new instance of this <code>XHTMLSerializer</code>
092: */
093: public XHTMLSerializer() {
094: super (XHTML_ENCODER);
095: }
096:
097: /**
098: * Create a new instance of this <code>XHTMLSerializer</code>
099: */
100: protected XHTMLSerializer(XHTMLEncoder encoder) {
101: super (encoder);
102: }
103:
104: /**
105: * Return the MIME Content-Type produced by this serializer.
106: */
107: public String getMimeType() {
108: if (this .charset == null)
109: return ("text/html");
110: return ("text/html; charset=" + this .charset.getName());
111: }
112:
113: /**
114: * Configure this instance by selecting the default document type to use.
115: */
116: public void configure(Configuration conf)
117: throws ConfigurationException {
118: super .configure(conf);
119:
120: this .omitXmlDeclaration = conf.getChild("omit-xml-declaration")
121: .getValue(null);
122:
123: String doctype = conf.getChild("doctype-default")
124: .getValue(null);
125: if ("none".equalsIgnoreCase(doctype)) {
126: this .doctype_default = null;
127: } else if ("strict".equalsIgnoreCase(doctype)) {
128: this .doctype_default = XHTML1_DOCTYPE_STRICT;
129: } else if ("loose".equalsIgnoreCase(doctype)) {
130: this .doctype_default = XHTML1_DOCTYPE_TRANSITIONAL;
131: } else if ("frameset".equalsIgnoreCase(doctype)) {
132: this .doctype_default = XHTML1_DOCTYPE_FRAMESET;
133: } else {
134: /* Default is transitional */
135: this .doctype_default = XHTML1_DOCTYPE_TRANSITIONAL;
136: }
137: }
138:
139: /* ====================================================================== */
140:
141: /**
142: * Write the XML document header.
143: * <p>
144: * This method will write out the <code><?xml version="1.0"
145: * ...></code> header unless omit-xml-declaration is set.
146: * </p>
147: */
148: protected void head() throws SAXException {
149: if (!"yes".equals(this .omitXmlDeclaration)) {
150: super .head();
151: }
152: }
153:
154: /**
155: * Receive notification of the beginning of the document body.
156: *
157: * @param uri The namespace URI of the root element.
158: * @param local The local name of the root element.
159: * @param qual The fully-qualified name of the root element.
160: */
161: public void body(String uri, String local, String qual)
162: throws SAXException {
163: if (this .doctype == null)
164: this .doctype = this .doctype_default;
165: if (this .namespaces.getUri("").length() == 0) {
166: this .namespaces.push("", XHTML1_NAMESPACE);
167: }
168: super .body(uri, local, qual);
169: }
170:
171: /**
172: * Receive notification of the beginning of an element.
173: *
174: * @param uri The namespace URI of the root element.
175: * @param local The local name of the root element.
176: * @param qual The fully-qualified name of the root element.
177: * @param namespaces An array of <code>String</code> objects containing
178: * the namespaces to be declared by this element.
179: * @param attributes An array of <code>String</code> objects containing
180: * all attributes of this element.
181: */
182: public void startElementImpl(String uri, String local, String qual,
183: String namespaces[][], String attributes[][])
184: throws SAXException {
185: if (uri.length() == 0)
186: uri = XHTML1_NAMESPACE;
187: super
188: .startElementImpl(uri, local, qual, namespaces,
189: attributes);
190: }
191:
192: /**
193: * Receive notification of the end of an element.
194: *
195: * @param uri The namespace URI of the root element.
196: * @param local The local name of the root element.
197: * @param qual The fully-qualified name of the root element.
198: */
199: public void endElementImpl(String uri, String local, String qual)
200: throws SAXException {
201: if (uri.length() == 0)
202: uri = XHTML1_NAMESPACE;
203:
204: if (XHTML1_NAMESPACE.equals(uri)) {
205: if ((local.equalsIgnoreCase("textarea"))
206: || (local.equalsIgnoreCase("script"))
207: || (local.equalsIgnoreCase("style"))) {
208: this .closeElement(false);
209: } else if (local.equalsIgnoreCase("head")) {
210: String loc = "meta";
211: String qua = namespaces.qualify(XHTML1_NAMESPACE, loc,
212: "meta");
213: String nsp[][] = new String[0][0];
214: String att[][] = new String[2][ATTRIBUTE_LENGTH];
215:
216: att[0][ATTRIBUTE_NSURI] = att[1][ATTRIBUTE_NSURI] = "";
217: att[0][ATTRIBUTE_LOCAL] = att[0][ATTRIBUTE_QNAME] = "http-equiv";
218: att[1][ATTRIBUTE_LOCAL] = att[1][ATTRIBUTE_QNAME] = "content";
219: att[0][ATTRIBUTE_VALUE] = "Content-Type";
220: att[1][ATTRIBUTE_VALUE] = this .getMimeType();
221:
222: this .closeElement(false);
223: this.startElementImpl(XHTML1_NAMESPACE, loc, qua, nsp,
224: att);
225: this.endElementImpl(XHTML1_NAMESPACE, loc, qua);
226: }
227: }
228: super.endElementImpl(uri, local, qual);
229: }
230:
231: }
|