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.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: 
  88:   public TransformerFactoryImpl()
  89:   {
  90:     xpathFactory = new gnu.xml.xpath.XPathFactoryImpl();
  91:     resolver = new XSLURIResolver();
  92:   }
  93: 
  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: 
 106:   public Transformer newTransformer()
 107:     throws TransformerConfigurationException
 108:   {
 109:     return new TransformerImpl(this, null, new Properties());
 110:   }
 111: 
 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: 
 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: 
 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: 
 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: 
 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: 
 300:   public void setURIResolver(URIResolver resolver)
 301:   {
 302:     userResolver = resolver;
 303:   }
 304: 
 305:   public URIResolver getURIResolver()
 306:   {
 307:     return userResolver;
 308:   }
 309: 
 310:   public void setFeature(String name, boolean value)
 311:     throws TransformerConfigurationException
 312:   {
 313:     throw new TransformerConfigurationException("not supported");
 314:   }
 315: 
 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: 
 331:   public void setAttribute(String name, Object value)
 332:     throws IllegalArgumentException
 333:   {
 334:     throw new IllegalArgumentException("not supported");
 335:   }
 336: 
 337:   public Object getAttribute(String name)
 338:     throws IllegalArgumentException
 339:   {
 340:     throw new IllegalArgumentException("not supported");
 341:   }
 342: 
 343:   public void setErrorListener(ErrorListener listener)
 344:     throws IllegalArgumentException
 345:   {
 346:     userListener = listener;
 347:   }
 348: 
 349:   public ErrorListener getErrorListener()
 350:   {
 351:     return userListener;
 352:   }
 353: 
 354:   // -- SAXTransformerFactory --
 355: 
 356:   public TemplatesHandler newTemplatesHandler()
 357:     throws TransformerConfigurationException
 358:   {
 359:     return new SAXTemplatesHandler(this);
 360:   }
 361: 
 362:   public TransformerHandler newTransformerHandler()
 363:     throws TransformerConfigurationException
 364:   {
 365:     Transformer transformer = newTransformer();
 366:     return new SAXTransformerHandler(this, transformer);
 367:   }
 368: 
 369:   public TransformerHandler newTransformerHandler(Source source)
 370:     throws TransformerConfigurationException
 371:   {
 372:     Transformer transformer = newTransformer(source);
 373:     return new SAXTransformerHandler(this, transformer);
 374:   }
 375: 
 376:   public TransformerHandler newTransformerHandler(Templates templates)
 377:     throws TransformerConfigurationException
 378:   {
 379:     Transformer transformer = templates.newTransformer();
 380:     return new SAXTransformerHandler(this, transformer);
 381:   }
 382: 
 383:   public XMLFilter newXMLFilter(Source source)
 384:     throws TransformerConfigurationException
 385:   {
 386:     throw new UnsupportedOperationException();
 387:   }
 388: 
 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:    */
 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: }