1 /* TransformerFactoryImpl.java -- 2 Copyright (C) 2004,2006 Free Software Foundation, Inc. 3 4 This file is part of GNU Classpath. 5 6 GNU Classpath is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GNU Classpath is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GNU Classpath; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19 02110-1301 USA. 20 21 Linking this library statically or dynamically with other modules is 22 making a combined work based on this library. Thus, the terms and 23 conditions of the GNU General Public License cover the whole 24 combination. 25 26 As a special exception, the copyright holders of this library give you 27 permission to link this library with independent modules to produce an 28 executable, regardless of the license terms of these independent 29 modules, and to copy and distribute the resulting executable under 30 terms of your choice, provided that you also meet, for each linked 31 independent module, the terms and conditions of the license of that 32 module. An independent module is a module which is not derived from 33 or based on this library. If you modify this library, you may extend 34 this exception to your version of the library, but you are not 35 obligated to do so. If you do not wish to do so, delete this 36 exception statement from your version. */ 37 38 package gnu.xml.transform; 39 40 import java.io.FileInputStream; 41 import java.io.FileOutputStream; 42 import java.io.InputStream; 43 import java.io.IOException; 44 import java.io.OutputStream; 45 import java.net.URL; 46 import java.util.Iterator; 47 import java.util.LinkedHashMap; 48 import java.util.LinkedList; 49 import java.util.Map; 50 import java.util.Properties; 51 import javax.xml.transform.ErrorListener; 52 import javax.xml.transform.Source; 53 import javax.xml.transform.Templates; 54 import javax.xml.transform.Transformer; 55 import javax.xml.transform.TransformerConfigurationException; 56 import javax.xml.transform.TransformerException; 57 import javax.xml.transform.TransformerFactory; 58 import javax.xml.transform.URIResolver; 59 import javax.xml.transform.dom.DOMResult; 60 import javax.xml.transform.dom.DOMSource; 61 import javax.xml.transform.sax.SAXResult; 62 import javax.xml.transform.sax.SAXSource; 63 import javax.xml.transform.sax.SAXTransformerFactory; 64 import javax.xml.transform.sax.TemplatesHandler; 65 import javax.xml.transform.sax.TransformerHandler; 66 import javax.xml.transform.stream.StreamResult; 67 import javax.xml.transform.stream.StreamSource; 68 import javax.xml.xpath.XPathFactory; 69 import org.w3c.dom.Document; 70 import org.w3c.dom.Node; 71 import org.xml.sax.XMLFilter; 72 import gnu.xml.dom.DomDocument; 73 74 /** 75 * GNU transformer factory implementation. 76 * 77 * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a> 78 */ 79 public class TransformerFactoryImpl 80 extends SAXTransformerFactory 81 { 82 83 final XPathFactory xpathFactory; 84 final XSLURIResolver resolver; 85 ErrorListener userListener; 86 URIResolver userResolver; 87 TransformerFactoryImpl()88 public TransformerFactoryImpl() 89 { 90 xpathFactory = new gnu.xml.xpath.XPathFactoryImpl(); 91 resolver = new XSLURIResolver(); 92 } 93 newTransformer(Source source)94 public Transformer newTransformer(Source source) 95 throws TransformerConfigurationException 96 { 97 Stylesheet stylesheet = newStylesheet(source, 0, null); 98 Properties outputProperties = 99 new TransformerOutputProperties(stylesheet); 100 TransformerImpl transformer = 101 new TransformerImpl(this, stylesheet, outputProperties); 102 stylesheet.transformer = transformer; 103 return transformer; 104 } 105 newTransformer()106 public Transformer newTransformer() 107 throws TransformerConfigurationException 108 { 109 return new TransformerImpl(this, null, new Properties()); 110 } 111 newTemplates(Source source)112 public Templates newTemplates(Source source) 113 throws TransformerConfigurationException 114 { 115 Stylesheet stylesheet = newStylesheet(source, 0, null); 116 return new TemplatesImpl(this, stylesheet); 117 } 118 newStylesheet(Source source, int precedence, Stylesheet parent)119 Stylesheet newStylesheet(Source source, int precedence, Stylesheet parent) 120 throws TransformerConfigurationException 121 { 122 Document doc = null; 123 String systemId = null; 124 if (source != null) 125 { 126 try 127 { 128 DOMSource ds; 129 synchronized (resolver) 130 { 131 resolver.setUserResolver(userResolver); 132 resolver.setUserListener(userListener); 133 ds = resolver.resolveDOM(source, null, null); 134 } 135 Node node = ds.getNode(); 136 if (node == null) 137 { 138 throw new TransformerConfigurationException("no source document"); 139 } 140 doc = (node instanceof Document) ? (Document) node : 141 node.getOwnerDocument(); 142 systemId = ds.getSystemId(); 143 } 144 catch (TransformerException e) 145 { 146 throw new TransformerConfigurationException(e); 147 } 148 } 149 return new Stylesheet(this, parent, doc, systemId, precedence); 150 } 151 getAssociatedStylesheet(Source source, String media, String title, String charset)152 public Source getAssociatedStylesheet(Source source, 153 String media, 154 String title, 155 String charset) 156 throws TransformerConfigurationException 157 { 158 try 159 { 160 DOMSource ds; 161 synchronized (resolver) 162 { 163 resolver.setUserResolver(userResolver); 164 resolver.setUserListener(userListener); 165 ds = resolver.resolveDOM(source, null, null); 166 } 167 Node node = ds.getNode(); 168 if (node == null) 169 { 170 throw new TransformerConfigurationException("no source document"); 171 } 172 Document doc = (node instanceof Document) ? (Document) node : 173 node.getOwnerDocument(); 174 LinkedList matches = new LinkedList(); 175 for (node = doc.getFirstChild(); 176 node != null; 177 node = node.getNextSibling()) 178 { 179 if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE && 180 "xml-stylesheet".equals(node.getNodeName())) 181 { 182 Map params = parseParameters(node.getNodeValue()); 183 if (media != null && !media.equals(params.get("media"))) 184 { 185 continue; 186 } 187 if (title != null && !title.equals(params.get("title"))) 188 { 189 continue; 190 } 191 if (charset != null && !charset.equals(params.get("charset"))) 192 { 193 continue; 194 } 195 String href = (String) params.get("href"); 196 URL url = resolver.resolveURL(null, node.getBaseURI(), href); 197 matches.add(url); 198 } 199 } 200 switch (matches.size()) 201 { 202 case 0: 203 return null; 204 case 1: 205 return new StreamSource(((URL) matches.getFirst()).toString()); 206 default: 207 // Create a source representing a stylesheet with a list of 208 // imports 209 DomDocument ssDoc = new DomDocument(); 210 ssDoc.setBuilding(true); 211 // Create document element 212 Node root = 213 ssDoc.createElementNS(Stylesheet.XSL_NS, "stylesheet"); 214 Node version = 215 ssDoc.createAttributeNS(null, "version"); 216 version.setNodeValue("1.0"); 217 root.getAttributes().setNamedItemNS(version); 218 ssDoc.appendChild(root); 219 // Create xsl:import for each URL 220 for (Iterator i = matches.iterator(); i.hasNext(); ) 221 { 222 URL url = (URL) i.next(); 223 Node imp = 224 ssDoc.createElementNS(Stylesheet.XSL_NS, "import"); 225 Node href = 226 ssDoc.createAttributeNS(null, "href"); 227 href.setNodeValue(url.toString()); 228 imp.getAttributes().setNamedItemNS(href); 229 root.appendChild(imp); 230 } 231 ssDoc.setBuilding(false); 232 return new DOMSource(ssDoc); 233 } 234 } 235 catch (IOException e) 236 { 237 throw new TransformerConfigurationException(e); 238 } 239 catch (TransformerException e) 240 { 241 throw new TransformerConfigurationException(e); 242 } 243 } 244 parseParameters(String data)245 Map parseParameters(String data) 246 { 247 Map ret = new LinkedHashMap(); 248 int len = data.length(); 249 String key = null; 250 int start = 0; 251 char quoteChar = '\u0000'; 252 for (int i = 0; i < len; i++) 253 { 254 char c = data.charAt(i); 255 if (quoteChar == '\u0000' && c == ' ') 256 { 257 if (key == null && start < i) 258 { 259 key = data.substring(start, i); 260 } 261 else 262 { 263 String val = unquote(data.substring(start, i).trim()); 264 ret.put(key, val); 265 key = null; 266 } 267 start = i + 1; 268 } 269 else if (c == '"') 270 { 271 quoteChar = (quoteChar == c) ? '\u0000' : c; 272 } 273 else if (c == '\'') 274 { 275 quoteChar = (quoteChar == c) ? '\u0000' : c; 276 } 277 } 278 if (start < len && key != null) 279 { 280 String val = unquote(data.substring(start, len).trim()); 281 ret.put(key, val); 282 } 283 return ret; 284 } 285 unquote(String text)286 String unquote(String text) 287 { 288 int end = text.length() - 1; 289 if (text.charAt(0) == '\'' && text.charAt(end) == '\'') 290 { 291 return text.substring(1, end); 292 } 293 if (text.charAt(0) == '"' && text.charAt(end) == '"') 294 { 295 return text.substring(1, end); 296 } 297 return text; 298 } 299 setURIResolver(URIResolver resolver)300 public void setURIResolver(URIResolver resolver) 301 { 302 userResolver = resolver; 303 } 304 getURIResolver()305 public URIResolver getURIResolver() 306 { 307 return userResolver; 308 } 309 setFeature(String name, boolean value)310 public void setFeature(String name, boolean value) 311 throws TransformerConfigurationException 312 { 313 throw new TransformerConfigurationException("not supported"); 314 } 315 getFeature(String name)316 public boolean getFeature(String name) 317 { 318 if (SAXSource.FEATURE.equals(name) || 319 SAXResult.FEATURE.equals(name) || 320 StreamSource.FEATURE.equals(name) || 321 StreamResult.FEATURE.equals(name) || 322 DOMSource.FEATURE.equals(name) || 323 DOMResult.FEATURE.equals(name) || 324 SAXTransformerFactory.FEATURE.equals(name)) 325 { 326 return true; 327 } 328 return false; 329 } 330 setAttribute(String name, Object value)331 public void setAttribute(String name, Object value) 332 throws IllegalArgumentException 333 { 334 throw new IllegalArgumentException("not supported"); 335 } 336 getAttribute(String name)337 public Object getAttribute(String name) 338 throws IllegalArgumentException 339 { 340 throw new IllegalArgumentException("not supported"); 341 } 342 setErrorListener(ErrorListener listener)343 public void setErrorListener(ErrorListener listener) 344 throws IllegalArgumentException 345 { 346 userListener = listener; 347 } 348 getErrorListener()349 public ErrorListener getErrorListener() 350 { 351 return userListener; 352 } 353 354 // -- SAXTransformerFactory -- 355 newTemplatesHandler()356 public TemplatesHandler newTemplatesHandler() 357 throws TransformerConfigurationException 358 { 359 return new SAXTemplatesHandler(this); 360 } 361 newTransformerHandler()362 public TransformerHandler newTransformerHandler() 363 throws TransformerConfigurationException 364 { 365 Transformer transformer = newTransformer(); 366 return new SAXTransformerHandler(this, transformer); 367 } 368 newTransformerHandler(Source source)369 public TransformerHandler newTransformerHandler(Source source) 370 throws TransformerConfigurationException 371 { 372 Transformer transformer = newTransformer(source); 373 return new SAXTransformerHandler(this, transformer); 374 } 375 newTransformerHandler(Templates templates)376 public TransformerHandler newTransformerHandler(Templates templates) 377 throws TransformerConfigurationException 378 { 379 Transformer transformer = templates.newTransformer(); 380 return new SAXTransformerHandler(this, transformer); 381 } 382 newXMLFilter(Source source)383 public XMLFilter newXMLFilter(Source source) 384 throws TransformerConfigurationException 385 { 386 throw new UnsupportedOperationException(); 387 } 388 newXMLFilter(Templates templates)389 public XMLFilter newXMLFilter(Templates templates) 390 throws TransformerConfigurationException 391 { 392 throw new UnsupportedOperationException(); 393 } 394 395 // -- SAXTransformerFactory end -- 396 397 /** 398 * Syntax: TransformerFactoryImpl [<stylesheet> [<input> [<output>]]] 399 */ main(String[] args)400 public static void main(String[] args) 401 throws Exception 402 { 403 InputStream stylesheet = null, in = null; 404 OutputStream out = null; 405 try 406 { 407 if (args.length > 0) 408 { 409 stylesheet = new FileInputStream(args[0]); 410 if (args.length > 1) 411 { 412 in = new FileInputStream(args[1]); 413 if (args.length > 2) 414 out = new FileOutputStream(args[2]); 415 } 416 } 417 if (in == null) 418 in = System.in; 419 if (out == null) 420 out = System.out; 421 TransformerFactory f = new TransformerFactoryImpl(); 422 Transformer t = (stylesheet != null) ? 423 f.newTransformer(new StreamSource(stylesheet)) : 424 f.newTransformer(); 425 t.transform(new StreamSource(in), new StreamResult(out)); 426 } 427 finally 428 { 429 if (stylesheet != null) 430 stylesheet.close(); 431 if (in != null && in instanceof FileInputStream) 432 in.close(); 433 if (out != null && out instanceof FileOutputStream) 434 out.close(); 435 } 436 } 437 438 } 439