Source for gnu.xml.transform.TransformerFactoryImpl

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