source: greenstone3/trunk/src/java/org/greenstone/gsdl3/util/XMLTransformer.java@ 18452

Last change on this file since 18452 was 18452, checked in by max, 15 years ago

Some additional information given on a Transformer(Configuration)Exception: what the calling method was and, if the xml files used are known, then the names of those files as well.

  • Property svn:keywords set to Author Date Id Revision
File size: 12.8 KB
Line 
1/*
2 * XMLTransformer.java
3 * Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19package org.greenstone.gsdl3.util;
20
21// XML classes
22import javax.xml.transform.Transformer;
23import javax.xml.transform.TransformerFactory;
24import javax.xml.transform.TransformerConfigurationException;
25import javax.xml.transform.TransformerException;
26import javax.xml.transform.ErrorListener;
27
28import javax.xml.transform.stream.StreamSource;
29import javax.xml.transform.dom.DOMSource;
30import javax.xml.transform.stream.StreamResult;
31import javax.xml.transform.dom.DOMResult;
32
33import javax.xml.parsers.DocumentBuilderFactory;
34import javax.xml.parsers.DocumentBuilder;
35import org.w3c.dom.Element;
36import org.w3c.dom.Document;
37
38import org.w3c.dom.Node;
39import org.w3c.dom.NodeList;
40
41// other java classes
42import java.io.StringReader;
43import java.io.StringWriter;
44import java.io.File;
45import java.util.HashMap;
46import java.util.Set;
47import java.util.Map;
48import java.util.Iterator;
49
50import org.apache.xml.utils.DefaultErrorHandler;
51
52import org.apache.log4j.*;
53
54/** XMLTransformer - utility class for greenstone
55 *
56 * transforms xml using xslt
57 *
58 * @author <a href="mailto:[email protected]">Katherine Don</a>
59 * @version $Revision: 18452 $
60 */
61public class XMLTransformer {
62
63 static Logger logger = Logger.getLogger(org.greenstone.gsdl3.util.XMLTransformer.class.getName());
64
65 /** The transformer factory we're using */
66 TransformerFactory t_factory=null;
67
68 /**
69 * The no-arguments constructor.
70 *
71 * Any exceptions thrown are caught internally
72 *
73 * @see javax.xml.transform.TransformerFactory
74 */
75 public XMLTransformer() {
76
77 // make sure we are using the xalan transformer
78 System.setProperty("javax.xml.transform.TransformerFactory", "org.apache.xalan.processor.TransformerFactoryImpl");
79 try {
80 this.t_factory = org.apache.xalan.processor.TransformerFactoryImpl.newInstance();
81
82 } catch (Exception e) {
83 logger.error("exception "+e.getMessage());
84 }
85 }
86
87
88
89 /**
90 * Transform an XML document using a XSLT stylesheet
91 *
92 * @param stylesheet a filename for an XSLT stylesheet
93 * @param xml_in the XML to be transformed
94 * @return the transformed XML
95 */
96 public String transform(String stylesheet, String xml_in) {
97
98 try {
99 // Use the TransformerFactory to process the stylesheet Source and generate a Transformer.
100 Transformer transformer = this.t_factory.newTransformer(new StreamSource(stylesheet));
101 transformer.setErrorListener(new TransformErrorListener());
102
103 // Use the Transformer to transform an XML Source and send the output to a Result object.
104 StringWriter output = new StringWriter();
105
106 transformer.transform(new StreamSource(new StringReader(xml_in)), new StreamResult(output));
107 return output.toString();
108 } catch (TransformerConfigurationException e) {
109 logger.error("couldn't create transformer object: "+e.getMessageAndLocation());
110 logger.error(e.getLocationAsString());
111 return "";
112 } catch (TransformerException e) {
113 logger.error("couldn't transform the source: " + e.getMessageAndLocation());
114 return "";
115 }
116 }
117
118 public String transformToString(Document stylesheet, Document source) {
119 return transformToString(stylesheet, source, null);
120 }
121
122 public String transformToString(Document stylesheet, Document source, HashMap parameters) {
123
124 try {
125 // Use the TransformerFactory to process the stylesheet Source and generate a Transformer.
126 Transformer transformer = this.t_factory.newTransformer(new DOMSource(stylesheet));
127 transformer.setErrorListener(new TransformErrorListener());
128 if (parameters != null) {
129 Set params = parameters.entrySet();
130 Iterator i = params.iterator();
131 while (i.hasNext()) {
132 Map.Entry m = (Map.Entry)i.next();
133 transformer.setParameter((String)m.getKey(), m.getValue());
134 }
135 }
136 //transformer.setParameter("page_lang", source.getDocumentElement().getAttribute(GSXML.LANG_ATT));
137
138
139 // Use the Transformer to transform an XML Source and send the output to a Result object.
140 StringWriter output = new StringWriter();
141
142 transformer.transform(new DOMSource(source), new StreamResult(output));
143 return output.toString();
144 } catch (TransformerConfigurationException e) {
145 logger.error("couldn't create transformer object: "+e.getMessageAndLocation());
146 logger.error(e.getLocationAsString());
147 return "";
148 } catch (TransformerException e) {
149 logger.error("couldn't transform the source: " + e.getMessageAndLocation());
150 return "";
151 }
152 }
153
154 public Node transform(Document stylesheet, Document source) {
155 return transform(stylesheet, source, null, null);
156 }
157
158 public Node transform(Document stylesheet, Document source, HashMap parameters, Document docDocType) {
159 try {
160 // Use the TransformerFactory to process the stylesheet Source and generate a Transformer.
161 Transformer transformer = this.t_factory.newTransformer(new DOMSource(stylesheet));
162 transformer.setErrorListener(new TransformErrorListener());
163 if (parameters != null) {
164 Set params = parameters.entrySet();
165 Iterator i = params.iterator();
166 while (i.hasNext()) {
167 Map.Entry m = (Map.Entry)i.next();
168 transformer.setParameter((String)m.getKey(), m.getValue());
169 }
170 }
171
172 // When we transform the DOMResult, we need to make sure the result of
173 // the transformation has a DocType. For that to happen, we need to create
174 // the DOMResult using a Document with a predefined docType.
175 // If we don't have a DocType then do the transformation with a DOMResult
176 // that does not contain any doctype (like we use to do before).
177 DOMResult result = docDocType == null ? new DOMResult() : new DOMResult(docDocType);
178 transformer.transform(new DOMSource(source), result);
179 return result.getNode(); // pass the entire document
180 }
181 catch (TransformerConfigurationException e) {
182 return transformError("XMLTransformer.transform(Doc, Doc, HashMap, Doc)"
183 + "\ncouldn't create transformer object", e);
184 }
185 catch (TransformerException e) {
186 return transformError("XMLTransformer.transform(Doc, Doc, HashMap, Doc)"
187 + "\ncouldn't transform the source", e);
188 }
189 }
190
191 public Node transform(File stylesheet, File source) {
192 try {
193 Transformer transformer = this.t_factory.newTransformer(new StreamSource(stylesheet));
194 transformer.setErrorListener(new TransformErrorListener());
195 DOMResult result = new DOMResult();
196 transformer.transform(new StreamSource(source), result);
197 return result.getNode().getFirstChild();
198 } catch (TransformerConfigurationException e) {
199 return transformError("XMLTransformer.transform(File, File)"
200 + "\ncouldn't create transformer object for files\n"
201 + stylesheet + "\n" + source, e);
202 }
203 catch (TransformerException e) {
204 return transformError("XMLTransformer.transform(File, File)"
205 + "\ncouldn't transform the source for files\n"
206 + stylesheet + "\n" + source, e);
207 }
208 }
209
210 public Node transform(File stylesheet, File source, Document docDocType) {
211 try {
212 Transformer transformer = this.t_factory.newTransformer(new StreamSource(stylesheet));
213 transformer.setErrorListener(new TransformErrorListener());
214 DOMResult result = new DOMResult(docDocType);
215 transformer.transform(new StreamSource(source), result);
216 return result.getNode().getFirstChild();
217 } catch (TransformerConfigurationException e) {
218 return transformError("XMLTransformer.transform(File, File, Doc)"
219 + "\ncouldn't create transformer object for files\n"
220 + stylesheet + "\n" + source, e);
221 }
222 catch (TransformerException e) {
223 return transformError("XMLTransformer.transform(File, File, Doc)"
224 + "\ncouldn't transform the source for files\n"
225 + stylesheet + "\n" + source, e);
226 }
227 }
228
229 // Given a heading string on the sort of transformation error that occurred and the exception object itself,
230 // this method prints the exception to the tomcat window (system.err) and the greenstone log and then returns
231 // an xhtml error page that is constructed from it.
232 protected Node transformError(String heading, TransformerException e) {
233 String message = heading + "\n" + e.getMessage();
234 logger.error(heading + ": " + e.getMessage());
235
236 String location = e.getLocationAsString();
237 if(location != null) {
238 logger.error(location);
239 message = message + "\n" + location;
240 }
241 System.err.println("****\n" + message + "\n****");
242 return constructErrorXHTMLPage(message);
243 }
244
245 // Given an error message, splits it into separate lines based on any newlines present and generates an xhtml page
246 // (xml Element) with paragraphs for each line. This is then returned so that it can be displayed in the browser.
247 public static Element constructErrorXHTMLPage(String message) {
248 try{
249 String[] lines = message.split("\n");
250
251 Document xhtmlDoc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
252 // <html></html>
253 Node htmlNode = xhtmlDoc.createElement("html");
254 xhtmlDoc.appendChild(htmlNode);
255 // <head></head>
256 Node headNode = xhtmlDoc.createElement("head");
257 htmlNode.appendChild(headNode);
258 // <title></title>
259 Node titleNode = xhtmlDoc.createElement("title");
260 headNode.appendChild(titleNode);
261 Node titleString = xhtmlDoc.createTextNode("Error occurred");
262 titleNode.appendChild(titleString);
263
264 // <body></body>
265 Node bodyNode = xhtmlDoc.createElement("body");
266 htmlNode.appendChild(bodyNode);
267
268 // finally put the message in the body
269 Node h1Node = xhtmlDoc.createElement("h1");
270 bodyNode.appendChild(h1Node);
271 Node headingString = xhtmlDoc.createTextNode("The following error occurred:");
272 h1Node.appendChild(headingString);
273
274 //Node textNode = xhtmlDoc.createTextNode(message);
275 //bodyNode.appendChild(textNode);
276
277 for (int i = 0; i < lines.length; i++) {
278 Node pNode = xhtmlDoc.createElement("p");
279 Node textNode = xhtmlDoc.createTextNode(lines[i]);
280 pNode.appendChild(textNode);
281 bodyNode.appendChild(pNode);
282 }
283
284 return xhtmlDoc.getDocumentElement();
285
286 }catch(Exception e) {
287 String errmsg = "Exception trying to construct error xhtml page from message: " + message
288 + "\n" + e.getMessage();
289 System.err.println(errmsg);
290 logger.error(errmsg);
291 return null;
292 }
293 }
294
295 // ErrorListener class that can be used to register a handler for any fatal errors, errors and warnings that may
296 // occur when transforming an xml file with an xslt stylesheet. The errors are printed both to the greenstone.log and
297 // to the tomcat console (System.err), and the error message is stored in the errorMessage variable so that it can
298 // be retrieved and be used to generate an xhtml error page.
299 static public class TransformErrorListener implements ErrorListener {
300 protected String errorMessage = null;
301
302 // Receive notification of a recoverable error.
303 public void error(TransformerException exception) {
304 handleError("Error:\n", exception);
305 }
306 // Receive notification of a non-recoverable error.
307 public void fatalError(TransformerException exception) {
308 handleError("Fatal Error:\n", exception);
309 }
310 // Receive notification of a warning.
311 public void warning(TransformerException exception) {
312 handleError("Warning:\n", exception);
313 }
314
315 public String toString(TransformerException e) {
316 String location = e.getLocationAsString();
317 if(location == null) {
318 return e.getMessage();
319 }
320 return e.getMessage() + "\n" + location;
321 }
322
323 // clears the errorPage variable after first call to this method
324 public String getErrorMessage() {
325 String errMsg = this.errorMessage;
326 if(this.errorMessage != null) {
327 this.errorMessage = null;
328 }
329 return errMsg;
330 }
331
332 // sets the errorMessage member variable to the data stored in the exception
333 // and writes the errorMessage to the logger and tomcat's System.err
334 protected void handleError(String errorType, TransformerException exception) {
335 this.errorMessage = errorType + toString(exception);
336 System.err.println("\n****Error transforming xml:\n" + this.errorMessage + "\n****\n");
337 logger.error(this.errorMessage);
338 }
339 }
340}
Note: See TracBrowser for help on using the repository browser.