1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 /* 6 * The Apache Software License, Version 1.1 7 * 8 * 9 * Copyright (c) 1999-2002 The Apache Software Foundation. 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in 21 * the documentation and/or other materials provided with the 22 * distribution. 23 * 24 * 3. The end-user documentation included with the redistribution, 25 * if any, must include the following acknowledgment: 26 * "This product includes software developed by the 27 * Apache Software Foundation (http://www.apache.org/)." 28 * Alternately, this acknowledgment may appear in the software itself, 29 * if and wherever such third-party acknowledgments normally appear. 30 * 31 * 4. The names "Xerces" and "Apache Software Foundation" must 32 * not be used to endorse or promote products derived from this 33 * software without prior written permission. For written 34 * permission, please contact apache@apache.org. 35 * 36 * 5. Products derived from this software may not be called "Apache", 37 * nor may "Apache" appear in their name, without prior written 38 * permission of the Apache Software Foundation. 39 * 40 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 41 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 42 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 43 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 44 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 46 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 47 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 48 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 49 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 50 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * ==================================================================== 53 * 54 * This software consists of voluntary contributions made by many 55 * individuals on behalf of the Apache Software Foundation and was 56 * originally based on software copyright (c) 1999, International 57 * Business Machines, Inc., http://www.apache.org. For more 58 * information on the Apache Software Foundation, please see 59 * <http://www.apache.org/>. 60 */ 61 62 package com.sun.org.apache.xerces.internal.impl.dtd; 63 64 import java.util.ArrayList; 65 import java.util.HashMap; 66 import java.util.Iterator; 67 import java.util.Locale; 68 import java.util.Map; 69 import java.util.StringTokenizer; 70 71 import com.sun.org.apache.xerces.internal.impl.Constants; 72 import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter; 73 import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter; 74 import com.sun.org.apache.xerces.internal.util.SymbolTable; 75 import com.sun.org.apache.xerces.internal.util.XMLChar; 76 import com.sun.org.apache.xerces.internal.util.XMLSymbols; 77 import com.sun.org.apache.xerces.internal.xni.Augmentations; 78 import com.sun.org.apache.xerces.internal.xni.XMLDTDContentModelHandler; 79 import com.sun.org.apache.xerces.internal.xni.XMLDTDHandler; 80 import com.sun.org.apache.xerces.internal.xni.XMLLocator; 81 import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier; 82 import com.sun.org.apache.xerces.internal.xni.XMLString; 83 import com.sun.org.apache.xerces.internal.xni.XNIException; 84 import com.sun.org.apache.xerces.internal.xni.grammars.Grammar; 85 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarDescription; 86 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarPool; 87 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent; 88 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager; 89 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException; 90 import com.sun.org.apache.xerces.internal.xni.parser.XMLDTDContentModelFilter; 91 import com.sun.org.apache.xerces.internal.xni.parser.XMLDTDContentModelSource; 92 import com.sun.org.apache.xerces.internal.xni.parser.XMLDTDFilter; 93 import com.sun.org.apache.xerces.internal.xni.parser.XMLDTDSource; 94 95 /** 96 * The DTD processor. The processor implements a DTD 97 * filter: receiving DTD events from the DTD scanner; validating 98 * the content and structure; building a grammar, if applicable; 99 * and notifying the DTDHandler of the information resulting from the 100 * process. 101 * <p> 102 * This component requires the following features and properties from the 103 * component manager that uses it: 104 * <ul> 105 * <li>http://xml.org/sax/features/namespaces</li> 106 * <li>http://apache.org/xml/properties/internal/symbol-table</li> 107 * <li>http://apache.org/xml/properties/internal/error-reporter</li> 108 * <li>http://apache.org/xml/properties/internal/grammar-pool</li> 109 * <li>http://apache.org/xml/properties/internal/datatype-validator-factory</li> 110 * </ul> 111 * 112 * @xerces.internal 113 * 114 * @author Neil Graham, IBM 115 * 116 * @version $Id: XMLDTDProcessor.java,v 1.5 2010-11-01 04:39:42 joehw Exp $ 117 */ 118 public class XMLDTDProcessor 119 implements XMLComponent, XMLDTDFilter, XMLDTDContentModelFilter { 120 121 // 122 // Constants 123 // 124 125 /** Top level scope (-1). */ 126 private static final int TOP_LEVEL_SCOPE = -1; 127 128 // feature identifiers 129 130 /** Feature identifier: validation. */ 131 protected static final String VALIDATION = 132 Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE; 133 134 /** Feature identifier: notify character references. */ 135 protected static final String NOTIFY_CHAR_REFS = 136 Constants.XERCES_FEATURE_PREFIX + Constants.NOTIFY_CHAR_REFS_FEATURE; 137 138 /** Feature identifier: warn on duplicate attdef */ 139 protected static final String WARN_ON_DUPLICATE_ATTDEF = 140 Constants.XERCES_FEATURE_PREFIX +Constants.WARN_ON_DUPLICATE_ATTDEF_FEATURE; 141 142 /** Feature identifier: warn on undeclared element referenced in content model. */ 143 protected static final String WARN_ON_UNDECLARED_ELEMDEF = 144 Constants.XERCES_FEATURE_PREFIX + Constants.WARN_ON_UNDECLARED_ELEMDEF_FEATURE; 145 146 protected static final String PARSER_SETTINGS = 147 Constants.XERCES_FEATURE_PREFIX + Constants.PARSER_SETTINGS; 148 149 // property identifiers 150 151 /** Property identifier: symbol table. */ 152 protected static final String SYMBOL_TABLE = 153 Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; 154 155 /** Property identifier: error reporter. */ 156 protected static final String ERROR_REPORTER = 157 Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; 158 159 /** Property identifier: grammar pool. */ 160 protected static final String GRAMMAR_POOL = 161 Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY; 162 163 /** Property identifier: validator . */ 164 protected static final String DTD_VALIDATOR = 165 Constants.XERCES_PROPERTY_PREFIX + Constants.DTD_VALIDATOR_PROPERTY; 166 167 // recognized features and properties 168 169 /** Recognized features. */ 170 private static final String[] RECOGNIZED_FEATURES = { 171 VALIDATION, 172 WARN_ON_DUPLICATE_ATTDEF, 173 WARN_ON_UNDECLARED_ELEMDEF, 174 NOTIFY_CHAR_REFS, 175 }; 176 177 /** Feature defaults. */ 178 private static final Boolean[] FEATURE_DEFAULTS = { 179 null, 180 Boolean.FALSE, 181 Boolean.FALSE, 182 null, 183 }; 184 185 /** Recognized properties. */ 186 private static final String[] RECOGNIZED_PROPERTIES = { 187 SYMBOL_TABLE, 188 ERROR_REPORTER, 189 GRAMMAR_POOL, 190 DTD_VALIDATOR, 191 }; 192 193 /** Property defaults. */ 194 private static final Object[] PROPERTY_DEFAULTS = { 195 null, 196 null, 197 null, 198 null, 199 }; 200 201 // debugging 202 203 // 204 // Data 205 // 206 207 // features 208 209 /** Validation. */ 210 protected boolean fValidation; 211 212 /** Validation against only DTD */ 213 protected boolean fDTDValidation; 214 215 /** warn on duplicate attribute definition, this feature works only when validation is true */ 216 protected boolean fWarnDuplicateAttdef; 217 218 /** warn on undeclared element referenced in content model, this feature only works when valiation is true */ 219 protected boolean fWarnOnUndeclaredElemdef; 220 221 // properties 222 223 /** Symbol table. */ 224 protected SymbolTable fSymbolTable; 225 226 /** Error reporter. */ 227 protected XMLErrorReporter fErrorReporter; 228 229 /** Grammar bucket. */ 230 protected DTDGrammarBucket fGrammarBucket; 231 232 // the validator to which we look for our grammar bucket (the 233 // validator needs to hold the bucket so that it can initialize 234 // the grammar with details like whether it's for a standalone document... 235 protected XMLDTDValidator fValidator; 236 237 // the grammar pool we'll try to add the grammar to: 238 protected XMLGrammarPool fGrammarPool; 239 240 // what's our Locale? 241 protected Locale fLocale; 242 243 // handlers 244 245 /** DTD handler. */ 246 protected XMLDTDHandler fDTDHandler; 247 248 /** DTD source. */ 249 protected XMLDTDSource fDTDSource; 250 251 /** DTD content model handler. */ 252 protected XMLDTDContentModelHandler fDTDContentModelHandler; 253 254 /** DTD content model source. */ 255 protected XMLDTDContentModelSource fDTDContentModelSource; 256 257 // grammars 258 259 /** DTD Grammar. */ 260 protected DTDGrammar fDTDGrammar; 261 262 // state 263 264 /** Perform validation. */ 265 private boolean fPerformValidation; 266 267 /** True if in an ignore conditional section of the DTD. */ 268 protected boolean fInDTDIgnore; 269 270 // information regarding the current element 271 272 // validation states 273 274 /** Mixed. */ 275 private boolean fMixed; 276 277 // temporary variables 278 279 /** Temporary entity declaration. */ 280 private final XMLEntityDecl fEntityDecl = new XMLEntityDecl(); 281 282 /** Notation declaration hash. */ 283 private final HashMap fNDataDeclNotations = new HashMap(); 284 285 /** DTD element declaration name. */ 286 private String fDTDElementDeclName = null; 287 288 /** Mixed element type "hash". */ 289 private final ArrayList fMixedElementTypes = new ArrayList(); 290 291 /** Element declarations in DTD. */ 292 private final ArrayList fDTDElementDecls = new ArrayList(); 293 294 // to check for duplicate ID or ANNOTATION attribute declare in 295 // ATTLIST, and misc VCs 296 297 /** ID attribute names. */ 298 private HashMap fTableOfIDAttributeNames; 299 300 /** NOTATION attribute names. */ 301 private HashMap fTableOfNOTATIONAttributeNames; 302 303 /** NOTATION enumeration values. */ 304 private HashMap fNotationEnumVals; 305 306 // 307 // Constructors 308 // 309 310 /** Default constructor. */ 311 public XMLDTDProcessor() { 312 313 // initialize data 314 315 } // <init>() 316 317 // 318 // XMLComponent methods 319 // 320 321 /* 322 * Resets the component. The component can query the component manager 323 * about any features and properties that affect the operation of the 324 * component. 325 * 326 * @param componentManager The component manager. 327 * 328 * @throws SAXException Thrown by component on finitialization error. 329 * For example, if a feature or property is 330 * required for the operation of the component, the 331 * component manager may throw a 332 * SAXNotRecognizedException or a 333 * SAXNotSupportedException. 334 */ 335 public void reset(XMLComponentManager componentManager) throws XMLConfigurationException { 336 337 boolean parser_settings = componentManager.getFeature(PARSER_SETTINGS, true); 338 339 if (!parser_settings) { 340 // parser settings have not been changed 341 reset(); 342 return; 343 } 344 345 // sax features 346 fValidation = componentManager.getFeature(VALIDATION, false); 347 348 fDTDValidation = 349 !(componentManager 350 .getFeature( 351 Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE, false)); 352 353 // Xerces features 354 355 fWarnDuplicateAttdef = componentManager.getFeature(WARN_ON_DUPLICATE_ATTDEF, false); 356 fWarnOnUndeclaredElemdef = componentManager.getFeature(WARN_ON_UNDECLARED_ELEMDEF, false); 357 358 // get needed components 359 fErrorReporter = 360 (XMLErrorReporter) componentManager.getProperty( 361 Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY); 362 fSymbolTable = 363 (SymbolTable) componentManager.getProperty( 364 Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY); 365 366 fGrammarPool = (XMLGrammarPool) componentManager.getProperty(GRAMMAR_POOL, null); 367 368 try { 369 fValidator = (XMLDTDValidator) componentManager.getProperty(DTD_VALIDATOR, null); 370 } catch (ClassCastException e) { 371 fValidator = null; 372 } 373 // we get our grammarBucket from the validator... 374 if (fValidator != null) { 375 fGrammarBucket = fValidator.getGrammarBucket(); 376 } else { 377 fGrammarBucket = null; 378 } 379 reset(); 380 381 } // reset(XMLComponentManager) 382 383 protected void reset() { 384 // clear grammars 385 fDTDGrammar = null; 386 // initialize state 387 fInDTDIgnore = false; 388 389 fNDataDeclNotations.clear(); 390 391 // datatype validators 392 if (fValidation) { 393 394 if (fNotationEnumVals == null) { 395 fNotationEnumVals = new HashMap(); 396 } 397 fNotationEnumVals.clear(); 398 399 fTableOfIDAttributeNames = new HashMap(); 400 fTableOfNOTATIONAttributeNames = new HashMap(); 401 } 402 403 } 404 /** 405 * Returns a list of feature identifiers that are recognized by 406 * this component. This method may return null if no features 407 * are recognized by this component. 408 */ 409 public String[] getRecognizedFeatures() { 410 return (String[])(RECOGNIZED_FEATURES.clone()); 411 } // getRecognizedFeatures():String[] 412 413 /** 414 * Sets the state of a feature. This method is called by the component 415 * manager any time after reset when a feature changes state. 416 * <p> 417 * <strong>Note:</strong> Components should silently ignore features 418 * that do not affect the operation of the component. 419 * 420 * @param featureId The feature identifier. 421 * @param state The state of the feature. 422 * 423 * @throws SAXNotRecognizedException The component should not throw 424 * this exception. 425 * @throws SAXNotSupportedException The component should not throw 426 * this exception. 427 */ 428 public void setFeature(String featureId, boolean state) 429 throws XMLConfigurationException { 430 } // setFeature(String,boolean) 431 432 /** 433 * Returns a list of property identifiers that are recognized by 434 * this component. This method may return null if no properties 435 * are recognized by this component. 436 */ 437 public String[] getRecognizedProperties() { 438 return (String[])(RECOGNIZED_PROPERTIES.clone()); 439 } // getRecognizedProperties():String[] 440 441 /** 442 * Sets the value of a property. This method is called by the component 443 * manager any time after reset when a property changes value. 444 * <p> 445 * <strong>Note:</strong> Components should silently ignore properties 446 * that do not affect the operation of the component. 447 * 448 * @param propertyId The property identifier. 449 * @param value The value of the property. 450 * 451 * @throws SAXNotRecognizedException The component should not throw 452 * this exception. 453 * @throws SAXNotSupportedException The component should not throw 454 * this exception. 455 */ 456 public void setProperty(String propertyId, Object value) 457 throws XMLConfigurationException { 458 } // setProperty(String,Object) 459 460 /** 461 * Returns the default state for a feature, or null if this 462 * component does not want to report a default value for this 463 * feature. 464 * 465 * @param featureId The feature identifier. 466 * 467 * @since Xerces 2.2.0 468 */ 469 public Boolean getFeatureDefault(String featureId) { 470 for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) { 471 if (RECOGNIZED_FEATURES[i].equals(featureId)) { 472 return FEATURE_DEFAULTS[i]; 473 } 474 } 475 return null; 476 } // getFeatureDefault(String):Boolean 477 478 /** 479 * Returns the default state for a property, or null if this 480 * component does not want to report a default value for this 481 * property. 482 * 483 * @param propertyId The property identifier. 484 * 485 * @since Xerces 2.2.0 486 */ 487 public Object getPropertyDefault(String propertyId) { 488 for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) { 489 if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) { 490 return PROPERTY_DEFAULTS[i]; 491 } 492 } 493 return null; 494 } // getPropertyDefault(String):Object 495 496 // 497 // XMLDTDSource methods 498 // 499 500 /** 501 * Sets the DTD handler. 502 * 503 * @param dtdHandler The DTD handler. 504 */ 505 public void setDTDHandler(XMLDTDHandler dtdHandler) { 506 fDTDHandler = dtdHandler; 507 } // setDTDHandler(XMLDTDHandler) 508 509 /** 510 * Returns the DTD handler. 511 * 512 * @return The DTD handler. 513 */ 514 public XMLDTDHandler getDTDHandler() { 515 return fDTDHandler; 516 } // getDTDHandler(): XMLDTDHandler 517 518 // 519 // XMLDTDContentModelSource methods 520 // 521 522 /** 523 * Sets the DTD content model handler. 524 * 525 * @param dtdContentModelHandler The DTD content model handler. 526 */ 527 public void setDTDContentModelHandler(XMLDTDContentModelHandler dtdContentModelHandler) { 528 fDTDContentModelHandler = dtdContentModelHandler; 529 } // setDTDContentModelHandler(XMLDTDContentModelHandler) 530 531 /** 532 * Gets the DTD content model handler. 533 * 534 * @return dtdContentModelHandler The DTD content model handler. 535 */ 536 public XMLDTDContentModelHandler getDTDContentModelHandler() { 537 return fDTDContentModelHandler; 538 } // getDTDContentModelHandler(): XMLDTDContentModelHandler 539 540 // 541 // XMLDTDContentModelHandler and XMLDTDHandler methods 542 // 543 544 /** 545 * The start of the DTD external subset. 546 * 547 * @param augs Additional information that may include infoset 548 * augmentations. 549 * 550 * @throws XNIException Thrown by handler to signal an error. 551 */ 552 public void startExternalSubset(XMLResourceIdentifier identifier, 553 Augmentations augs) throws XNIException { 554 if(fDTDGrammar != null) 555 fDTDGrammar.startExternalSubset(identifier, augs); 556 if(fDTDHandler != null){ 557 fDTDHandler.startExternalSubset(identifier, augs); 558 } 559 } 560 561 /** 562 * The end of the DTD external subset. 563 * 564 * @param augs Additional information that may include infoset 565 * augmentations. 566 * 567 * @throws XNIException Thrown by handler to signal an error. 568 */ 569 public void endExternalSubset(Augmentations augs) throws XNIException { 570 if(fDTDGrammar != null) 571 fDTDGrammar.endExternalSubset(augs); 572 if(fDTDHandler != null){ 573 fDTDHandler.endExternalSubset(augs); 574 } 575 } 576 577 /** 578 * Check standalone entity reference. 579 * Made static to make common between the validator and loader. 580 * 581 * @param name 582 *@param grammar grammar to which entity belongs 583 * @param tempEntityDecl empty entity declaration to put results in 584 * @param errorReporter error reporter to send errors to 585 * 586 * @throws XNIException Thrown by application to signal an error. 587 */ 588 protected static void checkStandaloneEntityRef(String name, DTDGrammar grammar, 589 XMLEntityDecl tempEntityDecl, XMLErrorReporter errorReporter) throws XNIException { 590 // check VC: Standalone Document Declartion, entities references appear in the document. 591 int entIndex = grammar.getEntityDeclIndex(name); 592 if (entIndex > -1) { 593 grammar.getEntityDecl(entIndex, tempEntityDecl); 594 if (tempEntityDecl.inExternal) { 595 errorReporter.reportError( XMLMessageFormatter.XML_DOMAIN, 596 "MSG_REFERENCE_TO_EXTERNALLY_DECLARED_ENTITY_WHEN_STANDALONE", 597 new Object[]{name}, XMLErrorReporter.SEVERITY_ERROR); 598 } 599 } 600 } 601 602 /** 603 * A comment. 604 * 605 * @param text The text in the comment. 606 * @param augs Additional information that may include infoset augmentations 607 * 608 * @throws XNIException Thrown by application to signal an error. 609 */ 610 public void comment(XMLString text, Augmentations augs) throws XNIException { 611 612 // call handlers 613 if(fDTDGrammar != null) 614 fDTDGrammar.comment(text, augs); 615 if (fDTDHandler != null) { 616 fDTDHandler.comment(text, augs); 617 } 618 619 } // comment(XMLString) 620 621 622 /** 623 * A processing instruction. Processing instructions consist of a 624 * target name and, optionally, text data. The data is only meaningful 625 * to the application. 626 * <p> 627 * Typically, a processing instruction's data will contain a series 628 * of pseudo-attributes. These pseudo-attributes follow the form of 629 * element attributes but are <strong>not</strong> parsed or presented 630 * to the application as anything other than text. The application is 631 * responsible for parsing the data. 632 * 633 * @param target The target. 634 * @param data The data or null if none specified. 635 * @param augs Additional information that may include infoset augmentations 636 * 637 * @throws XNIException Thrown by handler to signal an error. 638 */ 639 public void processingInstruction(String target, XMLString data, Augmentations augs) 640 throws XNIException { 641 642 // call handlers 643 if(fDTDGrammar != null) 644 fDTDGrammar.processingInstruction(target, data, augs); 645 if (fDTDHandler != null) { 646 fDTDHandler.processingInstruction(target, data, augs); 647 } 648 } // processingInstruction(String,XMLString) 649 650 // 651 // XMLDTDHandler methods 652 // 653 654 /** 655 * The start of the DTD. 656 * 657 * @param locator The document locator, or null if the document 658 * location cannot be reported during the parsing of 659 * the document DTD. However, it is <em>strongly</em> 660 * recommended that a locator be supplied that can 661 * at least report the base system identifier of the 662 * DTD. 663 * @param augs Additional information that may include infoset 664 * augmentations. 665 * 666 * @throws XNIException Thrown by handler to signal an error. 667 */ 668 public void startDTD(XMLLocator locator, Augmentations augs) throws XNIException { 669 670 671 // initialize state 672 fNDataDeclNotations.clear(); 673 fDTDElementDecls.clear(); 674 675 // the grammar bucket's DTDGrammar will now be the 676 // one we want, whether we're constructing it or not. 677 // if we're not constructing it, then we should not have a reference 678 // to it! 679 if( !fGrammarBucket.getActiveGrammar().isImmutable()) { 680 fDTDGrammar = fGrammarBucket.getActiveGrammar(); 681 } 682 683 // call handlers 684 if(fDTDGrammar != null ) 685 fDTDGrammar.startDTD(locator, augs); 686 if (fDTDHandler != null) { 687 fDTDHandler.startDTD(locator, augs); 688 } 689 690 } // startDTD(XMLLocator) 691 692 /** 693 * Characters within an IGNORE conditional section. 694 * 695 * @param text The ignored text. 696 * @param augs Additional information that may include infoset 697 * augmentations. 698 * 699 * @throws XNIException Thrown by handler to signal an error. 700 */ 701 public void ignoredCharacters(XMLString text, Augmentations augs) throws XNIException { 702 703 // ignored characters in DTD 704 if(fDTDGrammar != null ) 705 fDTDGrammar.ignoredCharacters(text, augs); 706 if (fDTDHandler != null) { 707 fDTDHandler.ignoredCharacters(text, augs); 708 } 709 } 710 711 /** 712 * Notifies of the presence of a TextDecl line in an entity. If present, 713 * this method will be called immediately following the startParameterEntity call. 714 * <p> 715 * <strong>Note:</strong> This method is only called for external 716 * parameter entities referenced in the DTD. 717 * 718 * @param version The XML version, or null if not specified. 719 * @param encoding The IANA encoding name of the entity. 720 * @param augs Additional information that may include infoset 721 * augmentations. 722 * 723 * @throws XNIException Thrown by handler to signal an error. 724 */ 725 public void textDecl(String version, String encoding, Augmentations augs) throws XNIException { 726 727 // call handlers 728 if(fDTDGrammar != null ) 729 fDTDGrammar.textDecl(version, encoding, augs); 730 if (fDTDHandler != null) { 731 fDTDHandler.textDecl(version, encoding, augs); 732 } 733 } 734 735 /** 736 * This method notifies of the start of a parameter entity. The parameter 737 * entity name start with a '%' character. 738 * 739 * @param name The name of the parameter entity. 740 * @param identifier The resource identifier. 741 * @param encoding The auto-detected IANA encoding name of the entity 742 * stream. This value will be null in those situations 743 * where the entity encoding is not auto-detected (e.g. 744 * internal parameter entities). 745 * @param augs Additional information that may include infoset 746 * augmentations. 747 * 748 * @throws XNIException Thrown by handler to signal an error. 749 */ 750 public void startParameterEntity(String name, 751 XMLResourceIdentifier identifier, 752 String encoding, 753 Augmentations augs) throws XNIException { 754 755 if (fPerformValidation && fDTDGrammar != null && 756 fGrammarBucket.getStandalone()) { 757 checkStandaloneEntityRef(name, fDTDGrammar, fEntityDecl, fErrorReporter); 758 } 759 // call handlers 760 if(fDTDGrammar != null ) 761 fDTDGrammar.startParameterEntity(name, identifier, encoding, augs); 762 if (fDTDHandler != null) { 763 fDTDHandler.startParameterEntity(name, identifier, encoding, augs); 764 } 765 } 766 767 /** 768 * This method notifies the end of a parameter entity. Parameter entity 769 * names begin with a '%' character. 770 * 771 * @param name The name of the parameter entity. 772 * @param augs Additional information that may include infoset 773 * augmentations. 774 * 775 * @throws XNIException Thrown by handler to signal an error. 776 */ 777 public void endParameterEntity(String name, Augmentations augs) throws XNIException { 778 779 // call handlers 780 if(fDTDGrammar != null ) 781 fDTDGrammar.endParameterEntity(name, augs); 782 if (fDTDHandler != null) { 783 fDTDHandler.endParameterEntity(name, augs); 784 } 785 } 786 787 /** 788 * An element declaration. 789 * 790 * @param name The name of the element. 791 * @param contentModel The element content model. 792 * @param augs Additional information that may include infoset 793 * augmentations. 794 * 795 * @throws XNIException Thrown by handler to signal an error. 796 */ 797 public void elementDecl(String name, String contentModel, Augmentations augs) 798 throws XNIException { 799 800 //check VC: Unique Element Declaration 801 if (fValidation) { 802 if (fDTDElementDecls.contains(name)) { 803 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 804 "MSG_ELEMENT_ALREADY_DECLARED", 805 new Object[]{ name}, 806 XMLErrorReporter.SEVERITY_ERROR); 807 } 808 else { 809 fDTDElementDecls.add(name); 810 } 811 } 812 813 // call handlers 814 if(fDTDGrammar != null ) 815 fDTDGrammar.elementDecl(name, contentModel, augs); 816 if (fDTDHandler != null) { 817 fDTDHandler.elementDecl(name, contentModel, augs); 818 } 819 820 } // elementDecl(String,String) 821 822 /** 823 * The start of an attribute list. 824 * 825 * @param elementName The name of the element that this attribute 826 * list is associated with. 827 * @param augs Additional information that may include infoset 828 * augmentations. 829 * 830 * @throws XNIException Thrown by handler to signal an error. 831 */ 832 public void startAttlist(String elementName, Augmentations augs) 833 throws XNIException { 834 835 // call handlers 836 if(fDTDGrammar != null ) 837 fDTDGrammar.startAttlist(elementName, augs); 838 if (fDTDHandler != null) { 839 fDTDHandler.startAttlist(elementName, augs); 840 } 841 842 } // startAttlist(String) 843 844 /** 845 * An attribute declaration. 846 * 847 * @param elementName The name of the element that this attribute 848 * is associated with. 849 * @param attributeName The name of the attribute. 850 * @param type The attribute type. This value will be one of 851 * the following: "CDATA", "ENTITY", "ENTITIES", 852 * "ENUMERATION", "ID", "IDREF", "IDREFS", 853 * "NMTOKEN", "NMTOKENS", or "NOTATION". 854 * @param enumeration If the type has the value "ENUMERATION" or 855 * "NOTATION", this array holds the allowed attribute 856 * values; otherwise, this array is null. 857 * @param defaultType The attribute default type. This value will be 858 * one of the following: "#FIXED", "#IMPLIED", 859 * "#REQUIRED", or null. 860 * @param defaultValue The attribute default value, or null if no 861 * default value is specified. 862 * @param nonNormalizedDefaultValue The attribute default value with no normalization 863 * performed, or null if no default value is specified. 864 * @param augs Additional information that may include infoset 865 * augmentations. 866 * 867 * @throws XNIException Thrown by handler to signal an error. 868 */ 869 public void attributeDecl(String elementName, String attributeName, 870 String type, String[] enumeration, 871 String defaultType, XMLString defaultValue, 872 XMLString nonNormalizedDefaultValue, Augmentations augs) throws XNIException { 873 874 if (type != XMLSymbols.fCDATASymbol && defaultValue != null) { 875 normalizeDefaultAttrValue(defaultValue); 876 } 877 878 if (fValidation) { 879 880 boolean duplicateAttributeDef = false ; 881 882 //Get Grammar index to grammar array 883 DTDGrammar grammar = (fDTDGrammar != null? fDTDGrammar:fGrammarBucket.getActiveGrammar()); 884 int elementIndex = grammar.getElementDeclIndex( elementName); 885 if (grammar.getAttributeDeclIndex(elementIndex, attributeName) != -1) { 886 //more than one attribute definition is provided for the same attribute of a given element type. 887 duplicateAttributeDef = true ; 888 889 //this feature works only when validation is true. 890 if(fWarnDuplicateAttdef){ 891 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 892 "MSG_DUPLICATE_ATTRIBUTE_DEFINITION", 893 new Object[]{ elementName, attributeName }, 894 XMLErrorReporter.SEVERITY_WARNING ); 895 } 896 } 897 898 899 // 900 // a) VC: One ID per Element Type, If duplicate ID attribute 901 // b) VC: ID attribute Default. if there is a declareared attribute 902 // default for ID it should be of type #IMPLIED or #REQUIRED 903 if (type == XMLSymbols.fIDSymbol) { 904 if (defaultValue != null && defaultValue.length != 0) { 905 if (defaultType == null || 906 !(defaultType == XMLSymbols.fIMPLIEDSymbol || 907 defaultType == XMLSymbols.fREQUIREDSymbol)) { 908 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 909 "IDDefaultTypeInvalid", 910 new Object[]{ attributeName}, 911 XMLErrorReporter.SEVERITY_ERROR); 912 } 913 } 914 915 if (!fTableOfIDAttributeNames.containsKey(elementName)) { 916 fTableOfIDAttributeNames.put(elementName, attributeName); 917 } 918 else { 919 //we should not report an error, when there is duplicate attribute definition for given element type 920 //according to XML 1.0 spec, When more than one definition is provided for the same attribute of a given 921 //element type, the first declaration is binding and later declaration are *ignored*. So processor should 922 //ignore the second declarations, however an application would be warned of the duplicate attribute defintion 923 // if http://apache.org/xml/features/validation/warn-on-duplicate-attdef feature is set to true, 924 // one typical case where this could be a problem, when any XML file 925 // provide the ID type information through internal subset so that it is available to the parser which read 926 //only internal subset. Now that attribute declaration(ID Type) can again be part of external parsed entity 927 //referenced. At that time if parser doesn't make this distinction it will throw an error for VC One ID per 928 //Element Type, which (second defintion) actually should be ignored. Application behavior may differ on the 929 //basis of error or warning thrown. - nb. 930 931 if(!duplicateAttributeDef){ 932 String previousIDAttributeName = (String)fTableOfIDAttributeNames.get( elementName );//rule a) 933 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 934 "MSG_MORE_THAN_ONE_ID_ATTRIBUTE", 935 new Object[]{ elementName, previousIDAttributeName, attributeName}, 936 XMLErrorReporter.SEVERITY_ERROR); 937 } 938 } 939 } 940 941 // 942 // VC: One Notation Per Element Type, should check if there is a 943 // duplicate NOTATION attribute 944 945 if (type == XMLSymbols.fNOTATIONSymbol) { 946 // VC: Notation Attributes: all notation names in the 947 // (attribute) declaration must be declared. 948 for (int i=0; i<enumeration.length; i++) { 949 fNotationEnumVals.put(enumeration[i], attributeName); 950 } 951 952 if (fTableOfNOTATIONAttributeNames.containsKey( elementName ) == false) { 953 fTableOfNOTATIONAttributeNames.put( elementName, attributeName); 954 } 955 else { 956 //we should not report an error, when there is duplicate attribute definition for given element type 957 //according to XML 1.0 spec, When more than one definition is provided for the same attribute of a given 958 //element type, the first declaration is binding and later declaration are *ignored*. So processor should 959 //ignore the second declarations, however an application would be warned of the duplicate attribute definition 960 // if http://apache.org/xml/features/validation/warn-on-duplicate-attdef feature is set to true, Application behavior may differ on the basis of error or 961 //warning thrown. - nb. 962 963 if(!duplicateAttributeDef){ 964 965 String previousNOTATIONAttributeName = (String) fTableOfNOTATIONAttributeNames.get( elementName ); 966 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 967 "MSG_MORE_THAN_ONE_NOTATION_ATTRIBUTE", 968 new Object[]{ elementName, previousNOTATIONAttributeName, attributeName}, 969 XMLErrorReporter.SEVERITY_ERROR); 970 } 971 } 972 } 973 974 // VC: No Duplicate Tokens 975 // XML 1.0 SE Errata - E2 976 if (type == XMLSymbols.fENUMERATIONSymbol || type == XMLSymbols.fNOTATIONSymbol) { 977 outer: 978 for (int i = 0; i < enumeration.length; ++i) { 979 for (int j = i + 1; j < enumeration.length; ++j) { 980 if (enumeration[i].equals(enumeration[j])) { 981 // Only report the first uniqueness violation. There could be others, 982 // but additional overhead would be incurred tracking unique tokens 983 // that have already been encountered. -- mrglavas 984 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 985 type == XMLSymbols.fENUMERATIONSymbol 986 ? "MSG_DISTINCT_TOKENS_IN_ENUMERATION" 987 : "MSG_DISTINCT_NOTATION_IN_ENUMERATION", 988 new Object[]{ elementName, enumeration[i], attributeName }, 989 XMLErrorReporter.SEVERITY_ERROR); 990 break outer; 991 } 992 } 993 } 994 } 995 996 // VC: Attribute Default Legal 997 boolean ok = true; 998 if (defaultValue != null && 999 (defaultType == null || 1000 (defaultType != null && defaultType == XMLSymbols.fFIXEDSymbol))) { 1001 1002 String value = defaultValue.toString(); 1003 if (type == XMLSymbols.fNMTOKENSSymbol || 1004 type == XMLSymbols.fENTITIESSymbol || 1005 type == XMLSymbols.fIDREFSSymbol) { 1006 1007 StringTokenizer tokenizer = new StringTokenizer(value," "); 1008 if (tokenizer.hasMoreTokens()) { 1009 while (true) { 1010 String nmtoken = tokenizer.nextToken(); 1011 if (type == XMLSymbols.fNMTOKENSSymbol) { 1012 if (!isValidNmtoken(nmtoken)) { 1013 ok = false; 1014 break; 1015 } 1016 } 1017 else if (type == XMLSymbols.fENTITIESSymbol || 1018 type == XMLSymbols.fIDREFSSymbol) { 1019 if (!isValidName(nmtoken)) { 1020 ok = false; 1021 break; 1022 } 1023 } 1024 if (!tokenizer.hasMoreTokens()) { 1025 break; 1026 } 1027 } 1028 } 1029 1030 } 1031 else { 1032 if (type == XMLSymbols.fENTITYSymbol || 1033 type == XMLSymbols.fIDSymbol || 1034 type == XMLSymbols.fIDREFSymbol || 1035 type == XMLSymbols.fNOTATIONSymbol) { 1036 1037 if (!isValidName(value)) { 1038 ok = false; 1039 } 1040 1041 } 1042 else if (type == XMLSymbols.fNMTOKENSymbol || 1043 type == XMLSymbols.fENUMERATIONSymbol) { 1044 1045 if (!isValidNmtoken(value)) { 1046 ok = false; 1047 } 1048 } 1049 1050 if (type == XMLSymbols.fNOTATIONSymbol || 1051 type == XMLSymbols.fENUMERATIONSymbol) { 1052 ok = false; 1053 for (int i=0; i<enumeration.length; i++) { 1054 if (defaultValue.equals(enumeration[i])) { 1055 ok = true; 1056 } 1057 } 1058 } 1059 1060 } 1061 if (!ok) { 1062 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1063 "MSG_ATT_DEFAULT_INVALID", 1064 new Object[]{attributeName, value}, 1065 XMLErrorReporter.SEVERITY_ERROR); 1066 } 1067 } 1068 } 1069 1070 // call handlers 1071 if(fDTDGrammar != null) 1072 fDTDGrammar.attributeDecl(elementName, attributeName, 1073 type, enumeration, 1074 defaultType, defaultValue, nonNormalizedDefaultValue, augs); 1075 if (fDTDHandler != null) { 1076 fDTDHandler.attributeDecl(elementName, attributeName, 1077 type, enumeration, 1078 defaultType, defaultValue, nonNormalizedDefaultValue, augs); 1079 } 1080 1081 } // attributeDecl(String,String,String,String[],String,XMLString, XMLString, Augmentations) 1082 1083 /** 1084 * The end of an attribute list. 1085 * 1086 * @param augs Additional information that may include infoset 1087 * augmentations. 1088 * 1089 * @throws XNIException Thrown by handler to signal an error. 1090 */ 1091 public void endAttlist(Augmentations augs) throws XNIException { 1092 1093 // call handlers 1094 if(fDTDGrammar != null) 1095 fDTDGrammar.endAttlist(augs); 1096 if (fDTDHandler != null) { 1097 fDTDHandler.endAttlist(augs); 1098 } 1099 1100 } // endAttlist() 1101 1102 /** 1103 * An internal entity declaration. 1104 * 1105 * @param name The name of the entity. Parameter entity names start with 1106 * '%', whereas the name of a general entity is just the 1107 * entity name. 1108 * @param text The value of the entity. 1109 * @param nonNormalizedText The non-normalized value of the entity. This 1110 * value contains the same sequence of characters that was in 1111 * the internal entity declaration, without any entity 1112 * references expanded. 1113 * @param augs Additional information that may include infoset 1114 * augmentations. 1115 * 1116 * @throws XNIException Thrown by handler to signal an error. 1117 */ 1118 public void internalEntityDecl(String name, XMLString text, 1119 XMLString nonNormalizedText, 1120 Augmentations augs) throws XNIException { 1121 1122 DTDGrammar grammar = (fDTDGrammar != null? fDTDGrammar: fGrammarBucket.getActiveGrammar()); 1123 int index = grammar.getEntityDeclIndex(name) ; 1124 1125 //If the same entity is declared more than once, the first declaration 1126 //encountered is binding, SAX requires only effective(first) declaration 1127 //to be reported to the application 1128 1129 //REVISIT: Does it make sense to pass duplicate Entity information across 1130 //the pipeline -- nb? 1131 1132 //its a new entity and hasn't been declared. 1133 if(index == -1){ 1134 //store internal entity declaration in grammar 1135 if(fDTDGrammar != null) 1136 fDTDGrammar.internalEntityDecl(name, text, nonNormalizedText, augs); 1137 // call handlers 1138 if (fDTDHandler != null) { 1139 fDTDHandler.internalEntityDecl(name, text, nonNormalizedText, augs); 1140 } 1141 } 1142 1143 } // internalEntityDecl(String,XMLString,XMLString) 1144 1145 1146 /** 1147 * An external entity declaration. 1148 * 1149 * @param name The name of the entity. Parameter entity names start 1150 * with '%', whereas the name of a general entity is just 1151 * the entity name. 1152 * @param identifier An object containing all location information 1153 * pertinent to this external entity. 1154 * @param augs Additional information that may include infoset 1155 * augmentations. 1156 * 1157 * @throws XNIException Thrown by handler to signal an error. 1158 */ 1159 public void externalEntityDecl(String name, XMLResourceIdentifier identifier, 1160 Augmentations augs) throws XNIException { 1161 1162 DTDGrammar grammar = (fDTDGrammar != null? fDTDGrammar: fGrammarBucket.getActiveGrammar()); 1163 int index = grammar.getEntityDeclIndex(name) ; 1164 1165 //If the same entity is declared more than once, the first declaration 1166 //encountered is binding, SAX requires only effective(first) declaration 1167 //to be reported to the application 1168 1169 //REVISIT: Does it make sense to pass duplicate entity information across 1170 //the pipeline -- nb? 1171 1172 //its a new entity and hasn't been declared. 1173 if(index == -1){ 1174 //store external entity declaration in grammar 1175 if(fDTDGrammar != null) 1176 fDTDGrammar.externalEntityDecl(name, identifier, augs); 1177 // call handlers 1178 if (fDTDHandler != null) { 1179 fDTDHandler.externalEntityDecl(name, identifier, augs); 1180 } 1181 } 1182 1183 } // externalEntityDecl(String,XMLResourceIdentifier, Augmentations) 1184 1185 /** 1186 * An unparsed entity declaration. 1187 * 1188 * @param name The name of the entity. 1189 * @param identifier An object containing all location information 1190 * pertinent to this entity. 1191 * @param notation The name of the notation. 1192 * @param augs Additional information that may include infoset 1193 * augmentations. 1194 * 1195 * @throws XNIException Thrown by handler to signal an error. 1196 */ 1197 public void unparsedEntityDecl(String name, XMLResourceIdentifier identifier, 1198 String notation, 1199 Augmentations augs) throws XNIException { 1200 1201 // VC: Notation declared, in the production of NDataDecl 1202 if (fValidation) { 1203 fNDataDeclNotations.put(name, notation); 1204 } 1205 1206 // call handlers 1207 if(fDTDGrammar != null) 1208 fDTDGrammar.unparsedEntityDecl(name, identifier, notation, augs); 1209 if (fDTDHandler != null) { 1210 fDTDHandler.unparsedEntityDecl(name, identifier, notation, augs); 1211 } 1212 1213 } // unparsedEntityDecl(String,XMLResourceIdentifier,String,Augmentations) 1214 1215 /** 1216 * A notation declaration 1217 * 1218 * @param name The name of the notation. 1219 * @param identifier An object containing all location information 1220 * pertinent to this notation. 1221 * @param augs Additional information that may include infoset 1222 * augmentations. 1223 * 1224 * @throws XNIException Thrown by handler to signal an error. 1225 */ 1226 public void notationDecl(String name, XMLResourceIdentifier identifier, 1227 Augmentations augs) throws XNIException { 1228 1229 // VC: Unique Notation Name 1230 if (fValidation) { 1231 DTDGrammar grammar = (fDTDGrammar != null ? fDTDGrammar : fGrammarBucket.getActiveGrammar()); 1232 if (grammar.getNotationDeclIndex(name) != -1) { 1233 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1234 "UniqueNotationName", 1235 new Object[]{name}, 1236 XMLErrorReporter.SEVERITY_ERROR); 1237 } 1238 } 1239 1240 // call handlers 1241 if(fDTDGrammar != null) 1242 fDTDGrammar.notationDecl(name, identifier, augs); 1243 if (fDTDHandler != null) { 1244 fDTDHandler.notationDecl(name, identifier, augs); 1245 } 1246 1247 } // notationDecl(String,XMLResourceIdentifier, Augmentations) 1248 1249 /** 1250 * The start of a conditional section. 1251 * 1252 * @param type The type of the conditional section. This value will 1253 * either be CONDITIONAL_INCLUDE or CONDITIONAL_IGNORE. 1254 * @param augs Additional information that may include infoset 1255 * augmentations. 1256 * 1257 * @throws XNIException Thrown by handler to signal an error. 1258 * 1259 * @see #CONDITIONAL_INCLUDE 1260 * @see #CONDITIONAL_IGNORE 1261 */ 1262 public void startConditional(short type, Augmentations augs) throws XNIException { 1263 1264 // set state 1265 fInDTDIgnore = type == XMLDTDHandler.CONDITIONAL_IGNORE; 1266 1267 // call handlers 1268 if(fDTDGrammar != null) 1269 fDTDGrammar.startConditional(type, augs); 1270 if (fDTDHandler != null) { 1271 fDTDHandler.startConditional(type, augs); 1272 } 1273 1274 } // startConditional(short) 1275 1276 /** 1277 * The end of a conditional section. 1278 * 1279 * @param augs Additional information that may include infoset 1280 * augmentations. 1281 * 1282 * @throws XNIException Thrown by handler to signal an error. 1283 */ 1284 public void endConditional(Augmentations augs) throws XNIException { 1285 1286 // set state 1287 fInDTDIgnore = false; 1288 1289 // call handlers 1290 if(fDTDGrammar != null) 1291 fDTDGrammar.endConditional(augs); 1292 if (fDTDHandler != null) { 1293 fDTDHandler.endConditional(augs); 1294 } 1295 1296 } // endConditional() 1297 1298 /** 1299 * The end of the DTD. 1300 * 1301 * @param augs Additional information that may include infoset 1302 * augmentations. 1303 * 1304 * @throws XNIException Thrown by handler to signal an error. 1305 */ 1306 public void endDTD(Augmentations augs) throws XNIException { 1307 1308 1309 // save grammar 1310 if(fDTDGrammar != null) { 1311 fDTDGrammar.endDTD(augs); 1312 if(fGrammarPool != null) 1313 fGrammarPool.cacheGrammars(XMLGrammarDescription.XML_DTD, new Grammar[] {fDTDGrammar}); 1314 } 1315 if (fValidation) { 1316 DTDGrammar grammar = (fDTDGrammar != null? fDTDGrammar: fGrammarBucket.getActiveGrammar()); 1317 1318 // VC : Notation Declared. for external entity declaration [Production 76]. 1319 Iterator entities = fNDataDeclNotations.entrySet().iterator(); 1320 while (entities.hasNext()) { 1321 Map.Entry entry = (Map.Entry) entities.next(); 1322 String notation = (String) entry.getValue(); 1323 if (grammar.getNotationDeclIndex(notation) == -1) { 1324 String entity = (String) entry.getKey(); 1325 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1326 "MSG_NOTATION_NOT_DECLARED_FOR_UNPARSED_ENTITYDECL", 1327 new Object[]{entity, notation}, 1328 XMLErrorReporter.SEVERITY_ERROR); 1329 } 1330 } 1331 1332 // VC: Notation Attributes: 1333 // all notation names in the (attribute) declaration must be declared. 1334 Iterator notationVals = fNotationEnumVals.entrySet().iterator(); 1335 while (notationVals.hasNext()) { 1336 Map.Entry entry = (Map.Entry) notationVals.next(); 1337 String notation = (String) entry.getKey(); 1338 if (grammar.getNotationDeclIndex(notation) == -1) { 1339 String attributeName = (String) entry.getValue(); 1340 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1341 "MSG_NOTATION_NOT_DECLARED_FOR_NOTATIONTYPE_ATTRIBUTE", 1342 new Object[]{attributeName, notation}, 1343 XMLErrorReporter.SEVERITY_ERROR); 1344 } 1345 } 1346 1347 // VC: No Notation on Empty Element 1348 // An attribute of type NOTATION must not be declared on an element declared EMPTY. 1349 Iterator elementsWithNotations = fTableOfNOTATIONAttributeNames.entrySet().iterator(); 1350 while (elementsWithNotations.hasNext()) { 1351 Map.Entry entry = (Map.Entry) elementsWithNotations.next(); 1352 String elementName = (String) entry.getKey(); 1353 int elementIndex = grammar.getElementDeclIndex(elementName); 1354 if (grammar.getContentSpecType(elementIndex) == XMLElementDecl.TYPE_EMPTY) { 1355 String attributeName = (String) entry.getValue(); 1356 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1357 "NoNotationOnEmptyElement", 1358 new Object[]{elementName, attributeName}, 1359 XMLErrorReporter.SEVERITY_ERROR); 1360 } 1361 } 1362 1363 // should be safe to release these references 1364 fTableOfIDAttributeNames = null; 1365 fTableOfNOTATIONAttributeNames = null; 1366 1367 // check whether each element referenced in a content model is declared 1368 if (fWarnOnUndeclaredElemdef) { 1369 checkDeclaredElements(grammar); 1370 } 1371 } 1372 1373 // call handlers 1374 if (fDTDHandler != null) { 1375 fDTDHandler.endDTD(augs); 1376 } 1377 1378 } // endDTD() 1379 1380 // sets the XMLDTDSource of this handler 1381 public void setDTDSource(XMLDTDSource source ) { 1382 fDTDSource = source; 1383 } // setDTDSource(XMLDTDSource) 1384 1385 // returns the XMLDTDSource of this handler 1386 public XMLDTDSource getDTDSource() { 1387 return fDTDSource; 1388 } // getDTDSource(): XMLDTDSource 1389 1390 // 1391 // XMLDTDContentModelHandler methods 1392 // 1393 1394 // sets the XMLContentModelDTDSource of this handler 1395 public void setDTDContentModelSource(XMLDTDContentModelSource source ) { 1396 fDTDContentModelSource = source; 1397 } // setDTDContentModelSource(XMLDTDContentModelSource) 1398 1399 // returns the XMLDTDSource of this handler 1400 public XMLDTDContentModelSource getDTDContentModelSource() { 1401 return fDTDContentModelSource; 1402 } // getDTDContentModelSource(): XMLDTDContentModelSource 1403 1404 1405 /** 1406 * The start of a content model. Depending on the type of the content 1407 * model, specific methods may be called between the call to the 1408 * startContentModel method and the call to the endContentModel method. 1409 * 1410 * @param elementName The name of the element. 1411 * @param augs Additional information that may include infoset 1412 * augmentations. 1413 * 1414 * @throws XNIException Thrown by handler to signal an error. 1415 */ 1416 public void startContentModel(String elementName, Augmentations augs) 1417 throws XNIException { 1418 1419 if (fValidation) { 1420 fDTDElementDeclName = elementName; 1421 fMixedElementTypes.clear(); 1422 } 1423 1424 // call handlers 1425 if(fDTDGrammar != null) 1426 fDTDGrammar.startContentModel(elementName, augs); 1427 if (fDTDContentModelHandler != null) { 1428 fDTDContentModelHandler.startContentModel(elementName, augs); 1429 } 1430 1431 } // startContentModel(String) 1432 1433 /** 1434 * A content model of ANY. 1435 * 1436 * @param augs Additional information that may include infoset 1437 * augmentations. 1438 * 1439 * @throws XNIException Thrown by handler to signal an error. 1440 * 1441 * @see #empty 1442 * @see #startGroup 1443 */ 1444 public void any(Augmentations augs) throws XNIException { 1445 if(fDTDGrammar != null) 1446 fDTDGrammar.any(augs); 1447 if (fDTDContentModelHandler != null) { 1448 fDTDContentModelHandler.any(augs); 1449 } 1450 } // any() 1451 1452 /** 1453 * A content model of EMPTY. 1454 * 1455 * @param augs Additional information that may include infoset 1456 * augmentations. 1457 * 1458 * @throws XNIException Thrown by handler to signal an error. 1459 * 1460 * @see #any 1461 * @see #startGroup 1462 */ 1463 public void empty(Augmentations augs) throws XNIException { 1464 if(fDTDGrammar != null) 1465 fDTDGrammar.empty(augs); 1466 if (fDTDContentModelHandler != null) { 1467 fDTDContentModelHandler.empty(augs); 1468 } 1469 } // empty() 1470 1471 /** 1472 * A start of either a mixed or children content model. A mixed 1473 * content model will immediately be followed by a call to the 1474 * <code>pcdata()</code> method. A children content model will 1475 * contain additional groups and/or elements. 1476 * 1477 * @param augs Additional information that may include infoset 1478 * augmentations. 1479 * 1480 * @throws XNIException Thrown by handler to signal an error. 1481 * 1482 * @see #any 1483 * @see #empty 1484 */ 1485 public void startGroup(Augmentations augs) throws XNIException { 1486 1487 fMixed = false; 1488 // call handlers 1489 if(fDTDGrammar != null) 1490 fDTDGrammar.startGroup(augs); 1491 if (fDTDContentModelHandler != null) { 1492 fDTDContentModelHandler.startGroup(augs); 1493 } 1494 1495 } // startGroup() 1496 1497 /** 1498 * The appearance of "#PCDATA" within a group signifying a 1499 * mixed content model. This method will be the first called 1500 * following the content model's <code>startGroup()</code>. 1501 * 1502 * @param augs Additional information that may include infoset 1503 * augmentations. 1504 * 1505 * @throws XNIException Thrown by handler to signal an error. 1506 * 1507 * @see #startGroup 1508 */ 1509 public void pcdata(Augmentations augs) { 1510 fMixed = true; 1511 if(fDTDGrammar != null) 1512 fDTDGrammar.pcdata(augs); 1513 if (fDTDContentModelHandler != null) { 1514 fDTDContentModelHandler.pcdata(augs); 1515 } 1516 } // pcdata() 1517 1518 /** 1519 * A referenced element in a mixed or children content model. 1520 * 1521 * @param elementName The name of the referenced element. 1522 * @param augs Additional information that may include infoset 1523 * augmentations. 1524 * 1525 * @throws XNIException Thrown by handler to signal an error. 1526 */ 1527 public void element(String elementName, Augmentations augs) throws XNIException { 1528 1529 // check VC: No duplicate Types, in a single mixed-content declaration 1530 if (fMixed && fValidation) { 1531 if (fMixedElementTypes.contains(elementName)) { 1532 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1533 "DuplicateTypeInMixedContent", 1534 new Object[]{fDTDElementDeclName, elementName}, 1535 XMLErrorReporter.SEVERITY_ERROR); 1536 } 1537 else { 1538 fMixedElementTypes.add(elementName); 1539 } 1540 } 1541 1542 // call handlers 1543 if(fDTDGrammar != null) 1544 fDTDGrammar.element(elementName, augs); 1545 if (fDTDContentModelHandler != null) { 1546 fDTDContentModelHandler.element(elementName, augs); 1547 } 1548 1549 } // childrenElement(String) 1550 1551 /** 1552 * The separator between choices or sequences of a mixed or children 1553 * content model. 1554 * 1555 * @param separator The type of children separator. 1556 * @param augs Additional information that may include infoset 1557 * augmentations. 1558 * 1559 * @throws XNIException Thrown by handler to signal an error. 1560 * 1561 * @see #SEPARATOR_CHOICE 1562 * @see #SEPARATOR_SEQUENCE 1563 */ 1564 public void separator(short separator, Augmentations augs) 1565 throws XNIException { 1566 1567 // call handlers 1568 if(fDTDGrammar != null) 1569 fDTDGrammar.separator(separator, augs); 1570 if (fDTDContentModelHandler != null) { 1571 fDTDContentModelHandler.separator(separator, augs); 1572 } 1573 1574 } // separator(short) 1575 1576 /** 1577 * The occurrence count for a child in a children content model or 1578 * for the mixed content model group. 1579 * 1580 * @param occurrence The occurrence count for the last element 1581 * or group. 1582 * @param augs Additional information that may include infoset 1583 * augmentations. 1584 * 1585 * @throws XNIException Thrown by handler to signal an error. 1586 * 1587 * @see #OCCURS_ZERO_OR_ONE 1588 * @see #OCCURS_ZERO_OR_MORE 1589 * @see #OCCURS_ONE_OR_MORE 1590 */ 1591 public void occurrence(short occurrence, Augmentations augs) 1592 throws XNIException { 1593 1594 // call handlers 1595 if(fDTDGrammar != null) 1596 fDTDGrammar.occurrence(occurrence, augs); 1597 if (fDTDContentModelHandler != null) { 1598 fDTDContentModelHandler.occurrence(occurrence, augs); 1599 } 1600 1601 } // occurrence(short) 1602 1603 /** 1604 * The end of a group for mixed or children content models. 1605 * 1606 * @param augs Additional information that may include infoset 1607 * augmentations. 1608 * 1609 * @throws XNIException Thrown by handler to signal an error. 1610 */ 1611 public void endGroup(Augmentations augs) throws XNIException { 1612 1613 // call handlers 1614 if(fDTDGrammar != null) 1615 fDTDGrammar.endGroup(augs); 1616 if (fDTDContentModelHandler != null) { 1617 fDTDContentModelHandler.endGroup(augs); 1618 } 1619 1620 } // endGroup() 1621 1622 /** 1623 * The end of a content model. 1624 * 1625 * @param augs Additional information that may include infoset 1626 * augmentations. 1627 * 1628 * @throws XNIException Thrown by handler to signal an error. 1629 */ 1630 public void endContentModel(Augmentations augs) throws XNIException { 1631 1632 // call handlers 1633 if(fDTDGrammar != null) 1634 fDTDGrammar.endContentModel(augs); 1635 if (fDTDContentModelHandler != null) { 1636 fDTDContentModelHandler.endContentModel(augs); 1637 } 1638 1639 } // endContentModel() 1640 1641 // 1642 // Private methods 1643 // 1644 1645 /** 1646 * Normalize the attribute value of a non CDATA default attribute 1647 * collapsing sequences of space characters (x20) 1648 * 1649 * @param value The value to normalize 1650 * @return Whether the value was changed or not. 1651 */ 1652 private boolean normalizeDefaultAttrValue(XMLString value) { 1653 1654 boolean skipSpace = true; // skip leading spaces 1655 int current = value.offset; 1656 int end = value.offset + value.length; 1657 for (int i = value.offset; i < end; i++) { 1658 if (value.ch[i] == ' ') { 1659 if (!skipSpace) { 1660 // take the first whitespace as a space and skip the others 1661 value.ch[current++] = ' '; 1662 skipSpace = true; 1663 } 1664 else { 1665 // just skip it. 1666 } 1667 } 1668 else { 1669 // simply shift non space chars if needed 1670 if (current != i) { 1671 value.ch[current] = value.ch[i]; 1672 } 1673 current++; 1674 skipSpace = false; 1675 } 1676 } 1677 if (current != end) { 1678 if (skipSpace) { 1679 // if we finished on a space trim it 1680 current--; 1681 } 1682 // set the new value length 1683 value.length = current - value.offset; 1684 return true; 1685 } 1686 return false; 1687 } 1688 1689 protected boolean isValidNmtoken(String nmtoken) { 1690 return XMLChar.isValidNmtoken(nmtoken); 1691 } // isValidNmtoken(String): boolean 1692 1693 protected boolean isValidName(String name) { 1694 return XMLChar.isValidName(name); 1695 } // isValidName(String): boolean 1696 1697 /** 1698 * Checks that all elements referenced in content models have 1699 * been declared. This method calls out to the error handler 1700 * to indicate warnings. 1701 */ 1702 private void checkDeclaredElements(DTDGrammar grammar) { 1703 int elementIndex = grammar.getFirstElementDeclIndex(); 1704 XMLContentSpec contentSpec = new XMLContentSpec(); 1705 while (elementIndex >= 0) { 1706 int type = grammar.getContentSpecType(elementIndex); 1707 if (type == XMLElementDecl.TYPE_CHILDREN || type == XMLElementDecl.TYPE_MIXED) { 1708 checkDeclaredElements(grammar, 1709 elementIndex, 1710 grammar.getContentSpecIndex(elementIndex), 1711 contentSpec); 1712 } 1713 elementIndex = grammar.getNextElementDeclIndex(elementIndex); 1714 } 1715 } 1716 1717 /** 1718 * Does a recursive (if necessary) check on the specified element's 1719 * content spec to make sure that all children refer to declared 1720 * elements. 1721 */ 1722 private void checkDeclaredElements(DTDGrammar grammar, int elementIndex, 1723 int contentSpecIndex, XMLContentSpec contentSpec) { 1724 grammar.getContentSpec(contentSpecIndex, contentSpec); 1725 if (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_LEAF) { 1726 String value = (String) contentSpec.value; 1727 if (value != null && grammar.getElementDeclIndex(value) == -1) { 1728 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1729 "UndeclaredElementInContentSpec", 1730 new Object[]{grammar.getElementDeclName(elementIndex).rawname, value}, 1731 XMLErrorReporter.SEVERITY_WARNING); 1732 } 1733 } 1734 // It's not a leaf, so we have to recurse its left and maybe right 1735 // nodes. Save both values before we recurse and trash the node. 1736 else if ((contentSpec.type == XMLContentSpec.CONTENTSPECNODE_CHOICE) 1737 || (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_SEQ)) { 1738 final int leftNode = ((int[])contentSpec.value)[0]; 1739 final int rightNode = ((int[])contentSpec.otherValue)[0]; 1740 // Recurse on both children. 1741 checkDeclaredElements(grammar, elementIndex, leftNode, contentSpec); 1742 checkDeclaredElements(grammar, elementIndex, rightNode, contentSpec); 1743 } 1744 else if (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE 1745 || contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE 1746 || contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE) { 1747 final int leftNode = ((int[])contentSpec.value)[0]; 1748 checkDeclaredElements(grammar, elementIndex, leftNode, contentSpec); 1749 } 1750 } 1751 1752 } // class XMLDTDProcessor