1 /* TransformerFactoryImpl.java -- 2 Copyright (C) 2004 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.IOException; 41 import java.net.URL; 42 import java.util.Iterator; 43 import java.util.LinkedHashMap; 44 import java.util.LinkedList; 45 import java.util.Map; 46 import java.util.Properties; 47 import javax.xml.transform.ErrorListener; 48 import javax.xml.transform.Source; 49 import javax.xml.transform.Templates; 50 import javax.xml.transform.Transformer; 51 import javax.xml.transform.TransformerConfigurationException; 52 import javax.xml.transform.TransformerException; 53 import javax.xml.transform.TransformerFactory; 54 import javax.xml.transform.URIResolver; 55 import javax.xml.transform.dom.DOMResult; 56 import javax.xml.transform.dom.DOMSource; 57 import javax.xml.transform.sax.SAXResult; 58 import javax.xml.transform.sax.SAXSource; 59 import javax.xml.transform.stream.StreamResult; 60 import javax.xml.transform.stream.StreamSource; 61 import javax.xml.xpath.XPathFactory; 62 import org.w3c.dom.Document; 63 import org.w3c.dom.Node; 64 import gnu.xml.dom.DomDocument; 65 66 /** 67 * GNU transformer factory implementation. 68 * 69 * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a> 70 */ 71 public class TransformerFactoryImpl 72 extends TransformerFactory 73 { 74 75 final XPathFactory xpathFactory; 76 final XSLURIResolver resolver; 77 ErrorListener userListener; 78 URIResolver userResolver; 79 TransformerFactoryImpl()80 public TransformerFactoryImpl() 81 { 82 xpathFactory = new gnu.xml.xpath.XPathFactoryImpl(); 83 resolver = new XSLURIResolver(); 84 } 85 newTransformer(Source source)86 public Transformer newTransformer(Source source) 87 throws TransformerConfigurationException 88 { 89 Stylesheet stylesheet = newStylesheet(source, 0, null); 90 Properties outputProperties = 91 new TransformerOutputProperties(stylesheet); 92 TransformerImpl transformer = 93 new TransformerImpl(this, stylesheet, outputProperties); 94 stylesheet.transformer = transformer; 95 return transformer; 96 } 97 newTransformer()98 public Transformer newTransformer() 99 throws TransformerConfigurationException 100 { 101 return new TransformerImpl(this, null, new Properties()); 102 } 103 newTemplates(Source source)104 public Templates newTemplates(Source source) 105 throws TransformerConfigurationException 106 { 107 Stylesheet stylesheet = newStylesheet(source, 0, null); 108 return new TemplatesImpl(this, stylesheet); 109 } 110 newStylesheet(Source source, int precedence, Stylesheet parent)111 Stylesheet newStylesheet(Source source, int precedence, Stylesheet parent) 112 throws TransformerConfigurationException 113 { 114 Document doc = null; 115 String systemId = null; 116 if (source != null) 117 { 118 try 119 { 120 DOMSource ds; 121 synchronized (resolver) 122 { 123 resolver.setUserResolver(userResolver); 124 resolver.setUserListener(userListener); 125 ds = resolver.resolveDOM(source, null, null); 126 } 127 Node node = ds.getNode(); 128 if (node == null) 129 { 130 throw new TransformerConfigurationException("no source document"); 131 } 132 doc = (node instanceof Document) ? (Document) node : 133 node.getOwnerDocument(); 134 systemId = ds.getSystemId(); 135 } 136 catch (TransformerException e) 137 { 138 throw new TransformerConfigurationException(e); 139 } 140 } 141 return new Stylesheet(this, parent, doc, systemId, precedence); 142 } 143 getAssociatedStylesheet(Source source, String media, String title, String charset)144 public Source getAssociatedStylesheet(Source source, 145 String media, 146 String title, 147 String charset) 148 throws TransformerConfigurationException 149 { 150 try 151 { 152 DOMSource ds; 153 synchronized (resolver) 154 { 155 resolver.setUserResolver(userResolver); 156 resolver.setUserListener(userListener); 157 ds = resolver.resolveDOM(source, null, null); 158 } 159 Node node = ds.getNode(); 160 if (node == null) 161 { 162 throw new TransformerConfigurationException("no source document"); 163 } 164 Document doc = (node instanceof Document) ? (Document) node : 165 node.getOwnerDocument(); 166 LinkedList matches = new LinkedList(); 167 for (node = doc.getFirstChild(); 168 node != null; 169 node = node.getNextSibling()) 170 { 171 if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE && 172 "xml-stylesheet".equals(node.getNodeName())) 173 { 174 Map params = parseParameters(node.getNodeValue()); 175 if (media != null && !media.equals(params.get("media"))) 176 { 177 continue; 178 } 179 if (title != null && !title.equals(params.get("title"))) 180 { 181 continue; 182 } 183 if (charset != null && !charset.equals(params.get("charset"))) 184 { 185 continue; 186 } 187 String href = (String) params.get("href"); 188 URL url = resolver.resolveURL(null, node.getBaseURI(), href); 189 matches.add(url); 190 } 191 } 192 switch (matches.size()) 193 { 194 case 0: 195 return null; 196 case 1: 197 return new StreamSource(((URL) matches.getFirst()).toString()); 198 default: 199 // Create a source representing a stylesheet with a list of 200 // imports 201 DomDocument ssDoc = new DomDocument(); 202 ssDoc.setBuilding(true); 203 // Create document element 204 Node root = 205 ssDoc.createElementNS(Stylesheet.XSL_NS, "stylesheet"); 206 Node version = 207 ssDoc.createAttributeNS(null, "version"); 208 version.setNodeValue("1.0"); 209 root.getAttributes().setNamedItemNS(version); 210 ssDoc.appendChild(root); 211 // Create xsl:import for each URL 212 for (Iterator i = matches.iterator(); i.hasNext(); ) 213 { 214 URL url = (URL) i.next(); 215 Node imp = 216 ssDoc.createElementNS(Stylesheet.XSL_NS, "import"); 217 Node href = 218 ssDoc.createAttributeNS(null, "href"); 219 href.setNodeValue(url.toString()); 220 imp.getAttributes().setNamedItemNS(href); 221 root.appendChild(imp); 222 } 223 ssDoc.setBuilding(false); 224 return new DOMSource(ssDoc); 225 } 226 } 227 catch (IOException e) 228 { 229 throw new TransformerConfigurationException(e); 230 } 231 catch (TransformerException e) 232 { 233 throw new TransformerConfigurationException(e); 234 } 235 } 236 parseParameters(String data)237 Map parseParameters(String data) 238 { 239 Map ret = new LinkedHashMap(); 240 int len = data.length(); 241 String key = null; 242 int start = 0; 243 char quoteChar = '\u0000'; 244 for (int i = 0; i < len; i++) 245 { 246 char c = data.charAt(i); 247 if (quoteChar == '\u0000' && c == ' ') 248 { 249 if (key == null && start < i) 250 { 251 key = data.substring(start, i); 252 } 253 else 254 { 255 String val = unquote(data.substring(start, i).trim()); 256 ret.put(key, val); 257 key = null; 258 } 259 start = i + 1; 260 } 261 else if (c == '"') 262 { 263 quoteChar = (quoteChar == c) ? '\u0000' : c; 264 } 265 else if (c == '\'') 266 { 267 quoteChar = (quoteChar == c) ? '\u0000' : c; 268 } 269 } 270 if (start < len && key != null) 271 { 272 String val = unquote(data.substring(start, len).trim()); 273 ret.put(key, val); 274 } 275 return ret; 276 } 277 unquote(String text)278 String unquote(String text) 279 { 280 int end = text.length() - 1; 281 if (text.charAt(0) == '\'' && text.charAt(end) == '\'') 282 { 283 return text.substring(1, end); 284 } 285 if (text.charAt(0) == '"' && text.charAt(end) == '"') 286 { 287 return text.substring(1, end); 288 } 289 return text; 290 } 291 setURIResolver(URIResolver resolver)292 public void setURIResolver(URIResolver resolver) 293 { 294 userResolver = resolver; 295 } 296 getURIResolver()297 public URIResolver getURIResolver() 298 { 299 return userResolver; 300 } 301 setFeature(String name, boolean value)302 public void setFeature(String name, boolean value) 303 throws TransformerConfigurationException 304 { 305 throw new TransformerConfigurationException("not supported"); 306 } 307 getFeature(String name)308 public boolean getFeature(String name) 309 { 310 if (SAXSource.FEATURE.equals(name) || 311 SAXResult.FEATURE.equals(name) || 312 StreamSource.FEATURE.equals(name) || 313 StreamResult.FEATURE.equals(name) || 314 DOMSource.FEATURE.equals(name) || 315 DOMResult.FEATURE.equals(name)) 316 { 317 return true; 318 } 319 return false; 320 } 321 setAttribute(String name, Object value)322 public void setAttribute(String name, Object value) 323 throws IllegalArgumentException 324 { 325 throw new IllegalArgumentException("not supported"); 326 } 327 getAttribute(String name)328 public Object getAttribute(String name) 329 throws IllegalArgumentException 330 { 331 throw new IllegalArgumentException("not supported"); 332 } 333 setErrorListener(ErrorListener listener)334 public void setErrorListener(ErrorListener listener) 335 throws IllegalArgumentException 336 { 337 userListener = listener; 338 } 339 getErrorListener()340 public ErrorListener getErrorListener() 341 { 342 return userListener; 343 } 344 345 } 346