Source for gnu.xml.stream.XMLStreamReaderImpl

   1: /* XMLStreamReaderImpl.java -- 
   2:    Copyright (C) 2005  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.stream;
  39: 
  40: import java.io.InputStream;
  41: import java.io.IOException;
  42: import java.io.Reader;
  43: import java.util.Enumeration;
  44: import java.util.HashMap;
  45: import java.util.Iterator;
  46: import java.util.LinkedList;
  47: import java.util.Map;
  48: import javax.xml.namespace.NamespaceContext;
  49: import javax.xml.namespace.QName;
  50: import javax.xml.parsers.ParserConfigurationException;
  51: import javax.xml.parsers.SAXParser;
  52: import javax.xml.parsers.SAXParserFactory;
  53: import javax.xml.stream.Location;
  54: import javax.xml.stream.XMLResolver;
  55: import javax.xml.stream.XMLReporter;
  56: import javax.xml.stream.XMLStreamConstants;
  57: import javax.xml.stream.XMLStreamException;
  58: import javax.xml.stream.XMLStreamReader;
  59: 
  60: import javax.xml.stream.events.Attribute;
  61: import javax.xml.stream.events.Characters;
  62: import javax.xml.stream.events.Comment;
  63: import javax.xml.stream.events.DTD;
  64: import javax.xml.stream.events.EndDocument;
  65: import javax.xml.stream.events.EndElement;
  66: import javax.xml.stream.events.EndEntity;
  67: import javax.xml.stream.events.EntityDeclaration;
  68: import javax.xml.stream.events.EntityReference;
  69: import javax.xml.stream.events.Namespace;
  70: import javax.xml.stream.events.NotationDeclaration;
  71: import javax.xml.stream.events.ProcessingInstruction;
  72: import javax.xml.stream.events.StartDocument;
  73: import javax.xml.stream.events.StartElement;
  74: import javax.xml.stream.events.StartEntity;
  75: import javax.xml.stream.events.XMLEvent;
  76: 
  77: import org.xml.sax.Attributes;
  78: import org.xml.sax.ContentHandler;
  79: import org.xml.sax.DTDHandler;
  80: import org.xml.sax.EntityResolver;
  81: import org.xml.sax.ErrorHandler;
  82: import org.xml.sax.InputSource;
  83: import org.xml.sax.Locator;
  84: import org.xml.sax.SAXException;
  85: import org.xml.sax.SAXParseException;
  86: import org.xml.sax.XMLReader;
  87: import org.xml.sax.ext.Attributes2;
  88: import org.xml.sax.ext.DeclHandler;
  89: import org.xml.sax.ext.LexicalHandler;
  90: import org.xml.sax.ext.Locator2;
  91: import org.xml.sax.helpers.NamespaceSupport;
  92: 
  93: /**
  94:  * An XML parser.
  95:  *
  96:  * This implementation uses SAX to create a series of events in memory,
  97:  * and then iterates over this series. This has the advantage of being simple
  98:  * and unifying the existing XML parsing code. However, it is quite
  99:  * memory-inefficient and obviously won't cope with streams of arbitrary
 100:  * length.
 101:  *
 102:  * A future task could be to write a real, progressive/incremental
 103:  * implementation of this class. In that case we should consider making that
 104:  * the default XML parser implementation and using a SAX wrapper to it to
 105:  * provide the GNU SAX implementation.
 106:  *
 107:  * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
 108:  */
 109: public class XMLStreamReaderImpl
 110:   implements XMLStreamReader, NamespaceContext
 111: {
 112: 
 113:   private LinkedList events;
 114:   private XMLEvent currentEvent;
 115:   private int eventType;
 116:   private NamespaceSupport namespaces;
 117: 
 118:   protected String publicId;
 119:   protected String systemId;
 120: 
 121:   protected XMLResolver resolver;
 122:   protected XMLReporter reporter;
 123:   protected boolean validating;
 124:   protected boolean namespaceAware;
 125:   protected boolean coalescing;
 126:   protected boolean replacingEntityReferences;
 127:   protected boolean externalEntities;
 128:   protected boolean supportDTD;
 129: 
 130:   protected XMLStreamReaderImpl(InputStream in,
 131:                                 String publicId,
 132:                                 String systemId,
 133:                                 XMLResolver resolver,
 134:                                 XMLReporter reporter,
 135:                                 boolean validating,
 136:                                 boolean namespaceAware,
 137:                                 boolean coalescing,
 138:                                 boolean replacingEntityReferences,
 139:                                 boolean externalEntities,
 140:                                 boolean supportDTD)
 141:     throws XMLStreamException
 142:   {
 143:     //this.in = in;
 144:     this.publicId = publicId;
 145:     this.systemId = systemId;
 146:     this.resolver = resolver;
 147:     this.reporter = reporter;
 148:     this.validating = validating;
 149:     this.namespaceAware = namespaceAware;
 150:     this.coalescing = coalescing;
 151:     this.replacingEntityReferences = replacingEntityReferences;
 152:     this.externalEntities = externalEntities;
 153:     this.supportDTD = supportDTD;
 154:     namespaces = new NamespaceSupport();
 155:     events = new LinkedList();
 156:     
 157:     // Configure the SAX parser and perform the parse
 158:     try
 159:       {
 160:         SAXParserFactory f = SAXParserFactory.newInstance();
 161:         f.setNamespaceAware(namespaceAware);
 162:         f.setValidating(validating);
 163:         SAXParser p = f.newSAXParser();
 164:         XMLReader r = p.getXMLReader();
 165:         CallbackHandler ch = this.new CallbackHandler(r);
 166:         r.setFeature("http://xml.org/sax/features/external-general-entities", 
 167:                      externalEntities);
 168:         r.setFeature("http://xml.org/sax/features/namespaces", 
 169:                      namespaceAware);
 170:         r.setContentHandler(ch);
 171:         r.setDTDHandler(ch);
 172:         r.setEntityResolver(ch);
 173:         r.setErrorHandler(ch);
 174:         r.setProperty("http://xml.org/sax/properties/lexical-handler",
 175:                       ch);
 176:         InputSource source = new InputSource(in);
 177:         source.setSystemId(systemId);
 178:         r.parse(source);
 179:       }
 180:     catch (SAXException e)
 181:       {
 182:         events.add(e);
 183:       }
 184:     catch (IOException e)
 185:       {
 186:         events.add(e);
 187:       }
 188:     catch (ParserConfigurationException e)
 189:       {
 190:         XMLStreamException e2 = new XMLStreamException(e);
 191:         e2.initCause(e);
 192:         throw e2;
 193:       }
 194:   }
 195: 
 196:   protected XMLStreamReaderImpl(Reader reader,
 197:                                 String publicId,
 198:                                 String systemId,
 199:                                 XMLResolver resolver,
 200:                                 XMLReporter reporter,
 201:                                 boolean validating,
 202:                                 boolean namespaceAware,
 203:                                 boolean coalescing,
 204:                                 boolean replacingEntityReferences,
 205:                                 boolean externalEntities,
 206:                                 boolean supportDTD)
 207:     throws XMLStreamException
 208:   {
 209:     //this.reader = reader;
 210:     this.publicId = publicId;
 211:     this.systemId = systemId;
 212:     this.resolver = resolver;
 213:     this.reporter = reporter;
 214:     this.validating = validating;
 215:     this.namespaceAware = namespaceAware;
 216:     this.coalescing = coalescing;
 217:     this.replacingEntityReferences = replacingEntityReferences;
 218:     this.externalEntities = externalEntities;
 219:     this.supportDTD = supportDTD;
 220:     namespaces = new NamespaceSupport();
 221:     events = new LinkedList();
 222:     
 223:     // Configure the SAX parser and perform the parse
 224:     try
 225:       {
 226:         SAXParserFactory f = SAXParserFactory.newInstance();
 227:         f.setNamespaceAware(namespaceAware);
 228:         f.setValidating(validating);
 229:         SAXParser p = f.newSAXParser();
 230:         XMLReader r = p.getXMLReader();
 231:         CallbackHandler ch = this.new CallbackHandler(r);
 232:         r.setFeature("http://xml.org/sax/features/external-general-entities", 
 233:                      externalEntities);
 234:         r.setFeature("http://xml.org/sax/features/namespaces", 
 235:                      namespaceAware);
 236:         r.setContentHandler(ch);
 237:         r.setDTDHandler(ch);
 238:         r.setEntityResolver(ch);
 239:         r.setErrorHandler(ch);
 240:         r.setProperty("http://xml.org/sax/properties/lexical-handler",
 241:                       ch);
 242:         InputSource source = new InputSource(reader);
 243:         source.setSystemId(systemId);
 244:         r.parse(source);
 245:       }
 246:     catch (SAXException e)
 247:       {
 248:         events.add(e);
 249:       }
 250:     catch (IOException e)
 251:       {
 252:         events.add(e);
 253:       }
 254:     catch (ParserConfigurationException e)
 255:       {
 256:         XMLStreamException e2 = new XMLStreamException(e);
 257:         e2.initCause(e);
 258:         throw e2;
 259:       }
 260:   }
 261: 
 262:   public Object getProperty(String name)
 263:     throws IllegalArgumentException
 264:   {
 265:     throw new IllegalArgumentException(name);
 266:   }
 267: 
 268:   public int next()
 269:     throws XMLStreamException
 270:   {
 271:     if (events.isEmpty())
 272:       throw new XMLStreamException("EOF");
 273:     Object event = events.removeFirst();
 274:     if (event instanceof Exception)
 275:       {
 276:         Exception e = (Exception) event;
 277:         XMLStreamException e2 = new XMLStreamException(e);
 278:         e2.initCause(e);
 279:         throw e2;
 280:       }
 281:     currentEvent = (XMLEvent) event;
 282:     eventType = currentEvent.getEventType();
 283:     return eventType;
 284:   }
 285: 
 286:   public void require(int type, String namespaceURI, String localName)
 287:     throws XMLStreamException
 288:   {
 289:     // TODO
 290:     throw new UnsupportedOperationException();
 291:   }
 292: 
 293:   public String getElementText()
 294:     throws XMLStreamException
 295:   {
 296:     // TODO
 297:     throw new UnsupportedOperationException();
 298:   }
 299: 
 300:   public int nextTag()
 301:     throws XMLStreamException
 302:   {
 303:     int ret;
 304:     do
 305:       {
 306:         ret = next();
 307:       }
 308:     while (ret != XMLStreamConstants.START_ELEMENT &&
 309:            ret != XMLStreamConstants.END_ELEMENT);
 310:     return ret;
 311:   }
 312: 
 313:   public boolean hasNext()
 314:     throws XMLStreamException
 315:   {
 316:     return !events.isEmpty();
 317:   }
 318: 
 319:   public void close()
 320:     throws XMLStreamException
 321:   {
 322:   }
 323: 
 324:   public String getNamespaceURI(String prefix)
 325:   {
 326:     return namespaces.getURI(prefix);
 327:   }
 328: 
 329:   public String getPrefix(String namespaceURI)
 330:   {
 331:     return namespaces.getPrefix(namespaceURI);
 332:   }
 333: 
 334:   public Iterator getPrefixes(String namespaceURI)
 335:   {
 336:     LinkedList acc = new LinkedList();
 337:     for (Enumeration e = namespaces.getPrefixes(namespaceURI);
 338:          e.hasMoreElements(); )
 339:       acc.add(e.nextElement());
 340:     return acc.iterator();
 341:   }
 342: 
 343:   public boolean isStartElement()
 344:   {
 345:     return eventType == START_ELEMENT;
 346:   }
 347: 
 348:   public boolean isEndElement()
 349:   {
 350:     return eventType == END_ELEMENT;
 351:   }
 352: 
 353:   public boolean isCharacters()
 354:   {
 355:     return eventType == CHARACTERS || eventType == CDATA;
 356:   }
 357: 
 358:   public boolean isWhiteSpace()
 359:   {
 360:     return eventType == SPACE;
 361:   }
 362: 
 363:   public String getAttributeValue(String namespaceURI, String localName)
 364:   {
 365:     StartElement se = (StartElement) currentEvent;
 366:     for (Iterator i = se.getAttributes(); i.hasNext(); )
 367:       {
 368:         Attribute attr = (Attribute) i.next();
 369:         QName name = attr.getName();
 370:         if (namespaceURI != null &&
 371:             !namespaceURI.equals(name.getNamespaceURI()))
 372:           continue;
 373:         if (!localName.equals(name.getLocalPart()))
 374:           continue;
 375:         return attr.getValue();
 376:       }
 377:     return null;
 378:   }
 379: 
 380:   public int getAttributeCount()
 381:   {
 382:     StartElement se = (StartElement) currentEvent;
 383:     int count = 0;
 384:     for (Iterator i = se.getAttributes(); i.hasNext(); )
 385:       {
 386:         i.next();
 387:         count++;
 388:       }
 389:     return count;
 390:   }
 391: 
 392:   public QName getAttributeQName(int index)
 393:   {
 394:     StartElement se = (StartElement) currentEvent;
 395:     int count = 0;
 396:     for (Iterator i = se.getAttributes(); i.hasNext(); )
 397:       {
 398:         Attribute attr = (Attribute) i.next();
 399:         if (index == count)
 400:           return attr.getName();
 401:         count++;
 402:       }
 403:     return null;
 404:   }
 405: 
 406:   public String getAttributeNamespace(int index)
 407:   {
 408:     QName name = getAttributeQName(index);
 409:     return (name == null) ? null : name.getNamespaceURI();
 410:   }
 411: 
 412:   public String getAttributeName(int index)
 413:   {
 414:     QName name = getAttributeQName(index);
 415:     return (name == null) ? null : name.getLocalPart();
 416:   }
 417: 
 418:   public String getAttributePrefix(int index)
 419:   {
 420:     QName name = getAttributeQName(index);
 421:     return (name == null) ? null : name.getPrefix();
 422:   }
 423: 
 424:   public String getAttributeType(int index)
 425:   {
 426:     StartElement se = (StartElement) currentEvent;
 427:     int count = 0;
 428:     for (Iterator i = se.getAttributes(); i.hasNext(); )
 429:       {
 430:         Attribute attr = (Attribute) i.next();
 431:         if (index == count)
 432:           {
 433:             QName type = attr.getDTDType();
 434:             return (type == null) ? "CDATA" : type.toString();
 435:           }
 436:         count++;
 437:       }
 438:     return null;
 439:   }
 440: 
 441:   public String getAttributeValue(int index)
 442:   {
 443:     StartElement se = (StartElement) currentEvent;
 444:     int count = 0;
 445:     for (Iterator i = se.getAttributes(); i.hasNext(); )
 446:       {
 447:         Attribute attr = (Attribute) i.next();
 448:         if (index == count)
 449:           return attr.getValue();
 450:         count++;
 451:       }
 452:     return null;
 453:   }
 454: 
 455:   public boolean isAttributeSpecified(int index)
 456:   {
 457:     StartElement se = (StartElement) currentEvent;
 458:     int count = 0;
 459:     for (Iterator i = se.getAttributes(); i.hasNext(); )
 460:       {
 461:         Attribute attr = (Attribute) i.next();
 462:         if (index == count)
 463:           return attr.isSpecified();
 464:         count++;
 465:       }
 466:     return false;
 467:   }
 468: 
 469:   public int getNamespaceCount()
 470:   {
 471:     Iterator i = null;
 472:     switch (eventType)
 473:       {
 474:       case XMLStreamConstants.START_ELEMENT:
 475:         i = ((StartElement) currentEvent).getNamespaces();
 476:         break;
 477:       case XMLStreamConstants.END_ELEMENT:
 478:         i = ((EndElement) currentEvent).getNamespaces();
 479:         break;
 480:       default:
 481:         throw new IllegalStateException();
 482:       }
 483:     int count = 0;
 484:     while (i.hasNext())
 485:       {
 486:         i.next();
 487:         count++;
 488:       }
 489:     return count;
 490:   }
 491: 
 492:   public String getNamespacePrefix(int index)
 493:   {
 494:     Iterator i = null;
 495:     switch (eventType)
 496:       {
 497:       case XMLStreamConstants.START_ELEMENT:
 498:         i = ((StartElement) currentEvent).getNamespaces();
 499:         break;
 500:       case XMLStreamConstants.END_ELEMENT:
 501:         i = ((EndElement) currentEvent).getNamespaces();
 502:         break;
 503:       default:
 504:         throw new IllegalStateException();
 505:       }
 506:     int count = 0;
 507:     while (i.hasNext())
 508:       {
 509:         Namespace ns = (Namespace) i.next();
 510:         if (index == count)
 511:           return ns.getPrefix();
 512:         count++;
 513:       }
 514:     return null;
 515:   }
 516: 
 517:   public String getNamespaceURI(int index)
 518:   {
 519:     Iterator i = null;
 520:     switch (eventType)
 521:       {
 522:       case XMLStreamConstants.START_ELEMENT:
 523:         i = ((StartElement) currentEvent).getNamespaces();
 524:         break;
 525:       case XMLStreamConstants.END_ELEMENT:
 526:         i = ((EndElement) currentEvent).getNamespaces();
 527:         break;
 528:       default:
 529:         throw new IllegalStateException();
 530:       }
 531:     int count = 0;
 532:     while (i.hasNext())
 533:       {
 534:         Namespace ns = (Namespace) i.next();
 535:         if (index == count)
 536:           return ns.getNamespaceURI();
 537:         count++;
 538:       }
 539:     return null;
 540:   }
 541: 
 542:   public NamespaceContext getNamespaceContext()
 543:   {
 544:     return this;
 545:   }
 546: 
 547:   public int getEventType()
 548:   {
 549:     return eventType;
 550:   }
 551: 
 552:   public String getText()
 553:   {
 554:     switch (eventType)
 555:       {
 556:       case XMLStreamConstants.CHARACTERS:
 557:       case XMLStreamConstants.CDATA:
 558:       case XMLStreamConstants.SPACE:
 559:         return ((Characters) currentEvent).getData();
 560:       case XMLStreamConstants.COMMENT:
 561:         return ((Comment) currentEvent).getText();
 562:       case XMLStreamConstants.ENTITY_REFERENCE:
 563:         return ((EntityReference) currentEvent).getReplacementText();
 564:       case XMLStreamConstants.DTD:
 565:         return ((DTD) currentEvent).getDocumentTypeDeclaration();
 566:       }
 567:     return null;
 568:   }
 569: 
 570:   public char[] getTextCharacters()
 571:   {
 572:     String text = getText();
 573:     return (text == null) ? null : text.toCharArray();
 574:   }
 575: 
 576:   public int getTextCharacters(int sourceStart, char[] target,
 577:                                int targetStart, int length)
 578:     throws XMLStreamException
 579:   {
 580:     char[] source = getTextCharacters();
 581:     int len = Math.min(source.length, length);
 582:     System.arraycopy(source, sourceStart, target, targetStart, len);
 583:     return len;
 584:   }
 585: 
 586:   public int getTextStart()
 587:   {
 588:     return 0;
 589:   }
 590: 
 591:   public int getTextLength()
 592:   {
 593:     String text = getText();
 594:     return (text == null) ? 0 : text.length();
 595:   }
 596: 
 597:   public String getEncoding()
 598:   {
 599:     // XXX SAX doesn't provide this
 600:     return null;
 601:   }
 602: 
 603:   public boolean hasText()
 604:   {
 605:     return eventType == CHARACTERS || eventType == DTD ||
 606:       eventType == SPACE || eventType == ENTITY_REFERENCE ||
 607:       eventType == COMMENT || eventType == DTD;
 608:   }
 609: 
 610:   public Location getLocation()
 611:   {
 612:     return currentEvent.getLocation();
 613:   }
 614: 
 615:   public QName getName()
 616:   {
 617:     switch (eventType)
 618:       {
 619:       case XMLStreamConstants.START_ELEMENT:
 620:         return ((StartElement) currentEvent).getName();
 621:       case XMLStreamConstants.END_ELEMENT:
 622:         return ((EndElement) currentEvent).getName();
 623:       case XMLStreamConstants.ATTRIBUTE:
 624:         return ((Attribute) currentEvent).getName();
 625:       }
 626:     return null;
 627:   }
 628: 
 629:   public String getLocalName()
 630:   {
 631:     QName name = getName();
 632:     return (name == null) ? null : name.getLocalPart();
 633:   }
 634: 
 635:   public boolean hasName()
 636:   {
 637:     return getName() != null;
 638:   }
 639: 
 640:   public String getNamespaceURI()
 641:   {
 642:     QName name = getName();
 643:     return (name == null) ? null : name.getNamespaceURI();
 644:   }
 645: 
 646:   public String getPrefix()
 647:   {
 648:     QName name = getName();
 649:     return (name == null) ? null : name.getPrefix();
 650:   }
 651:   
 652:   public String getVersion()
 653:   {
 654:     StartDocument sd = (StartDocument) currentEvent;
 655:     return sd.getVersion();
 656:   }
 657: 
 658:   public boolean isStandalone()
 659:   {
 660:     StartDocument sd = (StartDocument) currentEvent;
 661:     return sd.isStandalone();
 662:   }
 663: 
 664:   public boolean standaloneSet()
 665:   {
 666:     StartDocument sd = (StartDocument) currentEvent;
 667:     return sd.standaloneSet();
 668:   }
 669:   
 670:   public String getCharacterEncodingScheme()
 671:   {
 672:     StartDocument sd = (StartDocument) currentEvent;
 673:     return sd.getCharacterEncodingScheme();
 674:   }
 675: 
 676:   public String getPITarget()
 677:   {
 678:     ProcessingInstruction pi = (ProcessingInstruction) currentEvent;
 679:     return pi.getTarget();
 680:   }
 681: 
 682:   public String getPIData()
 683:   {
 684:     ProcessingInstruction pi = (ProcessingInstruction) currentEvent;
 685:     return pi.getData();
 686:   }
 687: 
 688:   /**
 689:    * This class is used to construct the event series from SAX callbacks.
 690:    */
 691:   class CallbackHandler
 692:     implements ContentHandler, DTDHandler, LexicalHandler,
 693:                DeclHandler, EntityResolver, ErrorHandler
 694:   {
 695: 
 696:     XMLReader reader;
 697:     Locator locator;
 698:     Location location;
 699:     private boolean inCDATA;
 700:     private LinkedList namespaces = new LinkedList();
 701:     private LinkedList notations;
 702:     private LinkedList entities;
 703: 
 704:     CallbackHandler(XMLReader reader)
 705:     {
 706:       this.reader = reader;
 707:     }
 708: 
 709:     public void setDocumentLocator(Locator locator)
 710:     {
 711:       this.locator = locator;
 712:       location = new LocationImpl(-1,
 713:                                   locator.getColumnNumber(),
 714:                                   locator.getLineNumber(),
 715:                                   locator.getSystemId());
 716:     }
 717: 
 718:     public void startDocument()
 719:       throws SAXException
 720:     {
 721:       String version = (locator instanceof Locator2) ?
 722:         ((Locator2) locator).getXMLVersion() : null;
 723:       String encoding = (locator instanceof Locator2) ? 
 724:         ((Locator2) locator).getEncoding() : null;
 725:       boolean standalone =
 726:         reader.getFeature("http://xml.org/sax/features/is-standalone");
 727:       boolean standaloneDeclared = standalone;
 728:       boolean encodingDeclared = (encoding != null);
 729:       events.add(new StartDocumentImpl(location,
 730:                                        location.getLocationURI(),
 731:                                        encoding,
 732:                                        version,
 733:                                        standalone,
 734:                                        standaloneDeclared,
 735:                                        encodingDeclared));
 736:     }
 737: 
 738:     public void endDocument()
 739:       throws SAXException
 740:     {
 741:       events.add(new EndDocumentImpl(location));
 742:     }
 743:     
 744:     public void startPrefixMapping(String prefix, String uri)
 745:       throws SAXException
 746:     {
 747:       namespaces.add(new NamespaceImpl(location, prefix, uri));
 748:     }
 749: 
 750:     public void endPrefixMapping(String prefix)
 751:       throws SAXException
 752:     {
 753:     }
 754: 
 755:     public void startElement(String namespaceURI, String localName,
 756:                              String qName, Attributes atts)
 757:       throws SAXException
 758:     {
 759:       LinkedList ns = namespaces;
 760:       namespaces = new LinkedList();
 761:       int ci = qName.indexOf(':');
 762:       String prefix = null;
 763:       localName = qName;
 764:       if (ci != -1)
 765:         {
 766:           prefix = qName.substring(0, ci);
 767:           localName = qName.substring(ci + 1);
 768:         }
 769:       QName name = new QName(namespaceURI, localName, prefix);
 770:       LinkedList attrs = new LinkedList();
 771:       StartElementImpl se = new StartElementImpl(location, name,
 772:                                                  attrs, ns, null);
 773:       events.add(se);
 774:       // Add namespaces
 775:       //for (Iterator i = ns.iterator(); i.hasNext(); )
 776:       //  events.add(i.next());
 777:       // Add attributes
 778:       int len = atts.getLength();
 779:       for (int i = 0; i < len; i++)
 780:         {
 781:           String attURI = atts.getURI(i);
 782:           String attQName = atts.getQName(i);
 783:           String value = atts.getValue(i);
 784:           QName type = QName.valueOf(atts.getType(i));
 785:           boolean specified = (atts instanceof Attributes2) &&
 786:             ((Attributes2) atts).isSpecified(i);
 787:           ci = attQName.indexOf(':');
 788:           String attPrefix = null;
 789:           String attLocalName = attQName;
 790:           if (ci != -1)
 791:             {
 792:               attPrefix = attQName.substring(0, ci);
 793:               attLocalName = attQName.substring(ci + 1);
 794:             }
 795:           if ("xmlns".equals(attPrefix) || "xmlns".equals(attQName))
 796:             continue;
 797:           QName attrName = new QName(attURI, attLocalName, attPrefix);
 798:           AttributeImpl attr = new AttributeImpl(location, attrName,
 799:                                                  value, type, specified);
 800:           attrs.add(attr);
 801:           //events.add(attr);
 802:         }
 803:     }
 804: 
 805:     public void endElement(String namespaceURI, String localName,
 806:                            String qName)
 807:       throws SAXException
 808:     {
 809:       int ci = qName.indexOf(':');
 810:       String prefix = null;
 811:       localName = qName;
 812:       if (ci != -1)
 813:         {
 814:           prefix = qName.substring(0, ci);
 815:           localName = qName.substring(ci + 1);
 816:         }
 817:       QName name = new QName(namespaceURI, localName, prefix);
 818:       events.add(new EndElementImpl(location, name, new LinkedList()));
 819:       // TODO namespaces out of scope
 820:     }
 821: 
 822:     public void characters(char[] ch, int start, int length)
 823:       throws SAXException
 824:     {
 825:       boolean whitespace = isWhitespace(ch, start, length);
 826:       events.add(new CharactersImpl(location, new String(ch, start, length),
 827:                                     whitespace, inCDATA, false));
 828:     }
 829:     
 830:     public void ignorableWhitespace(char[] ch, int start, int length)
 831:       throws SAXException
 832:     {
 833:       boolean whitespace = isWhitespace(ch, start, length);
 834:       events.add(new CharactersImpl(location, new String(ch, start, length),
 835:                                     whitespace, inCDATA, true));
 836:     }
 837: 
 838:     boolean isWhitespace(char[] ch, int start, int len)
 839:     {
 840:       int end = start + len;
 841:       for (int i = start; i < end; i++)
 842:         {
 843:           char c = ch[i];
 844:           if (c != ' ' && c != '\t' && c != '\n' && c != '\r')
 845:             return false;
 846:         }
 847:       return true;
 848:     }
 849: 
 850:     public void processingInstruction(String target, String data)
 851:       throws SAXException
 852:     {
 853:       events.add(new ProcessingInstructionImpl(location, target, data));
 854:     }
 855: 
 856:     public void skippedEntity(String name)
 857:       throws SAXException
 858:     {
 859:     }
 860: 
 861:     public void startDTD(String name, String publicId, String systemId)
 862:       throws SAXException
 863:     {
 864:       notations = new LinkedList();
 865:       entities = new LinkedList();
 866:       events.add(new DTDImpl(location, null, null, notations, entities));
 867:     }
 868: 
 869:     public void endDTD()
 870:       throws SAXException
 871:     {
 872:     }
 873: 
 874:     public void startEntity(String name)
 875:       throws SAXException
 876:     {
 877:       events.add(new StartEntityImpl(location, name));
 878:     }
 879: 
 880:     public void endEntity(String name)
 881:       throws SAXException
 882:     {
 883:       events.add(new EndEntityImpl(location, name));
 884:     }
 885: 
 886:     public void startCDATA()
 887:       throws SAXException
 888:     {
 889:       inCDATA = true;
 890:     }
 891: 
 892:     public void endCDATA()
 893:       throws SAXException
 894:     {
 895:       inCDATA = false;
 896:     }
 897: 
 898:     public void comment(char[] ch, int start, int length)
 899:       throws SAXException
 900:     {
 901:       events.add(new CommentImpl(location, new String(ch, start, length)));
 902:     }
 903: 
 904:     public void notationDecl(String name, String publicId, String systemId)
 905:       throws SAXException
 906:     {
 907:       Object n = new NotationDeclarationImpl(location, name, publicId,
 908:                                              systemId);
 909:       notations.add(n);
 910:       //events.add(n);
 911:     }
 912: 
 913:     public void unparsedEntityDecl(String name, String publicId,
 914:                                    String systemId, String notationName)
 915:       throws SAXException
 916:     {
 917:       Object e = new EntityDeclarationImpl(location, publicId, systemId,
 918:                                            name, notationName,
 919:                                            null, null);
 920:       entities.add(e);
 921:       //events.add(e);
 922:     }
 923: 
 924:     public void elementDecl(String name, String model)
 925:       throws SAXException
 926:     {
 927:     }
 928: 
 929:     public void attributeDecl(String eName, String aName, String type,
 930:                               String valueDefault, String value)
 931:       throws SAXException
 932:     {
 933:     }
 934: 
 935:     public void internalEntityDecl(String name, String value)
 936:       throws SAXException
 937:     {
 938:       Object e = new EntityDeclarationImpl(location, null, null,
 939:                                            name, null, value, null);
 940:       entities.add(e);
 941:       //events.add(e);
 942:     }
 943: 
 944:     public void externalEntityDecl(String name, String publicId,
 945:                                    String systemId)
 946:       throws SAXException
 947:     {
 948:       Object e = new EntityDeclarationImpl(location, publicId, systemId,
 949:                                            name, null, null, null);
 950:       entities.add(e);
 951:       //events.add(e);
 952:     }
 953: 
 954:     public void warning(SAXParseException e)
 955:       throws SAXException
 956:     {
 957:       if (reporter != null)
 958:         {
 959:           try
 960:             {
 961:               reporter.report(e.getMessage(), "warning", e, location);
 962:             }
 963:           catch (XMLStreamException e2)
 964:             {
 965:               SAXException e3 = new SAXException(e2.getMessage());
 966:               e3.initCause(e2);
 967:               throw e3;
 968:             }
 969:         }
 970:     }
 971:     
 972:     public void error(SAXParseException e)
 973:       throws SAXException
 974:     {
 975:       if (reporter != null)
 976:         {
 977:           try
 978:             {
 979:               reporter.report(e.getMessage(), "error", e, location);
 980:             }
 981:           catch (XMLStreamException e2)
 982:             {
 983:               SAXException e3 = new SAXException(e2.getMessage());
 984:               e3.initCause(e2);
 985:               throw e3;
 986:             }
 987:         }
 988:     }
 989:     
 990:     public void fatalError(SAXParseException e)
 991:       throws SAXException
 992:     {
 993:       if (reporter != null)
 994:         {
 995:           try
 996:             {
 997:               reporter.report(e.getMessage(), "fatal-error", e, location);
 998:             }
 999:           catch (XMLStreamException e2)
1000:             {
1001:               SAXException e3 = new SAXException(e2.getMessage());
1002:               e3.initCause(e2);
1003:               throw e3;
1004:             }
1005:         }
1006:     }
1007: 
1008:     public InputSource resolveEntity(String publicId, String systemId)
1009:       throws SAXException, IOException
1010:     {
1011:       if (resolver != null)
1012:         {
1013:           try
1014:             {
1015:               InputStream in = resolver.resolve(systemId);
1016:               if (in != null)
1017:                 {
1018:                   InputSource ret = new InputSource(in);
1019:                   ret.setPublicId(publicId);
1020:                   ret.setSystemId(systemId);
1021:                   return ret;
1022:                 }
1023:             }
1024:           catch (XMLStreamException e)
1025:             {
1026:               SAXException e2 = new SAXException(e.getMessage());
1027:               e2.initCause(e);
1028:               throw e2;
1029:             }
1030:         }
1031:       return null;
1032:     }
1033:     
1034:   }
1035:   
1036: }