Source for gnu.xml.dom.ls.DomLSParser

   1: /* DomLSParser.java -- 
   2:    Copyright (C) 1999,2000,2001 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.dom.ls;
  39: 
  40: import java.io.File;
  41: import java.io.InputStream;
  42: import java.io.IOException;
  43: import java.net.MalformedURLException;
  44: import java.net.URL;
  45: import java.util.Arrays;
  46: import java.util.List;
  47: import javax.xml.parsers.ParserConfigurationException;
  48: import javax.xml.parsers.SAXParser;
  49: import javax.xml.parsers.SAXParserFactory;
  50: import org.w3c.dom.Document;
  51: import org.w3c.dom.DOMConfiguration;
  52: import org.w3c.dom.DOMException;
  53: import org.w3c.dom.DOMStringList;
  54: import org.w3c.dom.Node;
  55: import org.w3c.dom.ls.DOMImplementationLS;
  56: import org.w3c.dom.ls.LSException;
  57: import org.w3c.dom.ls.LSInput;
  58: import org.w3c.dom.ls.LSParser;
  59: import org.w3c.dom.ls.LSParserFilter;
  60: import org.xml.sax.EntityResolver;
  61: import org.xml.sax.ErrorHandler;
  62: import org.xml.sax.InputSource;
  63: import org.xml.sax.SAXException;
  64: import org.xml.sax.SAXNotRecognizedException;
  65: import org.xml.sax.SAXParseException;
  66: import org.xml.sax.XMLReader;
  67: import gnu.xml.dom.DomDocument;
  68: import gnu.xml.dom.DomDOMException;
  69: 
  70: /**
  71:  * Parser implementation for GNU DOM.
  72:  *
  73:  * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
  74:  */
  75: public class DomLSParser
  76:   implements LSParser, DOMConfiguration, DOMStringList, ErrorHandler
  77: {
  78: 
  79:   private static final List SUPPORTED_PARAMETERS
  80:     = Arrays.asList(new String[] { "cdata-sections",
  81:                     "comments",
  82:                     "element-content-whitespace",
  83:                     "namespaces",
  84:                     "expand-entity-references",
  85:                     "coalescing",
  86:                     "validating",
  87:                     "xinclude-aware",
  88:                     "entity-resolver",
  89:                     "error-handler" });
  90: 
  91:   private LSParserFilter filter;
  92:   private final boolean async;
  93:   private String schemaType;
  94:   private SAXEventSink eventSink;
  95:   private SAXParserFactory factory;
  96:   private XMLReader reader;
  97: 
  98:   private boolean namespaceAware = true;
  99:   private boolean ignoreWhitespace;
 100:   private boolean expandEntityReferences;
 101:   private boolean ignoreComments;
 102:   private boolean coalescing;
 103:   private boolean validating;
 104:   private boolean xIncludeAware;
 105:   private EntityResolver entityResolver;
 106:   private ErrorHandler errorHandler;
 107: 
 108:   public DomLSParser(short mode, String schemaType)
 109:     throws DOMException
 110:   {
 111:     switch (mode)
 112:       {
 113:       case DOMImplementationLS.MODE_ASYNCHRONOUS:
 114:         async = true;
 115:         break;
 116:       case DOMImplementationLS.MODE_SYNCHRONOUS:
 117:         async = false;
 118:         break;
 119:       default:
 120:         throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR);
 121:       }
 122:     // TODO schemaType
 123:     this.schemaType = schemaType;
 124:     factory = SAXParserFactory.newInstance();
 125:   }
 126: 
 127:   // -- LSParser --
 128:   
 129:   public DOMConfiguration getDomConfig()
 130:   {
 131:     return this;
 132:   }
 133:   
 134:   public LSParserFilter getFilter()
 135:   {
 136:     return filter;
 137:   }
 138: 
 139:   public void setFilter(LSParserFilter filter)
 140:   {
 141:     this.filter = filter;
 142:   }
 143: 
 144:   public boolean getAsync()
 145:   {
 146:     return async;
 147:   }
 148: 
 149:   public boolean getBusy()
 150:   {
 151:     return eventSink != null;
 152:   }
 153: 
 154:   public Document parse(LSInput input)
 155:     throws DOMException, LSException
 156:   {
 157:     if (async)
 158:       {
 159:         return doParse(input);
 160:       }
 161:     else
 162:       {
 163:         synchronized (this)
 164:           {
 165:             return doParse(input);
 166:           }
 167:       }
 168:   }
 169: 
 170:   public Document parseURI(String uri)
 171:     throws DOMException, LSException
 172:   {
 173:     LSInput input = new DomLSInput();
 174:     input.setSystemId(uri);
 175:     return parse(input);
 176:   }
 177: 
 178:   public Node parseWithContext(LSInput input, Node context, short action)
 179:     throws DOMException, LSException
 180:   {
 181:     Document doc = (context.getNodeType() == Node.DOCUMENT_NODE) ?
 182:       (Document) context : context.getOwnerDocument();
 183:     input.setBaseURI(doc.getDocumentURI());
 184:     // TODO use namespaces defined on context node
 185:     Document ret = parse(input);
 186:     Node root = ret.getDocumentElement();
 187:     root = doc.adoptNode(root);
 188:     switch (action)
 189:       {
 190:       case ACTION_APPEND_AS_CHILDREN:
 191:         context.appendChild(root);
 192:         break;
 193:       case ACTION_REPLACE_CHILDREN:
 194:         Node c1 = context.getFirstChild();
 195:         while (c1 != null)
 196:           {
 197:             Node next = c1.getNextSibling();
 198:             context.removeChild(c1);
 199:             c1 = next;
 200:           }
 201:         context.appendChild(root);
 202:         break;
 203:       case ACTION_INSERT_BEFORE:
 204:         Node p1 = context.getParentNode();
 205:         p1.insertBefore(root, context);
 206:         break;
 207:       case ACTION_INSERT_AFTER:
 208:         Node p2 = context.getParentNode();
 209:         Node r1 = context.getNextSibling();
 210:         if (r1 == null)
 211:           {
 212:             p2.appendChild(root);
 213:           }
 214:         else
 215:           {
 216:             p2.insertBefore(root, r1);
 217:           }
 218:         break;
 219:       case ACTION_REPLACE:
 220:         Node p3 = context.getParentNode();
 221:         Node r2 = context.getNextSibling();
 222:         p3.removeChild(context);
 223:         if (r2 == null)
 224:           {
 225:             p3.appendChild(root);
 226:           }
 227:         else
 228:           {
 229:             p3.insertBefore(root, r2);
 230:           }
 231:         break;
 232:       }
 233:     return root;
 234:   }
 235: 
 236:   public void abort()
 237:   {
 238:     if (eventSink != null)
 239:       {
 240:         eventSink.interrupt();
 241:       }
 242:   }
 243: 
 244:   private Document doParse(LSInput input)
 245:     throws DOMException, LSException
 246:   {
 247:     // create event sink
 248:     if (eventSink != null)
 249:       {
 250:         throw new LSException(LSException.PARSE_ERR, "parse in progress");
 251:       }
 252:     InputSource source = getInputSource(input);
 253:     eventSink = (filter == null) ? new SAXEventSink() :
 254:       new FilteredSAXEventSink(filter);
 255:     // configure sink
 256:     eventSink.namespaceAware = namespaceAware;
 257:     eventSink.ignoreWhitespace = ignoreWhitespace;
 258:     eventSink.expandEntityReferences = expandEntityReferences;
 259:     eventSink.ignoreComments = ignoreComments;
 260:     eventSink.coalescing = coalescing;
 261:     // get and configure reader
 262:     XMLReader reader = getXMLReader();
 263:     try
 264:       {
 265:         reader.setContentHandler(eventSink);
 266:         reader.setDTDHandler(eventSink);
 267:         reader.setProperty("http://xml.org/sax/properties/lexical-handler",
 268:                            eventSink);
 269:         reader.setProperty("http://xml.org/sax/properties/declaration-handler",
 270:                            eventSink);
 271:         reader.setFeature("http://xml.org/sax/features/namespaces",
 272:                           namespaceAware);
 273:         reader.setFeature("http://xml.org/sax/features/namespace-prefixes",
 274:                           true);
 275:         reader.setFeature("http://xml.org/sax/features/validation",
 276:                           validating);
 277:         try
 278:           {
 279:             reader.setFeature("http://xml.org/sax/features/use-attributes2",
 280:                               true);
 281:           }
 282:         catch (SAXNotRecognizedException e)
 283:           {
 284:             // ignore
 285:           }
 286:         try
 287:           {
 288:             reader.setFeature("http://xml.org/sax/features/external-general-entities",
 289:                               true);
 290:           }
 291:         catch (SAXNotRecognizedException e)
 292:           {
 293:             // ignore
 294:           }
 295:         reader.setEntityResolver(entityResolver);
 296:         reader.setErrorHandler(errorHandler);
 297:         // parse
 298:         reader.parse(source);
 299:       }
 300:     catch (DOMException e)
 301:       {
 302:         reader = null;
 303:         eventSink = null;
 304:         throw e;
 305:       }
 306:     catch (SAXException e)
 307:       {
 308:         reader = null;
 309:         eventSink = null;
 310:         throw new DomLSException(LSException.PARSE_ERR, e);
 311:       }
 312:     catch (IOException e)
 313:       {
 314:         reader = null;
 315:         eventSink = null;
 316:         throw new DomLSException(LSException.PARSE_ERR, e);
 317:       }
 318:     // return document
 319:     Document ret = eventSink.doc;
 320:     String systemId = input.getSystemId();
 321:     if (systemId != null && ret instanceof DomDocument)
 322:       {
 323:         ((DomDocument) ret).setDocumentURI(systemId);
 324:       }
 325:     eventSink = null;
 326:     return ret;
 327:   }
 328: 
 329:   private XMLReader getXMLReader()
 330:     throws LSException
 331:   {
 332:     if (reader == null)
 333:       {
 334:         factory.setNamespaceAware(namespaceAware);
 335:         factory.setValidating(validating);
 336:         factory.setXIncludeAware(xIncludeAware);
 337:         try
 338:           {
 339:             SAXParser parser = factory.newSAXParser();
 340:             reader = parser.getXMLReader();
 341:           }
 342:         catch (ParserConfigurationException e)
 343:           {
 344:             throw new DomLSException(LSException.PARSE_ERR, e);
 345:           }
 346:         catch (SAXException e)
 347:           {
 348:             throw new DomLSException(LSException.PARSE_ERR, e);
 349:           }
 350:       }
 351:     return reader;
 352:   }
 353: 
 354:   private InputSource getInputSource(LSInput input)
 355:     throws LSException
 356:   {
 357:     InputSource source = null;
 358:     String systemId = input.getSystemId();
 359:     InputStream in = input.getByteStream();
 360:     if (in != null)
 361:       {
 362:         source = new InputSource(in);
 363:         source.setSystemId(systemId);
 364:       }
 365:     if (source == null && entityResolver != null)
 366:       {
 367:         String publicId = input.getPublicId();
 368:         try
 369:           {
 370:             source = entityResolver.resolveEntity(publicId, systemId);
 371:           }
 372:         catch (SAXException e)
 373:           {
 374:             throw new DomLSException(LSException.PARSE_ERR, e);
 375:           } 
 376:         catch (IOException e)
 377:           {
 378:             throw new DomLSException(LSException.PARSE_ERR, e);
 379:           } 
 380:       }
 381:     if (source == null)
 382:       {
 383:         URL url = null;
 384:         String base = input.getBaseURI();
 385:         try
 386:           {
 387:             try
 388:               {
 389:                 URL baseURL = (base == null) ? null : new URL(base);
 390:                 url = (baseURL == null) ? new URL(systemId) :
 391:                   new URL(baseURL, systemId);
 392:               }
 393:             catch (MalformedURLException e)
 394:               {
 395:                 File baseFile = (base == null) ? null : new File(base);
 396:                 url = (baseFile == null) ? new File(systemId).toURL() :
 397:                   new File(baseFile, systemId).toURL();
 398:               }
 399:             in = url.openStream();
 400:             systemId = url.toString();
 401:             source = new InputSource(in);
 402:             source.setSystemId(systemId);
 403:           }
 404:         catch (IOException e)
 405:           {
 406:             throw new DomLSException(LSException.PARSE_ERR, e);
 407:           }
 408:       }
 409:     return source;
 410:   }
 411: 
 412:   // -- DOMConfiguration --
 413: 
 414:   public void setParameter(String name, Object value)
 415:     throws DOMException
 416:   {
 417:     name = name.toLowerCase();
 418:     if ("cdata-sections".equals(name))
 419:       {
 420:         coalescing = !((Boolean) value).booleanValue();
 421:       }
 422:     else if ("comments".equals(name))
 423:       {
 424:         ignoreComments = !((Boolean) value).booleanValue();
 425:       }
 426:     else if ("element-content-whitespace".equals(name))
 427:       {
 428:         ignoreWhitespace = !((Boolean) value).booleanValue();
 429:       }
 430:     else if ("namespaces".equals(name))
 431:       {
 432:         namespaceAware = ((Boolean) value).booleanValue();
 433:       }
 434:     else if ("expand-entity-references".equals(name))
 435:       {
 436:         expandEntityReferences = ((Boolean) value).booleanValue();
 437:       }
 438:     else if ("coalescing".equals(name))
 439:       {
 440:         coalescing = ((Boolean) value).booleanValue();
 441:       }
 442:     else if ("validating".equals(name))
 443:       {
 444:         validating = ((Boolean) value).booleanValue();
 445:       }
 446:     else if ("xinclude-aware".equals(name))
 447:       {
 448:         xIncludeAware = ((Boolean) value).booleanValue();
 449:       }
 450:     else if ("entity-resolver".equals(name))
 451:       {
 452:         entityResolver = (EntityResolver) value;
 453:       }
 454:     else if ("error-handler".equals(name))
 455:       {
 456:         errorHandler = (ErrorHandler) value;
 457:       }
 458:     else
 459:       {
 460:         throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR);
 461:       }
 462:     // invalidate reader, a new one will be created
 463:     reader = null;
 464:   }
 465: 
 466:   public Object getParameter(String name)
 467:     throws DOMException
 468:   {
 469:     name = name.toLowerCase();
 470:     if ("cdata-sections".equals(name))
 471:       {
 472:         return coalescing ? Boolean.FALSE : Boolean.TRUE;
 473:       }
 474:     else if ("comments".equals(name))
 475:       {
 476:         return ignoreComments ? Boolean.FALSE : Boolean.TRUE;
 477:       }
 478:     else if ("element-content-whitespace".equals(name))
 479:       {
 480:         return ignoreWhitespace ? Boolean.FALSE : Boolean.TRUE;
 481:       }
 482:     else if ("namespaces".equals(name))
 483:       {
 484:         return namespaceAware ? Boolean.TRUE : Boolean.FALSE;
 485:       }
 486:     else if ("expand-entity-references".equals(name))
 487:       {
 488:         return expandEntityReferences ? Boolean.TRUE : Boolean.FALSE;
 489:       }
 490:     else if ("coalescing".equals(name))
 491:       {
 492:         return coalescing ? Boolean.TRUE : Boolean.FALSE;
 493:       }
 494:     else if ("validating".equals(name))
 495:       {
 496:         return validating ? Boolean.TRUE : Boolean.FALSE;
 497:       }
 498:     else if ("xinclude-aware".equals(name))
 499:       {
 500:         return xIncludeAware ? Boolean.TRUE : Boolean.FALSE;
 501:       }
 502:     else if ("entity-resolver".equals(name))
 503:       {
 504:         return entityResolver;
 505:       }
 506:     else if ("error-handler".equals(name))
 507:       {
 508:         return errorHandler;
 509:       }
 510:     else
 511:       {
 512:         throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR);
 513:       }
 514:   }
 515: 
 516:   public boolean canSetParameter(String name, Object value)
 517:   {
 518:     return contains(name);
 519:   }
 520: 
 521:   public DOMStringList getParameterNames()
 522:   {
 523:     return this;
 524:   }
 525: 
 526:   // -- DOMStringList --
 527: 
 528:   public String item(int i)
 529:   {
 530:     return (String) SUPPORTED_PARAMETERS.get(i);
 531:   }
 532: 
 533:   public int getLength()
 534:   {
 535:     return SUPPORTED_PARAMETERS.size();
 536:   }
 537: 
 538:   public boolean contains(String str)
 539:   {
 540:     return SUPPORTED_PARAMETERS.contains(str);
 541:   }
 542: 
 543:   // -- ErrorHandler --
 544: 
 545:   public void warning(SAXParseException e)
 546:     throws SAXException
 547:   {
 548:     if (errorHandler != null)
 549:       {
 550:         errorHandler.warning(e);
 551:       }
 552:   }
 553: 
 554:   public void error(SAXParseException e)
 555:     throws SAXException
 556:   {
 557:     if (errorHandler != null)
 558:       {
 559:         errorHandler.error(e);
 560:       }
 561:   }
 562: 
 563:   public void fatalError(SAXParseException e)
 564:     throws SAXException
 565:   {
 566:     if (errorHandler != null)
 567:       {
 568:         errorHandler.fatalError(e);
 569:       }
 570:     abort();
 571:   }
 572:   
 573: }