Source for gnu.xml.transform.TransformerFactoryImpl

   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: 
  80:   public TransformerFactoryImpl()
  81:   {
  82:     xpathFactory = new gnu.xml.xpath.XPathFactoryImpl();
  83:     resolver = new XSLURIResolver();
  84:   }
  85: 
  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: 
  98:   public Transformer newTransformer()
  99:     throws TransformerConfigurationException
 100:   {
 101:     return new TransformerImpl(this, null, new Properties());
 102:   }
 103: 
 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: 
 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:   
 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: 
 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: 
 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: 
 292:   public void setURIResolver(URIResolver resolver)
 293:   {
 294:     userResolver = resolver;
 295:   }
 296: 
 297:   public URIResolver getURIResolver()
 298:   {
 299:     return userResolver;
 300:   }
 301: 
 302:   public void setFeature(String name, boolean value)
 303:     throws TransformerConfigurationException
 304:   {
 305:     throw new TransformerConfigurationException("not supported");
 306:   }
 307: 
 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: 
 322:   public void setAttribute(String name, Object value)
 323:     throws IllegalArgumentException
 324:   {
 325:     throw new IllegalArgumentException("not supported");
 326:   }
 327: 
 328:   public Object getAttribute(String name)
 329:     throws IllegalArgumentException
 330:   {
 331:     throw new IllegalArgumentException("not supported");
 332:   }
 333: 
 334:   public void setErrorListener(ErrorListener listener)
 335:     throws IllegalArgumentException
 336:   {
 337:     userListener = listener;
 338:   }
 339: 
 340:   public ErrorListener getErrorListener()
 341:   {
 342:     return userListener;
 343:   }
 344:   
 345: }