001: package net.sf.saxon.event;
002:
003: import net.sf.saxon.Controller;
004: import net.sf.saxon.Configuration;
005: import net.sf.saxon.om.ExternalObjectModel;
006: import net.sf.saxon.trans.DynamicError;
007: import net.sf.saxon.trans.XPathException;
008:
009: import javax.xml.transform.OutputKeys;
010: import javax.xml.transform.Result;
011: import javax.xml.transform.sax.SAXResult;
012: import javax.xml.transform.stream.StreamResult;
013: import java.util.List;
014: import java.util.Properties;
015:
016: /**
017: * Helper class to construct a serialization pipeline for a given result destination
018: * and a given set of output properties. The pipeline is represented by a Receiver object
019: * to which result tree events are sent
020: */
021:
022: public class ResultWrapper {
023:
024: // Class is never instantiated
025: private ResultWrapper() {
026: }
027:
028: /**
029: * Get a Receiver that wraps a given Result object
030: */
031:
032: public static Receiver getReceiver(Result result,
033: PipelineConfiguration pipe, Properties props)
034: throws XPathException {
035: if (result instanceof Emitter) {
036: ((Emitter) result).setOutputProperties(props);
037: return (Emitter) result;
038: } else if (result instanceof Receiver) {
039: Receiver builder = (Receiver) result;
040: builder.setSystemId(result.getSystemId());
041: builder.setPipelineConfiguration(pipe);
042: builder.open();
043: builder.startDocument(0);
044: return builder;
045: } else if (result instanceof SAXResult) {
046: ContentHandlerProxy proxy = new ContentHandlerProxy();
047: proxy.setUnderlyingContentHandler(((SAXResult) result)
048: .getHandler());
049: proxy.setPipelineConfiguration(pipe);
050: return proxy;
051: } else if (result instanceof StreamResult) {
052:
053: // The "target" is the start of the output pipeline, the Receiver that
054: // instructions will actually write to (except that other things like a
055: // NamespaceReducer may get added in front of it). The "emitter" is the
056: // last thing in the output pipeline, the Receiver that actually generates
057: // characters or bytes that are written to the StreamResult.
058:
059: Receiver target;
060: Emitter emitter;
061:
062: CharacterMapExpander characterMapExpander = null;
063: String useMaps = props
064: .getProperty(SaxonOutputKeys.USE_CHARACTER_MAPS);
065: if (useMaps != null) {
066: Controller controller = pipe.getController();
067: if (controller == null) {
068: throw new DynamicError(
069: "Cannot use character maps in an environment with no Controller");
070: }
071: characterMapExpander = controller
072: .makeCharacterMapExpander(useMaps);
073: }
074:
075: UnicodeNormalizer normalizer = null;
076: String normForm = props
077: .getProperty(SaxonOutputKeys.NORMALIZATION_FORM);
078: if (normForm != null && !normForm.equals("none")) {
079: normalizer = new UnicodeNormalizer(normForm);
080: }
081:
082: String method = props.getProperty(OutputKeys.METHOD);
083: if (method == null) {
084: target = new UncommittedSerializer(result, props);
085: target.setPipelineConfiguration(pipe);
086: return target;
087:
088: } else if ("html".equals(method)) {
089: emitter = new HTMLEmitter();
090: emitter.setPipelineConfiguration(pipe);
091: target = createHTMLSerializer(emitter, props, pipe,
092: characterMapExpander, normalizer);
093:
094: } else if ("xml".equals(method)) {
095: emitter = new XMLEmitter();
096: emitter.setPipelineConfiguration(pipe);
097: target = createXMLSerializer(emitter, props, pipe,
098: normalizer, characterMapExpander);
099:
100: } else if ("xhtml".equals(method)) {
101: emitter = new XHTMLEmitter();
102: emitter.setPipelineConfiguration(pipe);
103: target = createXHTMLSerializer(emitter, props, pipe,
104: normalizer, characterMapExpander);
105:
106: } else if ("text".equals(method)) {
107: emitter = new TEXTEmitter();
108: emitter.setPipelineConfiguration(pipe);
109: target = createTextSerializer(emitter,
110: characterMapExpander, normalizer);
111:
112: } else {
113: Receiver userReceiver;
114: // See if this output method is recognized by the Configuration
115: userReceiver = pipe.getConfiguration().getOutputMethod(
116: method);
117: if (userReceiver == null) {
118: int brace = method.indexOf('}');
119: String localName = method.substring(brace + 1);
120: int colon = localName.indexOf(':');
121: localName = localName.substring(colon + 1);
122: userReceiver = Emitter.makeEmitter(localName, pipe
123: .getController());
124: }
125: userReceiver.setPipelineConfiguration(pipe);
126: target = userReceiver;
127: if (userReceiver instanceof Emitter) {
128: emitter = (Emitter) userReceiver;
129: } else {
130: return userReceiver;
131: }
132: }
133: emitter.setOutputProperties(props);
134: StreamResult sr = (StreamResult) result;
135: emitter.setStreamResult(sr);
136: return target;
137:
138: } else {
139: // try to find an external object model that knows this kind of Result
140: List externalObjectModels = pipe.getConfiguration()
141: .getExternalObjectModels();
142: for (int m = 0; m < externalObjectModels.size(); m++) {
143: ExternalObjectModel model = (ExternalObjectModel) externalObjectModels
144: .get(m);
145: Receiver builder = model.getDocumentBuilder(result);
146: if (builder != null) {
147: builder.setSystemId(result.getSystemId());
148: builder.setPipelineConfiguration(pipe);
149: return builder;
150: }
151: }
152: }
153:
154: throw new IllegalArgumentException("Unknown type of result: "
155: + result.getClass());
156: }
157:
158: private static Receiver createHTMLSerializer(Emitter emitter,
159: Properties props, PipelineConfiguration pipe,
160: CharacterMapExpander characterMapExpander,
161: UnicodeNormalizer normalizer) throws XPathException {
162: Receiver target;
163: target = emitter;
164: if (!"no".equals(props.getProperty(OutputKeys.INDENT))) {
165: HTMLIndenter in = new HTMLIndenter();
166: in.setUnderlyingReceiver(target);
167: in.setPipelineConfiguration(pipe);
168: in.setOutputProperties(props);
169: target = in;
170: }
171: if (!"no".equals(props
172: .getProperty(SaxonOutputKeys.INCLUDE_CONTENT_TYPE))) {
173: MetaTagAdjuster in = new MetaTagAdjuster();
174: in.setUnderlyingReceiver(target);
175: in.setPipelineConfiguration(pipe);
176: in.setIsXHTML(false);
177: in.setOutputProperties(props);
178: target = in;
179: }
180: if (normalizer != null) {
181: normalizer.setUnderlyingReceiver(target);
182: target = normalizer;
183: target.setPipelineConfiguration(pipe);
184: }
185: if (characterMapExpander != null) {
186: characterMapExpander.setUnderlyingReceiver(target);
187: target = characterMapExpander;
188: target.setPipelineConfiguration(pipe);
189: }
190: if (!"no".equals(props
191: .getProperty(SaxonOutputKeys.ESCAPE_URI_ATTRIBUTES))) {
192: HTMLURIEscaper escaper = new HTMLURIEscaper();
193: escaper.setUnderlyingReceiver(target);
194: target = escaper;
195: target.setPipelineConfiguration(pipe);
196: }
197: return target;
198: }
199:
200: private static Receiver createTextSerializer(Emitter emitter,
201: CharacterMapExpander characterMapExpander,
202: UnicodeNormalizer normalizer) {
203: Receiver target;
204: target = emitter;
205: if (characterMapExpander != null) {
206: characterMapExpander.setUnderlyingReceiver(target);
207: characterMapExpander.setUseNullMarkers(false);
208: target = characterMapExpander;
209: }
210: if (normalizer != null) {
211: normalizer.setUnderlyingReceiver(target);
212: target = normalizer;
213: }
214: return target;
215: }
216:
217: private static Receiver createXHTMLSerializer(Emitter emitter,
218: Properties props, PipelineConfiguration pipe,
219: UnicodeNormalizer normalizer,
220: CharacterMapExpander characterMapExpander)
221: throws XPathException {
222: Receiver target;
223: target = emitter;
224: if (!"no".equals(props.getProperty(OutputKeys.INDENT))) {
225: XHTMLIndenter in = new XHTMLIndenter();
226: in.setUnderlyingReceiver(target);
227: in.setPipelineConfiguration(pipe);
228: in.setOutputProperties(props);
229: target = in;
230: }
231: if (!"no".equals(props
232: .getProperty(SaxonOutputKeys.INCLUDE_CONTENT_TYPE))) {
233: MetaTagAdjuster in = new MetaTagAdjuster();
234: in.setUnderlyingReceiver(target);
235: in.setPipelineConfiguration(pipe);
236: in.setIsXHTML(true);
237: in.setOutputProperties(props);
238: target = in;
239: }
240: String cdataElements = props
241: .getProperty(OutputKeys.CDATA_SECTION_ELEMENTS);
242: if (cdataElements != null && cdataElements.length() > 0) {
243: CDATAFilter filter = new CDATAFilter();
244: filter.setUnderlyingReceiver(target);
245: filter.setPipelineConfiguration(pipe);
246: filter.setOutputProperties(props);
247: target = filter;
248: }
249: if (normalizer != null) {
250: normalizer.setUnderlyingReceiver(target);
251: normalizer.setPipelineConfiguration(pipe);
252: target = normalizer;
253: }
254: if (characterMapExpander != null) {
255: characterMapExpander.setUnderlyingReceiver(target);
256: characterMapExpander.setPipelineConfiguration(pipe);
257: target = characterMapExpander;
258: }
259: if (!"no".equals(props
260: .getProperty(SaxonOutputKeys.ESCAPE_URI_ATTRIBUTES))) {
261: HTMLURIEscaper escaper = new HTMLURIEscaper();
262: escaper.setUnderlyingReceiver(target);
263: escaper.setPipelineConfiguration(pipe);
264: target = escaper;
265: }
266: return target;
267: }
268:
269: private static Receiver createXMLSerializer(Emitter emitter,
270: Properties props, PipelineConfiguration pipe,
271: UnicodeNormalizer normalizer,
272: CharacterMapExpander characterMapExpander)
273: throws XPathException {
274: Receiver target;
275: target = emitter;
276: if ("1.0".equals(props.getProperty(OutputKeys.VERSION))
277: && pipe.getConfiguration().getXMLVersion() == Configuration.XML11) {
278: // Check result meets XML 1.0 constraints if configuration allows XML 1.1 input but
279: // this result document must conform to 1.0
280: XML10ContentChecker in = new XML10ContentChecker();
281: in.setUnderlyingReceiver(target);
282: in.setPipelineConfiguration(pipe);
283: target = in;
284: }
285: if ("yes".equals(props.getProperty(OutputKeys.INDENT))) {
286: XMLIndenter in = new XMLIndenter();
287: in.setUnderlyingReceiver(target);
288: in.setPipelineConfiguration(pipe);
289: in.setOutputProperties(props);
290: target = in;
291: }
292: String cdataElements = props
293: .getProperty(OutputKeys.CDATA_SECTION_ELEMENTS);
294: if (cdataElements != null && cdataElements.length() > 0) {
295: CDATAFilter filter = new CDATAFilter();
296: filter.setUnderlyingReceiver(target);
297: filter.setPipelineConfiguration(pipe);
298: filter.setOutputProperties(props);
299: target = filter;
300: }
301: if (normalizer != null) {
302: normalizer.setUnderlyingReceiver(target);
303: target = normalizer;
304: }
305: if (characterMapExpander != null) {
306: characterMapExpander.setUnderlyingReceiver(target);
307: target = characterMapExpander;
308: }
309: return target;
310: }
311: }
312:
313: //
314: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
315: // you may not use this file except in compliance with the License. You may obtain a copy of the
316: // License at http://www.mozilla.org/MPL/
317: //
318: // Software distributed under the License is distributed on an "AS IS" basis,
319: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
320: // See the License for the specific language governing rights and limitations under the License.
321: //
322: // The Original Code is: all this file.
323: //
324: // The Initial Developer of the Original Code is Michael H. Kay.
325: //
326: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
327: //
328: // Contributor(s): none.
329: //
|