/**
* Copyright (C) 2010 Orbeon, Inc.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the Free Software Foundation; either version
* 2.1 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* The full text of the license is available at http://www.gnu.org/copyleft/lesser.html
*/
package org.orbeon.oxf.xml;
import org.orbeon.dom.Document;
import org.orbeon.dom.io.DocumentSource;
import org.orbeon.oxf.common.OXFException;
import org.orbeon.oxf.pipeline.api.TransformerXMLReceiver;
import org.orbeon.oxf.processor.transformer.TransformerURIResolver;
import org.orbeon.oxf.resources.URLFactory;
import org.orbeon.oxf.util.StringBuilderWriter;
import org.orbeon.oxf.util.XPath;
import org.orbeon.oxf.xml.dom4j.*;
import org.orbeon.saxon.Configuration;
import org.orbeon.saxon.TransformerFactoryImpl;
import org.orbeon.dom.saxon.DocumentWrapper;
import org.orbeon.saxon.om.DocumentInfo;
import org.orbeon.saxon.om.NodeInfo;
import org.orbeon.saxon.tinytree.TinyBuilder;
import org.w3c.dom.Node;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import scala.Tuple2;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
/**
* Utility class for XSLT and other transformations.
*/
public class TransformerUtils {
public static final String DEFAULT_OUTPUT_ENCODING = "utf-8";
/**
* Property name to use for choosing the amount of indentation.
*/
public static final String INDENT_AMOUNT_PROPERTY = "{http://orbeon.org/oxf/}indent-spaces";
private static final String SAXON_INDENT_AMOUNT_PROPERTY = "{http://saxon.sf.net/}indent-spaces";
// Class.forName is expensive, so we cache mappings
private static Map<String, Class> classNameToHandlerClass = new HashMap<String, Class>();
private static Class getTransformerClass(String clazz) throws ClassNotFoundException {
Class transformerClass = classNameToHandlerClass.get(clazz);
if (transformerClass == null) {
transformerClass = Class.forName(clazz);
classNameToHandlerClass.put(clazz, transformerClass);
}
return transformerClass;
}
/*
* NOTE: Factories are not thread-safe. So we should not store them into transformerFactories
* for now, or we should make sure there is one factory per thread, or that we synchronize.
*/
public static SAXTransformerFactory getFactory(String className, Map attributes, Configuration configuration) {
try {
final SAXTransformerFactory factory; {
if (className.equals(TransformerFactoryImpl.class.getName())) {
factory = new TransformerFactoryImpl(configuration);
} else {
factory = (SAXTransformerFactory) getTransformerClass(className).newInstance();
}
}
for (Iterator i = attributes.keySet().iterator(); i.hasNext();) {
final String key = (String) i.next();
factory.setAttribute(key, attributes.get(key));
}
return factory;
} catch (Exception e) {
throw new OXFException(e);
}
}
/*
* NOTE: Factories are not thread-safe. So we should not store them into transformerFactories
* for now, or we should make sure there is one factory per thread, or that we synchronize.
*/
public static SAXTransformerFactory getFactory(String clazz) {
try {
return (SAXTransformerFactory) getTransformerClass(clazz).newInstance();
} catch (Exception e) {
throw new OXFException(e);
}
}
public static Transformer getXMLIdentityTransformer() {
try {
Transformer transformer = getIdentityTransformer();
transformer.setOutputProperty(OutputKeys.ENCODING, DEFAULT_OUTPUT_ENCODING);
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.VERSION, "1.0");
transformer.setOutputProperty(OutputKeys.INDENT, "no");
transformer.setOutputProperty(INDENT_AMOUNT_PROPERTY, "0");
return transformer;
} catch (TransformerException e) {
throw new OXFException(e);
}
}
/**
* Apply output properties on a Transformer.
*
* @param transformer transformer to apply properties on
* @param method output method
* @param version HTML or XML version
* @param publicDoctype public doctype
* @param systemDoctype system doctype
* @param encoding character encoding
* @param omitXMLDeclaration whether XML declaration must be omitted
* @param standalone whether a standalone declaration must be set and to what value
* @param indent whether the HTML or XML must be indented
* @param indentAmount amount of indenting for the markup
*/
public static void applyOutputProperties(Transformer transformer,
String method,
String version,
String publicDoctype,
String systemDoctype,
String encoding,
boolean omitXMLDeclaration,
Boolean standalone,
boolean indent,
int indentAmount) {
if (method != null && !"".equals(method))
transformer.setOutputProperty(OutputKeys.METHOD, method);
if (version != null && !"".equals(version))
transformer.setOutputProperty(OutputKeys.VERSION, version);
if (publicDoctype != null && !"".equals(publicDoctype))
transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, publicDoctype);
if (systemDoctype != null && !"".equals(systemDoctype))
transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, systemDoctype);
if (encoding != null && !"".equals(encoding))
transformer.setOutputProperty(OutputKeys.ENCODING, encoding);
transformer.setOutputProperty(OutputKeys.INDENT, indent ? "yes" : "no");
if (indent)
transformer.setOutputProperty(INDENT_AMOUNT_PROPERTY, String.valueOf(indentAmount));
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, omitXMLDeclaration ? "yes" : "no");
if (standalone != null)
transformer.setOutputProperty(OutputKeys.STANDALONE, standalone ? "yes" : "no");
}
/**
* Return a new identity transformer object.
*
* @return a new identity Transformer object
* @throws TransformerConfigurationException
*/
public static Transformer getIdentityTransformer() throws TransformerConfigurationException {
return getIdentityTransformer(XPath.GlobalConfiguration());
}
public static Transformer getIdentityTransformer(Configuration configuration) throws TransformerConfigurationException {
// See https://github.com/orbeon/orbeon-forms/issues/2577
final Transformer transformer = new IdentityTransformerWithFixup(configuration);
return new TransformerWrapper(transformer, INDENT_AMOUNT_PROPERTY, SAXON_INDENT_AMOUNT_PROPERTY);
}
/**
* Return a new identity TransformerHandler object.
*
* @return a new identity TransformerHandler object
*/
public static TransformerXMLReceiver getIdentityTransformerHandler() {
return getIdentityTransformerHandler(XPath.GlobalConfiguration());
}
public static TransformerXMLReceiver getIdentityTransformerHandler(Configuration configuration) {
try {
TransformerHandler transformerHandler = new TransformerFactoryImpl(configuration).newTransformerHandler();
// Wrap TransformerHandler for properties
return new TransformerHandlerWrapper(transformerHandler, INDENT_AMOUNT_PROPERTY, SAXON_INDENT_AMOUNT_PROPERTY);
} catch (TransformerException e) {
throw new OXFException(e);
}
}
public static TransformerHandler getTransformerHandler(Templates templates, String clazz, Map attributes, Configuration configuration) throws TransformerConfigurationException {
return ((attributes != null) ? getFactory(clazz, attributes, configuration) : getFactory(clazz)).newTransformerHandler(templates);
}
public static Templates getTemplates(Source source, String clazz, Map attributes, Configuration configuration, ErrorListener errorListener, URIResolver uriResolver)
throws TransformerConfigurationException {
final SAXTransformerFactory factory = (attributes != null) ? getFactory(clazz, attributes, configuration) : getFactory(clazz);
factory.setErrorListener(errorListener);
factory.setURIResolver(uriResolver);
final Templates templates = factory.newTemplates(source);
// These should only be used during stylesheet compilation. It is dangerous to keep them around when the
// Templates object is cached especially the URI Resolver which may reference PipelineContext objects.
// factory.setErrorListener(null);// This causes issues with Xalan
factory.setURIResolver(null);
return templates;
}
/**
* Transform a W3C DOM node into a dom4j document
*
* @param node W3C DOM node
* @return dom4j document
* @throws TransformerException
*/
public static Document domToDom4jDocument(org.w3c.dom.Node node) throws TransformerException {
final Transformer identity = getIdentityTransformer();
final LocationDocumentResult documentResult = new LocationDocumentResult();
identity.transform(new DOMSource(node), documentResult);
return documentResult.getDocument();
}
/**
* Transform a SAXStore into a dom4j document
*
* @param saxStore input SAXStore
* @return dom4j document
*/
public static Document saxStoreToDom4jDocument(SAXStore saxStore) {
final TransformerXMLReceiver identity = getIdentityTransformerHandler();
final LocationDocumentResult documentResult = new LocationDocumentResult();
identity.setResult(documentResult);
try {
saxStore.replay(identity);
} catch (SAXException e) {
throw new OXFException(e);
}
return documentResult.getDocument();
}
// Transform a SAXStore mark into a dom4j document
public static Document saxStoreMarkToDom4jDocument(SAXStore.Mark mark) {
final TransformerXMLReceiver identity = getIdentityTransformerHandler();
final LocationDocumentResult documentResult = new LocationDocumentResult();
identity.setResult(documentResult);
try {
identity.startDocument();
mark.replay(identity);
identity.endDocument();
} catch (SAXException e) {
throw new OXFException(e);
}
return documentResult.getDocument();
}
/**
* Transform a SAXStore into a TinyTree document
*
* @param saxStore input SAXStore
* @return DocumentInfo
*/
public static DocumentInfo saxStoreToTinyTree(Configuration configuration, SAXStore saxStore) {
final TinyBuilder treeBuilder = new TinyBuilder();
try {
final TransformerXMLReceiver identity = getIdentityTransformerHandler(configuration);
identity.setResult(treeBuilder);
saxStore.replay(identity);
} catch (SAXException e) {
throw new OXFException(e);
}
return (DocumentInfo) treeBuilder.getCurrentRoot();
}
/**
* Transform a SAXStore into a DOM document
*
* @param saxStore input SAXStore
* @return DOM document
*/
public static org.w3c.dom.Document saxStoreToDomDocument(SAXStore saxStore) {
try {
// Convert to dom4j and then to DOM
return TransformerUtils.dom4jToDomDocument(saxStoreToDom4jDocument(saxStore));
} catch (TransformerException e) {
throw new OXFException(e);
}
// NOTE: The more straight and efficient implementation below doesn't seem to work
// final TransformerHandler identity = getIdentityTransformerHandler();
// final DOMResult domResult = new DOMResult();
// identity.setResult(domResult);
// try {
// saxStore.replay(identity);
// } catch (SAXException e) {
// throw new OXFException(e);
// }
// return domResult.getNode().getOwnerDocument();
}
/**
* Transform a dom4j Document into a TinyTree.
*/
public static DocumentInfo dom4jToTinyTree(Configuration configuration, Document document, boolean location) {
final TinyBuilder treeBuilder = new TinyBuilder();
try {
final Transformer identity = getIdentityTransformer(configuration);
identity.transform(location ? new LocationDocumentSource(document) : new DocumentSource(document), treeBuilder);
} catch (TransformerException e) {
throw new OXFException(e);
}
return (DocumentInfo) treeBuilder.getCurrentRoot();
}
/**
* Transform a dom4j document into a W3C DOM document
*
* @param document dom4j document
* @return W3C DOM document
* @throws TransformerException
*/
public static org.w3c.dom.Document dom4jToDomDocument(Document document) throws TransformerException {
final Transformer identity = getIdentityTransformer();
final DOMResult domResult = new DOMResult();
identity.transform(new DocumentSource(document), domResult);
final Node resultNode = domResult.getNode();
return (resultNode instanceof org.w3c.dom.Document) ? ((org.w3c.dom.Document) resultNode) : resultNode.getOwnerDocument();
}
public static Transformer testCreateTransformerWrapper(Transformer transformer, String publicProperty, String privateProperty) {
return new TransformerWrapper(transformer, publicProperty, privateProperty);
}
/**
* Transform an InputStream to a dom4j Document.
*/
public static Document readDom4j(InputStream inputStream, String systemId, boolean handleXInclude, boolean handleLexical) {
final LocationSAXContentHandler dom4jResult = new LocationSAXContentHandler();
{
final TransformerURIResolver resolver;
final XMLReceiver xmlReceiver;
if (handleXInclude) {
// Insert XIncludeContentHandler
resolver = new TransformerURIResolver(XMLParsing.ParserConfiguration.PLAIN);
xmlReceiver = new XIncludeReceiver(null, dom4jResult, null, resolver);
} else {
resolver = null;
xmlReceiver = dom4jResult;
}
try {
XMLParsing.inputStreamToSAX(inputStream, systemId, xmlReceiver, XMLParsing.ParserConfiguration.PLAIN, handleLexical);
} finally {
if (resolver != null)
resolver.destroy();
}
}
return dom4jResult.getDocument();
}
/**
* Transform an InputStream to a dom4j Document.
*/
public static Document readDom4j(Source source, boolean handleXInclude) {
final LocationSAXContentHandler dom4jResult = new LocationSAXContentHandler();
{
final TransformerURIResolver resolver;
final XMLReceiver xmlReceiver;
if (handleXInclude) {
// Insert XIncludeContentHandler
resolver = new TransformerURIResolver(XMLParsing.ParserConfiguration.PLAIN);
xmlReceiver = new XIncludeReceiver(null, dom4jResult, null, resolver);
} else {
resolver = null;
xmlReceiver = dom4jResult;
}
try {
sourceToSAX(source, xmlReceiver);
} finally {
if (resolver != null)
resolver.destroy();
}
}
return dom4jResult.getDocument();
}
public static Tuple2<TinyBuilder, XMLReceiver> createTinyBuilder(Configuration configuration) {
final TinyBuilder treeBuilder = new TinyBuilder();
final TransformerXMLReceiver identityHandler = getIdentityTransformerHandler(configuration);
identityHandler.setResult(treeBuilder);
return new Tuple2<TinyBuilder, XMLReceiver>(treeBuilder, identityHandler);
}
/**
* Transform an InputStream to a TinyTree.
*/
public static DocumentInfo readTinyTree(Configuration configuration, InputStream inputStream, String systemId, boolean handleXInclude, boolean handleLexical) {
final TinyBuilder treeBuilder = new TinyBuilder();
{
final TransformerXMLReceiver identityHandler = getIdentityTransformerHandler(configuration);
identityHandler.setResult(treeBuilder);
final TransformerURIResolver resolver;
final XMLReceiver xmlReceiver;
if (handleXInclude) {
// Insert XIncludeContentHandler
resolver = new TransformerURIResolver(XMLParsing.ParserConfiguration.PLAIN);
xmlReceiver = new XIncludeReceiver(null, identityHandler, null, resolver);
} else {
resolver = null;
xmlReceiver = identityHandler;
}
try {
XMLParsing.inputStreamToSAX(inputStream, systemId, xmlReceiver, XMLParsing.ParserConfiguration.PLAIN, handleLexical);
} finally {
if (resolver != null)
resolver.destroy();
}
}
return (DocumentInfo) treeBuilder.getCurrentRoot();
}
/**
* Transform a SAX Source to a TinyTree.
*/
public static DocumentInfo readTinyTree(Configuration configuration, Source source, boolean handleXInclude) {
final TinyBuilder treeBuilder = new TinyBuilder();
try {
final TransformerURIResolver resolver;
if (handleXInclude) {
resolver = new TransformerURIResolver(XMLParsing.ParserConfiguration.PLAIN);
} else {
resolver = null;
}
try {
if (handleXInclude) {
// Insert XIncludeContentHandler
final TransformerXMLReceiver identityHandler = getIdentityTransformerHandler(configuration);
identityHandler.setResult(treeBuilder);
final XMLReceiver receiver = new XIncludeReceiver(null, identityHandler, null, resolver);
TransformerUtils.sourceToSAX(source, receiver);
} else {
final Transformer identity = getIdentityTransformer(configuration);
identity.transform(source, treeBuilder);
}
} finally {
if (resolver != null)
resolver.destroy();
}
} catch (TransformerException e) {
throw new OXFException(e);
}
return (DocumentInfo) treeBuilder.getCurrentRoot();
}
/**
* Transform a TinyTree to a dom4j document.
*/
public static Document tinyTreeToDom4j(NodeInfo nodeInfo) {
try {
final Transformer identity = getXMLIdentityTransformer();
final LocationDocumentResult documentResult = new LocationDocumentResult();
identity.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
identity.transform(nodeInfo, documentResult);
return documentResult.getDocument();
} catch (Exception e) {
throw new OXFException(e);
}
}
public static DocumentWrapper extractAsMutableDocument(NodeInfo elementOrDocument) {
return new DocumentWrapper(tinyTreeToDom4j(elementOrDocument), null, XPath.GlobalConfiguration());
}
/**
* Transform a String to a TinyTree.
*/
public static DocumentInfo stringToTinyTree(Configuration configuration, String string, boolean handleXInclude, boolean handleLexical) {
try {
return readTinyTree(configuration, new ByteArrayInputStream(string.getBytes("utf-8")), null, handleXInclude, handleLexical);
} catch (UnsupportedEncodingException e) {
throw new OXFException(e);// should not happen
}
}
public static DocumentInfo urlToTinyTree(String url) {
try {
final InputStream inputStream = URLFactory.createURL(url).openStream();
try {
return readTinyTree(XPath.GlobalConfiguration(), inputStream, null, true, true);
} finally {
inputStream.close();
}
} catch (IOException e) {
throw new OXFException(e);
}
}
/**
* Transform a TinyTree to SAX events.
*/
public static void writeTinyTree(NodeInfo nodeInfo, XMLReceiver xmlReceiver) {
sourceToSAX(nodeInfo, xmlReceiver);
}
/**
* Transform a SAX source to SAX events.
*/
public static void sourceToSAX(Source source, XMLReceiver xmlReceiver) {
try {
final Transformer identity = getIdentityTransformer();
final SAXResult saxResult = new SAXResult(xmlReceiver);
saxResult.setLexicalHandler(xmlReceiver);
identity.transform(source, saxResult);
} catch (TransformerException e) {
throw new OXFException(e);
}
}
/**
* Transform a SAX source to SAX events.
*/
private static void sourceToSAX(Source source, ContentHandler contentHandler) {
try {
final Transformer identity = getIdentityTransformer();
final SAXResult saxResult = new SAXResult(contentHandler);
identity.transform(source, saxResult);
} catch (TransformerException e) {
throw new OXFException(e);
}
}
/**
* Transform a dom4j Node to SAX events.
*/
public static void writeDom4j(org.orbeon.dom.Document document, XMLReceiver xmlReceiver) {
// NOTE: Use dom4j directly instead of sourceToSAX as performance is better
final LocationSAXWriter locationSAXWriter = new LocationSAXWriter();
locationSAXWriter.setContentHandler(xmlReceiver);
locationSAXWriter.setLexicalHandler(xmlReceiver);
locationSAXWriter.write(document);
}
/**
* Transform a dom4j Node to SAX events.
*/
public static void writeDom4j(org.orbeon.dom.Node node, ContentHandler contentHandler) {
sourceToSAX(new LocationDocumentSource(node), contentHandler);
}
/**
* Transform a dom4j document to a String.
*/
public static String dom4jToString(Document document, boolean location) {
try {
final Transformer identity = getXMLIdentityTransformer();
identity.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
final StringBuilderWriter writer = new StringBuilderWriter();
identity.transform(location ? new LocationDocumentSource(document) : new DocumentSource(document), new StreamResult(writer));
return writer.toString();
} catch (TransformerException e) {
throw new OXFException(e);
}
}
/**
* Transform a TinyTree to a String.
*/
public static String tinyTreeToString(NodeInfo nodeInfo) {
try {
final Transformer identity = getXMLIdentityTransformer();
identity.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
final StringBuilderWriter writer = new StringBuilderWriter();
identity.transform(nodeInfo, new StreamResult(writer));
return writer.toString();
} catch (TransformerException e) {
throw new OXFException(e);
}
}
/**
* Transform a TinyTree to a SAXStore.
*/
public static SAXStore tinyTreeToSAXStore(NodeInfo nodeInfo) {
final SAXStore saxStore = new SAXStore();
sourceToSAX(nodeInfo, saxStore);
return saxStore;
}
/**
* Transform a dom4j document to a SAXStore.
*/
public static SAXStore dom4jToSAXStore(Document document, boolean location) {
final SAXStore saxStore = new SAXStore();
sourceToSAX(location ? new LocationDocumentSource(document) : new DocumentSource(document), saxStore);
return saxStore;
}
public static String domToString(Node node) {
try {
Transformer transformer = getXMLIdentityTransformer();
DOMSource source = new DOMSource(node);
StringBuilderWriter writer = new StringBuilderWriter();
transformer.transform(source, new StreamResult(writer));
return writer.toString();
} catch (TransformerException e) {
throw new OXFException(e);
}
}
}
class TransformerWrapper extends Transformer {
private Transformer transformer;
private String publicProperty;
private String privateProperty;
public TransformerWrapper(Transformer transformer, String publicProperty, String privateProperty) {
this.transformer = transformer;
this.publicProperty = publicProperty;
this.privateProperty = privateProperty;
}
public void clearParameters() {
transformer.clearParameters();
}
public ErrorListener getErrorListener() {
return transformer.getErrorListener();
}
public Properties getOutputProperties() {
Properties properties = transformer.getOutputProperties();
if (properties.get(privateProperty) == null) {
// Optimize case where we don't need to map
return properties;
} else {
// Switch property
properties.put(publicProperty, properties.get(privateProperty));
properties.remove(privateProperty);
return properties;
}
}
public String getOutputProperty(String name) throws IllegalArgumentException {
if (publicProperty.equals(name))
return transformer.getOutputProperty(privateProperty);
else
return transformer.getOutputProperty(name);
}
public Object getParameter(String name) {
return transformer.getParameter(name);
}
public URIResolver getURIResolver() {
return transformer.getURIResolver();
}
public void setErrorListener(ErrorListener listener) throws IllegalArgumentException {
transformer.setErrorListener(listener);
}
public void setOutputProperties(Properties oformat) throws IllegalArgumentException {
if (oformat.get(publicProperty) == null) {
// Optimize case where we don't need to map
transformer.setOutputProperties(oformat);
} else {
Properties newProperties = (Properties) oformat.clone();
newProperties.put(privateProperty, oformat.get(publicProperty));
newProperties.remove(publicProperty);
transformer.setOutputProperties(newProperties);
}
}
public void setOutputProperty(String name, String value) throws IllegalArgumentException {
if (publicProperty.equals(name))
transformer.setOutputProperty(privateProperty, value);
else
transformer.setOutputProperty(name, value);
}
public void setParameter(String name, Object value) {
transformer.setParameter(name, value);
}
public void setURIResolver(URIResolver resolver) {
transformer.setURIResolver(resolver);
}
public void transform(Source xmlSource, Result outputTarget) throws TransformerException {
transformer.transform(xmlSource, outputTarget);
}
}
class TransformerHandlerWrapper extends ForwardingXMLReceiver implements TransformerXMLReceiver {
private TransformerHandler transformerHandler;
private String publicProperty;
private String privateProperty;
public TransformerHandlerWrapper(TransformerHandler transformerHandler, String publicProperty, String privateProperty) {
super(transformerHandler, transformerHandler);
this.transformerHandler = transformerHandler;
this.publicProperty = publicProperty;
this.privateProperty = privateProperty;
}
public String getSystemId() {
return transformerHandler.getSystemId();
}
public Transformer getTransformer() {
return new TransformerWrapper(transformerHandler.getTransformer(), publicProperty, privateProperty);
}
public void setResult(Result result) throws IllegalArgumentException {
transformerHandler.setResult(result);
}
public void setSystemId(String systemID) {
transformerHandler.setSystemId(systemID);
}
public void comment(char ch[], int start, int length) throws SAXException {
transformerHandler.comment(ch, start, length);
}
public void endCDATA() throws SAXException {
transformerHandler.endCDATA();
}
public void endDTD() throws SAXException {
transformerHandler.endDTD();
}
public void endEntity(String name) throws SAXException {
transformerHandler.endEntity(name);
}
public void startCDATA() throws SAXException {
transformerHandler.startCDATA();
}
public void startDTD(String name, String publicId, String systemId) throws SAXException {
transformerHandler.startDTD(name, publicId, systemId);
}
public void startEntity(String name) throws SAXException {
transformerHandler.startEntity(name);
}
public void notationDecl(String name, String publicId, String systemId) throws SAXException {
transformerHandler.notationDecl(name, publicId, systemId);
}
public void unparsedEntityDecl(String name, String publicId, String systemId, String notationName) throws SAXException {
transformerHandler.unparsedEntityDecl(name, publicId, systemId, notationName);
}
}