Source for gnu.xml.dom.ls.DomLSParser

   1: /* DomLSParser.java --
   2:    Copyright (C) 1999,2000,2001,2007 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.setNamespaceAware(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:     eventSink.reader = reader;
 264:     try
 265:       {
 266:         reader.setContentHandler(eventSink);
 267:         reader.setDTDHandler(eventSink);
 268:         reader.setProperty("http://xml.org/sax/properties/lexical-handler",
 269:                            eventSink);
 270:         reader.setProperty("http://xml.org/sax/properties/declaration-handler",
 271:                            eventSink);
 272:         reader.setFeature("http://xml.org/sax/features/namespaces",
 273:                           namespaceAware);
 274:         reader.setFeature("http://xml.org/sax/features/namespace-prefixes",
 275:                           true);
 276:         reader.setFeature("http://xml.org/sax/features/validation",
 277:                           validating);
 278:         try
 279:           {
 280:             reader.setFeature("http://gnu.org/sax/features/coalescing",
 281:                               coalescing);
 282:           }
 283:         catch (SAXNotRecognizedException e)
 284:           {
 285:             // ignore
 286:           }
 287:         try
 288:           {
 289:             reader.setFeature("http://xml.org/sax/features/use-attributes2",
 290:                               true);
 291:           }
 292:         catch (SAXNotRecognizedException e)
 293:           {
 294:             // ignore
 295:           }
 296:         try
 297:           {
 298:             reader.setFeature("http://xml.org/sax/features/external-general-entities",
 299:                               true);
 300:           }
 301:         catch (SAXNotRecognizedException e)
 302:           {
 303:             // ignore
 304:           }
 305:         reader.setEntityResolver(entityResolver);
 306:         reader.setErrorHandler(errorHandler);
 307:         // parse
 308:         reader.parse(source);
 309:       }
 310:     catch (DOMException e)
 311:       {
 312:         reader = null;
 313:         eventSink = null;
 314:         throw e;
 315:       }
 316:     catch (SAXException e)
 317:       {
 318:         reader = null;
 319:         eventSink = null;
 320:         throw new DomLSException(LSException.PARSE_ERR, e);
 321:       }
 322:     catch (IOException e)
 323:       {
 324:         reader = null;
 325:         eventSink = null;
 326:         throw new DomLSException(LSException.PARSE_ERR, e);
 327:       }
 328:     // return document
 329:     Document ret = eventSink.doc;
 330:     String systemId = input.getSystemId();
 331:     if (systemId != null && ret instanceof DomDocument)
 332:       {
 333:         ((DomDocument) ret).setDocumentURI(systemId);
 334:       }
 335:     eventSink = null;
 336:     return ret;
 337:   }
 338: 
 339:   private XMLReader getXMLReader()
 340:     throws LSException
 341:   {
 342:     if (reader == null)
 343:       {
 344:         factory.setNamespaceAware(namespaceAware);
 345:         factory.setValidating(validating);
 346:         factory.setXIncludeAware(xIncludeAware);
 347:         try
 348:           {
 349:             SAXParser parser = factory.newSAXParser();
 350:             reader = parser.getXMLReader();
 351:           }
 352:         catch (ParserConfigurationException e)
 353:           {
 354:             throw new DomLSException(LSException.PARSE_ERR, e);
 355:           }
 356:         catch (SAXException e)
 357:           {
 358:             throw new DomLSException(LSException.PARSE_ERR, e);
 359:           }
 360:       }
 361:     return reader;
 362:   }
 363: 
 364:   private InputSource getInputSource(LSInput input)
 365:     throws LSException
 366:   {
 367:     InputSource source = null;
 368:     String systemId = input.getSystemId();
 369:     InputStream in = input.getByteStream();
 370:     if (in != null)
 371:       {
 372:         source = new InputSource(in);
 373:         source.setSystemId(systemId);
 374:       }
 375:     if (source == null)
 376:       {
 377:         URL url = null;
 378:         String base = input.getBaseURI();
 379:         try
 380:           {
 381:             try
 382:               {
 383:                 URL baseURL = (base == null) ? null : new URL(base);
 384:                 url = (baseURL == null) ? new URL(systemId) :
 385:                   new URL(baseURL, systemId);
 386:               }
 387:             catch (MalformedURLException e)
 388:               {
 389:                 File baseFile = (base == null) ? null : new File(base);
 390:                 url = (baseFile == null) ? new File(systemId).toURL() :
 391:                   new File(baseFile, systemId).toURL();
 392:               }
 393:             in = url.openStream();
 394:             systemId = url.toString();
 395:             source = new InputSource(in);
 396:             source.setSystemId(systemId);
 397:           }
 398:         catch (IOException e)
 399:           {
 400:             throw new DomLSException(LSException.PARSE_ERR, e);
 401:           }
 402:       }
 403:     return source;
 404:   }
 405: 
 406:   // -- DOMConfiguration --
 407: 
 408:   public void setParameter(String name, Object value)
 409:     throws DOMException
 410:   {
 411:     name = name.toLowerCase();
 412:     if ("cdata-sections".equals(name))
 413:       {
 414:         coalescing = !((Boolean) value).booleanValue();
 415:       }
 416:     else if ("comments".equals(name))
 417:       {
 418:         ignoreComments = !((Boolean) value).booleanValue();
 419:       }
 420:     else if ("element-content-whitespace".equals(name))
 421:       {
 422:         ignoreWhitespace = !((Boolean) value).booleanValue();
 423:       }
 424:     else if ("namespaces".equals(name))
 425:       {
 426:         namespaceAware = ((Boolean) value).booleanValue();
 427:       }
 428:     else if ("expand-entity-references".equals(name))
 429:       {
 430:         expandEntityReferences = ((Boolean) value).booleanValue();
 431:       }
 432:     else if ("coalescing".equals(name))
 433:       {
 434:         coalescing = ((Boolean) value).booleanValue();
 435:       }
 436:     else if ("validating".equals(name))
 437:       {
 438:         validating = ((Boolean) value).booleanValue();
 439:       }
 440:     else if ("xinclude-aware".equals(name))
 441:       {
 442:         xIncludeAware = ((Boolean) value).booleanValue();
 443:       }
 444:     else if ("entity-resolver".equals(name))
 445:       {
 446:         entityResolver = (EntityResolver) value;
 447:       }
 448:     else if ("error-handler".equals(name))
 449:       {
 450:         errorHandler = (ErrorHandler) value;
 451:       }
 452:     else
 453:       {
 454:         throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR);
 455:       }
 456:     // invalidate reader, a new one will be created
 457:     reader = null;
 458:   }
 459: 
 460:   public Object getParameter(String name)
 461:     throws DOMException
 462:   {
 463:     name = name.toLowerCase();
 464:     if ("cdata-sections".equals(name))
 465:       {
 466:         return coalescing ? Boolean.FALSE : Boolean.TRUE;
 467:       }
 468:     else if ("comments".equals(name))
 469:       {
 470:         return ignoreComments ? Boolean.FALSE : Boolean.TRUE;
 471:       }
 472:     else if ("element-content-whitespace".equals(name))
 473:       {
 474:         return ignoreWhitespace ? Boolean.FALSE : Boolean.TRUE;
 475:       }
 476:     else if ("namespaces".equals(name))
 477:       {
 478:         return namespaceAware ? Boolean.TRUE : Boolean.FALSE;
 479:       }
 480:     else if ("expand-entity-references".equals(name))
 481:       {
 482:         return expandEntityReferences ? Boolean.TRUE : Boolean.FALSE;
 483:       }
 484:     else if ("coalescing".equals(name))
 485:       {
 486:         return coalescing ? Boolean.TRUE : Boolean.FALSE;
 487:       }
 488:     else if ("validating".equals(name))
 489:       {
 490:         return validating ? Boolean.TRUE : Boolean.FALSE;
 491:       }
 492:     else if ("xinclude-aware".equals(name))
 493:       {
 494:         return xIncludeAware ? Boolean.TRUE : Boolean.FALSE;
 495:       }
 496:     else if ("entity-resolver".equals(name))
 497:       {
 498:         return entityResolver;
 499:       }
 500:     else if ("error-handler".equals(name))
 501:       {
 502:         return errorHandler;
 503:       }
 504:     else
 505:       {
 506:         throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR);
 507:       }
 508:   }
 509: 
 510:   public boolean canSetParameter(String name, Object value)
 511:   {
 512:     return contains(name);
 513:   }
 514: 
 515:   public DOMStringList getParameterNames()
 516:   {
 517:     return this;
 518:   }
 519: 
 520:   // -- DOMStringList --
 521: 
 522:   public String item(int i)
 523:   {
 524:     return (String) SUPPORTED_PARAMETERS.get(i);
 525:   }
 526: 
 527:   public int getLength()
 528:   {
 529:     return SUPPORTED_PARAMETERS.size();
 530:   }
 531: 
 532:   public boolean contains(String str)
 533:   {
 534:     return SUPPORTED_PARAMETERS.contains(str);
 535:   }
 536: 
 537:   // -- ErrorHandler --
 538: 
 539:   public void warning(SAXParseException e)
 540:     throws SAXException
 541:   {
 542:     if (errorHandler != null)
 543:       {
 544:         errorHandler.warning(e);
 545:       }
 546:   }
 547: 
 548:   public void error(SAXParseException e)
 549:     throws SAXException
 550:   {
 551:     if (errorHandler != null)
 552:       {
 553:         errorHandler.error(e);
 554:       }
 555:   }
 556: 
 557:   public void fatalError(SAXParseException e)
 558:     throws SAXException
 559:   {
 560:     if (errorHandler != null)
 561:       {
 562:         errorHandler.fatalError(e);
 563:       }
 564:     abort();
 565:   }
 566: 
 567: }