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: SAXContentHandler.java,v 1.42 2002/03/02 14:23:25 slehmann Exp $ 008 */ 009 010package org.dom4j.io; 011 012import java.util.ArrayList; 013import java.util.Iterator; 014import java.util.HashMap; 015import java.util.HashSet; 016import java.util.List; 017import java.util.Map; 018import java.util.Set; 019 020import org.dom4j.Attribute; 021import org.dom4j.Branch; 022import org.dom4j.CDATA; 023import org.dom4j.Comment; 024import org.dom4j.Document; 025import org.dom4j.DocumentType; 026import org.dom4j.DocumentFactory; 027import org.dom4j.Element; 028import org.dom4j.ElementHandler; 029import org.dom4j.Entity; 030import org.dom4j.Namespace; 031import org.dom4j.QName; 032import org.dom4j.ProcessingInstruction; 033import org.dom4j.DocumentException; 034 035import org.dom4j.dtd.AttributeDecl; 036import org.dom4j.dtd.ElementDecl; 037import org.dom4j.dtd.ExternalEntityDecl; 038import org.dom4j.dtd.InternalEntityDecl; 039 040import org.dom4j.tree.AbstractElement; 041import org.dom4j.tree.NamespaceStack; 042 043import org.xml.sax.Attributes; 044import org.xml.sax.DTDHandler; 045import org.xml.sax.EntityResolver; 046import org.xml.sax.InputSource; 047import org.xml.sax.SAXException; 048import org.xml.sax.SAXParseException; 049import org.xml.sax.ext.LexicalHandler; 050import org.xml.sax.ext.DeclHandler; 051import org.xml.sax.helpers.DefaultHandler; 052 053/** <p><code>SAXHandler</code> builds a DOM4J tree via SAX events.</p> 054 * 055 * @author <a href="mailto:jstrachan@apache.org">James Strachan</a> 056 * @version $Revision: 1.42 $ 057 */ 058public class SAXContentHandler extends DefaultHandler implements LexicalHandler, DeclHandler, DTDHandler { 059 060 /** The factory used to create new <code>Document</code> instances */ 061 private DocumentFactory documentFactory; 062 063 /** The document that is being built */ 064 private Document document; 065 066 /** stack of <code>Element</code> objects */ 067 private ElementStack elementStack; 068 069 /** stack of <code>Namespace</code> and <code>QName</code> objects */ 070 private NamespaceStack namespaceStack; 071 072 /** the <code>ElementHandler</code> called as the elements are complete */ 073 private ElementHandler elementHandler; 074 075 /** The name of the current entity */ 076 private String entity; 077 078 /** Flag used to indicate that we are inside a DTD section */ 079 private boolean insideDTDSection; 080 081 /** Flag used to indicate that we are inside a CDATA section */ 082 private boolean insideCDATASection; 083 084 /** namespaces that are available for use */ 085 private Map availableNamespaceMap = new HashMap(); 086 087 /** declared namespaces that are not yet available for use */ 088 private List declaredNamespaceList = new ArrayList(); 089 090 /** internal DTD declarations */ 091 private List internalDTDDeclarations; 092 093 /** external DTD declarations */ 094 private List externalDTDDeclarations; 095 096 /** The number of namespaces that are declared in the current scope */ 097 private int declaredNamespaceIndex; 098 099 /** The entity resolver */ 100 private EntityResolver entityResolver; 101 102 private InputSource inputSource; 103 104 /** The current element we are on */ 105 private Element currentElement; 106 107 /** Should internal DTD declarations be expanded into a List in the DTD */ 108 private boolean includeInternalDTDDeclarations = false; 109 110 /** Should external DTD declarations be expanded into a List in the DTD */ 111 private boolean includeExternalDTDDeclarations = false; 112 113 /** The number of levels deep we are inside a startEntity / endEntity call */ 114 private int entityLevel; 115 116 /** Are we in an internal DTD subset? */ 117 private boolean internalDTDsubset = false; 118 119 /** Whether adjacent text nodes should be merged */ 120 private boolean mergeAdjacentText = false; 121 122 /** Have we added text to the buffer */ 123 private boolean textInTextBuffer = false; 124 125 /** Buffer used to concatenate text together */ 126 private StringBuffer textBuffer; 127 128 /** Holds value of property stripWhitespaceText. */ 129 private boolean stripWhitespaceText = false; 130 131 132 public SAXContentHandler() { 133 this( DocumentFactory.getInstance() ); 134 } 135 136 public SAXContentHandler(DocumentFactory documentFactory) { 137 this.documentFactory = documentFactory; 138 this.namespaceStack = new NamespaceStack(documentFactory); 139 } 140 141 public SAXContentHandler(DocumentFactory documentFactory, ElementHandler elementHandler) { 142 this.documentFactory = documentFactory; 143 this.elementHandler = elementHandler; 144 this.namespaceStack = new NamespaceStack(documentFactory); 145 } 146 147 public SAXContentHandler(DocumentFactory documentFactory, ElementHandler elementHandler, ElementStack elementStack) { 148 this.documentFactory = documentFactory; 149 this.elementHandler = elementHandler; 150 this.elementStack = elementStack; 151 this.namespaceStack = new NamespaceStack(documentFactory); 152 } 153 154 /** @return the document that has been or is being built 155 */ 156 public Document getDocument() { 157 if ( document == null ) { 158 document = createDocument(); 159 } 160 return document; 161 } 162 163 // ContentHandler interface 164 //------------------------------------------------------------------------- 165 166 public void processingInstruction(String target, String data) throws SAXException { 167 if ( mergeAdjacentText && textInTextBuffer ) { 168 completeCurrentTextNode(); 169 } 170 if ( currentElement != null ) { 171 currentElement.addProcessingInstruction(target, data); 172 } 173 else { 174 document.addProcessingInstruction(target, data); 175 } 176 } 177 178 public void startPrefixMapping(String prefix, String uri) throws SAXException { 179 namespaceStack.push( prefix, uri ); 180 } 181 182 public void endPrefixMapping(String prefix) throws SAXException { 183 namespaceStack.pop( prefix ); 184 declaredNamespaceIndex = namespaceStack.size(); 185 } 186 187 public void startDocument() throws SAXException { 188 document = createDocument(); 189 currentElement = null; 190 191 if ( elementStack == null ) { 192 elementStack = createElementStack(); 193 } 194 else { 195 elementStack.clear(); 196 } 197 if ( (elementHandler != null) && 198 (elementHandler instanceof DispatchHandler) ) { 199 elementStack.setDispatchHandler((DispatchHandler)elementHandler); 200 } 201 202 namespaceStack.clear(); 203 declaredNamespaceIndex = 0; 204 205 if ( mergeAdjacentText && textBuffer == null ) { 206 textBuffer = new StringBuffer(); 207 } 208 textInTextBuffer = false; 209 } 210 211 public void endDocument() throws SAXException { 212 namespaceStack.clear(); 213 elementStack.clear(); 214 currentElement = null; 215 textBuffer = null; 216 } 217 218 public void startElement(String namespaceURI, String localName, String qualifiedName, Attributes attributes) throws SAXException { 219 if ( mergeAdjacentText && textInTextBuffer ) { 220 completeCurrentTextNode(); 221 } 222 223 QName qName = namespaceStack.getQName( 224 namespaceURI, localName, qualifiedName 225 ); 226 227 Branch branch = currentElement; 228 if ( branch == null ) { 229 branch = document; 230 } 231 Element element = branch.addElement(qName); 232 233 // add all declared namespaces 234 addDeclaredNamespaces(element); 235 236 // now lets add all attribute values 237 addAttributes( element, attributes ); 238 239 elementStack.pushElement(element); 240 currentElement = element; 241 242 243 if ( elementHandler != null ) { 244 elementHandler.onStart(elementStack); 245 } 246 } 247 248 public void endElement(String namespaceURI, String localName, String qName) { 249 if ( mergeAdjacentText && textInTextBuffer ) { 250 completeCurrentTextNode(); 251 } 252 253 if ( elementHandler != null && currentElement != null ) { 254 elementHandler.onEnd(elementStack); 255 } 256 elementStack.popElement(); 257 currentElement = elementStack.peekElement(); 258 } 259 260 public void characters(char[] ch, int start, int end) throws SAXException { 261 if ( end == 0 ) { 262 return; 263 } 264 if ( currentElement != null ) { 265 String text = new String(ch, start, end); 266 if (entity != null) { 267 if ( mergeAdjacentText && textInTextBuffer ) { 268 completeCurrentTextNode(); 269 } 270 currentElement.addEntity(entity, new String(ch, start, end)); 271 entity = null; 272 } 273 else if (insideCDATASection) { 274 if ( mergeAdjacentText && textInTextBuffer ) { 275 completeCurrentTextNode(); 276 } 277 currentElement.addCDATA(new String(ch, start, end)); 278 } 279 else { 280 if ( mergeAdjacentText ) { 281 textBuffer.append(ch, start, end); 282 textInTextBuffer = true; 283 } 284 else { 285 currentElement.addText(new String(ch, start, end)); 286 } 287 } 288 } 289 } 290 291 // ErrorHandler interface 292 //------------------------------------------------------------------------- 293 294 /** This method is called when a warning occurs during the parsing 295 * of the document. 296 * This method does nothing. 297 */ 298 public void warning(SAXParseException exception) throws SAXException { 299 // ignore warnings by default 300 } 301 302 /** This method is called when an error is detected during parsing 303 * such as a validation error. 304 * This method rethrows the exception 305 */ 306 public void error(SAXParseException exception) throws SAXException { 307 throw exception; 308 } 309 310 /** This method is called when a fatal error occurs during parsing. 311 * This method rethrows the exception 312 */ 313 public void fatalError(SAXParseException exception) throws SAXException { 314 throw exception; 315 } 316 317 // LexicalHandler interface 318 //------------------------------------------------------------------------- 319 320 public void startDTD(String name, String publicId, String systemId) throws SAXException { 321 if (document != null) { 322 document.addDocType(name, publicId, systemId); 323 } 324 insideDTDSection = true; 325 internalDTDsubset = true; 326 } 327 328 public void endDTD() throws SAXException { 329 insideDTDSection = false; 330 if ( document != null ) { 331 DocumentType docType = document.getDocType(); 332 if ( docType != null ) { 333 if ( internalDTDDeclarations != null ) { 334 docType.setInternalDeclarations( internalDTDDeclarations ); 335 } 336 if ( externalDTDDeclarations != null ) { 337 docType.setExternalDeclarations( externalDTDDeclarations ); 338 } 339 } 340 } 341 internalDTDDeclarations = null; 342 externalDTDDeclarations = null; 343 } 344 345 public void startEntity(String name) throws SAXException { 346 ++entityLevel; 347 348 // Ignore DTD references 349 entity = null; 350 if (! insideDTDSection ) { 351 if ( ! isIgnorableEntity(name) ) { 352 entity = name; 353 } 354 } 355 356 // internal DTD subsets can only appear outside of a 357 // startEntity/endEntity block 358 // see the startDTD method in 359 // http://dom4j.org/javadoc/org/xml/sax/ext/LexicalHandler.html 360 // or here:- 361 // http://dom4j.org/javadoc/org/xml/sax/ext/LexicalHandler.html#startDTD(java.lang.String, java.lang.String, java.lang.String) 362 internalDTDsubset = false; 363 } 364 365 public void endEntity(String name) throws SAXException { 366 --entityLevel; 367 entity = null; 368 if ( entityLevel == 0 ) { 369 internalDTDsubset = true; 370 } 371 } 372 373 public void startCDATA() throws SAXException { 374 insideCDATASection = true; 375 } 376 377 public void endCDATA() throws SAXException { 378 insideCDATASection = false; 379 } 380 381 public void comment(char[] ch, int start, int end) throws SAXException { 382 if ( mergeAdjacentText && textInTextBuffer ) { 383 completeCurrentTextNode(); 384 } 385 String text = new String(ch, start, end); 386 if (!insideDTDSection && text.length() > 0) { 387 if ( currentElement != null ) { 388 currentElement.addComment(text); 389 } 390 else { 391 document.addComment(text); 392 } 393 } 394 } 395 396 // DeclHandler interface 397 //------------------------------------------------------------------------- 398 399 /** 400 * Report an element type declaration. 401 * 402 * <p>The content model will consist of the string "EMPTY", the 403 * string "ANY", or a parenthesised group, optionally followed 404 * by an occurrence indicator. The model will be normalized so 405 * that all parameter entities are fully resolved and all whitespace 406 * is removed,and will include the enclosing parentheses. Other 407 * normalization (such as removing redundant parentheses or 408 * simplifying occurrence indicators) is at the discretion of the 409 * parser.</p> 410 * 411 * @param name The element type name. 412 * @param model The content model as a normalized string. 413 * @exception SAXException The application may raise an exception. 414 */ 415 public void elementDecl(String name, String model) throws SAXException { 416 if ( internalDTDsubset ) { 417 if ( includeInternalDTDDeclarations ) { 418 addDTDDeclaration( new ElementDecl( name, model ) ); 419 } 420 } 421 else { 422 if ( includeExternalDTDDeclarations ) { 423 addExternalDTDDeclaration( new ElementDecl( name, model ) ); 424 } 425 } 426 } 427 428 /** 429 * Report an attribute type declaration. 430 * 431 * <p>Only the effective (first) declaration for an attribute will 432 * be reported. The type will be one of the strings "CDATA", 433 * "ID", "IDREF", "IDREFS", "NMTOKEN", "NMTOKENS", "ENTITY", 434 * "ENTITIES", a parenthesized token group with 435 * the separator "|" and all whitespace removed, or the word 436 * "NOTATION" followed by a space followed by a parenthesized 437 * token group with all whitespace removed.</p> 438 * 439 * <p>Any parameter entities in the attribute value will be 440 * expanded, but general entities will not.</p> 441 * 442 * @param eName The name of the associated element. 443 * @param aName The name of the attribute. 444 * @param type A string representing the attribute type. 445 * @param valueDefault A string representing the attribute default 446 * ("#IMPLIED", "#REQUIRED", or "#FIXED") or null if 447 * none of these applies. 448 * @param value A string representing the attribute's default value, 449 * or null if there is none. 450 * @exception SAXException The application may raise an exception. 451 */ 452 public void attributeDecl(String eName,String aName,String type,String valueDefault,String value) throws SAXException { 453 if ( internalDTDsubset ) { 454 if ( includeInternalDTDDeclarations ) { 455 addDTDDeclaration( new AttributeDecl( eName, aName, type, valueDefault, value) ); 456 } 457 } 458 else { 459 if ( includeExternalDTDDeclarations ) { 460 addExternalDTDDeclaration( new AttributeDecl( eName, aName, type, valueDefault, value) ); 461 } 462 } 463 } 464 465 /** 466 * Report an internal entity declaration. 467 * 468 * <p>Only the effective (first) declaration for each entity 469 * will be reported. All parameter entities in the value 470 * will be expanded, but general entities will not.</p> 471 * 472 * @param name The name of the entity. If it is a parameter 473 * entity, the name will begin with '%'. 474 * @param value The replacement text of the entity. 475 * @exception SAXException The application may raise an exception. 476 * @see #externalEntityDecl 477 * @see org.xml.sax.DTDHandler#unparsedEntityDecl 478 */ 479 public void internalEntityDecl(String name, String value) throws SAXException { 480 if ( internalDTDsubset ) { 481 if ( includeInternalDTDDeclarations ) { 482 addDTDDeclaration( new InternalEntityDecl( name, value ) ); 483 } 484 } 485 else { 486 if ( includeExternalDTDDeclarations ) { 487 addExternalDTDDeclaration( new InternalEntityDecl( name, value ) ); 488 } 489 } 490 } 491 492 /** 493 * Report a parsed external entity declaration. 494 * 495 * <p>Only the effective (first) declaration for each entity 496 * will be reported.</p> 497 * 498 * @param name The name of the entity. If it is a parameter 499 * entity, the name will begin with '%'. 500 * @param publicId The declared public identifier of the entity, or 501 * null if none was declared. 502 * @param systemId The declared system identifier of the entity. 503 * @exception SAXException The application may raise an exception. 504 * @see #internalEntityDecl 505 * @see org.xml.sax.DTDHandler#unparsedEntityDecl 506 */ 507 public void externalEntityDecl(String name, String publicID, String systemID) throws SAXException { 508 if ( internalDTDsubset ) { 509 if ( includeInternalDTDDeclarations ) { 510 addDTDDeclaration( new ExternalEntityDecl( name, publicID, systemID ) ); 511 } 512 } 513 else { 514 if ( includeExternalDTDDeclarations ) { 515 addExternalDTDDeclaration( new ExternalEntityDecl( name, publicID, systemID ) ); 516 } 517 } 518 } 519 520 521 // DTDHandler interface 522 //------------------------------------------------------------------------- 523 524 /** 525 * Receive notification of a notation declaration event. 526 * 527 * <p>It is up to the application to record the notation for later 528 * reference, if necessary.</p> 529 * 530 * <p>At least one of publicId and systemId must be non-null. 531 * If a system identifier is present, and it is a URL, the SAX 532 * parser must resolve it fully before passing it to the 533 * application through this event.</p> 534 * 535 * <p>There is no guarantee that the notation declaration will be 536 * reported before any unparsed entities that use it.</p> 537 * 538 * @param name The notation name. 539 * @param publicId The notation's public identifier, or null if 540 * none was given. 541 * @param systemId The notation's system identifier, or null if 542 * none was given. 543 * @exception org.xml.sax.SAXException Any SAX exception, possibly 544 * wrapping another exception. 545 * @see #unparsedEntityDecl 546 * @see org.xml.sax.AttributeList 547 */ 548 public void notationDecl(String name,String publicId,String systemId) throws SAXException { 549 // #### not supported yet! 550 } 551 552 /** 553 * Receive notification of an unparsed entity declaration event. 554 * 555 * <p>Note that the notation name corresponds to a notation 556 * reported by the {@link #notationDecl notationDecl} event. 557 * It is up to the application to record the entity for later 558 * reference, if necessary.</p> 559 * 560 * <p>If the system identifier is a URL, the parser must resolve it 561 * fully before passing it to the application.</p> 562 * 563 * @exception org.xml.sax.SAXException Any SAX exception, possibly 564 * wrapping another exception. 565 * @param name The unparsed entity's name. 566 * @param publicId The entity's public identifier, or null if none 567 * was given. 568 * @param systemId The entity's system identifier. 569 * @param notation name The name of the associated notation. 570 * @see #notationDecl 571 * @see org.xml.sax.AttributeList 572 */ 573 public void unparsedEntityDecl(String name,String publicId,String systemId,String notationName) throws SAXException { 574 // #### not supported yet! 575 } 576 577 578 // Properties 579 //------------------------------------------------------------------------- 580 public ElementStack getElementStack() { 581 return elementStack; 582 } 583 584 public void setElementStack(ElementStack elementStack) { 585 this.elementStack = elementStack; 586 } 587 588 public EntityResolver getEntityResolver() { 589 return entityResolver; 590 } 591 592 public void setEntityResolver(EntityResolver entityResolver) { 593 this.entityResolver = entityResolver; 594 } 595 596 public InputSource getInputSource() { 597 return inputSource; 598 } 599 600 public void setInputSource(InputSource inputSource) { 601 this.inputSource = inputSource; 602 } 603 604 /** @return whether internal DTD declarations should be expanded into the DocumentType 605 * object or not. 606 */ 607 public boolean isIncludeInternalDTDDeclarations() { 608 return includeInternalDTDDeclarations; 609 } 610 611 /** Sets whether internal DTD declarations should be expanded into the DocumentType 612 * object or not. 613 * 614 * @param includeInternalDTDDeclarations whether or not DTD declarations should be expanded 615 * and included into the DocumentType object. 616 */ 617 public void setIncludeInternalDTDDeclarations(boolean includeInternalDTDDeclarations) { 618 this.includeInternalDTDDeclarations = includeInternalDTDDeclarations; 619 } 620 621 /** @return whether external DTD declarations should be expanded into the DocumentType 622 * object or not. 623 */ 624 public boolean isIncludeExternalDTDDeclarations() { 625 return includeExternalDTDDeclarations; 626 } 627 628 /** Sets whether DTD external declarations should be expanded into the DocumentType 629 * object or not. 630 * 631 * @param includeInternalDTDDeclarations whether or not DTD declarations should be expanded 632 * and included into the DocumentType object. 633 */ 634 public void setIncludeExternalDTDDeclarations(boolean includeExternalDTDDeclarations) { 635 this.includeExternalDTDDeclarations = includeExternalDTDDeclarations; 636 } 637 638 /** Returns whether adjacent text nodes should be merged together. 639 * @return Value of property mergeAdjacentText. 640 */ 641 public boolean isMergeAdjacentText() { 642 return mergeAdjacentText; 643 } 644 645 /** Sets whether or not adjacent text nodes should be merged 646 * together when parsing. 647 * @param mergeAdjacentText New value of property mergeAdjacentText. 648 */ 649 public void setMergeAdjacentText(boolean mergeAdjacentText) { 650 this.mergeAdjacentText = mergeAdjacentText; 651 } 652 653 654 /** Sets whether whitespace between element start and end tags should be ignored 655 * 656 * @return Value of property stripWhitespaceText. 657 */ 658 public boolean isStripWhitespaceText() { 659 return stripWhitespaceText; 660 } 661 662 /** Sets whether whitespace between element start and end tags should be ignored. 663 * 664 * @param stripWhitespaceText New value of property stripWhitespaceText. 665 */ 666 public void setStripWhitespaceText(boolean stripWhitespaceText) { 667 this.stripWhitespaceText = stripWhitespaceText; 668 } 669 670 // Implementation methods 671 //------------------------------------------------------------------------- 672 673 /** If the current text buffer contains any text then create a new 674 * text node with it and add it to the current element 675 */ 676 protected void completeCurrentTextNode() { 677 if ( stripWhitespaceText ) { 678 boolean whitespace = true; 679 for ( int i = 0, size = textBuffer.length(); i < size; i++ ) { 680 if ( ! Character.isWhitespace( textBuffer.charAt(i) ) ) { 681 whitespace = false; 682 break; 683 } 684 } 685 if ( ! whitespace ) { 686 currentElement.addText( textBuffer.toString() ); 687 } 688 } 689 else { 690 currentElement.addText( textBuffer.toString() ); 691 } 692 textBuffer.setLength(0); 693 textInTextBuffer = false; 694 } 695 696 /** @return the current document 697 */ 698 protected Document createDocument() { 699 Document document = documentFactory.createDocument(); 700 701 // set the EntityResolver 702 document.setEntityResolver(entityResolver); 703 if ( inputSource != null ) { 704 document.setName( inputSource.getSystemId() ); 705 } 706 707 return document; 708 } 709 710 /** a Strategy Method to determine if a given entity name is ignorable 711 */ 712 protected boolean isIgnorableEntity(String name) { 713 return "amp".equals( name ) 714 || "apos".equals( name ) 715 || "gt".equals( name ) 716 || "lt".equals( name ) 717 || "quot".equals( name ); 718 } 719 720 721 /** Add all namespaces declared before the startElement() SAX event 722 * to the current element so that they are available to child elements 723 * and attributes 724 */ 725 protected void addDeclaredNamespaces(Element element) { 726 Namespace elementNamespace = element.getNamespace(); 727 for ( int size = namespaceStack.size(); declaredNamespaceIndex < size; declaredNamespaceIndex++ ) { 728 Namespace namespace = namespaceStack.getNamespace(declaredNamespaceIndex); 729 if ( namespace != elementNamespace ) { 730 element.add( namespace ); 731 } 732 } 733 } 734 735 /** Add all the attributes to the given elements 736 */ 737 protected void addAttributes( Element element, Attributes attributes ) { 738 // XXXX: as an optimisation, we could deduce this value from the current 739 // SAX parser settings, the SAX namespaces-prefixes feature 740 741 boolean noNamespaceAttributes = false; 742 if ( element instanceof AbstractElement ) { 743 // optimised method 744 AbstractElement baseElement = (AbstractElement) element; 745 baseElement.setAttributes( attributes, namespaceStack, noNamespaceAttributes ); 746 } 747 else { 748 int size = attributes.getLength(); 749 for ( int i = 0; i < size; i++ ) { 750 String attributeQualifiedName = attributes.getQName(i); 751 if ( noNamespaceAttributes || ! attributeQualifiedName.startsWith( "xmlns" ) ) { 752 String attributeURI = attributes.getURI(i); 753 String attributeLocalName = attributes.getLocalName(i); 754 String attributeValue = attributes.getValue(i); 755 756 QName attributeQName = namespaceStack.getAttributeQName( 757 attributeURI, attributeLocalName, attributeQualifiedName 758 ); 759 element.addAttribute(attributeQName, attributeValue); 760 } 761 } 762 } 763 } 764 765 766 /** Adds an internal DTD declaration to the list of declarations */ 767 protected void addDTDDeclaration(Object declaration) { 768 if ( internalDTDDeclarations == null ) { 769 internalDTDDeclarations = new ArrayList(); 770 } 771 internalDTDDeclarations.add( declaration ); 772 } 773 774 /** Adds an external DTD declaration to the list of declarations */ 775 protected void addExternalDTDDeclaration(Object declaration) { 776 if ( externalDTDDeclarations == null ) { 777 externalDTDDeclarations = new ArrayList(); 778 } 779 externalDTDDeclarations.add( declaration ); 780 } 781 782 protected ElementStack createElementStack() { 783 return new ElementStack(); 784 } 785} 786 787 788 789 790/* 791 * Redistribution and use of this software and associated documentation 792 * ("Software"), with or without modification, are permitted provided 793 * that the following conditions are met: 794 * 795 * 1. Redistributions of source code must retain copyright 796 * statements and notices. Redistributions must also contain a 797 * copy of this document. 798 * 799 * 2. Redistributions in binary form must reproduce the 800 * above copyright notice, this list of conditions and the 801 * following disclaimer in the documentation and/or other 802 * materials provided with the distribution. 803 * 804 * 3. The name "DOM4J" must not be used to endorse or promote 805 * products derived from this Software without prior written 806 * permission of MetaStuff, Ltd. For written permission, 807 * please contact dom4j-info@metastuff.com. 808 * 809 * 4. Products derived from this Software may not be called "DOM4J" 810 * nor may "DOM4J" appear in their names without prior written 811 * permission of MetaStuff, Ltd. DOM4J is a registered 812 * trademark of MetaStuff, Ltd. 813 * 814 * 5. Due credit should be given to the DOM4J Project 815 * (http://dom4j.org/). 816 * 817 * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS 818 * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT 819 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 820 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 821 * METASTUFF, LTD. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 822 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 823 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 824 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 825 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 826 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 827 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 828 * OF THE POSSIBILITY OF SUCH DAMAGE. 829 * 830 * Copyright 2001 (C) MetaStuff, Ltd. All Rights Reserved. 831 * 832 * $Id: SAXContentHandler.java,v 1.42 2002/03/02 14:23:25 slehmann Exp $ 833 */