Project

General

Profile

1
package eu.dnetlib.miscutils.functional.xml;
2

    
3
import java.io.File;
4
import java.io.IOException;
5
import java.io.InputStream;
6
import java.io.StringReader;
7
import java.io.StringWriter;
8
import java.util.Map;
9

    
10
import javax.xml.transform.OutputKeys;
11
import javax.xml.transform.Result;
12
import javax.xml.transform.Source;
13
import javax.xml.transform.Transformer;
14
import javax.xml.transform.TransformerConfigurationException;
15
import javax.xml.transform.TransformerException;
16
import javax.xml.transform.TransformerFactory;
17
import javax.xml.transform.URIResolver;
18
import javax.xml.transform.stream.StreamResult;
19
import javax.xml.transform.stream.StreamSource;
20

    
21
import org.apache.commons.logging.Log;
22
import org.apache.commons.logging.LogFactory;
23
import org.springframework.core.io.ClassPathResource;
24
import org.springframework.core.io.Resource;
25

    
26
import eu.dnetlib.miscutils.functional.UnaryFunction;
27

    
28
/**
29
 * This function applies a stylesheet to something which can be transformed to a javax.xml.Source.
30
 * 
31
 * <p>Subclasses are specialized and know how to transform K into a Source</p>
32
 * 
33
 * @author marko
34
 *
35
 * @param <K>
36
 */
37
public abstract class AbstractApplyXslt<K> implements UnaryFunction<String, K> {
38
	private static final String UNKNOWN_XSLT_NAME = "unknown xslt name";
39

    
40
	private static final Log log = LogFactory.getLog(AbstractApplyXslt.class); // NOPMD by marko on 11/24/08 5:02 PM
41

    
42
	private Transformer transformer;
43
	
44
	/**
45
	 * optional, useful to keep track of xslt name for debugging purposes.
46
	 */
47
	private String xsltName;
48

    
49
	public AbstractApplyXslt(final Resource xslt) {
50
		this(xslt, null);
51
	}
52

    
53
	public AbstractApplyXslt(final Resource xslt, Map<String, String> parameters) {
54
		this(new StreamSource(getInputStream(xslt)), getFileName((ClassPathResource) xslt), parameters);
55
	}
56
	
57
	public AbstractApplyXslt(final String xslt) {
58
		this(xslt, UNKNOWN_XSLT_NAME);
59
	}
60

    
61
	public AbstractApplyXslt(final String xslt, String name) {
62
		this(xslt, name, null);
63
	}
64

    
65
	public AbstractApplyXslt(final String xslt, String name, Map<String, String> parameters) {
66
		this(new StreamSource(new StringReader(xslt)), name, parameters);
67
	}
68

    
69
	public AbstractApplyXslt(final Source xslt) {
70
		this(xslt, UNKNOWN_XSLT_NAME);
71
	}
72

    
73
	public AbstractApplyXslt(final Source xslt, String name) {
74
		this(xslt, name, null);
75
	}
76

    
77
	/**
78
	 * Base method for all the others.
79
	 * @param xslt
80
	 * @param name
81
	 * @param parameters
82
	 */
83
	public AbstractApplyXslt(final Source xslt, String name, Map<String, String> parameters) {
84
		try {
85
			this.xsltName = name;
86
			TransformerFactory factory = TransformerFactory.newInstance();
87
			if (! UNKNOWN_XSLT_NAME.equals(name))
88
				factory.setURIResolver(new ExternalResourceURIResolver(name.replaceFirst("[^/]+$", "")));
89
			transformer = factory.newTransformer(xslt);
90
			if(parameters != null)
91
				for(Map.Entry<String, String> parameter : parameters.entrySet())
92
					transformer.setParameter(parameter.getKey(), parameter.getValue());
93
			
94
		} catch (final Throwable e) {
95
			log.error("Problems with transformer!\n" + xslt + "--" + name, e);
96
			log.error(xsltDump(xslt));
97
			throw new IllegalStateException(e);
98
		}
99
	}
100
	
101
	/**
102
	 * This class contains the login enabling imports of peer external resources for the current xslt (<xsl:import>)
103
	 * The method resolve() first looks for the resource within the file system; if this fails, it looks in the classpath.
104
	 * @author Andrea Mannocci
105
	 *
106
	 */
107
	private class ExternalResourceURIResolver implements URIResolver {
108
		private final String xsltBasePath;
109
		
110
		public ExternalResourceURIResolver(String xsltBasePath) {
111
			this.xsltBasePath = xsltBasePath;
112
		}
113
		@Override
114
		public Source resolve(String href, String base) throws TransformerException {
115
			String externalResource = this.xsltBasePath + href;
116
			try{
117
				log.debug("trying to load external resource from file system: " + externalResource);
118
				return new StreamSource(new File(externalResource));
119
			} catch (final Throwable e) {
120
				log.debug("trying to load external resource from file system: " + externalResource);
121
				return new StreamSource(getInputStream(new ClassPathResource(externalResource)));
122
			}
123
		}
124
	}
125
	
126
	private String xsltDump(Source xslt) {
127
		Transformer transformer;
128
		try {
129
			transformer = TransformerFactory.newInstance().newTransformer();
130
			transformer.setOutputProperty(OutputKeys.INDENT, "yes");
131
			StringWriter outWriter = new StringWriter();
132
			Result result = new StreamResult(outWriter);
133
			transformer.transform(xslt, result);
134
			StringBuffer sb = outWriter.getBuffer(); 
135
			return sb.toString();
136
		} catch (TransformerConfigurationException e) {
137
			// TODO Auto-generated catch block
138
			e.printStackTrace();
139
		} catch (TransformerException e) {
140
			// TODO Auto-generated catch block
141
			e.printStackTrace();
142
		}
143
		return "error dumping the xslt";
144
	}
145

    
146
	@Override
147
	public String evaluate(final K input) {
148
		try {
149
			final StringWriter output = new StringWriter();
150
			transformer.transform(toStream(input), new StreamResult(output));
151
			return output.toString();
152
		} catch (final TransformerException e) {
153
			log.error("cannot transform record", e);
154
			log.debug(input.toString());
155
			return "";
156
		}
157
	}
158

    
159
	public abstract Source toStream(K input);
160
	
161
	public abstract String toString(K input);
162

    
163
	/**
164
	 * Used only to convert checked to unchecked exception.
165
	 * 
166
	 * @param xslt
167
	 * @return
168
	 */
169
	private static InputStream getInputStream(final Resource xslt) {
170
		try {
171
			return xslt.getInputStream();
172
		} catch (final IOException e) {
173
			throw new IllegalArgumentException(e);
174
		}
175
	}
176
	
177
	private static String getFileName(ClassPathResource xslt) {
178
		return xslt.getPath();
179
	}
180

    
181
	public Transformer getTransformer() {
182
		return transformer;
183
	}
184

    
185
	public void setTransformer(final Transformer transformer) {
186
		this.transformer = transformer;
187
	}
188

    
189
	public String getXsltName() {
190
		return xsltName;
191
	}
192

    
193
	public void setXsltName(String xsltName) {
194
		this.xsltName = xsltName;
195
	}
196

    
197
}
(1-1/8)