KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xalan > xsltc > compiler > Output


1 /*
2  * Copyright 2001-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 /*
17  * $Id: Output.java,v 1.25 2004/02/24 03:55:48 zongaro Exp $
18  */

19
20 package org.apache.xalan.xsltc.compiler;
21
22 import java.io.OutputStreamWriter JavaDoc;
23 import java.util.Properties JavaDoc;
24 import java.util.StringTokenizer JavaDoc;
25
26 import javax.xml.transform.OutputKeys JavaDoc;
27
28 import org.apache.bcel.generic.ConstantPoolGen;
29 import org.apache.bcel.generic.INVOKEVIRTUAL;
30 import org.apache.bcel.generic.InstructionList;
31 import org.apache.bcel.generic.PUSH;
32 import org.apache.bcel.generic.PUTFIELD;
33 import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
34 import org.apache.xalan.xsltc.compiler.util.ErrorMsg;
35 import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
36 import org.apache.xalan.xsltc.compiler.util.Util;
37 import org.apache.xml.serializer.Encodings;
38 import org.apache.xml.utils.XMLChar;
39
40 /**
41  * @author Jacek Ambroziak
42  * @author Santiago Pericas-Geertsen
43  * @author Morten Jorgensen
44  */

45 final class Output extends TopLevelElement {
46
47     // TODO: use three-value variables for boolean values: true/false/default
48

49     // These attributes are extracted from the xsl:output element. They also
50
// appear as fields (with the same type, only public) in the translet
51
private String JavaDoc _version;
52     private String JavaDoc _method;
53     private String JavaDoc _encoding;
54     private boolean _omitHeader = false;
55     private String JavaDoc _standalone;
56     private String JavaDoc _doctypePublic;
57     private String JavaDoc _doctypeSystem;
58     private String JavaDoc _cdata;
59     private boolean _indent = false;
60     private String JavaDoc _mediaType;
61     private String JavaDoc _cdataToMerge;
62
63     // Disables this output element (when other element has higher precedence)
64
private boolean _disabled = false;
65
66     // Some global constants
67
private final static String JavaDoc STRING_SIG = "Ljava/lang/String;";
68     private final static String JavaDoc XML_VERSION = "1.0";
69     private final static String JavaDoc HTML_VERSION = "4.0";
70
71     /**
72      * Displays the contents of this element (for debugging)
73      */

74     public void display(int indent) {
75     indent(indent);
76     Util.println("Output " + _method);
77     }
78
79     /**
80      * Disables this <xsl:output> element in case where there are some other
81      * <xsl:output> element (from a different imported/included stylesheet)
82      * with higher precedence.
83      */

84     public void disable() {
85     _disabled = true;
86     }
87
88     public boolean enabled() {
89     return !_disabled;
90     }
91
92     public String JavaDoc getCdata() {
93     return _cdata;
94     }
95
96     public String JavaDoc getOutputMethod() {
97         return _method;
98     }
99     
100     public void mergeCdata(String JavaDoc cdata) {
101     _cdataToMerge = cdata;
102     }
103
104     /**
105      * Scans the attribute list for the xsl:output instruction
106      */

107     public void parseContents(Parser parser) {
108     final Properties JavaDoc outputProperties = new Properties JavaDoc();
109
110     // Ask the parser if it wants this <xsl:output> element
111
parser.setOutput(this);
112
113     // Do nothing if other <xsl:output> element has higher precedence
114
if (_disabled) return;
115
116     String JavaDoc attrib = null;
117
118     // Get the output version
119
_version = getAttribute("version");
120     if (_version == null || _version.equals(Constants.EMPTYSTRING)) {
121         _version = null;
122     }
123     else {
124         outputProperties.setProperty(OutputKeys.VERSION, _version);
125     }
126
127     // Get the output method - "xml", "html", "text" or <qname> (but not ncname)
128
_method = getAttribute("method");
129     if (_method.equals(Constants.EMPTYSTRING)) {
130         _method = null;
131     }
132     if (_method != null) {
133             _method = _method.toLowerCase();
134             if ((_method.equals("xml"))||
135                 (_method.equals("html"))||
136                 (_method.equals("text"))||
137                 ((XMLChar.isValidQName(_method)&&(_method.indexOf(":") > 0)))) {
138            outputProperties.setProperty(OutputKeys.METHOD, _method);
139             } else {
140                 reportError(this, parser, ErrorMsg.INVALID_METHOD_IN_OUTPUT, _method);
141             }
142     }
143
144     // Get the output encoding - any value accepted here
145
_encoding = getAttribute("encoding");
146     if (_encoding.equals(Constants.EMPTYSTRING)) {
147         _encoding = null;
148     }
149     else {
150         try {
151         // Create a write to verify encoding support
152
String JavaDoc canonicalEncoding;
153         canonicalEncoding = Encodings.convertMime2JavaEncoding(_encoding);
154         OutputStreamWriter JavaDoc writer =
155             new OutputStreamWriter JavaDoc(System.out, canonicalEncoding);
156         }
157         catch (java.io.UnsupportedEncodingException JavaDoc e) {
158         ErrorMsg msg = new ErrorMsg(ErrorMsg.UNSUPPORTED_ENCODING,
159                         _encoding, this);
160         parser.reportError(Constants.WARNING, msg);
161         }
162         outputProperties.setProperty(OutputKeys.ENCODING, _encoding);
163     }
164
165     // Should the XML header be omitted - translate to true/false
166
attrib = getAttribute("omit-xml-declaration");
167     if (attrib != null && !attrib.equals(Constants.EMPTYSTRING)) {
168         if (attrib.equals("yes")) {
169         _omitHeader = true;
170         }
171         outputProperties.setProperty(OutputKeys.OMIT_XML_DECLARATION, attrib);
172     }
173
174     // Add 'standalone' decaration to output - use text as is
175
_standalone = getAttribute("standalone");
176     if (_standalone.equals(Constants.EMPTYSTRING)) {
177         _standalone = null;
178     }
179     else {
180         outputProperties.setProperty(OutputKeys.STANDALONE, _standalone);
181     }
182
183     // Get system/public identifiers for output DOCTYPE declaration
184
_doctypeSystem = getAttribute("doctype-system");
185     if (_doctypeSystem.equals(Constants.EMPTYSTRING)) {
186         _doctypeSystem = null;
187     }
188     else {
189         outputProperties.setProperty(OutputKeys.DOCTYPE_SYSTEM, _doctypeSystem);
190     }
191
192
193     _doctypePublic = getAttribute("doctype-public");
194     if (_doctypePublic.equals(Constants.EMPTYSTRING)) {
195         _doctypePublic = null;
196     }
197     else {
198         outputProperties.setProperty(OutputKeys.DOCTYPE_PUBLIC, _doctypePublic);
199     }
200
201     // Names the elements of whose text contents should be output as CDATA
202
_cdata = getAttribute("cdata-section-elements");
203     if (_cdata != null && _cdata.equals(Constants.EMPTYSTRING)) {
204         _cdata = null;
205     }
206     else {
207         StringBuffer JavaDoc expandedNames = new StringBuffer JavaDoc();
208         StringTokenizer JavaDoc tokens = new StringTokenizer JavaDoc(_cdata);
209
210         // Make sure to store names in expanded form
211
while (tokens.hasMoreTokens()) {
212                 String JavaDoc qname = tokens.nextToken();
213                 if (!XMLChar.isValidQName(qname)) {
214                     ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, qname, this);
215                     parser.reportError(Constants.ERROR, err);
216                 }
217         expandedNames.append(
218                parser.getQName(qname).toString()).append(' ');
219         }
220         _cdata = expandedNames.toString();
221         if (_cdataToMerge != null) {
222         _cdata = _cdata + _cdataToMerge;
223         }
224         outputProperties.setProperty(OutputKeys.CDATA_SECTION_ELEMENTS,
225         _cdata);
226     }
227
228     // Get the indent setting - only has effect for xml and html output
229
attrib = getAttribute("indent");
230     if (attrib != null && !attrib.equals(EMPTYSTRING)) {
231         if (attrib.equals("yes")) {
232         _indent = true;
233         }
234         outputProperties.setProperty(OutputKeys.INDENT, attrib);
235     }
236     else if (_method != null && _method.equals("html")) {
237         _indent = true;
238     }
239
240     // Get the MIME type for the output file
241
_mediaType = getAttribute("media-type");
242     if (_mediaType.equals(Constants.EMPTYSTRING)) {
243         _mediaType = null;
244     }
245     else {
246         outputProperties.setProperty(OutputKeys.MEDIA_TYPE, _mediaType);
247     }
248
249     // Implied properties
250
if (_method != null) {
251         if (_method.equals("html")) {
252         if (_version == null) {
253             _version = HTML_VERSION;
254         }
255         if (_mediaType == null) {
256             _mediaType = "text/html";
257         }
258         }
259         else if (_method.equals("text")) {
260         if (_mediaType == null) {
261             _mediaType = "text/plain";
262         }
263         }
264     }
265
266     // Set output properties in current stylesheet
267
parser.getCurrentStylesheet().setOutputProperties(outputProperties);
268     }
269
270     /**
271      * Compile code that passes the information in this <xsl:output> element
272      * to the appropriate fields in the translet
273      */

