zcommon/src/main/java/org/zkoss/idom/transform/Transformer.java
/* Transformer.java
Purpose:
Description:
History:
Mon May 13 17:31:01 2002, Created by andrewho
May 19 2003, Modified by tomyeh to make API more complete
and let developer know about Source and Result
Copyright (C) 2002 Potix Corporation. All Rights Reserved.
{{IS_RIGHT
This program is distributed under LGPL Version 2.1 in the hope that
it will be useful, but WITHOUT ANY WARRANTY.
}}IS_RIGHT
*/
package org.zkoss.idom.transform;
import java.util.Properties;
import javax.xml.XMLConstants;
import javax.xml.transform.ErrorListener;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXResult;
import org.zkoss.idom.DocType;
import org.zkoss.idom.Document;
import org.zkoss.idom.Element;
import org.zkoss.idom.input.SAXHandler;
/**
* Transforms an iDOM Document.
*
* @author <a href="mailto:andrewho@potix.com">andrewho@potix.com</a>
* @author tomyeh
*/
public class Transformer {
/** The transformer. */
private final javax.xml.transform.Transformer _tfmr;
/** Whether to output doc-type. */
private boolean _outDocType = true;
/**
* Transformer constructor without stylesheet.
*/
public Transformer()
throws TransformerConfigurationException {
final TransformerFactory tf = initFactory();
_tfmr = tf.newTransformer();
}
/** Constructs a transformer with a stylesheet in form of Source.
*
* <p>Examples:<br>
* <dl>
* <dt>File file</dt>
* <dd>new Transformer(new javax.xml.transform.stream.StreamSource(file));</dd>
* <dt>Reader reader</dt>
* <dd>new Transformer(new javax.xml.transform.stream.StreamSource(reader));</dd>
* <dt>URL url</dt>
* <dd>new Transformer(new javax.xml.transform.stream.StreamSource(url.openStream()));</dd>
* <dt>iDOM or DOM dom</dt>
* <dd>new Transformer(new javax.xml.transform.dom.DOMSource(dom));</dd>
* </dl>
*
* <p>See javax.xml.transform.stream.StreamSource
* and javax.xml.transform.dom.DOMSource
*/
public Transformer(Source source)
throws TransformerConfigurationException {
final TransformerFactory tf = initFactory();
_tfmr = source != null ? tf.newTransformer(source): tf.newTransformer();
}
// Fix XXE issue
private TransformerFactory initFactory() {
final TransformerFactory tf = TransformerFactory.newInstance();
try {
// Prevents external entity attacks (XXE)
tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
// Alternatively, you can use the following settings
// These settings might be required for some Java versions
tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
tf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
tf.setFeature("http://xml.org/sax/features/external-general-entities", false);
tf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
} catch (TransformerConfigurationException e) {
// Handle the potential exception here
}
return tf;
}
/** Sets whether to output the doc type.
* Default: true.
*
* <p>Useful only if {@link Document} is used in transform(), e.g.,
* {@link #transform(Document, Result)}.
* If not, you have to set OutputKeys.DOCTYPE_SYSTEM and
* OutputKeys.DOCTYPE_PUBLIC explicitly (thru {@link #getTransformer}).
*/
public final void enableOutputDocType(boolean enable) {
_outDocType = enable;
}
private final Document processDocType(final Document doc) {
if (!_outDocType)
return doc;
final DocType dt = doc.getDocType();
if (dt == null)
return doc;
final String sysid = dt.getSystemId();
if (sysid != null && sysid.length() > 0)
_tfmr.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, sysid);
final String pubid = dt.getPublicId();
if (pubid != null && pubid.length() > 0)
_tfmr.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, pubid);
return doc;
}
/** Returns the JAXP transformer encapsulated by this object.
* Then, you can use it to set properties, listener and so on.
* <p>Notice: OutputKeys.DOCTYPE_SYSTEM and OutputKeys.DOCTYPE_PUBLIC
* are set automatically if outDocType is true when constructing
* this object and {@link Document} is used to transform.
*/
public final javax.xml.transform.Transformer getTransformer() {
return _tfmr;
}
/**
* Transforms from a source to a result.
*
* and javax.xml.transform.dom.DOMSource
* @param source the source
* @param result the result
* @see #transform(Document, Result)
*/
public final void transform(Source source, Result result)
throws TransformerException {
_tfmr.transform(source, result);
}
/**
* Transforms from an iDOM document to a result.
*
* <p>Examples:<br>
* <dl>
* <dt>File file</dt>
* <dd>transformer.transform(doc, new javax.xml.transform.stream.StreamResult(file));</dd>
* <dt>Writer writer</dt>
* <dd>transformer.transform(doc, new javax.xml.transform.stream.StreamResult(writer));</dd>
* <dt>URL url</dt>
* <dd>No simple way yet.</dd>
* <dt>iDOM or DOM dom</dt>
* <dd>{@link #transform(Source)} and {@link #transform(Document)}.</dd>
* <dt>String systemId</dt>
* <dd>transformer.transform(doc, new javax.xml.transform.stream.StreamResult(systemId));</dd>
* </dl>
*
* <p>See javax.xml.transform.stream.StreamResult
* and javax.xml.transform.dom.DOMResult
*
* @param doc the source document
* @param result the result
* @see #transform(Source, Result)
* @see #transform(Document)
*/
public final void transform(Document doc, Result result)
throws TransformerException {
_tfmr.transform(new DOMSource(processDocType(doc)), result);
}
/**
* Transforms from an iDOM element to a result.
*
* @param elm the source element
* @param result the result
*/
public final void transform(Element elm, Result result)
throws TransformerException {
_tfmr.transform(new DOMSource(elm), result);
}
/**
* Transforms a source and returns the transformed result as
* an iDOM Document.
*
* @param source the source
* @return the transformed result in an iDOM document
*/
public final Document transform(Source source)
throws TransformerException {
final SAXHandler hdl = new SAXHandler();
_tfmr.transform(source, new SAXResult(hdl));
return hdl.getDocument();
}
/**
* Transforms an iDOM document and returns the transformed result as
* another iDOM Document.
*
* @param doc the source document
* @return the transformed result in an iDOM document
*/
public final Document transform(Document doc)
throws TransformerException {
return transform(new DOMSource(processDocType(doc)));
}
/**
* Transforms an iDOM element and returns the transformed result as
* another iDOM Document.
*
* @param elm the source element
* @return the transformed result in an iDOM document
*/
public final Document transform(Element elm)
throws TransformerException {
return transform(new DOMSource(elm));
}
/** Get a copy of the output properties for the transformation.
*/
public final Properties getOutputProperties() {
return _tfmr.getOutputProperties();
}
/** Get an output property that is in effect for the transformation.
*/
public final String getOutputProperty(String name) {
return _tfmr.getOutputProperty(name);
}
/** Set an output property that will be in effect for the transformation.
*/
public final void setOutputProperty(String name, String value) {
_tfmr.setOutputProperty(name, value);
}
/** Set the output properties for the transformation.
*/
public final void setOutputProperties(Properties props) {
_tfmr.setOutputProperties(props);
}
/** Get the error event handler in effect for the transformation.
*/
public final ErrorListener getErrorListener() {
return _tfmr.getErrorListener();
}
/** Set the error event listener in effect for the transformation.
*/
public final void setErrorListener(ErrorListener listener) {
_tfmr.setErrorListener(listener);
}
}