dnet-docker/dnet-app/libs/dnet-common-mapping/src/main/java/eu/dnetlib/common/mapping/xslt/XsltTransformerFactory.java

97 lines
3.6 KiB
Java

package eu.dnetlib.common.mapping.xslt;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.xml.transform.stream.StreamSource;
import org.apache.commons.io.IOUtils;
import eu.dnetlib.common.clients.DnetServiceClientFactory;
import eu.dnetlib.common.clients.SimpleResourceClient;
import eu.dnetlib.common.clients.VocabularyClient;
import eu.dnetlib.common.mapping.RecordTransformer;
import eu.dnetlib.common.mapping.xslt.functions.CalculateMd5;
import eu.dnetlib.common.mapping.xslt.functions.XsltDateCleaner;
import eu.dnetlib.common.mapping.xslt.functions.XsltPersonCleaner;
import eu.dnetlib.common.mapping.xslt.functions.XsltVocabularyCleaner;
import eu.dnetlib.errors.TransformationException;
import net.sf.saxon.s9api.Processor;
import net.sf.saxon.s9api.QName;
import net.sf.saxon.s9api.SaxonApiException;
import net.sf.saxon.s9api.Serializer;
import net.sf.saxon.s9api.XdmAtomicValue;
import net.sf.saxon.s9api.XdmNode;
import net.sf.saxon.s9api.XmlProcessingError;
import net.sf.saxon.s9api.XsltCompiler;
import net.sf.saxon.s9api.XsltExecutable;
import net.sf.saxon.s9api.XsltTransformer;
public class XsltTransformerFactory {
private final DnetServiceClientFactory clientFactory;
public static final String QNAME_BASE_URI = "http://eu/dnetlib/transform";
public XsltTransformerFactory(final DnetServiceClientFactory clientFactory) {
this.clientFactory = clientFactory;
}
public RecordTransformer<String, String> getTransformerById(final String ruleId, final Map<String, Object> params) throws TransformationException {
final String xsltText =
this.clientFactory.getClient(SimpleResourceClient.class)
.findResourceContent(SimpleResourceClient.ResourceType.transformation_rule_xslt, ruleId, String.class);
return getTransformerByXSLT(xsltText, params);
}
public RecordTransformer<String, String> getTransformerByXSLT(final String xsltText, final Map<String, Object> params) throws TransformationException {
final Processor processor = new Processor(false);
processor.registerExtensionFunction(new CalculateMd5());
processor.registerExtensionFunction(new XsltDateCleaner());
processor.registerExtensionFunction(new XsltPersonCleaner());
processor.registerExtensionFunction(new XsltVocabularyCleaner(this.clientFactory.getClient(VocabularyClient.class)));
final List<XmlProcessingError> errorList = new ArrayList<>();
final XsltCompiler comp = processor.newXsltCompiler();
comp.setErrorList(errorList);
params.forEach((k, v) -> comp.setParameter(new QName(k), XdmAtomicValue.makeAtomicValue(v)));
try {
final XsltExecutable xslt = comp.compile(new StreamSource(IOUtils.toInputStream(xsltText, StandardCharsets.UTF_8)));
return xml -> {
try {
final XdmNode source = processor
.newDocumentBuilder()
.build(new StreamSource(IOUtils.toInputStream(xml, StandardCharsets.UTF_8)));
final XsltTransformer trans = xslt.load();
trans.setInitialContextNode(source);
final StringWriter output = new StringWriter();
final Serializer out = processor.newSerializer(output);
out.setOutputProperty(Serializer.Property.METHOD, "xml");
out.setOutputProperty(Serializer.Property.INDENT, "yes");
trans.setDestination(out);
trans.transform();
return output.toString();
} catch (final SaxonApiException e) {
throw new RuntimeException(e);
}
};
} catch (final Throwable e) {
final StringWriter sw = new StringWriter();
sw.append("XSLT failure");
errorList.forEach(err -> sw.append("\n\t[XSLT ERR] " + err.getMessage()));
throw new TransformationException(sw.toString(), e);
}
}
}