274     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
275
276     // Do nothing if other <xsl:output> element has higher precedence
277
if (_disabled) return;
278
279     ConstantPoolGen cpg = classGen.getConstantPool();
280     InstructionList il = methodGen.getInstructionList();
281
282     int field = 0;
283         il.append(classGen.loadTranslet());
284
285     // Only update _version field if set and different from default
286
if ((_version != null) && (!_version.equals(XML_VERSION))) {
287         field = cpg.addFieldref(TRANSLET_CLASS, "_version", STRING_SIG);
288         il.append(DUP);
289         il.append(new PUSH(cpg, _version));
290         il.append(new PUTFIELD(field));
291     }
292
293     // Only update _method field if "method" attribute used
294
if (_method != null) {
295         field = cpg.addFieldref(TRANSLET_CLASS, "_method", STRING_SIG);
296         il.append(DUP);
297         il.append(new PUSH(cpg, _method));
298         il.append(new PUTFIELD(field));
299     }
300
301     // Only update if _encoding field is "encoding" attribute used
302
if (_encoding != null) {
303         field = cpg.addFieldref(TRANSLET_CLASS, "_encoding", STRING_SIG);
304         il.append(DUP);
305         il.append(new PUSH(cpg, _encoding));
306         il.append(new PUTFIELD(field));
307     }
308
309     // Only update if "omit-xml-declaration" used and set to 'yes'
310
if (_omitHeader) {
311         field = cpg.addFieldref(TRANSLET_CLASS, "_omitHeader", "Z");
312         il.append(DUP);
313         il.append(new PUSH(cpg, _omitHeader));
314         il.append(new PUTFIELD(field));
315     }
316
317     // Add 'standalone' decaration to output - use text as is
318
if (_standalone != null) {
319         field = cpg.addFieldref(TRANSLET_CLASS, "_standalone", STRING_SIG);
320         il.append(DUP);
321         il.append(new PUSH(cpg, _standalone));
322         il.append(new PUTFIELD(field));
323     }
324
325     // Set system/public doctype only if both are set
326
field = cpg.addFieldref(TRANSLET_CLASS,"_doctypeSystem",STRING_SIG);
327     il.append(DUP);
328     il.append(new PUSH(cpg, _doctypeSystem));
329     il.append(new PUTFIELD(field));
330     field = cpg.addFieldref(TRANSLET_CLASS,"_doctypePublic",STRING_SIG);
331     il.append(DUP);
332     il.append(new PUSH(cpg, _doctypePublic));
333     il.append(new PUTFIELD(field));
334     
335     // Add 'medye-type' decaration to output - if used
336
if (_mediaType != null) {
337         field = cpg.addFieldref(TRANSLET_CLASS, "_mediaType", STRING_SIG);
338         il.append(DUP);
339         il.append(new PUSH(cpg, _mediaType));
340         il.append(new PUTFIELD(field));
341     }
342
343     // Compile code to set output indentation on/off
344
if (_indent) {
345         field = cpg.addFieldref(TRANSLET_CLASS, "_indent", "Z");
346         il.append(DUP);
347         il.append(new PUSH(cpg, _indent));
348         il.append(new PUTFIELD(field));
349     }
350
351     // Forward to the translet any elements that should be output as CDATA
352
if (_cdata != null) {
353         int index = cpg.addMethodref(TRANSLET_CLASS,
354                      "addCdataElement",
355                      "(Ljava/lang/String;)V");
356
357         StringTokenizer JavaDoc tokens = new StringTokenizer JavaDoc(_cdata);
358         while (tokens.hasMoreTokens()) {
359         il.append(DUP);
360         il.append(new PUSH(cpg, tokens.nextToken()));
361         il.append(new INVOKEVIRTUAL(index));
362         }
363     }
364     il.append(POP); // Cleanup - pop last translet reference off stack
365
}
366
367 }
368
Popular Tags