001/* 002 * Copyright 2001 (C) MetaStuff, Ltd. All Rights Reserved. 003 * 004 * This software is open source. 005 * See the bottom of this file for the licence. 006 * 007 * $Id: SAXReader.java,v 1.39 2001/11/15 23:38:29 jstrachan Exp $ 008 */ 009 010package org.dom4j.io; 011 012import java.lang.reflect.InvocationTargetException; 013import java.lang.reflect.Method; 014import java.io.BufferedReader; 015import java.io.File; 016import java.io.FileReader; 017import java.io.FileNotFoundException; 018import java.io.InputStream; 019import java.io.IOException; 020import java.io.Reader; 021import java.io.Serializable; 022import java.net.MalformedURLException; 023import java.net.URL; 024import java.util.ArrayList; 025import java.util.StringTokenizer; 026 027import org.dom4j.Document; 028import org.dom4j.DocumentFactory; 029import org.dom4j.ElementHandler; 030import org.dom4j.DocumentException; 031 032import org.xml.sax.ContentHandler; 033import org.xml.sax.EntityResolver; 034import org.xml.sax.ErrorHandler; 035import org.xml.sax.InputSource; 036import org.xml.sax.SAXException; 037import org.xml.sax.SAXNotRecognizedException; 038import org.xml.sax.SAXNotSupportedException; 039import org.xml.sax.SAXParseException; 040import org.xml.sax.XMLFilter; 041import org.xml.sax.XMLReader; 042import org.xml.sax.ext.LexicalHandler; 043import org.xml.sax.helpers.DefaultHandler; 044import org.xml.sax.helpers.XMLReaderFactory; 045 046/** <p><code>SAXReader</code> creates a DOM4J tree from SAX parsing events.</p> 047 * 048 * <p>The actual SAX parser that is used by this class is configurable 049 * so you can use your favourite SAX parser if you wish. DOM4J comes 050 * configured with its own SAX parser so you do not need to worry about 051 * configuring the SAX parser.</p> 052 * 053 * <p>To explicitly configure the SAX parser that is used via Java code you 054 * can use a constructor or use the 055 * {@link #setXMLReader(XMLReader)} or 056 * {@link #setXMLReaderClassName(String)} methods.</p> 057 * 058 * <p>If the parser is not specified explicitly then the standard SAX 059 * policy of using the <code>org.xml.sax.driver</code> system property is 060 * used to determine the implementation class of {@link XMLReader}.</p> 061 * 062 * <p>If the <code>org.xml.sax.driver</code> system property is not defined 063 * then JAXP is used via reflection (so that DOM4J is not explicitly dependent 064 * on the JAXP classes) to load the JAXP configured SAXParser. 065 * If there is any error creating a JAXP SAXParser an informational message is 066 * output and then the default (Aelfred) SAX parser is used instead.</p> 067 * 068 * <p>If you are trying to use JAXP to explicitly set your SAX parser 069 * and are experiencing problems, you can turn on verbose error reporting 070 * by defining the system property <code>org.dom4j.verbose</code> to be "true" 071 * which will output a more detailed description of why JAXP could not find a 072 * SAX parser</p> 073 * 074 * <p> 075 * For more information on JAXP please go to 076 * <a href="http://java.sun.com/xml/">Sun's Java & XML site</a></p> 077 * 078 * @author <a href="mailto:james.strachan@metastuff.com">James Strachan</a> 079 * @version $Revision: 1.39 $ 080 */ 081public class SAXReader { 082 083 /** <code>DocumentFactory</code> used to create new document objects */ 084 private DocumentFactory factory; 085 086 /** <code>XMLReader</code> used to parse the SAX events */ 087 private XMLReader xmlReader; 088 089 /** Whether validation should occur */ 090 private boolean validating; 091 092 /** DispatchHandler to call when each <code>Element</code> is encountered */ 093 private DispatchHandler dispatchHandler; 094 095 /** ErrorHandler class to use */ 096 private ErrorHandler errorHandler; 097 098 /** The entity resolver */ 099 private EntityResolver entityResolver; 100 101 /** Should element & attribute names and namespace URIs be interned? */ 102 private boolean stringInternEnabled = true; 103 104 /** Should internal DTD declarations be expanded into a List in the DTD */ 105 private boolean includeInternalDTDDeclarations = false; 106 107 /** Should external DTD declarations be expanded into a List in the DTD */ 108 private boolean includeExternalDTDDeclarations = false; 109 110 /** Whether adjacent text nodes should be merged */ 111 private boolean mergeAdjacentText = false; 112 113 /** Holds value of property stripWhitespaceText. */ 114 private boolean stripWhitespaceText = false; 115 116 117 //private boolean includeExternalGeneralEntities = false; 118 //private boolean includeExternalParameterEntities = false; 119 120 /** The SAX filter used to filter SAX events */ 121 private XMLFilter xmlFilter; 122 123 124 public SAXReader() { 125 } 126 127 public SAXReader(boolean validating) { 128 this.validating = validating; 129 } 130 131 public SAXReader(DocumentFactory factory) { 132 this.factory = factory; 133 } 134 135 public SAXReader(DocumentFactory factory, boolean validating) { 136 this.factory = factory; 137 this.validating = validating; 138 } 139 140 public SAXReader(XMLReader xmlReader) { 141 this.xmlReader = xmlReader; 142 } 143 144 public SAXReader(XMLReader xmlReader, boolean validating) { 145 this.xmlReader = xmlReader; 146 this.validating = validating; 147 } 148 149 public SAXReader(String xmlReaderClassName) throws SAXException { 150 if (xmlReaderClassName != null) { 151 this.xmlReader = XMLReaderFactory.createXMLReader(xmlReaderClassName); 152 } 153 } 154 155 public SAXReader(String xmlReaderClassName, boolean validating) throws SAXException { 156 if (xmlReaderClassName != null) { 157 this.xmlReader = XMLReaderFactory.createXMLReader(xmlReaderClassName); 158 } 159 this.validating = validating; 160 } 161 162 163 164 /** Allows a SAX property to be set on the underlying SAX parser. 165 * This can be useful to set parser-specific properties 166 * such as the location of schema or DTD resources. 167 * Though use this method with caution as it has the possibility 168 * of breaking the standard behaviour. 169 * An alternative to calling this method is to correctly configure an 170 * XMLReader object instance and call the {@link #setXMLReader(XMLReader)} method 171 * 172 * @name is the SAX property name 173 * @value is the value of the SAX property 174 * @throws SAXException if the XMLReader could not be created or 175 * the property could not be changed. 176 */ 177 public void setProperty(String name, Object value) throws SAXException { 178 getXMLReader().setProperty(name, value); 179 } 180 181 182 /** Allows a SAX featuer on the underlying SAX parser. 183 * This can be useful to set parser-specific features. 184 * Though use this method with caution as it has the possibility 185 * of breaking the standard behaviour. 186 * An alternative to calling this method is to correctly configure an 187 * XMLReader object instance and call the {@link #setXMLReader(XMLReader)} method 188 * 189 * @name is the SAX feature name 190 * @value is the value of the SAX feature 191 * @throws SAXException if the XMLReader could not be created or 192 * the feature could not be changed. 193 */ 194 public void setFeature(String name, boolean value) throws SAXException { 195 getXMLReader().setFeature(name, value); 196 } 197 198 199 /** <p>Reads a Document from the given <code>File</code></p> 200 * 201 * @param file is the <code>File</code> to read from. 202 * @return the newly created Document instance 203 * @throws DocumentException if an error occurs during parsing. 204 * @throws MalformedURLException if a URL could not be made for the given File 205 */ 206 public Document read(File file) throws DocumentException, MalformedURLException { 207 return read( file.toURL() ); 208 } 209 210 /** <p>Reads a Document from the given <code>URL</code> using SAX</p> 211 * 212 * @param url <code>URL</code> to read from. 213 * @return the newly created Document instance 214 * @throws DocumentException if an error occurs during parsing. 215 */ 216 public Document read(URL url) throws DocumentException { 217 String systemID = url.toExternalForm(); 218 return read(new InputSource(systemID)); 219 } 220 221 /** <p>Reads a Document from the given URL or filename using SAX.</p> 222 * 223 * <p> 224 * If the systemId contains a <code>':'</code> character then it is 225 * assumed to be a URL otherwise its assumed to be a file name. 226 * If you want finer grained control over this mechansim then please 227 * explicitly pass in either a {@link URL} or a {@link File} instance 228 * instead of a {@link String} to denote the source of the document. 229 * </p> 230 * 231 * @param systemId is a URL for a document or a file name. 232 * @return the newly created Document instance 233 * @throws DocumentException if an error occurs during parsing. 234 */ 235 public Document read(String systemId) throws DocumentException { 236 return read(new InputSource(systemId)); 237 } 238 239 /** <p>Reads a Document from the given stream using SAX</p> 240 * 241 * @param in <code>InputStream</code> to read from. 242 * @return the newly created Document instance 243 * @throws DocumentException if an error occurs during parsing. 244 */ 245 public Document read(InputStream in) throws DocumentException { 246 return read(new InputSource(in)); 247 } 248 249 /** <p>Reads a Document from the given <code>Reader</code> using SAX</p> 250 * 251 * @param reader is the reader for the input 252 * @return the newly created Document instance 253 * @throws DocumentException if an error occurs during parsing. 254 */ 255 public Document read(Reader reader) throws DocumentException { 256 return read(new InputSource(reader)); 257 } 258 259 /** <p>Reads a Document from the given stream using SAX</p> 260 * 261 * @param in <code>InputStream</code> to read from. 262 * @param systemId is the URI for the input 263 * @return the newly created Document instance 264 * @throws DocumentException if an error occurs during parsing. 265 */ 266 public Document read(InputStream in, String systemId) throws DocumentException { 267 InputSource source = new InputSource(in); 268 source.setSystemId(systemId); 269 return read(source); 270 } 271 272 /** <p>Reads a Document from the given <code>Reader</code> using SAX</p> 273 * 274 * @param reader is the reader for the input 275 * @param systemId is the URI for the input 276 * @return the newly created Document instance 277 * @throws DocumentException if an error occurs during parsing. 278 */ 279 public Document read(Reader reader, String SystemId) throws DocumentException { 280 InputSource source = new InputSource(reader); 281 source.setSystemId(SystemId); 282 return read(source); 283 } 284 285 /** <p>Reads a Document from the given <code>InputSource</code> using SAX</p> 286 * 287 * @param in <code>InputSource</code> to read from. 288 * @param systemId is the URI for the input 289 * @return the newly created Document instance 290 * @throws DocumentException if an error occurs during parsing. 291 */ 292 public Document read(InputSource in) throws DocumentException { 293 try { 294 XMLReader xmlReader = getXMLReader(); 295 296 xmlReader = installXMLFilter(xmlReader); 297 298 EntityResolver entityResolver = xmlReader.getEntityResolver(); 299 if ( entityResolver == null ) { 300 entityResolver = this.entityResolver; 301 if ( entityResolver == null ) { 302 entityResolver = createDefaultEntityResolver( in.getSystemId() ); 303 } 304 xmlReader.setEntityResolver( entityResolver ); 305 } 306 else { 307 if ( this.entityResolver != null ) { 308 xmlReader.setEntityResolver( this.entityResolver ); 309 } 310 } 311 312 SAXContentHandler contentHandler = createContentHandler(xmlReader); 313 contentHandler.setEntityResolver( entityResolver ); 314 contentHandler.setInputSource( in ); 315 contentHandler.setIncludeInternalDTDDeclarations( isIncludeInternalDTDDeclarations() ); 316 contentHandler.setIncludeExternalDTDDeclarations( isIncludeExternalDTDDeclarations() ); 317 contentHandler.setMergeAdjacentText( isMergeAdjacentText() ); 318 contentHandler.setStripWhitespaceText( isStripWhitespaceText() ); 319 xmlReader.setContentHandler(contentHandler); 320 321 configureReader(xmlReader, contentHandler); 322 323 xmlReader.parse(in); 324 return contentHandler.getDocument(); 325 } 326 catch (Exception e) { 327 if (e instanceof SAXParseException) { 328 //e.printStackTrace(); 329 SAXParseException parseException = (SAXParseException) e; 330 String systemId = parseException.getSystemId(); 331 if ( systemId == null ) { 332 systemId = ""; 333 } 334 String message = "Error on line " 335 + parseException.getLineNumber() 336 + " of document " + systemId 337 + " : " + parseException.getMessage(); 338 339 throw new DocumentException(message, e); 340 } 341 else { 342 throw new DocumentException(e.getMessage(), e); 343 } 344 } 345 } 346 347 348 349 // Properties 350 //------------------------------------------------------------------------- 351 352 /** @return the validation mode, true if validating will be done 353 * otherwise false. 354 */ 355 public boolean isValidating() { 356 return validating; 357 } 358 359 /** Sets the validation mode. 360 * 361 * @param validating indicates whether or not validation should occur. 362 */ 363 public void setValidation(boolean validating) { 364 this.validating = validating; 365 } 366 367 /** @return whether internal DTD declarations should be expanded into the DocumentType 368 * object or not. 369 */ 370 public boolean isIncludeInternalDTDDeclarations() { 371 return includeInternalDTDDeclarations; 372 } 373 374 /** Sets whether internal DTD declarations should be expanded into the DocumentType 375 * object or not. 376 * 377 * @param includeInternalDTDDeclarations whether or not DTD declarations should be expanded 378 * and included into the DocumentType object. 379 */ 380 public void setIncludeInternalDTDDeclarations(boolean includeInternalDTDDeclarations) { 381 this.includeInternalDTDDeclarations = includeInternalDTDDeclarations; 382 } 383 384 /** @return whether external DTD declarations should be expanded into the DocumentType 385 * object or not. 386 */ 387 public boolean isIncludeExternalDTDDeclarations() { 388 return includeExternalDTDDeclarations; 389 } 390 391 /** Sets whether DTD external declarations should be expanded into the DocumentType 392 * object or not. 393 * 394 * @param includeInternalDTDDeclarations whether or not DTD declarations should be expanded 395 * and included into the DocumentType object. 396 */ 397 public void setIncludeExternalDTDDeclarations(boolean includeExternalDTDDeclarations) { 398 this.includeExternalDTDDeclarations = includeExternalDTDDeclarations; 399 } 400 401 /** Sets whether String interning 402 * is enabled or disabled for element & attribute names and namespace URIs. 403 * This proprety is enabled by default. 404 */ 405 public boolean isStringInternEnabled() { 406 return stringInternEnabled; 407 } 408 409 /** Sets whether String interning 410 * is enabled or disabled for element & attribute names and namespace URIs 411 */ 412 public void setStringInternEnabled(boolean stringInternEnabled) { 413 this.stringInternEnabled = stringInternEnabled; 414 } 415 416 /** Returns whether adjacent text nodes should be merged together. 417 * @return Value of property mergeAdjacentText. 418 */ 419 public boolean isMergeAdjacentText() { 420 return mergeAdjacentText; 421 } 422 423 /** Sets whether or not adjacent text nodes should be merged 424 * together when parsing. 425 * @param mergeAdjacentText New value of property mergeAdjacentText. 426 */ 427 public void setMergeAdjacentText(boolean mergeAdjacentText) { 428 this.mergeAdjacentText = mergeAdjacentText; 429 } 430 431 /** Sets whether whitespace between element start and end tags should be ignored 432 * 433 * @return Value of property stripWhitespaceText. 434 */ 435 public boolean isStripWhitespaceText() { 436 return stripWhitespaceText; 437 } 438 439 /** Sets whether whitespace between element start and end tags should be ignored. 440 * 441 * @param stripWhitespaceText New value of property stripWhitespaceText. 442 */ 443 public void setStripWhitespaceText(boolean stripWhitespaceText) { 444 this.stripWhitespaceText = stripWhitespaceText; 445 } 446 447 448 /** @return the <code>DocumentFactory</code> used to create document objects 449 */ 450 public DocumentFactory getDocumentFactory() { 451 if (factory == null) { 452 factory = DocumentFactory.getInstance(); 453 } 454 return factory; 455 } 456 457 /** <p>This sets the <code>DocumentFactory</code> used to create new documents. 458 * This method allows the building of custom DOM4J tree objects to be implemented 459 * easily using a custom derivation of {@link DocumentFactory}</p> 460 * 461 * @param factory <code>DocumentFactory</code> used to create DOM4J objects 462 */ 463 public void setDocumentFactory(DocumentFactory factory) { 464 this.factory = factory; 465 } 466 467 /** @return the <code>ErrorHandler</code> used by SAX 468 */ 469 public ErrorHandler getErrorHandler() { 470 return errorHandler; 471 } 472 473 /** Sets the <code>ErrorHandler</code> used by the SAX 474 * <code>XMLReader</code>. 475 * 476 * @param errorHandler is the <code>ErrorHandler</code> used by SAX 477 */ 478 public void setErrorHandler(ErrorHandler errorHandler) { 479 this.errorHandler = errorHandler; 480 } 481 482 /** Returns the current entity resolver used to resolve entities 483 */ 484 public EntityResolver getEntityResolver() { 485 return entityResolver; 486 } 487 488 /** Sets the entity resolver used to resolve entities. 489 */ 490 public void setEntityResolver(EntityResolver entityResolver) { 491 this.entityResolver = entityResolver; 492 } 493 494 /** @return the <code>XMLReader</code> used to parse SAX events 495 */ 496 public XMLReader getXMLReader() throws SAXException { 497 if (xmlReader == null) { 498 xmlReader = createXMLReader(); 499 } 500 return xmlReader; 501 } 502 503 /** Sets the <code>XMLReader</code> used to parse SAX events 504 * 505 * @param xmlReader is the <code>XMLReader</code> to parse SAX events 506 */ 507 public void setXMLReader(XMLReader xmlReader) { 508 this.xmlReader = xmlReader; 509 } 510 511 /** Sets the class name of the <code>XMLReader</code> to be used 512 * to parse SAX events. 513 * 514 * @param xmlReaderClassName is the class name of the <code>XMLReader</code> 515 * to parse SAX events 516 */ 517 public void setXMLReaderClassName(String xmlReaderClassName) throws SAXException { 518 setXMLReader( XMLReaderFactory.createXMLReader(xmlReaderClassName) ); 519 } 520 521 522 /** Adds the <code>ElementHandler</code> to be called when the 523 * specified path is encounted. 524 * 525 * @param path is the path to be handled 526 * @param handler is the <code>ElementHandler</code> to be called 527 * by the event based processor. 528 */ 529 public void addHandler(String path, ElementHandler handler) { 530 getDispatchHandler().addHandler(path, handler); 531 } 532 533 /** Removes the <code>ElementHandler</code> from the event based 534 * processor, for the specified path. 535 * 536 * @param path is the path to remove the <code>ElementHandler</code> for. 537 */ 538 public void removeHandler(String path) { 539 getDispatchHandler().removeHandler(path); 540 } 541 542 /** When multiple <code>ElementHandler</code> instances have been 543 * registered, this will set a default <code>ElementHandler</code> 544 * to be called for any path which does <b>NOT</b> have a handler 545 * registered. 546 * @param handler is the <code>ElementHandler</code> to be called 547 * by the event based processor. 548 */ 549 public void setDefaultHandler(ElementHandler handler) { 550 getDispatchHandler().setDefaultHandler(handler); 551 } 552 553 554 /** Returns the SAX filter being used to filter SAX events. 555 * 556 * @return the SAX filter being used or null if no SAX filter is installed 557 */ 558 public XMLFilter getXMLFilter() { 559 return xmlFilter; 560 } 561 562 /** Sets the SAX filter to be used when filtering SAX events 563 * 564 * @param xmlFilter is the SAX filter to use or null to disable filtering 565 */ 566 public void setXMLFilter(XMLFilter xmlFilter) { 567 this.xmlFilter = xmlFilter; 568 } 569 570 // Implementation methods 571 //------------------------------------------------------------------------- 572 573 /** Installs any XMLFilter objects required to allow the SAX event stream 574 * to be filtered and preprocessed before it gets to dom4j. 575 * 576 * @return the new XMLFilter if applicable or the original XMLReader if no 577 * filter is being used. 578 */ 579 protected XMLReader installXMLFilter(XMLReader xmlReader) { 580 XMLFilter xmlFilter = getXMLFilter(); 581 if ( xmlFilter != null ) { 582 // find the root XMLFilter 583 XMLFilter root = xmlFilter; 584 while (true) { 585 XMLReader parent = root.getParent(); 586 if ( parent instanceof XMLFilter ) { 587 root = (XMLFilter) parent; 588 } 589 else { 590 break; 591 } 592 } 593 root.setParent(xmlReader); 594 return xmlFilter; 595 } 596 return xmlReader; 597 } 598 599 600 protected DispatchHandler getDispatchHandler() { 601 if (dispatchHandler == null) { 602 dispatchHandler = new DispatchHandler(); 603 } 604 return dispatchHandler; 605 } 606 607 protected void setDispatchHandler(DispatchHandler dispatchHandler) { 608 this.dispatchHandler = dispatchHandler; 609 } 610 611 /** Factory Method to allow alternate methods of 612 * creating and configuring XMLReader objects 613 */ 614 protected XMLReader createXMLReader() throws SAXException { 615 return SAXHelper.createXMLReader( isValidating() ); 616 } 617 618 /** Configures the XMLReader before use */ 619 protected void configureReader(XMLReader reader, DefaultHandler contentHandler) throws DocumentException { 620 // configure lexical handling 621 SAXHelper.setParserProperty( 622 reader, 623 "http://xml.org/sax/handlers/LexicalHandler", 624 contentHandler 625 ); 626 627 // try alternate property just in case 628 SAXHelper.setParserProperty( 629 reader, 630 "http://xml.org/sax/properties/lexical-handler", 631 contentHandler 632 ); 633 634 // register the DeclHandler 635 if ( includeInternalDTDDeclarations ) { 636 SAXHelper.setParserProperty( 637 reader, 638 "http://xml.org/sax/properties/declaration-handler", 639 contentHandler 640 ); 641 } 642 643 // configure namespace support 644 SAXHelper.setParserFeature( 645 reader, 646 "http://xml.org/sax/features/namespaces", 647 true 648 ); 649 650 SAXHelper.setParserFeature( 651 reader, 652 "http://xml.org/sax/features/namespace-prefixes", 653 false 654 ); 655 656 // string interning 657 SAXHelper.setParserFeature( 658 reader, 659 "http://xml.org/sax/features/string-interning", 660 isStringInternEnabled() 661 ); 662 663 // external entites 664/* 665 SAXHelper.setParserFeature( 666 reader, 667 "http://xml.org/sax/properties/external-general-entities", 668 includeExternalGeneralEntities 669 ); 670 SAXHelper.setParserFeature( 671 reader, 672 "http://xml.org/sax/properties/external-parameter-entities", 673 includeExternalParameterEntities 674 ); 675*/ 676 try { 677 // configure validation support 678 reader.setFeature( 679 "http://xml.org/sax/features/validation", 680 isValidating() 681 ); 682 if (errorHandler != null) { 683 reader.setErrorHandler(errorHandler); 684 } 685 else { 686 reader.setErrorHandler(contentHandler); 687 } 688 } 689 catch (Exception e) { 690 if (isValidating()) { 691 throw new DocumentException( 692 "Validation not supported for XMLReader: " + reader, 693 e 694 ); 695 } 696 697 } 698 } 699 700 /** Factory Method to allow user derived SAXContentHandler objects to be used 701 */ 702 protected SAXContentHandler createContentHandler(XMLReader reader) { 703 return new SAXContentHandler( 704 getDocumentFactory(), dispatchHandler 705 ); 706 } 707 708 protected EntityResolver createDefaultEntityResolver( String documentSystemId ) { 709 String prefix = null; 710 if ( documentSystemId != null && documentSystemId.length() > 0 ) { 711 int idx = documentSystemId.lastIndexOf( '/' ); 712 if ( idx > 0 ) { 713 prefix = documentSystemId.substring(0, idx+1); 714 715 } 716 } 717 return new SAXEntityResolver(prefix); 718 } 719 720 protected static class SAXEntityResolver implements EntityResolver, Serializable { 721 String uriPrefix; 722 723 public SAXEntityResolver(String uriPrefix) { 724 this.uriPrefix = uriPrefix; 725 } 726 727 public InputSource resolveEntity(String publicId, String systemId) { 728 // try create a relative URI reader... 729 if ( systemId != null && systemId.length() > 0 ) { 730 if ( uriPrefix != null && systemId.indexOf( ':' ) <= 0 ) { 731 systemId = uriPrefix + systemId; 732 } 733 } 734 return new InputSource(systemId); 735 } 736 } 737 738 739 740} 741 742 743 744 745/* 746 * Redistribution and use of this software and associated documentation 747 * ("Software"), with or without modification, are permitted provided 748 * that the following conditions are met: 749 * 750 * 1. Redistributions of source code must retain copyright 751 * statements and notices. Redistributions must also contain a 752 * copy of this document. 753 * 754 * 2. Redistributions in binary form must reproduce the 755 * above copyright notice, this list of conditions and the 756 * following disclaimer in the documentation and/or other 757 * materials provided with the distribution. 758 * 759 * 3. The name "DOM4J" must not be used to endorse or promote 760 * products derived from this Software without prior written 761 * permission of MetaStuff, Ltd. For written permission, 762 * please contact dom4j-info@metastuff.com. 763 * 764 * 4. Products derived from this Software may not be called "DOM4J" 765 * nor may "DOM4J" appear in their names without prior written 766 * permission of MetaStuff, Ltd. DOM4J is a registered 767 * trademark of MetaStuff, Ltd. 768 * 769 * 5. Due credit should be given to the DOM4J Project 770 * (http://dom4j.org/). 771 * 772 * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS 773 * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT 774 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 775 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 776 * METASTUFF, LTD. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 777 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 778 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 779 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 780 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 781 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 782 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 783 * OF THE POSSIBILITY OF SUCH DAMAGE. 784 * 785 * Copyright 2001 (C) MetaStuff, Ltd. All Rights Reserved. 786 * 787 * $Id: SAXReader.java,v 1.39 2001/11/15 23:38:29 jstrachan Exp $ 788 */