dnet-core/dnet-core-components/src/main/java/eu/dnetlib/miscutils/functional/xml/AbstractApplyXslt.java

198 lines
5.8 KiB
Java

package eu.dnetlib.miscutils.functional.xml;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Map;
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.TransformerFactory;
import javax.xml.transform.URIResolver;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import eu.dnetlib.miscutils.functional.UnaryFunction;
/**
* This function applies a stylesheet to something which can be transformed to a javax.xml.Source.
*
* <p>Subclasses are specialized and know how to transform K into a Source</p>
*
* @author marko
*
* @param <K>
*/
public abstract class AbstractApplyXslt<K> implements UnaryFunction<String, K> {
private static final String UNKNOWN_XSLT_NAME = "unknown xslt name";
private static final Log log = LogFactory.getLog(AbstractApplyXslt.class); // NOPMD by marko on 11/24/08 5:02 PM
private Transformer transformer;
/**
* optional, useful to keep track of xslt name for debugging purposes.
*/
private String xsltName;
public AbstractApplyXslt(final Resource xslt) {
this(xslt, null);
}
public AbstractApplyXslt(final Resource xslt, Map<String, String> parameters) {
this(new StreamSource(getInputStream(xslt)), getFileName((ClassPathResource) xslt), parameters);
}
public AbstractApplyXslt(final String xslt) {
this(xslt, UNKNOWN_XSLT_NAME);
}
public AbstractApplyXslt(final String xslt, String name) {
this(xslt, name, null);
}
public AbstractApplyXslt(final String xslt, String name, Map<String, String> parameters) {
this(new StreamSource(new StringReader(xslt)), name, parameters);
}
public AbstractApplyXslt(final Source xslt) {
this(xslt, UNKNOWN_XSLT_NAME);
}
public AbstractApplyXslt(final Source xslt, String name) {
this(xslt, name, null);
}
/**
* Base method for all the others.
* @param xslt
* @param name
* @param parameters
*/
public AbstractApplyXslt(final Source xslt, String name, Map<String, String> parameters) {
try {
this.xsltName = name;
TransformerFactory factory = TransformerFactory.newInstance();
if (! UNKNOWN_XSLT_NAME.equals(name))
factory.setURIResolver(new ExternalResourceURIResolver(name.replaceFirst("[^/]+$", "")));
transformer = factory.newTransformer(xslt);
if(parameters != null)
for(Map.Entry<String, String> parameter : parameters.entrySet())
transformer.setParameter(parameter.getKey(), parameter.getValue());
} catch (final Throwable e) {
log.error("Problems with transformer!\n" + xslt + "--" + name, e);
log.error(xsltDump(xslt));
throw new IllegalStateException(e);
}
}
/**
* This class contains the login enabling imports of peer external resources for the current xslt (<xsl:import>)
* The method resolve() first looks for the resource within the file system; if this fails, it looks in the classpath.
* @author Andrea Mannocci
*
*/
private class ExternalResourceURIResolver implements URIResolver {
private final String xsltBasePath;
public ExternalResourceURIResolver(String xsltBasePath) {
this.xsltBasePath = xsltBasePath;
}
@Override
public Source resolve(String href, String base) throws TransformerException {
String externalResource = this.xsltBasePath + href;
try{
log.debug("trying to load external resource from file system: " + externalResource);
return new StreamSource(new File(externalResource));
} catch (final Throwable e) {
log.debug("trying to load external resource from file system: " + externalResource);
return new StreamSource(getInputStream(new ClassPathResource(externalResource)));
}
}
}
private String xsltDump(Source xslt) {
Transformer transformer;
try {
transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
StringWriter outWriter = new StringWriter();
Result result = new StreamResult(outWriter);
transformer.transform(xslt, result);
StringBuffer sb = outWriter.getBuffer();
return sb.toString();
} catch (TransformerConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "error dumping the xslt";
}
@Override
public String evaluate(final K input) {
try {
final StringWriter output = new StringWriter();
transformer.transform(toStream(input), new StreamResult(output));
return output.toString();
} catch (final TransformerException e) {
log.error("cannot transform record", e);
log.debug(input.toString());
return "";
}
}
public abstract Source toStream(K input);
public abstract String toString(K input);
/**
* Used only to convert checked to unchecked exception.
*
* @param xslt
* @return
*/
private static InputStream getInputStream(final Resource xslt) {
try {
return xslt.getInputStream();
} catch (final IOException e) {
throw new IllegalArgumentException(e);
}
}
private static String getFileName(ClassPathResource xslt) {
return xslt.getPath();
}
public Transformer getTransformer() {
return transformer;
}
public void setTransformer(final Transformer transformer) {
this.transformer = transformer;
}
public String getXsltName() {
return xsltName;
}
public void setXsltName(String xsltName) {
this.xsltName = xsltName;
}
}