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