1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 /* 6 * Copyright 1999-2005 The Apache Software Foundation. 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 */ 20 21 package com.sun.org.apache.xerces.internal.impl.dtd; 22 23 import com.sun.org.apache.xerces.internal.impl.Constants; 24 import com.sun.org.apache.xerces.internal.impl.RevalidationHandler; 25 import com.sun.org.apache.xerces.internal.impl.XMLEntityManager; 26 import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter; 27 import com.sun.org.apache.xerces.internal.impl.dtd.models.ContentModelValidator; 28 import com.sun.org.apache.xerces.internal.impl.dv.DTDDVFactory; 29 import com.sun.org.apache.xerces.internal.impl.dv.DatatypeValidator; 30 import com.sun.org.apache.xerces.internal.impl.dv.InvalidDatatypeValueException; 31 import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter; 32 import com.sun.org.apache.xerces.internal.impl.validation.ValidationManager; 33 import com.sun.org.apache.xerces.internal.impl.validation.ValidationState; 34 import com.sun.org.apache.xerces.internal.util.SymbolTable; 35 import com.sun.org.apache.xerces.internal.util.XMLChar; 36 import com.sun.org.apache.xerces.internal.util.XMLSymbols; 37 import com.sun.org.apache.xerces.internal.xni.Augmentations; 38 import com.sun.org.apache.xerces.internal.xni.NamespaceContext; 39 import com.sun.org.apache.xerces.internal.xni.QName; 40 import com.sun.org.apache.xerces.internal.xni.XMLAttributes; 41 import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler; 42 import com.sun.org.apache.xerces.internal.xni.XMLLocator; 43 import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier; 44 import com.sun.org.apache.xerces.internal.xni.XMLString; 45 import com.sun.org.apache.xerces.internal.xni.XNIException; 46 import com.sun.org.apache.xerces.internal.xni.grammars.Grammar; 47 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarDescription; 48 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarPool; 49 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent; 50 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager; 51 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException; 52 import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentFilter; 53 import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentSource; 54 55 /** 56 * The DTD validator. The validator implements a document 57 * filter: receiving document events from the scanner; validating 58 * the content and structure; augmenting the InfoSet, if applicable; 59 * and notifying the parser of the information resulting from the 60 * validation process. 61 * <p> Formerly, this component also handled DTD events and grammar construction. 62 * To facilitate the development of a meaningful DTD grammar caching/preparsing 63 * framework, this functionality has been moved into the XMLDTDLoader 64 * class. Therefore, this class no longer implements the DTDFilter 65 * or DTDContentModelFilter interfaces. 66 * <p> 67 * This component requires the following features and properties from the 68 * component manager that uses it: 69 * <ul> 70 * <li>http://xml.org/sax/features/namespaces</li> 71 * <li>http://xml.org/sax/features/validation</li> 72 * <li>http://apache.org/xml/features/validation/dynamic</li> 73 * <li>http://apache.org/xml/properties/internal/symbol-table</li> 74 * <li>http://apache.org/xml/properties/internal/error-reporter</li> 75 * <li>http://apache.org/xml/properties/internal/grammar-pool</li> 76 * <li>http://apache.org/xml/properties/internal/datatype-validator-factory</li> 77 * </ul> 78 * 79 * @xerces.internal 80 * 81 * @author Eric Ye, IBM 82 * @author Andy Clark, IBM 83 * @author Jeffrey Rodriguez IBM 84 * @author Neil Graham, IBM 85 * 86 * @version $Id: XMLDTDValidator.java,v 1.8 2010-11-01 04:39:42 joehw Exp $ 87 */ 88 public class XMLDTDValidator 89 implements XMLComponent, XMLDocumentFilter, XMLDTDValidatorFilter, RevalidationHandler { 90 91 // 92 // Constants 93 // 94 95 /** Symbol: "<<datatypes>>". */ 96 97 /** Top level scope (-1). */ 98 private static final int TOP_LEVEL_SCOPE = -1; 99 100 // feature identifiers 101 102 /** Feature identifier: namespaces. */ 103 protected static final String NAMESPACES = 104 Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE; 105 106 /** Feature identifier: validation. */ 107 protected static final String VALIDATION = 108 Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE; 109 110 /** Feature identifier: dynamic validation. */ 111 protected static final String DYNAMIC_VALIDATION = 112 Constants.XERCES_FEATURE_PREFIX + Constants.DYNAMIC_VALIDATION_FEATURE; 113 114 /** Feature identifier: balance syntax trees. */ 115 protected static final String BALANCE_SYNTAX_TREES = 116 Constants.XERCES_FEATURE_PREFIX + Constants.BALANCE_SYNTAX_TREES; 117 118 /** Feature identifier: warn on duplicate attdef */ 119 protected static final String WARN_ON_DUPLICATE_ATTDEF = 120 Constants.XERCES_FEATURE_PREFIX + Constants.WARN_ON_DUPLICATE_ATTDEF_FEATURE; 121 122 protected static final String PARSER_SETTINGS = 123 Constants.XERCES_FEATURE_PREFIX + Constants.PARSER_SETTINGS; 124 125 126 127 // property identifiers 128 129 /** Property identifier: symbol table. */ 130 protected static final String SYMBOL_TABLE = 131 Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; 132 133 /** Property identifier: error reporter. */ 134 protected static final String ERROR_REPORTER = 135 Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; 136 137 /** Property identifier: grammar pool. */ 138 protected static final String GRAMMAR_POOL = 139 Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY; 140 141 /** Property identifier: datatype validator factory. */ 142 protected static final String DATATYPE_VALIDATOR_FACTORY = 143 Constants.XERCES_PROPERTY_PREFIX + Constants.DATATYPE_VALIDATOR_FACTORY_PROPERTY; 144 145 // property identifier: ValidationManager 146 protected static final String VALIDATION_MANAGER = 147 Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY; 148 149 // recognized features and properties 150 151 /** Recognized features. */ 152 private static final String[] RECOGNIZED_FEATURES = { 153 NAMESPACES, 154 VALIDATION, 155 DYNAMIC_VALIDATION, 156 BALANCE_SYNTAX_TREES 157 }; 158 159 /** Feature defaults. */ 160 private static final Boolean[] FEATURE_DEFAULTS = { 161 null, 162 null, 163 Boolean.FALSE, 164 Boolean.FALSE, 165 }; 166 167 /** Recognized properties. */ 168 private static final String[] RECOGNIZED_PROPERTIES = { 169 SYMBOL_TABLE, 170 ERROR_REPORTER, 171 GRAMMAR_POOL, 172 DATATYPE_VALIDATOR_FACTORY, 173 VALIDATION_MANAGER 174 }; 175 176 /** Property defaults. */ 177 private static final Object[] PROPERTY_DEFAULTS = { 178 null, 179 null, 180 null, 181 null, 182 null, 183 }; 184 185 // debugging 186 187 /** Compile to true to debug attributes. */ 188 private static final boolean DEBUG_ATTRIBUTES = false; 189 190 /** Compile to true to debug element children. */ 191 private static final boolean DEBUG_ELEMENT_CHILDREN = false; 192 193 // 194 // Data 195 // 196 197 // updated during reset 198 protected ValidationManager fValidationManager = null; 199 200 // validation state 201 protected final ValidationState fValidationState = new ValidationState(); 202 203 // features 204 205 /** Namespaces. */ 206 protected boolean fNamespaces; 207 208 /** Validation. */ 209 protected boolean fValidation; 210 211 /** Validation against only DTD */ 212 protected boolean fDTDValidation; 213 214 /** 215 * Dynamic validation. This state of this feature is only useful when 216 * the validation feature is set to <code>true</code>. 217 */ 218 protected boolean fDynamicValidation; 219 220 /** Controls whether the DTD grammar produces balanced syntax trees. */ 221 protected boolean fBalanceSyntaxTrees; 222 223 /** warn on duplicate attribute definition, this feature works only when validation is true */ 224 protected boolean fWarnDuplicateAttdef; 225 226 // properties 227 228 /** Symbol table. */ 229 protected SymbolTable fSymbolTable; 230 231 /** Error reporter. */ 232 protected XMLErrorReporter fErrorReporter; 233 234 // the grammar pool 235 protected XMLGrammarPool fGrammarPool; 236 237 /** Grammar bucket. */ 238 protected DTDGrammarBucket fGrammarBucket; 239 240 /* location of the document as passed in from startDocument call */ 241 protected XMLLocator fDocLocation; 242 243 /** Namespace support. */ 244 protected NamespaceContext fNamespaceContext = null; 245 246 /** Datatype validator factory. */ 247 protected DTDDVFactory fDatatypeValidatorFactory; 248 249 // handlers 250 251 /** Document handler. */ 252 protected XMLDocumentHandler fDocumentHandler; 253 254 protected XMLDocumentSource fDocumentSource; 255 // grammars 256 257 /** DTD Grammar. */ 258 protected DTDGrammar fDTDGrammar; 259 260 // state 261 262 /** True if seen DOCTYPE declaration. */ 263 protected boolean fSeenDoctypeDecl = false; 264 265 /** Perform validation. */ 266 private boolean fPerformValidation; 267 268 /** Schema type: None, DTD, Schema */ 269 private String fSchemaType; 270 271 // information regarding the current element 272 273 /** Current element name. */ 274 private final QName fCurrentElement = new QName(); 275 276 /** Current element index. */ 277 private int fCurrentElementIndex = -1; 278 279 /** Current content spec type. */ 280 private int fCurrentContentSpecType = -1; 281 282 /** The root element name. */ 283 private final QName fRootElement = new QName(); 284 285 private boolean fInCDATASection = false; 286 // element stack 287 288 /** Element index stack. */ 289 private int[] fElementIndexStack = new int[8]; 290 291 /** Content spec type stack. */ 292 private int[] fContentSpecTypeStack = new int[8]; 293 294 /** Element name stack. */ 295 private QName[] fElementQNamePartsStack = new QName[8]; 296 297 // children list and offset stack 298 299 /** 300 * Element children. This data structure is a growing stack that 301 * holds the children of elements from the root to the current 302 * element depth. This structure never gets "deeper" than the 303 * deepest element. Space is re-used once each element is closed. 304 * <p> 305 * <strong>Note:</strong> This is much more efficient use of memory 306 * than creating new arrays for each element depth. 307 * <p> 308 * <strong>Note:</strong> The use of this data structure is for 309 * validation "on the way out". If the validation model changes to 310 * "on the way in", then this data structure is not needed. 311 */ 312 private QName[] fElementChildren = new QName[32]; 313 314 /** Element children count. */ 315 private int fElementChildrenLength = 0; 316 317 /** 318 * Element children offset stack. This stack refers to offsets 319 * into the <code>fElementChildren</code> array. 320 * @see #fElementChildren 321 */ 322 private int[] fElementChildrenOffsetStack = new int[32]; 323 324 /** Element depth. */ 325 private int fElementDepth = -1; 326 327 // validation states 328 329 /** True if seen the root element. */ 330 private boolean fSeenRootElement = false; 331 332 /** True if inside of element content. */ 333 private boolean fInElementContent = false; 334 335 // temporary variables 336 337 /** Temporary element declaration. */ 338 private XMLElementDecl fTempElementDecl = new XMLElementDecl(); 339 340 /** Temporary atribute declaration. */ 341 private final XMLAttributeDecl fTempAttDecl = new XMLAttributeDecl(); 342 343 /** Temporary entity declaration. */ 344 private final XMLEntityDecl fEntityDecl = new XMLEntityDecl(); 345 346 /** Temporary qualified name. */ 347 private final QName fTempQName = new QName(); 348 349 /** Temporary string buffers. */ 350 private final StringBuffer fBuffer = new StringBuffer(); 351 352 // symbols: general 353 354 // attribute validators 355 356 /** Datatype validator: ID. */ 357 protected DatatypeValidator fValID; 358 359 /** Datatype validator: IDREF. */ 360 protected DatatypeValidator fValIDRef; 361 362 /** Datatype validator: IDREFS. */ 363 protected DatatypeValidator fValIDRefs; 364 365 /** Datatype validator: ENTITY. */ 366 protected DatatypeValidator fValENTITY; 367 368 /** Datatype validator: ENTITIES. */ 369 protected DatatypeValidator fValENTITIES; 370 371 /** Datatype validator: NMTOKEN. */ 372 protected DatatypeValidator fValNMTOKEN; 373 374 /** Datatype validator: NMTOKENS. */ 375 protected DatatypeValidator fValNMTOKENS; 376 377 /** Datatype validator: NOTATION. */ 378 protected DatatypeValidator fValNOTATION; 379 380 // to check for duplicate ID or ANNOTATION attribute declare in 381 // ATTLIST, and misc VCs 382 383 // 384 // Constructors 385 // 386 387 /** Default constructor. */ 388 public XMLDTDValidator() { 389 390 // initialize data 391 for (int i = 0; i < fElementQNamePartsStack.length; i++) { 392 fElementQNamePartsStack[i] = new QName(); 393 } 394 fGrammarBucket = new DTDGrammarBucket(); 395 396 } // <init>() 397 398 DTDGrammarBucket getGrammarBucket() { 399 return fGrammarBucket; 400 } // getGrammarBucket(): DTDGrammarBucket 401 402 // 403 // XMLComponent methods 404 // 405 406 /* 407 * Resets the component. The component can query the component manager 408 * about any features and properties that affect the operation of the 409 * component. 410 * 411 * @param componentManager The component manager. 412 * 413 * @throws SAXException Thrown by component on finitialization error. 414 * For example, if a feature or property is 415 * required for the operation of the component, the 416 * component manager may throw a 417 * SAXNotRecognizedException or a 418 * SAXNotSupportedException. 419 */ 420 public void reset(XMLComponentManager componentManager) 421 throws XMLConfigurationException { 422 423 // clear grammars 424 fDTDGrammar = null; 425 fSeenDoctypeDecl = false; 426 fInCDATASection = false; 427 // initialize state 428 fSeenRootElement = false; 429 fInElementContent = false; 430 fCurrentElementIndex = -1; 431 fCurrentContentSpecType = -1; 432 433 fRootElement.clear(); 434 435 fValidationState.resetIDTables(); 436 437 fGrammarBucket.clear(); 438 fElementDepth = -1; 439 fElementChildrenLength = 0; 440 441 boolean parser_settings = componentManager.getFeature(PARSER_SETTINGS, true); 442 443 if (!parser_settings){ 444 // parser settings have not been changed 445 fValidationManager.addValidationState(fValidationState); 446 return; 447 } 448 449 // sax features 450 fNamespaces = componentManager.getFeature(NAMESPACES, true); 451 fValidation = componentManager.getFeature(VALIDATION, false); 452 fDTDValidation = !(componentManager.getFeature(Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE, false)); 453 454 // Xerces features 455 fDynamicValidation = componentManager.getFeature(DYNAMIC_VALIDATION, false); 456 fBalanceSyntaxTrees = componentManager.getFeature(BALANCE_SYNTAX_TREES, false); 457 fWarnDuplicateAttdef = componentManager.getFeature(WARN_ON_DUPLICATE_ATTDEF, false); 458 459 fSchemaType = (String)componentManager.getProperty (Constants.JAXP_PROPERTY_PREFIX 460 + Constants.SCHEMA_LANGUAGE, null); 461 462 fValidationManager= (ValidationManager)componentManager.getProperty(VALIDATION_MANAGER); 463 fValidationManager.addValidationState(fValidationState); 464 fValidationState.setUsingNamespaces(fNamespaces); 465 466 // get needed components 467 fErrorReporter = (XMLErrorReporter)componentManager.getProperty(Constants.XERCES_PROPERTY_PREFIX+Constants.ERROR_REPORTER_PROPERTY); 468 fSymbolTable = (SymbolTable)componentManager.getProperty(Constants.XERCES_PROPERTY_PREFIX+Constants.SYMBOL_TABLE_PROPERTY); 469 fGrammarPool= (XMLGrammarPool)componentManager.getProperty(GRAMMAR_POOL, null); 470 471 fDatatypeValidatorFactory = (DTDDVFactory)componentManager.getProperty(Constants.XERCES_PROPERTY_PREFIX + Constants.DATATYPE_VALIDATOR_FACTORY_PROPERTY); 472 init(); 473 474 } // reset(XMLComponentManager) 475 476 /** 477 * Returns a list of feature identifiers that are recognized by 478 * this component. This method may return null if no features 479 * are recognized by this component. 480 */ 481 public String[] getRecognizedFeatures() { 482 return (String[])(RECOGNIZED_FEATURES.clone()); 483 } // getRecognizedFeatures():String[] 484 485 /** 486 * Sets the state of a feature. This method is called by the component 487 * manager any time after reset when a feature changes state. 488 * <p> 489 * <strong>Note:</strong> Components should silently ignore features 490 * that do not affect the operation of the component. 491 * 492 * @param featureId The feature identifier. 493 * @param state The state of the feature. 494 * 495 * @throws SAXNotRecognizedException The component should not throw 496 * this exception. 497 * @throws SAXNotSupportedException The component should not throw 498 * this exception. 499 */ 500 public void setFeature(String featureId, boolean state) 501 throws XMLConfigurationException { 502 } // setFeature(String,boolean) 503 504 /** 505 * Returns a list of property identifiers that are recognized by 506 * this component. This method may return null if no properties 507 * are recognized by this component. 508 */ 509 public String[] getRecognizedProperties() { 510 return (String[])(RECOGNIZED_PROPERTIES.clone()); 511 } // getRecognizedProperties():String[] 512 513 /** 514 * Sets the value of a property. This method is called by the component 515 * manager any time after reset when a property changes value. 516 * <p> 517 * <strong>Note:</strong> Components should silently ignore properties 518 * that do not affect the operation of the component. 519 * 520 * @param propertyId The property identifier. 521 * @param value The value of the property. 522 * 523 * @throws SAXNotRecognizedException The component should not throw 524 * this exception. 525 * @throws SAXNotSupportedException The component should not throw 526 * this exception. 527 */ 528 public void setProperty(String propertyId, Object value) 529 throws XMLConfigurationException { 530 } // setProperty(String,Object) 531 532 /** 533 * Returns the default state for a feature, or null if this 534 * component does not want to report a default value for this 535 * feature. 536 * 537 * @param featureId The feature identifier. 538 * 539 * @since Xerces 2.2.0 540 */ 541 public Boolean getFeatureDefault(String featureId) { 542 for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) { 543 if (RECOGNIZED_FEATURES[i].equals(featureId)) { 544 return FEATURE_DEFAULTS[i]; 545 } 546 } 547 return null; 548 } // getFeatureDefault(String):Boolean 549 550 /** 551 * Returns the default state for a property, or null if this 552 * component does not want to report a default value for this 553 * property. 554 * 555 * @param propertyId The property identifier. 556 * 557 * @since Xerces 2.2.0 558 */ 559 public Object getPropertyDefault(String propertyId) { 560 for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) { 561 if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) { 562 return PROPERTY_DEFAULTS[i]; 563 } 564 } 565 return null; 566 } // getPropertyDefault(String):Object 567 568 // 569 // XMLDocumentSource methods 570 // 571 572 /** Sets the document handler to receive information about the document. */ 573 public void setDocumentHandler(XMLDocumentHandler documentHandler) { 574 fDocumentHandler = documentHandler; 575 } // setDocumentHandler(XMLDocumentHandler) 576 577 /** Returns the document handler */ 578 public XMLDocumentHandler getDocumentHandler() { 579 return fDocumentHandler; 580 } // getDocumentHandler(): XMLDocumentHandler 581 582 583 // 584 // XMLDocumentHandler methods 585 // 586 587 /** Sets the document source */ 588 public void setDocumentSource(XMLDocumentSource source){ 589 fDocumentSource = source; 590 } // setDocumentSource 591 592 /** Returns the document source */ 593 public XMLDocumentSource getDocumentSource (){ 594 return fDocumentSource; 595 } // getDocumentSource 596 597 /** 598 * The start of the document. 599 * 600 * @param locator The system identifier of the entity if the entity 601 * is external, null otherwise. 602 * @param encoding The auto-detected IANA encoding name of the entity 603 * stream. This value will be null in those situations 604 * where the entity encoding is not auto-detected (e.g. 605 * internal entities or a document entity that is 606 * parsed from a java.io.Reader). 607 * @param namespaceContext 608 * The namespace context in effect at the 609 * start of this document. 610 * This object represents the current context. 611 * Implementors of this class are responsible 612 * for copying the namespace bindings from the 613 * the current context (and its parent contexts) 614 * if that information is important. 615 * @param augs Additional information that may include infoset augmentations 616 * 617 * @throws XNIException Thrown by handler to signal an error. 618 */ 619 public void startDocument(XMLLocator locator, String encoding, 620 NamespaceContext namespaceContext, Augmentations augs) 621 throws XNIException { 622 623 // call handlers 624 // get initial grammars 625 if (fGrammarPool != null) { 626 Grammar [] grammars = fGrammarPool.retrieveInitialGrammarSet(XMLGrammarDescription.XML_DTD); 627 final int length = (grammars != null) ? grammars.length : 0; 628 for (int i = 0; i < length; ++i) { 629 fGrammarBucket.putGrammar((DTDGrammar)grammars[i]); 630 } 631 } 632 fDocLocation = locator; 633 fNamespaceContext = namespaceContext; 634 635 if (fDocumentHandler != null) { 636 fDocumentHandler.startDocument(locator, encoding, namespaceContext, augs); 637 } 638 639 } // startDocument(XMLLocator,String) 640 641 /** 642 * Notifies of the presence of an XMLDecl line in the document. If 643 * present, this method will be called immediately following the 644 * startDocument call. 645 * 646 * @param version The XML version. 647 * @param encoding The IANA encoding name of the document, or null if 648 * not specified. 649 * @param standalone The standalone value, or null if not specified. 650 * @param augs Additional information that may include infoset augmentations 651 * 652 * @throws XNIException Thrown by handler to signal an error. 653 */ 654 public void xmlDecl(String version, String encoding, String standalone, Augmentations augs) 655 throws XNIException { 656 657 // save standalone state 658 fGrammarBucket.setStandalone(standalone != null && standalone.equals("yes")); 659 660 // call handlers 661 if (fDocumentHandler != null) { 662 fDocumentHandler.xmlDecl(version, encoding, standalone, augs); 663 } 664 665 } // xmlDecl(String,String,String) 666 667 /** 668 * Notifies of the presence of the DOCTYPE line in the document. 669 * 670 * @param rootElement The name of the root element. 671 * @param publicId The public identifier if an external DTD or null 672 * if the external DTD is specified using SYSTEM. 673 * @param systemId The system identifier if an external DTD, null 674 * otherwise. 675 * @param augs Additional information that may include infoset augmentations 676 * 677 * @throws XNIException Thrown by handler to signal an error. 678 */ 679 public void doctypeDecl(String rootElement, String publicId, String systemId, 680 Augmentations augs) 681 throws XNIException { 682 683 // save root element state 684 fSeenDoctypeDecl = true; 685 fRootElement.setValues(null, rootElement, rootElement, null); 686 // find or create grammar: 687 String eid = null; 688 try { 689 eid = XMLEntityManager.expandSystemId(systemId, fDocLocation.getExpandedSystemId(), false); 690 } catch (java.io.IOException e) { 691 } 692 XMLDTDDescription grammarDesc = new XMLDTDDescription(publicId, systemId, fDocLocation.getExpandedSystemId(), eid, rootElement); 693 fDTDGrammar = fGrammarBucket.getGrammar(grammarDesc); 694 if(fDTDGrammar == null) { 695 // give grammar pool a chance... 696 // 697 // Do not bother checking the pool if no public or system identifier was provided. 698 // Since so many different DTDs have roots in common, using only a root name as the 699 // key may cause an unexpected grammar to be retrieved from the grammar pool. This scenario 700 // would occur when an ExternalSubsetResolver has been queried and the 701 // XMLInputSource returned contains an input stream but no external identifier. 702 // This can never happen when the instance document specified a DOCTYPE. -- mrglavas 703 if (fGrammarPool != null && (systemId != null || publicId != null)) { 704 fDTDGrammar = (DTDGrammar)fGrammarPool.retrieveGrammar(grammarDesc); 705 } 706 } 707 if(fDTDGrammar == null) { 708 // we'll have to create it... 709 if (!fBalanceSyntaxTrees) { 710 fDTDGrammar = new DTDGrammar(fSymbolTable, grammarDesc); 711 } 712 else { 713 fDTDGrammar = new BalancedDTDGrammar(fSymbolTable, grammarDesc); 714 } 715 } else { 716 // we've found a cached one;so let's make sure not to read 717 // any external subset! 718 fValidationManager.setCachedDTD(true); 719 } 720 fGrammarBucket.setActiveGrammar(fDTDGrammar); 721 722 // call handlers 723 if (fDocumentHandler != null) { 724 fDocumentHandler.doctypeDecl(rootElement, publicId, systemId, augs); 725 } 726 727 } // doctypeDecl(String,String,String, Augmentations) 728 729 730 /** 731 * The start of an element. 732 * 733 * @param element The name of the element. 734 * @param attributes The element attributes. 735 * @param augs Additional information that may include infoset augmentations 736 * 737 * @throws XNIException Thrown by handler to signal an error. 738 */ 739 public void startElement(QName element, XMLAttributes attributes, Augmentations augs) 740 throws XNIException { 741 742 handleStartElement(element, attributes, augs); 743 // call handlers 744 if (fDocumentHandler != null) { 745 fDocumentHandler.startElement(element, attributes, augs); 746 747 } 748 749 } // startElement(QName,XMLAttributes) 750 751 /** 752 * An empty element. 753 * 754 * @param element The name of the element. 755 * @param attributes The element attributes. 756 * @param augs Additional information that may include infoset augmentations 757 * 758 * @throws XNIException Thrown by handler to signal an error. 759 */ 760 public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs) 761 throws XNIException { 762 763 boolean removed = handleStartElement(element, attributes, augs); 764 765 if (fDocumentHandler !=null) { 766 fDocumentHandler.emptyElement(element, attributes, augs); 767 } 768 if (!removed) { 769 handleEndElement(element, augs, true); 770 } 771 772 773 } // emptyElement(QName,XMLAttributes) 774 775 /** 776 * Character content. 777 * 778 * @param text The content. 779 * 780 * @param augs Additional information that may include infoset augmentations 781 * 782 * @throws XNIException Thrown by handler to signal an error. 783 */ 784 public void characters(XMLString text, Augmentations augs) throws XNIException { 785 786 boolean callNextCharacters = true; 787 788 // REVISIT: [Q] Is there a more efficient way of doing this? 789 // Perhaps if the scanner told us so we don't have to 790 // look at the characters again. -Ac 791 boolean allWhiteSpace = true; 792 for (int i=text.offset; i< text.offset+text.length; i++) { 793 if (!isSpace(text.ch[i])) { 794 allWhiteSpace = false; 795 break; 796 } 797 } 798 // call the ignoreableWhiteSpace callback 799 // never call ignorableWhitespace if we are in cdata section 800 if (fInElementContent && allWhiteSpace && !fInCDATASection) { 801 if (fDocumentHandler != null) { 802 fDocumentHandler.ignorableWhitespace(text, augs); 803 callNextCharacters = false; 804 } 805 } 806 807 // validate 808 if (fPerformValidation) { 809 if (fInElementContent) { 810 if (fGrammarBucket.getStandalone() && 811 fDTDGrammar.getElementDeclIsExternal(fCurrentElementIndex)) { 812 if (allWhiteSpace) { 813 fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN, 814 "MSG_WHITE_SPACE_IN_ELEMENT_CONTENT_WHEN_STANDALONE", 815 null, XMLErrorReporter.SEVERITY_ERROR); 816 } 817 } 818 if (!allWhiteSpace) { 819 charDataInContent(); 820 } 821 822 // For E15.2 823 if (augs != null && augs.getItem(Constants.CHAR_REF_PROBABLE_WS) == Boolean.TRUE) { 824 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 825 "MSG_CONTENT_INVALID_SPECIFIED", 826 new Object[]{ fCurrentElement.rawname, 827 fDTDGrammar.getContentSpecAsString(fElementDepth), 828 "character reference"}, 829 XMLErrorReporter.SEVERITY_ERROR); 830 } 831 } 832 833 if (fCurrentContentSpecType == XMLElementDecl.TYPE_EMPTY) { 834 charDataInContent(); 835 } 836 } 837 838 // call handlers 839 if (callNextCharacters && fDocumentHandler != null) { 840 fDocumentHandler.characters(text, augs); 841 } 842 843 } // characters(XMLString) 844 845 846 847 /** 848 * Ignorable whitespace. For this method to be called, the document 849 * source must have some way of determining that the text containing 850 * only whitespace characters should be considered ignorable. For 851 * example, the validator can determine if a length of whitespace 852 * characters in the document are ignorable based on the element 853 * content model. 854 * 855 * @param text The ignorable whitespace. 856 * @param augs Additional information that may include infoset augmentations 857 * 858 * @throws XNIException Thrown by handler to signal an error. 859 */ 860 public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException { 861 862 // call handlers 863 if (fDocumentHandler != null) { 864 fDocumentHandler.ignorableWhitespace(text, augs); 865 } 866 867 } // ignorableWhitespace(XMLString) 868 869 /** 870 * The end of an element. 871 * 872 * @param element The name of the element. 873 * @param augs Additional information that may include infoset augmentations 874 * 875 * @throws XNIException Thrown by handler to signal an error. 876 */ 877 public void endElement(QName element, Augmentations augs) throws XNIException { 878 879 handleEndElement(element, augs, false); 880 881 } // endElement(QName) 882 883 /** 884 * The start of a CDATA section. 885 * @param augs Additional information that may include infoset augmentations 886 * 887 * @throws XNIException Thrown by handler to signal an error. 888 */ 889 public void startCDATA(Augmentations augs) throws XNIException { 890 891 if (fPerformValidation && fInElementContent) { 892 charDataInContent(); 893 } 894 fInCDATASection = true; 895 // call handlers 896 if (fDocumentHandler != null) { 897 fDocumentHandler.startCDATA(augs); 898 } 899 900 } // startCDATA() 901 902 /** 903 * The end of a CDATA section. 904 * @param augs Additional information that may include infoset augmentations 905 * 906 * @throws XNIException Thrown by handler to signal an error. 907 */ 908 public void endCDATA(Augmentations augs) throws XNIException { 909 910 fInCDATASection = false; 911 // call handlers 912 if (fDocumentHandler != null) { 913 fDocumentHandler.endCDATA(augs); 914 } 915 916 } // endCDATA() 917 918 /** 919 * The end of the document. 920 * @param augs Additional information that may include infoset augmentations 921 * 922 * @throws XNIException Thrown by handler to signal an error. 923 */ 924 public void endDocument(Augmentations augs) throws XNIException { 925 926 // call handlers 927 if (fDocumentHandler != null) { 928 fDocumentHandler.endDocument(augs); 929 } 930 931 } // endDocument() 932 933 /** 934 * A comment. 935 * 936 * @param text The text in the comment. 937 * @param augs Additional information that may include infoset augmentations 938 * 939 * @throws XNIException Thrown by application to signal an error. 940 */ 941 public void comment(XMLString text, Augmentations augs) throws XNIException { 942 // fixes E15.1 943 if (fPerformValidation && fElementDepth >= 0 && fDTDGrammar != null) { 944 fDTDGrammar.getElementDecl(fCurrentElementIndex, fTempElementDecl); 945 if (fTempElementDecl.type == XMLElementDecl.TYPE_EMPTY) { 946 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 947 "MSG_CONTENT_INVALID_SPECIFIED", 948 new Object[]{ fCurrentElement.rawname, 949 "EMPTY", 950 "comment"}, 951 XMLErrorReporter.SEVERITY_ERROR); 952 } 953 } 954 // call handlers 955 if (fDocumentHandler != null) { 956 fDocumentHandler.comment(text, augs); 957 } 958 959 } // comment(XMLString) 960 961 962 /** 963 * A processing instruction. Processing instructions consist of a 964 * target name and, optionally, text data. The data is only meaningful 965 * to the application. 966 * <p> 967 * Typically, a processing instruction's data will contain a series 968 * of pseudo-attributes. These pseudo-attributes follow the form of 969 * element attributes but are <strong>not</strong> parsed or presented 970 * to the application as anything other than text. The application is 971 * responsible for parsing the data. 972 * 973 * @param target The target. 974 * @param data The data or null if none specified. 975 * @param augs Additional information that may include infoset augmentations 976 * 977 * @throws XNIException Thrown by handler to signal an error. 978 */ 979 public void processingInstruction(String target, XMLString data, Augmentations augs) 980 throws XNIException { 981 982 // fixes E15.1 983 if (fPerformValidation && fElementDepth >= 0 && fDTDGrammar != null) { 984 fDTDGrammar.getElementDecl(fCurrentElementIndex, fTempElementDecl); 985 if (fTempElementDecl.type == XMLElementDecl.TYPE_EMPTY) { 986 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 987 "MSG_CONTENT_INVALID_SPECIFIED", 988 new Object[]{ fCurrentElement.rawname, 989 "EMPTY", 990 "processing instruction"}, 991 XMLErrorReporter.SEVERITY_ERROR); 992 } 993 } 994 // call handlers 995 if (fDocumentHandler != null) { 996 fDocumentHandler.processingInstruction(target, data, augs); 997 } 998 } // processingInstruction(String,XMLString) 999 1000 /** 1001 * This method notifies the start of a general entity. 1002 * <p> 1003 * <strong>Note:</strong> This method is not called for entity references 1004 * appearing as part of attribute values. 1005 * 1006 * @param name The name of the general entity. 1007 * @param identifier The resource identifier. 1008 * @param encoding The auto-detected IANA encoding name of the entity 1009 * stream. This value will be null in those situations 1010 * where the entity encoding is not auto-detected (e.g. 1011 * internal entities or a document entity that is 1012 * parsed from a java.io.Reader). 1013 * @param augs Additional information that may include infoset augmentations 1014 * 1015 * @exception XNIException Thrown by handler to signal an error. 1016 */ 1017 public void startGeneralEntity(String name, 1018 XMLResourceIdentifier identifier, 1019 String encoding, 1020 Augmentations augs) throws XNIException { 1021 if (fPerformValidation && fElementDepth >= 0 && fDTDGrammar != null) { 1022 fDTDGrammar.getElementDecl(fCurrentElementIndex, fTempElementDecl); 1023 // fixes E15.1 1024 if (fTempElementDecl.type == XMLElementDecl.TYPE_EMPTY) { 1025 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1026 "MSG_CONTENT_INVALID_SPECIFIED", 1027 new Object[]{ fCurrentElement.rawname, 1028 "EMPTY", "ENTITY"}, 1029 XMLErrorReporter.SEVERITY_ERROR); 1030 } 1031 if (fGrammarBucket.getStandalone()) { 1032 XMLDTDLoader.checkStandaloneEntityRef(name, fDTDGrammar, fEntityDecl, fErrorReporter); 1033 } 1034 } 1035 if (fDocumentHandler != null) { 1036 fDocumentHandler.startGeneralEntity(name, identifier, encoding, augs); 1037 } 1038 } 1039 1040 /** 1041 * This method notifies the end of a general entity. 1042 * <p> 1043 * <strong>Note:</strong> This method is not called for entity references 1044 * appearing as part of attribute values. 1045 * 1046 * @param name The name of the entity. 1047 * @param augs Additional information that may include infoset augmentations 1048 * 1049 * @exception XNIException 1050 * Thrown by handler to signal an error. 1051 */ 1052 public void endGeneralEntity(String name, Augmentations augs) throws XNIException { 1053 // call handlers 1054 if (fDocumentHandler != null) { 1055 fDocumentHandler.endGeneralEntity(name, augs); 1056 } 1057 } // endEntity(String) 1058 1059 /** 1060 * Notifies of the presence of a TextDecl line in an entity. If present, 1061 * this method will be called immediately following the startParameterEntity call. 1062 * <p> 1063 * <strong>Note:</strong> This method is only called for external 1064 * parameter entities referenced in the DTD. 1065 * 1066 * @param version The XML version, or null if not specified. 1067 * @param encoding The IANA encoding name of the entity. 1068 * @param augs Additional information that may include infoset 1069 * augmentations. 1070 * 1071 * @throws XNIException Thrown by handler to signal an error. 1072 */ 1073 public void textDecl(String version, String encoding, Augmentations augs) throws XNIException { 1074 1075 // call handlers 1076 if (fDocumentHandler != null) { 1077 fDocumentHandler.textDecl(version, encoding, augs); 1078 } 1079 } 1080 1081 1082 public final boolean hasGrammar(){ 1083 1084 return (fDTDGrammar != null); 1085 } 1086 1087 public final boolean validate(){ 1088 // Do validation if all of the following are true: 1089 // 1. The JAXP Schema Language property is not XML Schema 1090 // REVISIT: since only DTD and Schema are supported at this time, 1091 // such checking is sufficient. but if more schema types 1092 // are introduced in the future, we'll need to change it 1093 // to something like 1094 // (fSchemaType == null || fSchemaType == NS_XML_DTD) 1095 // 2. One of the following is true (validation features) 1096 // 2.1 Dynamic validation is off, and validation is on 1097 // 2.2 Dynamic validation is on, and DOCTYPE was seen 1098 // 3 Xerces schema validation feature is off, or DOCTYPE was seen. 1099 return (fSchemaType != Constants.NS_XMLSCHEMA) && 1100 (!fDynamicValidation && fValidation || 1101 fDynamicValidation && fSeenDoctypeDecl) && 1102 (fDTDValidation || fSeenDoctypeDecl); 1103 } 1104 1105 //REVISIT:we can convert into functions.. adding default attribute values.. and one validating. 1106 1107 /** Add default attributes and validate. */ 1108 protected void addDTDDefaultAttrsAndValidate(QName elementName, int elementIndex, 1109 XMLAttributes attributes) 1110 throws XNIException { 1111 1112 // is there anything to do? 1113 if (elementIndex == -1 || fDTDGrammar == null) { 1114 return; 1115 } 1116 1117 // 1118 // Check after all specified attrs are scanned 1119 // (1) report error for REQUIRED attrs that are missing (V_TAGc) 1120 // (2) add default attrs (FIXED and NOT_FIXED) 1121 // 1122 int attlistIndex = fDTDGrammar.getFirstAttributeDeclIndex(elementIndex); 1123 1124 while (attlistIndex != -1) { 1125 1126 fDTDGrammar.getAttributeDecl(attlistIndex, fTempAttDecl); 1127 1128 if (DEBUG_ATTRIBUTES) { 1129 if (fTempAttDecl != null) { 1130 XMLElementDecl elementDecl = new XMLElementDecl(); 1131 fDTDGrammar.getElementDecl(elementIndex, elementDecl); 1132 System.out.println("element: "+(elementDecl.name.localpart)); 1133 System.out.println("attlistIndex " + attlistIndex + "\n"+ 1134 "attName : '"+(fTempAttDecl.name.localpart) + "'\n" 1135 + "attType : "+fTempAttDecl.simpleType.type + "\n" 1136 + "attDefaultType : "+fTempAttDecl.simpleType.defaultType + "\n" 1137 + "attDefaultValue : '"+fTempAttDecl.simpleType.defaultValue + "'\n" 1138 + attributes.getLength() +"\n" 1139 ); 1140 } 1141 } 1142 String attPrefix = fTempAttDecl.name.prefix; 1143 String attLocalpart = fTempAttDecl.name.localpart; 1144 String attRawName = fTempAttDecl.name.rawname; 1145 String attType = getAttributeTypeName(fTempAttDecl); 1146 int attDefaultType =fTempAttDecl.simpleType.defaultType; 1147 String attValue = null; 1148 1149 if (fTempAttDecl.simpleType.defaultValue != null) { 1150 attValue = fTempAttDecl.simpleType.defaultValue; 1151 } 1152 1153 boolean specified = false; 1154 boolean required = attDefaultType == XMLSimpleType.DEFAULT_TYPE_REQUIRED; 1155 boolean cdata = attType == XMLSymbols.fCDATASymbol; 1156 1157 if (!cdata || required || attValue != null) { 1158 int attrCount = attributes.getLength(); 1159 for (int i = 0; i < attrCount; i++) { 1160 if (attributes.getQName(i) == attRawName) { 1161 specified = true; 1162 break; 1163 } 1164 } 1165 } 1166 1167 if (!specified) { 1168 if (required) { 1169 if (fPerformValidation) { 1170 Object[] args = {elementName.localpart, attRawName}; 1171 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1172 "MSG_REQUIRED_ATTRIBUTE_NOT_SPECIFIED", args, 1173 XMLErrorReporter.SEVERITY_ERROR); 1174 } 1175 } 1176 else if (attValue != null) { 1177 if (fPerformValidation && fGrammarBucket.getStandalone()) { 1178 if (fDTDGrammar.getAttributeDeclIsExternal(attlistIndex)) { 1179 1180 Object[] args = { elementName.localpart, attRawName}; 1181 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1182 "MSG_DEFAULTED_ATTRIBUTE_NOT_SPECIFIED", args, 1183 XMLErrorReporter.SEVERITY_ERROR); 1184 } 1185 } 1186 1187 // add namespace information 1188 if (fNamespaces) { 1189 int index = attRawName.indexOf(':'); 1190 if (index != -1) { 1191 attPrefix = attRawName.substring(0, index); 1192 attPrefix = fSymbolTable.addSymbol(attPrefix); 1193 attLocalpart = attRawName.substring(index + 1); 1194 attLocalpart = fSymbolTable.addSymbol(attLocalpart); 1195 } 1196 } 1197 1198 // add attribute 1199 fTempQName.setValues(attPrefix, attLocalpart, attRawName, fTempAttDecl.name.uri); 1200 int newAttr = attributes.addAttribute(fTempQName, attType, attValue); 1201 } 1202 } 1203 // get next att decl in the Grammar for this element 1204 attlistIndex = fDTDGrammar.getNextAttributeDeclIndex(attlistIndex); 1205 } 1206 1207 // now iterate through the expanded attributes for 1208 // 1. if every attribute seen is declared in the DTD 1209 // 2. check if the VC: default_fixed holds 1210 // 3. validate every attribute. 1211 int attrCount = attributes.getLength(); 1212 for (int i = 0; i < attrCount; i++) { 1213 String attrRawName = attributes.getQName(i); 1214 boolean declared = false; 1215 if (fPerformValidation) { 1216 if (fGrammarBucket.getStandalone()) { 1217 // check VC: Standalone Document Declaration, entities 1218 // references appear in the document. 1219 // REVISIT: this can be combined to a single check in 1220 // startEntity if we add one more argument in 1221 // startEnity, inAttrValue 1222 String nonNormalizedValue = attributes.getNonNormalizedValue(i); 1223 if (nonNormalizedValue != null) { 1224 String entityName = getExternalEntityRefInAttrValue(nonNormalizedValue); 1225 if (entityName != null) { 1226 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1227 "MSG_REFERENCE_TO_EXTERNALLY_DECLARED_ENTITY_WHEN_STANDALONE", 1228 new Object[]{entityName}, 1229 XMLErrorReporter.SEVERITY_ERROR); 1230 } 1231 } 1232 } 1233 } 1234 int attDefIndex = -1; 1235 int position = 1236 fDTDGrammar.getFirstAttributeDeclIndex(elementIndex); 1237 while (position != -1) { 1238 fDTDGrammar.getAttributeDecl(position, fTempAttDecl); 1239 if (fTempAttDecl.name.rawname == attrRawName) { 1240 // found the match att decl, 1241 attDefIndex = position; 1242 declared = true; 1243 break; 1244 } 1245 position = fDTDGrammar.getNextAttributeDeclIndex(position); 1246 } 1247 if (!declared) { 1248 if (fPerformValidation) { 1249 // REVISIT - cache the elem/attr tuple so that we only 1250 // give this error once for each unique occurrence 1251 Object[] args = { elementName.rawname, attrRawName}; 1252 1253 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1254 "MSG_ATTRIBUTE_NOT_DECLARED", 1255 args,XMLErrorReporter.SEVERITY_ERROR); 1256 } 1257 continue; 1258 } 1259 // attribute is declared 1260 1261 // fTempAttDecl should have the right value set now, so 1262 // the following is not needed 1263 // fGrammar.getAttributeDecl(attDefIndex,fTempAttDecl); 1264 1265 String type = getAttributeTypeName(fTempAttDecl); 1266 attributes.setType(i, type); 1267 attributes.getAugmentations(i).putItem(Constants.ATTRIBUTE_DECLARED, Boolean.TRUE); 1268 1269 boolean changedByNormalization = false; 1270 String oldValue = attributes.getValue(i); 1271 String attrValue = oldValue; 1272 if (attributes.isSpecified(i) && type != XMLSymbols.fCDATASymbol) { 1273 changedByNormalization = normalizeAttrValue(attributes, i); 1274 attrValue = attributes.getValue(i); 1275 if (fPerformValidation && fGrammarBucket.getStandalone() 1276 && changedByNormalization 1277 && fDTDGrammar.getAttributeDeclIsExternal(position) 1278 ) { 1279 // check VC: Standalone Document Declaration 1280 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1281 "MSG_ATTVALUE_CHANGED_DURING_NORMALIZATION_WHEN_STANDALONE", 1282 new Object[]{attrRawName, oldValue, attrValue}, 1283 XMLErrorReporter.SEVERITY_ERROR); 1284 } 1285 } 1286 if (!fPerformValidation) { 1287 continue; 1288 } 1289 if (fTempAttDecl.simpleType.defaultType == 1290 XMLSimpleType.DEFAULT_TYPE_FIXED) { 1291 String defaultValue = fTempAttDecl.simpleType.defaultValue; 1292 1293 if (!attrValue.equals(defaultValue)) { 1294 Object[] args = {elementName.localpart, 1295 attrRawName, 1296 attrValue, 1297 defaultValue}; 1298 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1299 "MSG_FIXED_ATTVALUE_INVALID", 1300 args, XMLErrorReporter.SEVERITY_ERROR); 1301 } 1302 } 1303 1304 if (fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_ENTITY || 1305 fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_ENUMERATION || 1306 fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_ID || 1307 fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_IDREF || 1308 fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_NMTOKEN || 1309 fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_NOTATION 1310 ) { 1311 validateDTDattribute(elementName, attrValue, fTempAttDecl); 1312 } 1313 } // for all attributes 1314 1315 } // addDTDDefaultAttrsAndValidate(int,XMLAttrList) 1316 1317 /** Checks entities in attribute values for standalone VC. */ 1318 protected String getExternalEntityRefInAttrValue(String nonNormalizedValue) { 1319 int valLength = nonNormalizedValue.length(); 1320 int ampIndex = nonNormalizedValue.indexOf('&'); 1321 while (ampIndex != -1) { 1322 if (ampIndex + 1 < valLength && 1323 nonNormalizedValue.charAt(ampIndex+1) != '#') { 1324 int semicolonIndex = nonNormalizedValue.indexOf(';', ampIndex+1); 1325 String entityName = nonNormalizedValue.substring(ampIndex+1, semicolonIndex); 1326 entityName = fSymbolTable.addSymbol(entityName); 1327 int entIndex = fDTDGrammar.getEntityDeclIndex(entityName); 1328 if (entIndex > -1) { 1329 fDTDGrammar.getEntityDecl(entIndex, fEntityDecl); 1330 if (fEntityDecl.inExternal || 1331 (entityName = getExternalEntityRefInAttrValue(fEntityDecl.value)) != null) { 1332 return entityName; 1333 } 1334 } 1335 } 1336 ampIndex = nonNormalizedValue.indexOf('&', ampIndex+1); 1337 } 1338 return null; 1339 } // isExternalEntityRefInAttrValue(String):String 1340 1341 /** 1342 * Validate attributes in DTD fashion. 1343 */ 1344 protected void validateDTDattribute(QName element, String attValue, 1345 XMLAttributeDecl attributeDecl) 1346 throws XNIException { 1347 1348 switch (attributeDecl.simpleType.type) { 1349 case XMLSimpleType.TYPE_ENTITY: { 1350 // NOTE: Save this information because invalidStandaloneAttDef 1351 boolean isAlistAttribute = attributeDecl.simpleType.list; 1352 1353 try { 1354 if (isAlistAttribute) { 1355 fValENTITIES.validate(attValue, fValidationState); 1356 } 1357 else { 1358 fValENTITY.validate(attValue, fValidationState); 1359 } 1360 } 1361 catch (InvalidDatatypeValueException ex) { 1362 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1363 ex.getKey(), 1364 ex.getArgs(), 1365 XMLErrorReporter.SEVERITY_ERROR ); 1366 1367 } 1368 break; 1369 } 1370 1371 case XMLSimpleType.TYPE_NOTATION: 1372 case XMLSimpleType.TYPE_ENUMERATION: { 1373 boolean found = false; 1374 String [] enumVals = attributeDecl.simpleType.enumeration; 1375 if (enumVals == null) { 1376 found = false; 1377 } 1378 else 1379 for (int i = 0; i < enumVals.length; i++) { 1380 if (attValue == enumVals[i] || attValue.equals(enumVals[i])) { 1381 found = true; 1382 break; 1383 } 1384 } 1385 1386 if (!found) { 1387 StringBuffer enumValueString = new StringBuffer(); 1388 if (enumVals != null) 1389 for (int i = 0; i < enumVals.length; i++) { 1390 enumValueString.append(enumVals[i]+" "); 1391 } 1392 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1393 "MSG_ATTRIBUTE_VALUE_NOT_IN_LIST", 1394 new Object[]{attributeDecl.name.rawname, attValue, enumValueString}, 1395 XMLErrorReporter.SEVERITY_ERROR); 1396 } 1397 break; 1398 } 1399 1400 case XMLSimpleType.TYPE_ID: { 1401 try { 1402 fValID.validate(attValue, fValidationState); 1403 } 1404 catch (InvalidDatatypeValueException ex) { 1405 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1406 ex.getKey(), 1407 ex.getArgs(), 1408 XMLErrorReporter.SEVERITY_ERROR ); 1409 } 1410 break; 1411 } 1412 1413 case XMLSimpleType.TYPE_IDREF: { 1414 boolean isAlistAttribute = attributeDecl.simpleType.list;//Caveat - Save this information because invalidStandaloneAttDef 1415 1416 try { 1417 if (isAlistAttribute) { 1418 fValIDRefs.validate(attValue, fValidationState); 1419 } 1420 else { 1421 fValIDRef.validate(attValue, fValidationState); 1422 } 1423 } 1424 catch (InvalidDatatypeValueException ex) { 1425 if (isAlistAttribute) { 1426 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1427 "IDREFSInvalid", 1428 new Object[]{attValue}, 1429 XMLErrorReporter.SEVERITY_ERROR ); 1430 } 1431 else { 1432 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1433 ex.getKey(), 1434 ex.getArgs(), 1435 XMLErrorReporter.SEVERITY_ERROR ); 1436 } 1437 1438 } 1439 break; 1440 } 1441 1442 case XMLSimpleType.TYPE_NMTOKEN: { 1443 boolean isAlistAttribute = attributeDecl.simpleType.list;//Caveat - Save this information because invalidStandaloneAttDef 1444 //changes fTempAttDef 1445 try { 1446 if (isAlistAttribute) { 1447 fValNMTOKENS.validate(attValue, fValidationState); 1448 } 1449 else { 1450 fValNMTOKEN.validate(attValue, fValidationState); 1451 } 1452 } 1453 catch (InvalidDatatypeValueException ex) { 1454 if (isAlistAttribute) { 1455 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1456 "NMTOKENSInvalid", 1457 new Object[] { attValue}, 1458 XMLErrorReporter.SEVERITY_ERROR); 1459 } 1460 else { 1461 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1462 "NMTOKENInvalid", 1463 new Object[] { attValue}, 1464 XMLErrorReporter.SEVERITY_ERROR); 1465 } 1466 } 1467 break; 1468 } 1469 1470 } // switch 1471 1472 } // validateDTDattribute(QName,String,XMLAttributeDecl) 1473 1474 1475 /** Returns true if invalid standalone attribute definition. */ 1476 protected boolean invalidStandaloneAttDef(QName element, QName attribute) { 1477 // REVISIT: This obviously needs to be fixed! -Ac 1478 boolean state = true; 1479 /* 1480 if (fStandaloneReader == -1) { 1481 return false; 1482 } 1483 // we are normalizing a default att value... this ok? 1484 if (element.rawname == -1) { 1485 return false; 1486 } 1487 return getAttDefIsExternal(element, attribute); 1488 */ 1489 return state; 1490 } 1491 1492 1493 // 1494 // Private methods 1495 // 1496 1497 1498 /** 1499 * Normalize the attribute value of a non CDATA attributes collapsing 1500 * sequences of space characters (x20) 1501 * 1502 * @param attributes The list of attributes 1503 * @param index The index of the attribute to normalize 1504 */ 1505 private boolean normalizeAttrValue(XMLAttributes attributes, int index) { 1506 // vars 1507 boolean leadingSpace = true; 1508 boolean spaceStart = false; 1509 boolean readingNonSpace = false; 1510 int count = 0; 1511 int eaten = 0; 1512 String attrValue = attributes.getValue(index); 1513 char[] attValue = new char[attrValue.length()]; 1514 1515 fBuffer.setLength(0); 1516 attrValue.getChars(0, attrValue.length(), attValue, 0); 1517 for (int i = 0; i < attValue.length; i++) { 1518 1519 if (attValue[i] == ' ') { 1520 1521 // now the tricky part 1522 if (readingNonSpace) { 1523 spaceStart = true; 1524 readingNonSpace = false; 1525 } 1526 1527 if (spaceStart && !leadingSpace) { 1528 spaceStart = false; 1529 fBuffer.append(attValue[i]); 1530 count++; 1531 } 1532 else { 1533 if (leadingSpace || !spaceStart) { 1534 eaten ++; 1535 /*** BUG #3512 *** 1536 int entityCount = attributes.getEntityCount(index); 1537 for (int j = 0; j < entityCount; j++) { 1538 int offset = attributes.getEntityOffset(index, j); 1539 int length = attributes.getEntityLength(index, j); 1540 if (offset <= i-eaten+1) { 1541 if (offset+length >= i-eaten+1) { 1542 if (length > 0) 1543 length--; 1544 } 1545 } 1546 else { 1547 if (offset > 0) 1548 offset--; 1549 } 1550 attributes.setEntityOffset(index, j, offset); 1551 attributes.setEntityLength(index, j, length); 1552 } 1553 /***/ 1554 } 1555 } 1556 1557 } 1558 else { 1559 readingNonSpace = true; 1560 spaceStart = false; 1561 leadingSpace = false; 1562 fBuffer.append(attValue[i]); 1563 count++; 1564 } 1565 } 1566 1567 // check if the last appended character is a space. 1568 if (count > 0 && fBuffer.charAt(count-1) == ' ') { 1569 fBuffer.setLength(count-1); 1570 /*** BUG #3512 *** 1571 int entityCount = attributes.getEntityCount(index); 1572 for (int j=0; j < entityCount; j++) { 1573 int offset = attributes.getEntityOffset(index, j); 1574 int length = attributes.getEntityLength(index, j); 1575 if (offset < count-1) { 1576 if (offset+length == count) { 1577 length--; 1578 } 1579 } 1580 else { 1581 offset--; 1582 } 1583 attributes.setEntityOffset(index, j, offset); 1584 attributes.setEntityLength(index, j, length); 1585 } 1586 /***/ 1587 } 1588 String newValue = fBuffer.toString(); 1589 attributes.setValue(index, newValue); 1590 return ! attrValue.equals(newValue); 1591 } 1592 1593 /** Root element specified. */ 1594 private final void rootElementSpecified(QName rootElement) throws XNIException { 1595 if (fPerformValidation) { 1596 String root1 = fRootElement.rawname; 1597 String root2 = rootElement.rawname; 1598 if (root1 == null || !root1.equals(root2)) { 1599 fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN, 1600 "RootElementTypeMustMatchDoctypedecl", 1601 new Object[]{root1, root2}, 1602 XMLErrorReporter.SEVERITY_ERROR); 1603 } 1604 } 1605 } // rootElementSpecified(QName) 1606 1607 /** 1608 * Check that the content of an element is valid. 1609 * <p> 1610 * This is the method of primary concern to the validator. This method is called 1611 * upon the scanner reaching the end tag of an element. At that time, the 1612 * element's children must be structurally validated, so it calls this method. 1613 * The index of the element being checked (in the decl pool), is provided as 1614 * well as an array of element name indexes of the children. The validator must 1615 * confirm that this element can have these children in this order. 1616 * <p> 1617 * This can also be called to do 'what if' testing of content models just to see 1618 * if they would be valid. 1619 * <p> 1620 * Note that the element index is an index into the element decl pool, whereas 1621 * the children indexes are name indexes, i.e. into the string pool. 1622 * <p> 1623 * A value of -1 in the children array indicates a PCDATA node. All other 1624 * indexes will be positive and represent child elements. The count can be 1625 * zero, since some elements have the EMPTY content model and that must be 1626 * confirmed. 1627 * 1628 * @param elementIndex The index within the <code>ElementDeclPool</code> of this 1629 * element. 1630 * @param childCount The number of entries in the <code>children</code> array. 1631 * @param children The children of this element. 1632 * 1633 * @return The value -1 if fully valid, else the 0 based index of the child 1634 * that first failed. If the value returned is equal to the number 1635 * of children, then additional content is required to reach a valid 1636 * ending state. 1637 * 1638 * @exception Exception Thrown on error. 1639 */ 1640 private int checkContent(int elementIndex, 1641 QName[] children, 1642 int childOffset, 1643 int childCount) throws XNIException { 1644 1645 fDTDGrammar.getElementDecl(elementIndex, fTempElementDecl); 1646 1647 // Get the element name index from the element 1648 final String elementType = fCurrentElement.rawname; 1649 1650 // Get out the content spec for this element 1651 final int contentType = fCurrentContentSpecType; 1652 1653 1654 // 1655 // Deal with the possible types of content. We try to optimized here 1656 // by dealing specially with content models that don't require the 1657 // full DFA treatment. 1658 // 1659 if (contentType == XMLElementDecl.TYPE_EMPTY) { 1660 // 1661 // If the child count is greater than zero, then this is 1662 // an error right off the bat at index 0. 1663 // 1664 if (childCount != 0) { 1665 return 0; 1666 } 1667 } 1668 else if (contentType == XMLElementDecl.TYPE_ANY) { 1669 // 1670 // This one is open game so we don't pass any judgement on it 1671 // at all. Its assumed to fine since it can hold anything. 1672 // 1673 } 1674 else if (contentType == XMLElementDecl.TYPE_MIXED || 1675 contentType == XMLElementDecl.TYPE_CHILDREN) { 1676 // Get the content model for this element, faulting it in if needed 1677 ContentModelValidator cmElem = null; 1678 cmElem = fTempElementDecl.contentModelValidator; 1679 int result = cmElem.validate(children, childOffset, childCount); 1680 return result; 1681 } 1682 else if (contentType == -1) { 1683 //REVISIT 1684 /**** 1685 reportRecoverableXMLError(XMLMessages.MSG_ELEMENT_NOT_DECLARED, 1686 XMLMessages.VC_ELEMENT_VALID, 1687 elementType); 1688 /****/ 1689 } 1690 else if (contentType == XMLElementDecl.TYPE_SIMPLE) { 1691 1692 //REVISIT 1693 // this should never be reached in the case of DTD validation. 1694 1695 } 1696 else { 1697 //REVISIT 1698 /**** 1699 fErrorReporter.reportError(fErrorReporter.getLocator(), 1700 ImplementationMessages.XERCES_IMPLEMENTATION_DOMAIN, 1701 ImplementationMessages.VAL_CST, 1702 0, 1703 null, 1704 XMLErrorReporter.ERRORTYPE_FATAL_ERROR); 1705 /****/ 1706 } 1707 1708 // We succeeded 1709 return -1; 1710 1711 } // checkContent(int,int,QName[]):int 1712 1713 /** Returns the content spec type for an element index. */ 1714 private int getContentSpecType(int elementIndex) { 1715 1716 int contentSpecType = -1; 1717 if (elementIndex > -1) { 1718 if (fDTDGrammar.getElementDecl(elementIndex,fTempElementDecl)) { 1719 contentSpecType = fTempElementDecl.type; 1720 } 1721 } 1722 return contentSpecType; 1723 } 1724 1725 /** Character data in content. */ 1726 private void charDataInContent() { 1727 1728 if (DEBUG_ELEMENT_CHILDREN) { 1729 System.out.println("charDataInContent()"); 1730 } 1731 if (fElementChildren.length <= fElementChildrenLength) { 1732 QName[] newarray = new QName[fElementChildren.length * 2]; 1733 System.arraycopy(fElementChildren, 0, newarray, 0, fElementChildren.length); 1734 fElementChildren = newarray; 1735 } 1736 QName qname = fElementChildren[fElementChildrenLength]; 1737 if (qname == null) { 1738 for (int i = fElementChildrenLength; i < fElementChildren.length; i++) { 1739 fElementChildren[i] = new QName(); 1740 } 1741 qname = fElementChildren[fElementChildrenLength]; 1742 } 1743 qname.clear(); 1744 fElementChildrenLength++; 1745 1746 } // charDataInCount() 1747 1748 /** convert attribute type from ints to strings */ 1749 private String getAttributeTypeName(XMLAttributeDecl attrDecl) { 1750 1751 switch (attrDecl.simpleType.type) { 1752 case XMLSimpleType.TYPE_ENTITY: { 1753 return attrDecl.simpleType.list ? XMLSymbols.fENTITIESSymbol : XMLSymbols.fENTITYSymbol; 1754 } 1755 case XMLSimpleType.TYPE_ENUMERATION: { 1756 StringBuffer buffer = new StringBuffer(); 1757 buffer.append('('); 1758 for (int i=0; i<attrDecl.simpleType.enumeration.length ; i++) { 1759 if (i > 0) { 1760 buffer.append('|'); 1761 } 1762 buffer.append(attrDecl.simpleType.enumeration[i]); 1763 } 1764 buffer.append(')'); 1765 return fSymbolTable.addSymbol(buffer.toString()); 1766 } 1767 case XMLSimpleType.TYPE_ID: { 1768 return XMLSymbols.fIDSymbol; 1769 } 1770 case XMLSimpleType.TYPE_IDREF: { 1771 return attrDecl.simpleType.list ? XMLSymbols.fIDREFSSymbol : XMLSymbols.fIDREFSymbol; 1772 } 1773 case XMLSimpleType.TYPE_NMTOKEN: { 1774 return attrDecl.simpleType.list ? XMLSymbols.fNMTOKENSSymbol : XMLSymbols.fNMTOKENSymbol; 1775 } 1776 case XMLSimpleType.TYPE_NOTATION: { 1777 return XMLSymbols.fNOTATIONSymbol; 1778 } 1779 } 1780 return XMLSymbols.fCDATASymbol; 1781 1782 } // getAttributeTypeName(XMLAttributeDecl):String 1783 1784 /** initialization */ 1785 protected void init() { 1786 1787 // datatype validators 1788 if (fValidation || fDynamicValidation) { 1789 try { 1790 //REVISIT: datatypeRegistry + initialization of datatype 1791 // why do we cast to ListDatatypeValidator? 1792 fValID = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fIDSymbol); 1793 fValIDRef = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fIDREFSymbol); 1794 fValIDRefs = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fIDREFSSymbol); 1795 fValENTITY = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fENTITYSymbol); 1796 fValENTITIES = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fENTITIESSymbol); 1797 fValNMTOKEN = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fNMTOKENSymbol); 1798 fValNMTOKENS = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fNMTOKENSSymbol); 1799 fValNOTATION = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fNOTATIONSymbol); 1800 1801 } 1802 catch (Exception e) { 1803 // should never happen 1804 e.printStackTrace(System.err); 1805 } 1806 1807 } 1808 1809 } // init() 1810 1811 /** ensure element stack capacity */ 1812 private void ensureStackCapacity (int newElementDepth) { 1813 if (newElementDepth == fElementQNamePartsStack.length) { 1814 1815 QName[] newStackOfQueue = new QName[newElementDepth * 2]; 1816 System.arraycopy(this.fElementQNamePartsStack, 0, newStackOfQueue, 0, newElementDepth ); 1817 fElementQNamePartsStack = newStackOfQueue; 1818 1819 QName qname = fElementQNamePartsStack[newElementDepth]; 1820 if (qname == null) { 1821 for (int i = newElementDepth; i < fElementQNamePartsStack.length; i++) { 1822 fElementQNamePartsStack[i] = new QName(); 1823 } 1824 } 1825 1826 int[] newStack = new int[newElementDepth * 2]; 1827 System.arraycopy(fElementIndexStack, 0, newStack, 0, newElementDepth); 1828 fElementIndexStack = newStack; 1829 1830 newStack = new int[newElementDepth * 2]; 1831 System.arraycopy(fContentSpecTypeStack, 0, newStack, 0, newElementDepth); 1832 fContentSpecTypeStack = newStack; 1833 1834 } 1835 } // ensureStackCapacity 1836 1837 1838 // 1839 // Protected methods 1840 // 1841 1842 /** Handle element 1843 * @return true if validator is removed from the pipeline 1844 */ 1845 protected boolean handleStartElement(QName element, XMLAttributes attributes, Augmentations augs) 1846 throws XNIException { 1847 1848 1849 // VC: Root Element Type 1850 // see if the root element's name matches the one in DoctypeDecl 1851 if (!fSeenRootElement) { 1852 // REVISIT: Here are current assumptions about validation features 1853 // given that XMLSchema validator is in the pipeline 1854 // 1855 // http://xml.org/sax/features/validation = true 1856 // http://apache.org/xml/features/validation/schema = true 1857 // 1858 // [1] XML instance document only has reference to a DTD 1859 // Outcome: report validation errors only against dtd. 1860 // 1861 // [2] XML instance document has only XML Schema grammars: 1862 // Outcome: report validation errors only against schemas (no errors produced from DTD validator) 1863 // 1864 // [3] XML instance document has DTD and XML schemas: 1865 // [a] if schema language is not set outcome - validation errors reported against both grammars: DTD and schemas. 1866 // [b] if schema language is set to XML Schema - do not report validation errors 1867 // 1868 // if dynamic validation is on 1869 // validate only against grammar we've found (depending on settings 1870 // for schema feature) 1871 // 1872 // 1873 fPerformValidation = validate(); 1874 fSeenRootElement = true; 1875 fValidationManager.setEntityState(fDTDGrammar); 1876 fValidationManager.setGrammarFound(fSeenDoctypeDecl); 1877 rootElementSpecified(element); 1878 } 1879 if (fDTDGrammar == null) { 1880 1881 if (!fPerformValidation) { 1882 fCurrentElementIndex = -1; 1883 fCurrentContentSpecType = -1; 1884 fInElementContent = false; 1885 } 1886 if (fPerformValidation) { 1887 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1888 "MSG_GRAMMAR_NOT_FOUND", 1889 new Object[]{ element.rawname}, 1890 XMLErrorReporter.SEVERITY_ERROR); 1891 } 1892 // modify pipeline 1893 if (fDocumentSource !=null ) { 1894 fDocumentSource.setDocumentHandler(fDocumentHandler); 1895 if (fDocumentHandler != null) 1896 fDocumentHandler.setDocumentSource(fDocumentSource); 1897 return true; 1898 } 1899 } 1900 else { 1901 // resolve the element 1902 fCurrentElementIndex = fDTDGrammar.getElementDeclIndex(element); 1903 //changed here.. new function for getContentSpecType 1904 fCurrentContentSpecType = fDTDGrammar.getContentSpecType(fCurrentElementIndex); 1905 if (fCurrentContentSpecType == -1 && fPerformValidation) { 1906 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1907 "MSG_ELEMENT_NOT_DECLARED", 1908 new Object[]{ element.rawname}, 1909 XMLErrorReporter.SEVERITY_ERROR); 1910 } 1911 1912 // 0. insert default attributes 1913 // 1. normalize the attributes 1914 // 2. validate the attrivute list. 1915 // TO DO: 1916 //changed here.. also pass element name, 1917 addDTDDefaultAttrsAndValidate(element, fCurrentElementIndex, attributes); 1918 } 1919 1920 // set element content state 1921 fInElementContent = fCurrentContentSpecType == XMLElementDecl.TYPE_CHILDREN; 1922 1923 // increment the element depth, add this element's 1924 // QName to its enclosing element 's children list 1925 fElementDepth++; 1926 if (fPerformValidation) { 1927 // push current length onto stack 1928 if (fElementChildrenOffsetStack.length <= fElementDepth) { 1929 int newarray[] = new int[fElementChildrenOffsetStack.length * 2]; 1930 System.arraycopy(fElementChildrenOffsetStack, 0, newarray, 0, fElementChildrenOffsetStack.length); 1931 fElementChildrenOffsetStack = newarray; 1932 } 1933 fElementChildrenOffsetStack[fElementDepth] = fElementChildrenLength; 1934 1935 // add this element to children 1936 if (fElementChildren.length <= fElementChildrenLength) { 1937 QName[] newarray = new QName[fElementChildrenLength * 2]; 1938 System.arraycopy(fElementChildren, 0, newarray, 0, fElementChildren.length); 1939 fElementChildren = newarray; 1940 } 1941 QName qname = fElementChildren[fElementChildrenLength]; 1942 if (qname == null) { 1943 for (int i = fElementChildrenLength; i < fElementChildren.length; i++) { 1944 fElementChildren[i] = new QName(); 1945 } 1946 qname = fElementChildren[fElementChildrenLength]; 1947 } 1948 qname.setValues(element); 1949 fElementChildrenLength++; 1950 } 1951 1952 // save current element information 1953 fCurrentElement.setValues(element); 1954 ensureStackCapacity(fElementDepth); 1955 fElementQNamePartsStack[fElementDepth].setValues(fCurrentElement); 1956 fElementIndexStack[fElementDepth] = fCurrentElementIndex; 1957 fContentSpecTypeStack[fElementDepth] = fCurrentContentSpecType; 1958 startNamespaceScope(element, attributes, augs); 1959 return false; 1960 1961 } // handleStartElement(QName,XMLAttributes) 1962 1963 protected void startNamespaceScope(QName element, XMLAttributes attributes, Augmentations augs){ 1964 } 1965 1966 /** Handle end element. */ 1967 protected void handleEndElement(QName element, Augmentations augs, boolean isEmpty) 1968 throws XNIException { 1969 1970 // decrease element depth 1971 fElementDepth--; 1972 1973 // validate 1974 if (fPerformValidation) { 1975 int elementIndex = fCurrentElementIndex; 1976 if (elementIndex != -1 && fCurrentContentSpecType != -1) { 1977 QName children[] = fElementChildren; 1978 int childrenOffset = fElementChildrenOffsetStack[fElementDepth + 1] + 1; 1979 int childrenLength = fElementChildrenLength - childrenOffset; 1980 int result = checkContent(elementIndex, 1981 children, childrenOffset, childrenLength); 1982 1983 if (result != -1) { 1984 fDTDGrammar.getElementDecl(elementIndex, fTempElementDecl); 1985 if (fTempElementDecl.type == XMLElementDecl.TYPE_EMPTY) { 1986 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1987 "MSG_CONTENT_INVALID", 1988 new Object[]{ element.rawname, "EMPTY"}, 1989 XMLErrorReporter.SEVERITY_ERROR); 1990 } 1991 else { 1992 String messageKey = result != childrenLength ? 1993 "MSG_CONTENT_INVALID" : "MSG_CONTENT_INCOMPLETE"; 1994 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1995 messageKey, 1996 new Object[]{ element.rawname, 1997 fDTDGrammar.getContentSpecAsString(elementIndex)}, 1998 XMLErrorReporter.SEVERITY_ERROR); 1999 } 2000 } 2001 } 2002 fElementChildrenLength = fElementChildrenOffsetStack[fElementDepth + 1] + 1; 2003 } 2004 2005 endNamespaceScope(fCurrentElement, augs, isEmpty); 2006 2007 // now pop this element off the top of the element stack 2008 if (fElementDepth < -1) { 2009 throw new RuntimeException("FWK008 Element stack underflow"); 2010 } 2011 if (fElementDepth < 0) { 2012 fCurrentElement.clear(); 2013 fCurrentElementIndex = -1; 2014 fCurrentContentSpecType = -1; 2015 fInElementContent = false; 2016 2017 // TO DO : fix this 2018 // 2019 // Check after document is fully parsed 2020 // (1) check that there was an element with a matching id for every 2021 // IDREF and IDREFS attr (V_IDREF0) 2022 // 2023 if (fPerformValidation) { 2024 String value = fValidationState.checkIDRefID(); 2025 if (value != null) { 2026 fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN, 2027 "MSG_ELEMENT_WITH_ID_REQUIRED", 2028 new Object[]{value}, 2029 XMLErrorReporter.SEVERITY_ERROR ); 2030 } 2031 } 2032 return; 2033 } 2034 2035 // If Namespace enable then localName != rawName 2036 fCurrentElement.setValues(fElementQNamePartsStack[fElementDepth]); 2037 2038 fCurrentElementIndex = fElementIndexStack[fElementDepth]; 2039 fCurrentContentSpecType = fContentSpecTypeStack[fElementDepth]; 2040 fInElementContent = (fCurrentContentSpecType == XMLElementDecl.TYPE_CHILDREN); 2041 2042 } // handleEndElement(QName,boolean) 2043 2044 protected void endNamespaceScope(QName element, Augmentations augs, boolean isEmpty){ 2045 2046 // call handlers 2047 if (fDocumentHandler != null && !isEmpty) { 2048 // NOTE: The binding of the element doesn't actually happen 2049 // yet because the namespace binder does that. However, 2050 // if it does it before this point, then the endPrefix- 2051 // Mapping calls get made too soon! As long as the 2052 // rawnames match, we know it'll have a good binding, 2053 // so we can just use the current element. -Ac 2054 fDocumentHandler.endElement(fCurrentElement, augs); 2055 } 2056 } 2057 2058 // returns whether a character is space according to the 2059 // version of XML this validator supports. 2060 protected boolean isSpace(int c) { 2061 return XMLChar.isSpace(c); 2062 } // isSpace(int): boolean 2063 2064 public boolean characterData(String data, Augmentations augs) { 2065 characters(new XMLString(data.toCharArray(), 0, data.length()), augs); 2066 return true; 2067 } 2068 2069 } // class XMLDTDValidator