TransformerImpl.java [plain text]
package gnu.xml.transform;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.MalformedURLException;
import java.net.UnknownServiceException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Collection;
import java.util.Properties;
import javax.xml.transform.ErrorListener;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.URIResolver;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Node;
import org.w3c.dom.Text;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.ext.LexicalHandler;
import gnu.xml.dom.DomDoctype;
import gnu.xml.dom.DomDocument;
import gnu.xml.dom.ls.WriterOutputStream;
class TransformerImpl
extends Transformer
{
final TransformerFactoryImpl factory;
final Stylesheet stylesheet;
URIResolver uriResolver;
ErrorListener errorListener;
Properties outputProperties;
TransformerImpl(TransformerFactoryImpl factory,
Stylesheet stylesheet,
Properties outputProperties)
throws TransformerConfigurationException
{
this.factory = factory;
uriResolver = factory.userResolver;
errorListener = factory.userListener;
this.stylesheet = stylesheet;
this.outputProperties = outputProperties;
if (stylesheet != null)
{
stylesheet.bindings.push(false);
}
}
public void transform(Source xmlSource, Result outputTarget)
throws TransformerException
{
DOMSource source;
synchronized (factory.resolver)
{
factory.resolver.setUserResolver(uriResolver);
factory.resolver.setUserListener(errorListener);
source = factory.resolver.resolveDOM(xmlSource, null, null);
}
Node context = source.getNode();
Document doc = (context instanceof Document) ? (Document) context :
context.getOwnerDocument();
if (doc instanceof DomDocument)
{
((DomDocument) doc).setBuilding(true);
}
Node parent = null, nextSibling = null;
if (outputTarget instanceof DOMResult)
{
DOMResult dr = (DOMResult) outputTarget;
parent = dr.getNode();
nextSibling = dr.getNextSibling();
Document rdoc = (parent instanceof Document) ? (Document) parent :
parent.getOwnerDocument();
if (rdoc instanceof DomDocument)
{
DomDocument drdoc = (DomDocument) rdoc;
drdoc.setBuilding(true);
drdoc.setCheckWellformedness(false);
}
}
boolean created = false;
if (stylesheet != null)
{
if (parent == null)
{
DomDocument resultDoc = new DomDocument();
resultDoc.setBuilding(true);
resultDoc.setCheckWellformedness(false);
parent = resultDoc;
created = true;
}
context = context.cloneNode(true);
strip(context);
try
{
((TransformerOutputProperties) outputProperties).apply();
stylesheet.initTopLevelVariables(context);
TemplateNode t = stylesheet.getTemplate(null, context, false);
if (t != null)
{
stylesheet.current = context;
t.apply(stylesheet, null, context, 1, 1, parent, nextSibling);
}
}
catch (TransformerException e)
{
if (doc instanceof DomDocument)
{
((DomDocument) doc).setBuilding(false);
}
throw e;
}
}
else
{
Node clone = context.cloneNode(true);
if (context.getNodeType() != Node.DOCUMENT_NODE)
{
Document resultDoc;
if (parent == null)
{
DomDocument rd = new DomDocument();
rd.setBuilding(true);
rd.setCheckWellformedness(false);
parent = resultDoc = rd;
created = true;
}
else
{
resultDoc = (parent instanceof Document) ?
(Document) parent :
parent.getOwnerDocument();
}
Document sourceDoc = context.getOwnerDocument();
if (sourceDoc != resultDoc)
{
clone = resultDoc.adoptNode(clone);
}
if (nextSibling != null)
{
parent.insertBefore(clone, nextSibling);
}
else
{
parent.appendChild(clone);
}
}
else
{
parent = clone;
created = true;
}
}
String method = outputProperties.getProperty(OutputKeys.METHOD);
int outputMethod = "html".equals(method) ? Stylesheet.OUTPUT_HTML :
"text".equals(method) ? Stylesheet.OUTPUT_TEXT :
Stylesheet.OUTPUT_XML;
String encoding = outputProperties.getProperty(OutputKeys.ENCODING);
String publicId = outputProperties.getProperty(OutputKeys.DOCTYPE_PUBLIC);
String systemId = outputProperties.getProperty(OutputKeys.DOCTYPE_SYSTEM);
String version = outputProperties.getProperty(OutputKeys.VERSION);
boolean omitXmlDeclaration =
"yes".equals(outputProperties.getProperty(OutputKeys.OMIT_XML_DECLARATION));
boolean standalone =
"yes".equals(outputProperties.getProperty(OutputKeys.STANDALONE));
String mediaType = outputProperties.getProperty(OutputKeys.MEDIA_TYPE);
if (created)
{
DomDocument resultDoc = (DomDocument) parent;
Node root = resultDoc.getDocumentElement();
if ((publicId != null || systemId != null) &&
root != null)
{
resultDoc.appendChild(new DomDoctype(resultDoc,
root.getNodeName(),
publicId,
systemId));
}
resultDoc.setBuilding(false);
resultDoc.setCheckWellformedness(true);
}
else if (publicId != null || systemId != null)
{
switch (parent.getNodeType())
{
case Node.DOCUMENT_NODE:
case Node.DOCUMENT_FRAGMENT_NODE:
Document resultDoc = (parent instanceof Document) ?
(Document) parent :
parent.getOwnerDocument();
DOMImplementation impl = resultDoc.getImplementation();
DocumentType doctype =
impl.createDocumentType(resultDoc.getNodeName(),
publicId,
systemId);
Node ctx = parent.getFirstChild();
for (; ctx != null &&
ctx.getNodeType() != Node.ELEMENT_NODE;
ctx = ctx.getNextSibling())
{
}
if (ctx != null)
{
parent.insertBefore(doctype, ctx);
}
else
{
parent.appendChild(doctype);
}
}
}
if (version != null)
{
parent.setUserData("version", version, stylesheet);
}
if (omitXmlDeclaration)
{
parent.setUserData("omit-xml-declaration", "yes", stylesheet);
}
if (standalone)
{
parent.setUserData("standalone", "yes", stylesheet);
}
if (mediaType != null)
{
parent.setUserData("media-type", mediaType, stylesheet);
}
if (outputTarget instanceof DOMResult)
{
if (created)
{
DOMResult dr = (DOMResult) outputTarget;
dr.setNode(parent);
dr.setNextSibling(null);
}
}
else if (outputTarget instanceof StreamResult)
{
StreamResult sr = (StreamResult) outputTarget;
IOException ex = null;
try
{
writeStreamResult(parent, sr, outputMethod, encoding);
}
catch (UnsupportedEncodingException e)
{
try
{
writeStreamResult(parent, sr, outputMethod, "UTF-8");
}
catch (IOException e2)
{
ex = e2;
}
}
catch (IOException e)
{
ex = e;
}
if (ex != null)
{
if (errorListener != null)
{
errorListener.error(new TransformerException(ex));
}
else
{
ex.printStackTrace(System.err);
}
}
}
else if (outputTarget instanceof SAXResult)
{
SAXResult sr = (SAXResult) outputTarget;
try
{
ContentHandler ch = sr.getHandler();
LexicalHandler lh = sr.getLexicalHandler();
if (lh == null && ch instanceof LexicalHandler)
{
lh = (LexicalHandler) ch;
}
SAXSerializer serializer = new SAXSerializer();
serializer.serialize(parent, ch, lh);
}
catch (SAXException e)
{
if (errorListener != null)
{
errorListener.error(new TransformerException(e));
}
else
{
e.printStackTrace(System.err);
}
}
}
}
void strip(Node node)
throws TransformerConfigurationException
{
short nt = node.getNodeType();
if (nt == Node.ENTITY_REFERENCE_NODE)
{
Node parent = node.getParentNode();
Node child = node.getFirstChild();
if (child != null)
{
strip(child);
}
while (child != null)
{
Node next = child.getNextSibling();
node.removeChild(child);
parent.insertBefore(child, node);
child = next;
}
parent.removeChild(node);
}
if (nt == Node.TEXT_NODE) {
if (!stylesheet.isPreserved((Text) node))
{
node.getParentNode().removeChild(node);
}
}
else
{
for (Node child = node.getFirstChild(); child != null;
child = child.getNextSibling())
{
strip(child);
}
}
}
void writeStreamResult(Node node, StreamResult sr, int outputMethod,
String encoding)
throws IOException
{
OutputStream out = null;
try
{
out = sr.getOutputStream();
if (out == null)
{
Writer writer = sr.getWriter();
if (writer != null)
{
out = new WriterOutputStream(writer);
}
}
if (out == null)
{
String systemId = sr.getSystemId();
try
{
URL url = new URL(systemId);
URLConnection connection = url.openConnection();
connection.setDoOutput(true);
out = connection.getOutputStream();
}
catch (MalformedURLException e)
{
out = new FileOutputStream(systemId);
}
catch (UnknownServiceException e)
{
URL url = new URL(systemId);
out = new FileOutputStream(url.getPath());
}
}
out = new BufferedOutputStream(out);
StreamSerializer serializer =
new StreamSerializer(outputMethod, encoding, null);
if (stylesheet != null)
{
Collection celem = stylesheet.outputCdataSectionElements;
serializer.setCdataSectionElements(celem);
}
serializer.serialize(node, out);
out.flush();
}
finally
{
try
{
if (out != null)
{
out.close();
}
}
catch (IOException e)
{
}
}
}
void copyChildren(Document dstDoc, Node src, Node dst)
{
Node srcChild = src.getFirstChild();
while (srcChild != null)
{
Node dstChild = dstDoc.adoptNode(srcChild);
dst.appendChild(dstChild);
srcChild = srcChild.getNextSibling();
}
}
public void setParameter(String name, Object value)
{
if (stylesheet != null)
{
stylesheet.bindings.set(name, value, false);
}
}
public Object getParameter(String name)
{
if (stylesheet != null)
{
return stylesheet.bindings.get(name, null, 1, 1);
}
return null;
}
public void clearParameters()
{
if (stylesheet != null)
{
stylesheet.bindings.pop(false);
stylesheet.bindings.push(false);
}
}
public void setURIResolver(URIResolver resolver)
{
uriResolver = resolver;
}
public URIResolver getURIResolver()
{
return uriResolver;
}
public void setOutputProperties(Properties oformat)
throws IllegalArgumentException
{
if (oformat == null)
{
outputProperties.clear();
}
else
{
outputProperties.putAll(oformat);
}
}
public Properties getOutputProperties()
{
return (Properties) outputProperties.clone();
}
public void setOutputProperty(String name, String value)
throws IllegalArgumentException
{
outputProperties.put(name, value);
}
public String getOutputProperty(String name)
throws IllegalArgumentException
{
return outputProperties.getProperty(name);
}
public void setErrorListener(ErrorListener listener)
{
errorListener = listener;
}
public ErrorListener getErrorListener()
{
return errorListener;
}
}