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.xs; 22 23 import java.io.IOException; 24 import java.util.ArrayList; 25 import java.util.HashMap; 26 import java.util.Hashtable; 27 import java.util.Iterator; 28 import java.util.Map; 29 import java.util.Stack; 30 import java.util.Vector; 31 import java.util.ArrayList; 32 import javax.xml.XMLConstants; 33 import com.sun.org.apache.xerces.internal.impl.Constants; 34 import com.sun.org.apache.xerces.internal.impl.RevalidationHandler; 35 import com.sun.org.apache.xerces.internal.impl.XMLEntityManager; 36 import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter; 37 import com.sun.org.apache.xerces.internal.impl.dv.DatatypeException; 38 import com.sun.org.apache.xerces.internal.impl.dv.InvalidDatatypeValueException; 39 import com.sun.org.apache.xerces.internal.impl.dv.ValidatedInfo; 40 import com.sun.org.apache.xerces.internal.impl.dv.XSSimpleType; 41 import com.sun.org.apache.xerces.internal.impl.validation.ValidationManager; 42 import com.sun.org.apache.xerces.internal.impl.validation.ValidationState; 43 import com.sun.org.apache.xerces.internal.impl.xs.identity.Field; 44 import com.sun.org.apache.xerces.internal.impl.xs.identity.FieldActivator; 45 import com.sun.org.apache.xerces.internal.impl.xs.identity.IdentityConstraint; 46 import com.sun.org.apache.xerces.internal.impl.xs.identity.KeyRef; 47 import com.sun.org.apache.xerces.internal.impl.xs.identity.Selector; 48 import com.sun.org.apache.xerces.internal.impl.xs.identity.UniqueOrKey; 49 import com.sun.org.apache.xerces.internal.impl.xs.identity.ValueStore; 50 import com.sun.org.apache.xerces.internal.impl.xs.identity.XPathMatcher; 51 import com.sun.org.apache.xerces.internal.impl.xs.models.CMBuilder; 52 import com.sun.org.apache.xerces.internal.impl.xs.models.CMNodeFactory; 53 import com.sun.org.apache.xerces.internal.impl.xs.models.XSCMValidator; 54 import com.sun.org.apache.xerces.internal.util.AugmentationsImpl; 55 import com.sun.org.apache.xerces.internal.util.IntStack; 56 import com.sun.org.apache.xerces.internal.util.SymbolTable; 57 import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl; 58 import com.sun.org.apache.xerces.internal.util.XMLChar; 59 import com.sun.org.apache.xerces.internal.util.XMLSymbols; 60 import com.sun.org.apache.xerces.internal.util.URI.MalformedURIException; 61 import com.sun.org.apache.xerces.internal.xni.Augmentations; 62 import com.sun.org.apache.xerces.internal.xni.NamespaceContext; 63 import com.sun.org.apache.xerces.internal.xni.QName; 64 import com.sun.org.apache.xerces.internal.xni.XMLAttributes; 65 import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler; 66 import com.sun.org.apache.xerces.internal.xni.XMLLocator; 67 import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier; 68 import com.sun.org.apache.xerces.internal.xni.XMLString; 69 import com.sun.org.apache.xerces.internal.xni.XNIException; 70 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarDescription; 71 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarPool; 72 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent; 73 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager; 74 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException; 75 import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentFilter; 76 import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentSource; 77 import com.sun.org.apache.xerces.internal.xni.parser.XMLEntityResolver; 78 import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource; 79 import com.sun.org.apache.xerces.internal.xs.AttributePSVI; 80 import com.sun.org.apache.xerces.internal.xs.ElementPSVI; 81 import com.sun.org.apache.xerces.internal.xs.ShortList; 82 import com.sun.org.apache.xerces.internal.xs.StringList; 83 import com.sun.org.apache.xerces.internal.xs.XSConstants; 84 import com.sun.org.apache.xerces.internal.xs.XSObjectList; 85 import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition; 86 import com.sun.org.apache.xerces.internal.parsers.XMLParser; 87 88 /** 89 * The XML Schema validator. The validator implements a document 90 * filter: receiving document events from the scanner; validating 91 * the content and structure; augmenting the InfoSet, if applicable; 92 * and notifying the parser of the information resulting from the 93 * validation process. 94 * <p> 95 * This component requires the following features and properties from the 96 * component manager that uses it: 97 * <ul> 98 * <li>http://xml.org/sax/features/validation</li> 99 * <li>http://apache.org/xml/properties/internal/symbol-table</li> 100 * <li>http://apache.org/xml/properties/internal/error-reporter</li> 101 * <li>http://apache.org/xml/properties/internal/entity-resolver</li> 102 * </ul> 103 * 104 * @xerces.internal 105 * 106 * @author Sandy Gao IBM 107 * @author Elena Litani IBM 108 * @author Andy Clark IBM 109 * @author Neeraj Bajaj, Sun Microsystems, inc. 110 * @version $Id: XMLSchemaValidator.java,v 1.16 2010-11-01 04:39:55 joehw Exp $ 111 */ 112 public class XMLSchemaValidator 113 implements XMLComponent, XMLDocumentFilter, FieldActivator, RevalidationHandler { 114 115 // 116 // Constants 117 // 118 private static final boolean DEBUG = false; 119 120 // feature identifiers 121 122 /** Feature identifier: validation. */ 123 protected static final String VALIDATION = 124 Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE; 125 126 /** Feature identifier: validation. */ 127 protected static final String SCHEMA_VALIDATION = 128 Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE; 129 130 /** Feature identifier: schema full checking*/ 131 protected static final String SCHEMA_FULL_CHECKING = 132 Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_FULL_CHECKING; 133 134 /** Feature identifier: dynamic validation. */ 135 protected static final String DYNAMIC_VALIDATION = 136 Constants.XERCES_FEATURE_PREFIX + Constants.DYNAMIC_VALIDATION_FEATURE; 137 138 /** Feature identifier: expose schema normalized value */ 139 protected static final String NORMALIZE_DATA = 140 Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_NORMALIZED_VALUE; 141 142 /** Feature identifier: send element default value via characters() */ 143 protected static final String SCHEMA_ELEMENT_DEFAULT = 144 Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_ELEMENT_DEFAULT; 145 146 /** Feature identifier: augment PSVI */ 147 protected static final String SCHEMA_AUGMENT_PSVI = 148 Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_AUGMENT_PSVI; 149 150 /** Feature identifier: whether to recognize java encoding names */ 151 protected static final String ALLOW_JAVA_ENCODINGS = 152 Constants.XERCES_FEATURE_PREFIX + Constants.ALLOW_JAVA_ENCODINGS_FEATURE; 153 154 /** Feature identifier: standard uri conformant feature. */ 155 protected static final String STANDARD_URI_CONFORMANT_FEATURE = 156 Constants.XERCES_FEATURE_PREFIX + Constants.STANDARD_URI_CONFORMANT_FEATURE; 157 158 /** Feature: generate synthetic annotations */ 159 protected static final String GENERATE_SYNTHETIC_ANNOTATIONS = 160 Constants.XERCES_FEATURE_PREFIX + Constants.GENERATE_SYNTHETIC_ANNOTATIONS_FEATURE; 161 162 /** Feature identifier: validate annotations. */ 163 protected static final String VALIDATE_ANNOTATIONS = 164 Constants.XERCES_FEATURE_PREFIX + Constants.VALIDATE_ANNOTATIONS_FEATURE; 165 166 /** Feature identifier: honour all schemaLocations */ 167 protected static final String HONOUR_ALL_SCHEMALOCATIONS = 168 Constants.XERCES_FEATURE_PREFIX + Constants.HONOUR_ALL_SCHEMALOCATIONS_FEATURE; 169 170 /** Feature identifier: use grammar pool only */ 171 protected static final String USE_GRAMMAR_POOL_ONLY = 172 Constants.XERCES_FEATURE_PREFIX + Constants.USE_GRAMMAR_POOL_ONLY_FEATURE; 173 174 /** Feature identifier: whether to continue parsing a schema after a fatal error is encountered */ 175 protected static final String CONTINUE_AFTER_FATAL_ERROR = 176 Constants.XERCES_FEATURE_PREFIX + Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE; 177 178 protected static final String PARSER_SETTINGS = 179 Constants.XERCES_FEATURE_PREFIX + Constants.PARSER_SETTINGS; 180 181 /** Feature identifier: namespace growth */ 182 protected static final String NAMESPACE_GROWTH = 183 Constants.XERCES_FEATURE_PREFIX + Constants.NAMESPACE_GROWTH_FEATURE; 184 185 /** Feature identifier: tolerate duplicates */ 186 protected static final String TOLERATE_DUPLICATES = 187 Constants.XERCES_FEATURE_PREFIX + Constants.TOLERATE_DUPLICATES_FEATURE; 188 189 protected static final String REPORT_WHITESPACE = 190 Constants.SUN_SCHEMA_FEATURE_PREFIX + Constants.SUN_REPORT_IGNORED_ELEMENT_CONTENT_WHITESPACE; 191 192 // property identifiers 193 194 /** Property identifier: symbol table. */ 195 public static final String SYMBOL_TABLE = 196 Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; 197 198 /** Property identifier: error reporter. */ 199 public static final String ERROR_REPORTER = 200 Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; 201 202 /** Property identifier: entity resolver. */ 203 public static final String ENTITY_RESOLVER = 204 Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY; 205 206 /** Property identifier: grammar pool. */ 207 public static final String XMLGRAMMAR_POOL = 208 Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY; 209 210 protected static final String VALIDATION_MANAGER = 211 Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY; 212 213 protected static final String ENTITY_MANAGER = 214 Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY; 215 216 /** Property identifier: schema location. */ 217 protected static final String SCHEMA_LOCATION = 218 Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_LOCATION; 219 220 /** Property identifier: no namespace schema location. */ 221 protected static final String SCHEMA_NONS_LOCATION = 222 Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_NONS_LOCATION; 223 224 /** Property identifier: JAXP schema source. */ 225 protected static final String JAXP_SCHEMA_SOURCE = 226 Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_SOURCE; 227 228 /** Property identifier: JAXP schema language. */ 229 protected static final String JAXP_SCHEMA_LANGUAGE = 230 Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_LANGUAGE; 231 232 /** Property identifier: Schema DV Factory */ 233 protected static final String SCHEMA_DV_FACTORY = 234 Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_DV_FACTORY_PROPERTY; 235 236 /** property identifier: access external dtd. */ 237 private static final String ACCESS_EXTERNAL_DTD = XMLConstants.ACCESS_EXTERNAL_DTD; 238 239 /** Property identifier: access to external schema */ 240 private static final String ACCESS_EXTERNAL_SCHEMA = XMLConstants.ACCESS_EXTERNAL_SCHEMA; 241 242 protected static final String USE_SERVICE_MECHANISM = Constants.ORACLE_FEATURE_SERVICE_MECHANISM; 243 244 // recognized features and properties 245 246 /** Recognized features. */ 247 private static final String[] RECOGNIZED_FEATURES = 248 { 249 VALIDATION, 250 SCHEMA_VALIDATION, 251 DYNAMIC_VALIDATION, 252 SCHEMA_FULL_CHECKING, 253 ALLOW_JAVA_ENCODINGS, 254 CONTINUE_AFTER_FATAL_ERROR, 255 STANDARD_URI_CONFORMANT_FEATURE, 256 GENERATE_SYNTHETIC_ANNOTATIONS, 257 VALIDATE_ANNOTATIONS, 258 HONOUR_ALL_SCHEMALOCATIONS, 259 USE_GRAMMAR_POOL_ONLY, 260 NAMESPACE_GROWTH, 261 TOLERATE_DUPLICATES, 262 USE_SERVICE_MECHANISM 263 }; 264 265 /** Feature defaults. */ 266 private static final Boolean[] FEATURE_DEFAULTS = { null, 267 // NOTE: The following defaults are nulled out on purpose. 268 // If they are set, then when the XML Schema validator 269 // is constructed dynamically, these values may override 270 // those set by the application. This goes against the 271 // whole purpose of XMLComponent#getFeatureDefault but 272 // it can't be helped in this case. -Ac 273 null, //Boolean.FALSE, 274 null, //Boolean.FALSE, 275 null, //Boolean.FALSE, 276 null, //Boolean.FALSE, 277 null, //Boolean.FALSE, 278 null, 279 null, 280 null, 281 null, 282 null, 283 null, 284 null, 285 Boolean.TRUE 286 }; 287 288 /** Recognized properties. */ 289 private static final String[] RECOGNIZED_PROPERTIES = 290 { 291 SYMBOL_TABLE, 292 ERROR_REPORTER, 293 ENTITY_RESOLVER, 294 VALIDATION_MANAGER, 295 SCHEMA_LOCATION, 296 SCHEMA_NONS_LOCATION, 297 JAXP_SCHEMA_SOURCE, 298 JAXP_SCHEMA_LANGUAGE, 299 SCHEMA_DV_FACTORY, 300 ACCESS_EXTERNAL_DTD, 301 ACCESS_EXTERNAL_SCHEMA 302 }; 303 304 /** Property defaults. */ 305 private static final Object[] PROPERTY_DEFAULTS = 306 { null, null, null, null, null, null, null, null, null, null, null, null, null}; 307 308 // this is the number of valuestores of each kind 309 // we expect an element to have. It's almost 310 // never > 1; so leave it at that. 311 protected static final int ID_CONSTRAINT_NUM = 1; 312 313 // 314 private static final Hashtable EMPTY_TABLE = new Hashtable(); 315 316 // 317 // Data 318 // 319 320 /** current PSVI element info */ 321 protected ElementPSVImpl fCurrentPSVI = new ElementPSVImpl(); 322 323 // since it is the responsibility of each component to an 324 // Augmentations parameter if one is null, to save ourselves from 325 // having to create this object continually, it is created here. 326 // If it is not present in calls that we're passing on, we *must* 327 // clear this before we introduce it into the pipeline. 328 protected final AugmentationsImpl fAugmentations = new AugmentationsImpl(); 329 330 /** 331 * Map which is used to catch instance documents that try 332 * and match a field several times in the same scope. 333 */ 334 protected final HashMap fMayMatchFieldMap = new HashMap(); 335 336 // this is included for the convenience of handleEndElement 337 protected XMLString fDefaultValue; 338 339 // Validation features 340 protected boolean fDynamicValidation = false; 341 protected boolean fSchemaDynamicValidation = false; 342 protected boolean fDoValidation = false; 343 protected boolean fFullChecking = false; 344 protected boolean fNormalizeData = true; 345 protected boolean fSchemaElementDefault = true; 346 protected boolean fAugPSVI = true; 347 protected boolean fIdConstraint = false; 348 protected boolean fUseGrammarPoolOnly = false; 349 350 // Namespace growth feature 351 protected boolean fNamespaceGrowth = false; 352 353 /** Schema type: None, DTD, Schema */ 354 private String fSchemaType = null; 355 356 // to indicate whether we are in the scope of entity reference or CData 357 protected boolean fEntityRef = false; 358 protected boolean fInCDATA = false; 359 360 // Did we see only whitespace in element content? 361 protected boolean fSawOnlyWhitespaceInElementContent = false; 362 363 // properties 364 365 /** Symbol table. */ 366 protected SymbolTable fSymbolTable; 367 368 /** 369 * While parsing a document, keep the location of the document. 370 */ 371 private XMLLocator fLocator; 372 373 /** 374 * A wrapper of the standard error reporter. We'll store all schema errors 375 * in this wrapper object, so that we can get all errors (error codes) of 376 * a specific element. This is useful for PSVI. 377 */ 378 protected final class XSIErrorReporter { 379 380 // the error reporter property 381 XMLErrorReporter fErrorReporter; 382 383 // store error codes; starting position of the errors for each element; 384 // number of element (depth); and whether to record error 385 Vector fErrors = new Vector(); 386 int[] fContext = new int[INITIAL_STACK_SIZE]; 387 int fContextCount; 388 389 // set the external error reporter, clear errors 390 public void reset(XMLErrorReporter errorReporter) { 391 fErrorReporter = errorReporter; 392 fErrors.removeAllElements(); 393 fContextCount = 0; 394 } 395 396 // should be called when starting process an element or an attribute. 397 // store the starting position for the current context 398 public void pushContext() { 399 if (!fAugPSVI) { 400 return; 401 } 402 // resize array if necessary 403 if (fContextCount == fContext.length) { 404 int newSize = fContextCount + INC_STACK_SIZE; 405 int[] newArray = new int[newSize]; 406 System.arraycopy(fContext, 0, newArray, 0, fContextCount); 407 fContext = newArray; 408 } 409 410 fContext[fContextCount++] = fErrors.size(); 411 } 412 413 // should be called on endElement: get all errors of the current element 414 public String[] popContext() { 415 if (!fAugPSVI) { 416 return null; 417 } 418 // get starting position of the current element 419 int contextPos = fContext[--fContextCount]; 420 // number of errors of the current element 421 int size = fErrors.size() - contextPos; 422 // if no errors, return null 423 if (size == 0) 424 return null; 425 // copy errors from the list to an string array 426 String[] errors = new String[size]; 427 for (int i = 0; i < size; i++) { 428 errors[i] = (String) fErrors.elementAt(contextPos + i); 429 } 430 // remove errors of the current element 431 fErrors.setSize(contextPos); 432 return errors; 433 } 434 435 // should be called when an attribute is done: get all errors of 436 // this attribute, but leave the errors to the containing element 437 // also called after an element was strictly assessed. 438 public String[] mergeContext() { 439 if (!fAugPSVI) { 440 return null; 441 } 442 // get starting position of the current element 443 int contextPos = fContext[--fContextCount]; 444 // number of errors of the current element 445 int size = fErrors.size() - contextPos; 446 // if no errors, return null 447 if (size == 0) 448 return null; 449 // copy errors from the list to an string array 450 String[] errors = new String[size]; 451 for (int i = 0; i < size; i++) { 452 errors[i] = (String) fErrors.elementAt(contextPos + i); 453 } 454 // don't resize the vector: leave the errors for this attribute 455 // to the containing element 456 return errors; 457 } 458 459 public void reportError(String domain, String key, Object[] arguments, short severity) 460 throws XNIException { 461 fErrorReporter.reportError(domain, key, arguments, severity); 462 if (fAugPSVI) { 463 fErrors.addElement(key); 464 } 465 } // reportError(String,String,Object[],short) 466 467 public void reportError( 468 XMLLocator location, 469 String domain, 470 String key, 471 Object[] arguments, 472 short severity) 473 throws XNIException { 474 fErrorReporter.reportError(location, domain, key, arguments, severity); 475 if (fAugPSVI) { 476 fErrors.addElement(key); 477 } 478 } // reportError(XMLLocator,String,String,Object[],short) 479 } 480 481 /** Error reporter. */ 482 protected final XSIErrorReporter fXSIErrorReporter = new XSIErrorReporter(); 483 484 /** Entity resolver */ 485 protected XMLEntityResolver fEntityResolver; 486 487 // updated during reset 488 protected ValidationManager fValidationManager = null; 489 protected ValidationState fValidationState = new ValidationState(); 490 protected XMLGrammarPool fGrammarPool; 491 492 // schema location property values 493 protected String fExternalSchemas = null; 494 protected String fExternalNoNamespaceSchema = null; 495 496 //JAXP Schema Source property 497 protected Object fJaxpSchemaSource = null; 498 499 /** Schema Grammar Description passed, to give a chance to application to supply the Grammar */ 500 protected final XSDDescription fXSDDescription = new XSDDescription(); 501 protected final Hashtable fLocationPairs = new Hashtable(); 502 503 504 // handlers 505 506 /** Document handler. */ 507 protected XMLDocumentHandler fDocumentHandler; 508 509 protected XMLDocumentSource fDocumentSource; 510 511 boolean reportWhitespace = false; 512 513 // 514 // XMLComponent methods 515 // 516 517 /** 518 * Returns a list of feature identifiers that are recognized by 519 * this component. This method may return null if no features 520 * are recognized by this component. 521 */ 522 public String[] getRecognizedFeatures() { 523 return (String[]) (RECOGNIZED_FEATURES.clone()); 524 } // getRecognizedFeatures():String[] 525 526 /** 527 * Sets the state of a feature. This method is called by the component 528 * manager any time after reset when a feature changes state. 529 * <p> 530 * <strong>Note:</strong> Components should silently ignore features 531 * that do not affect the operation of the component. 532 * 533 * @param featureId The feature identifier. 534 * @param state The state of the feature. 535 * 536 * @throws SAXNotRecognizedException The component should not throw 537 * this exception. 538 * @throws SAXNotSupportedException The component should not throw 539 * this exception. 540 */ 541 public void setFeature(String featureId, boolean state) throws XMLConfigurationException { 542 } // setFeature(String,boolean) 543 544 /** 545 * Returns a list of property identifiers that are recognized by 546 * this component. This method may return null if no properties 547 * are recognized by this component. 548 */ 549 public String[] getRecognizedProperties() { 550 return (String[]) (RECOGNIZED_PROPERTIES.clone()); 551 } // getRecognizedProperties():String[] 552 553 /** 554 * Sets the value of a property. This method is called by the component 555 * manager any time after reset when a property changes value. 556 * <p> 557 * <strong>Note:</strong> Components should silently ignore properties 558 * that do not affect the operation of the component. 559 * 560 * @param propertyId The property identifier. 561 * @param value The value of the property. 562 * 563 * @throws SAXNotRecognizedException The component should not throw 564 * this exception. 565 * @throws SAXNotSupportedException The component should not throw 566 * this exception. 567 */ 568 public void setProperty(String propertyId, Object value) throws XMLConfigurationException { 569 } // setProperty(String,Object) 570 571 /** 572 * Returns the default state for a feature, or null if this 573 * component does not want to report a default value for this 574 * feature. 575 * 576 * @param featureId The feature identifier. 577 * 578 * @since Xerces 2.2.0 579 */ 580 public Boolean getFeatureDefault(String featureId) { 581 for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) { 582 if (RECOGNIZED_FEATURES[i].equals(featureId)) { 583 return FEATURE_DEFAULTS[i]; 584 } 585 } 586 return null; 587 } // getFeatureDefault(String):Boolean 588 589 /** 590 * Returns the default state for a property, or null if this 591 * component does not want to report a default value for this 592 * property. 593 * 594 * @param propertyId The property identifier. 595 * 596 * @since Xerces 2.2.0 597 */ 598 public Object getPropertyDefault(String propertyId) { 599 for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) { 600 if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) { 601 return PROPERTY_DEFAULTS[i]; 602 } 603 } 604 return null; 605 } // getPropertyDefault(String):Object 606 607 // 608 // XMLDocumentSource methods 609 // 610 611 /** Sets the document handler to receive information about the document. */ 612 public void setDocumentHandler(XMLDocumentHandler documentHandler) { 613 fDocumentHandler = documentHandler; 614 615 // Init reportWhitespace for this handler 616 if (documentHandler instanceof XMLParser) { 617 try { 618 reportWhitespace = 619 ((XMLParser) documentHandler).getFeature(REPORT_WHITESPACE); 620 } 621 catch (Exception e) { 622 reportWhitespace = false; 623 } 624 } 625 } // setDocumentHandler(XMLDocumentHandler) 626 627 /** Returns the document handler */ 628 public XMLDocumentHandler getDocumentHandler() { 629 return fDocumentHandler; 630 } // setDocumentHandler(XMLDocumentHandler) 631 632 // 633 // XMLDocumentHandler methods 634 // 635 636 /** Sets the document source */ 637 public void setDocumentSource(XMLDocumentSource source) { 638 fDocumentSource = source; 639 } // setDocumentSource 640 641 /** Returns the document source */ 642 public XMLDocumentSource getDocumentSource() { 643 return fDocumentSource; 644 } // getDocumentSource 645 646 /** 647 * The start of the document. 648 * 649 * @param locator The system identifier of the entity if the entity 650 * is external, null otherwise. 651 * @param encoding The auto-detected IANA encoding name of the entity 652 * stream. This value will be null in those situations 653 * where the entity encoding is not auto-detected (e.g. 654 * internal entities or a document entity that is 655 * parsed from a java.io.Reader). 656 * @param namespaceContext 657 * The namespace context in effect at the 658 * start of this document. 659 * This object represents the current context. 660 * Implementors of this class are responsible 661 * for copying the namespace bindings from the 662 * the current context (and its parent contexts) 663 * if that information is important. 664 * @param augs Additional information that may include infoset augmentations 665 * 666 * @throws XNIException Thrown by handler to signal an error. 667 */ 668 public void startDocument( 669 XMLLocator locator, 670 String encoding, 671 NamespaceContext namespaceContext, 672 Augmentations augs) 673 throws XNIException { 674 675 fValidationState.setNamespaceSupport(namespaceContext); 676 fState4XsiType.setNamespaceSupport(namespaceContext); 677 fState4ApplyDefault.setNamespaceSupport(namespaceContext); 678 fLocator = locator; 679 680 handleStartDocument(locator, encoding); 681 // call handlers 682 if (fDocumentHandler != null) { 683 fDocumentHandler.startDocument(locator, encoding, namespaceContext, augs); 684 } 685 686 } // startDocument(XMLLocator,String) 687 688 /** 689 * Notifies of the presence of an XMLDecl line in the document. If 690 * present, this method will be called immediately following the 691 * startDocument call. 692 * 693 * @param version The XML version. 694 * @param encoding The IANA encoding name of the document, or null if 695 * not specified. 696 * @param standalone The standalone value, or null if not specified. 697 * @param augs Additional information that may include infoset augmentations 698 * 699 * @throws XNIException Thrown by handler to signal an error. 700 */ 701 public void xmlDecl(String version, String encoding, String standalone, Augmentations augs) 702 throws XNIException { 703 704 // call handlers 705 if (fDocumentHandler != null) { 706 fDocumentHandler.xmlDecl(version, encoding, standalone, augs); 707 } 708 709 } // xmlDecl(String,String,String) 710 711 /** 712 * Notifies of the presence of the DOCTYPE line in the document. 713 * 714 * @param rootElement The name of the root element. 715 * @param publicId The public identifier if an external DTD or null 716 * if the external DTD is specified using SYSTEM. 717 * @param systemId The system identifier if an external DTD, null 718 * otherwise. 719 * @param augs Additional information that may include infoset augmentations 720 * 721 * @throws XNIException Thrown by handler to signal an error. 722 */ 723 public void doctypeDecl( 724 String rootElement, 725 String publicId, 726 String systemId, 727 Augmentations augs) 728 throws XNIException { 729 730 // call handlers 731 if (fDocumentHandler != null) { 732 fDocumentHandler.doctypeDecl(rootElement, publicId, systemId, augs); 733 } 734 735 } // doctypeDecl(String,String,String) 736 737 /** 738 * The start of an element. 739 * 740 * @param element The name of the element. 741 * @param attributes The element attributes. 742 * @param augs Additional information that may include infoset augmentations 743 * 744 * @throws XNIException Thrown by handler to signal an error. 745 */ 746 public void startElement(QName element, XMLAttributes attributes, Augmentations augs) 747 throws XNIException { 748 749 Augmentations modifiedAugs = handleStartElement(element, attributes, augs); 750 // call handlers 751 if (fDocumentHandler != null) { 752 fDocumentHandler.startElement(element, attributes, modifiedAugs); 753 } 754 755 } // startElement(QName,XMLAttributes, Augmentations) 756 757 /** 758 * An empty element. 759 * 760 * @param element The name of the element. 761 * @param attributes The element attributes. 762 * @param augs Additional information that may include infoset augmentations 763 * 764 * @throws XNIException Thrown by handler to signal an error. 765 */ 766 public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs) 767 throws XNIException { 768 769 Augmentations modifiedAugs = handleStartElement(element, attributes, augs); 770 771 // in the case where there is a {value constraint}, and the element 772 // doesn't have any text content, change emptyElement call to 773 // start + characters + end 774 fDefaultValue = null; 775 // fElementDepth == -2 indicates that the schema validator was removed 776 // from the pipeline. then we don't need to call handleEndElement. 777 if (fElementDepth != -2) 778 modifiedAugs = handleEndElement(element, modifiedAugs); 779 780 // call handlers 781 if (fDocumentHandler != null) { 782 if (!fSchemaElementDefault || fDefaultValue == null) { 783 fDocumentHandler.emptyElement(element, attributes, modifiedAugs); 784 } else { 785 fDocumentHandler.startElement(element, attributes, modifiedAugs); 786 fDocumentHandler.characters(fDefaultValue, null); 787 fDocumentHandler.endElement(element, modifiedAugs); 788 } 789 } 790 } // emptyElement(QName,XMLAttributes, Augmentations) 791 792 /** 793 * Character content. 794 * 795 * @param text The content. 796 * @param augs Additional information that may include infoset augmentations 797 * 798 * @throws XNIException Thrown by handler to signal an error. 799 */ 800 public void characters(XMLString text, Augmentations augs) throws XNIException { 801 text = handleCharacters(text); 802 803 if (fSawOnlyWhitespaceInElementContent) { 804 fSawOnlyWhitespaceInElementContent = false; 805 if (!reportWhitespace) { 806 ignorableWhitespace(text, augs); 807 return; 808 } 809 } 810 811 // call handlers 812 if (fDocumentHandler != null) { 813 if (fNormalizeData && fUnionType) { 814 // for union types we can't normalize data 815 // thus we only need to send augs information if any; 816 // the normalized data for union will be send 817 // after normalization is performed (at the endElement()) 818 if (augs != null) 819 fDocumentHandler.characters(fEmptyXMLStr, augs); 820 } else { 821 fDocumentHandler.characters(text, augs); 822 } 823 } 824 825 } // characters(XMLString) 826 827 /** 828 * Ignorable whitespace. For this method to be called, the document 829 * source must have some way of determining that the text containing 830 * only whitespace characters should be considered ignorable. For 831 * example, the validator can determine if a length of whitespace 832 * characters in the document are ignorable based on the element 833 * content model. 834 * 835 * @param text The ignorable whitespace. 836 * @param augs Additional information that may include infoset augmentations 837 * 838 * @throws XNIException Thrown by handler to signal an error. 839 */ 840 public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException { 841 handleIgnorableWhitespace(text); 842 // call handlers 843 if (fDocumentHandler != null) { 844 fDocumentHandler.ignorableWhitespace(text, augs); 845 } 846 847 } // ignorableWhitespace(XMLString) 848 849 /** 850 * The end of an element. 851 * 852 * @param element The name of the element. 853 * @param augs Additional information that may include infoset augmentations 854 * 855 * @throws XNIException Thrown by handler to signal an error. 856 */ 857 public void endElement(QName element, Augmentations augs) throws XNIException { 858 859 // in the case where there is a {value constraint}, and the element 860 // doesn't have any text content, add a characters call. 861 fDefaultValue = null; 862 Augmentations modifiedAugs = handleEndElement(element, augs); 863 // call handlers 864 if (fDocumentHandler != null) { 865 if (!fSchemaElementDefault || fDefaultValue == null) { 866 fDocumentHandler.endElement(element, modifiedAugs); 867 } else { 868 fDocumentHandler.characters(fDefaultValue, null); 869 fDocumentHandler.endElement(element, modifiedAugs); 870 } 871 } 872 } // endElement(QName, Augmentations) 873 874 /** 875 * The start of a CDATA section. 876 * 877 * @param augs Additional information that may include infoset augmentations 878 * 879 * @throws XNIException Thrown by handler to signal an error. 880 */ 881 public void startCDATA(Augmentations augs) throws XNIException { 882 883 // REVISIT: what should we do here if schema normalization is on?? 884 fInCDATA = true; 885 // call handlers 886 if (fDocumentHandler != null) { 887 fDocumentHandler.startCDATA(augs); 888 } 889 890 } // startCDATA() 891 892 /** 893 * The end of a CDATA section. 894 * 895 * @param augs Additional information that may include infoset augmentations 896 * 897 * @throws XNIException Thrown by handler to signal an error. 898 */ 899 public void endCDATA(Augmentations augs) throws XNIException { 900 901 // call handlers 902 fInCDATA = false; 903 if (fDocumentHandler != null) { 904 fDocumentHandler.endCDATA(augs); 905 } 906 907 } // endCDATA() 908 909 /** 910 * The end of the document. 911 * 912 * @param augs Additional information that may include infoset augmentations 913 * 914 * @throws XNIException Thrown by handler to signal an error. 915 */ 916 public void endDocument(Augmentations augs) throws XNIException { 917 918 handleEndDocument(); 919 920 // call handlers 921 if (fDocumentHandler != null) { 922 fDocumentHandler.endDocument(augs); 923 } 924 fLocator = null; 925 926 } // endDocument(Augmentations) 927 928 // 929 // DOMRevalidationHandler methods 930 // 931 932 933 934 935 936 public boolean characterData(String data, Augmentations augs) { 937 938 fSawText = fSawText || data.length() > 0; 939 940 // REVISIT: this methods basically duplicates implementation of 941 // handleCharacters(). We should be able to reuse some code 942 943 // if whitespace == -1 skip normalization, because it is a complexType 944 // or a union type. 945 if (fNormalizeData && fWhiteSpace != -1 && fWhiteSpace != XSSimpleType.WS_PRESERVE) { 946 // normalize data 947 normalizeWhitespace(data, fWhiteSpace == XSSimpleType.WS_COLLAPSE); 948 fBuffer.append(fNormalizedStr.ch, fNormalizedStr.offset, fNormalizedStr.length); 949 } else { 950 if (fAppendBuffer) 951 fBuffer.append(data); 952 } 953 954 // When it's a complex type with element-only content, we need to 955 // find out whether the content contains any non-whitespace character. 956 boolean allWhiteSpace = true; 957 if (fCurrentType != null 958 && fCurrentType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) { 959 XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType; 960 if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_ELEMENT) { 961 // data outside of element content 962 for (int i = 0; i < data.length(); i++) { 963 if (!XMLChar.isSpace(data.charAt(i))) { 964 allWhiteSpace = false; 965 fSawCharacters = true; 966 break; 967 } 968 } 969 } 970 } 971 972 return allWhiteSpace; 973 } 974 975 public void elementDefault(String data) { 976 // no-op 977 } 978 979 // 980 // XMLDocumentHandler and XMLDTDHandler methods 981 // 982 983 /** 984 * This method notifies the start of a general entity. 985 * <p> 986 * <strong>Note:</strong> This method is not called for entity references 987 * appearing as part of attribute values. 988 * 989 * @param name The name of the general entity. 990 * @param identifier The resource identifier. 991 * @param encoding The auto-detected IANA encoding name of the entity 992 * stream. This value will be null in those situations 993 * where the entity encoding is not auto-detected (e.g. 994 * internal entities or a document entity that is 995 * parsed from a java.io.Reader). 996 * @param augs Additional information that may include infoset augmentations 997 * 998 * @exception XNIException Thrown by handler to signal an error. 999 */ 1000 public void startGeneralEntity( 1001 String name, 1002 XMLResourceIdentifier identifier, 1003 String encoding, 1004 Augmentations augs) 1005 throws XNIException { 1006 1007 // REVISIT: what should happen if normalize_data_ is on?? 1008 fEntityRef = true; 1009 // call handlers 1010 if (fDocumentHandler != null) { 1011 fDocumentHandler.startGeneralEntity(name, identifier, encoding, augs); 1012 } 1013 1014 } // startEntity(String,String,String,String,String) 1015 1016 /** 1017 * Notifies of the presence of a TextDecl line in an entity. If present, 1018 * this method will be called immediately following the startEntity call. 1019 * <p> 1020 * <strong>Note:</strong> This method will never be called for the 1021 * document entity; it is only called for external general entities 1022 * referenced in document content. 1023 * <p> 1024 * <strong>Note:</strong> This method is not called for entity references 1025 * appearing as part of attribute values. 1026 * 1027 * @param version The XML version, or null if not specified. 1028 * @param encoding The IANA encoding name of the entity. 1029 * @param augs Additional information that may include infoset augmentations 1030 * 1031 * @throws XNIException Thrown by handler to signal an error. 1032 */ 1033 public void textDecl(String version, String encoding, Augmentations augs) throws XNIException { 1034 1035 // call handlers 1036 if (fDocumentHandler != null) { 1037 fDocumentHandler.textDecl(version, encoding, augs); 1038 } 1039 1040 } // textDecl(String,String) 1041 1042 /** 1043 * A comment. 1044 * 1045 * @param text The text in the comment. 1046 * @param augs Additional information that may include infoset augmentations 1047 * 1048 * @throws XNIException Thrown by application to signal an error. 1049 */ 1050 public void comment(XMLString text, Augmentations augs) throws XNIException { 1051 1052 // call handlers 1053 if (fDocumentHandler != null) { 1054 fDocumentHandler.comment(text, augs); 1055 } 1056 1057 } // comment(XMLString) 1058 1059 /** 1060 * A processing instruction. Processing instructions consist of a 1061 * target name and, optionally, text data. The data is only meaningful 1062 * to the application. 1063 * <p> 1064 * Typically, a processing instruction's data will contain a series 1065 * of pseudo-attributes. These pseudo-attributes follow the form of 1066 * element attributes but are <strong>not</strong> parsed or presented 1067 * to the application as anything other than text. The application is 1068 * responsible for parsing the data. 1069 * 1070 * @param target The target. 1071 * @param data The data or null if none specified. 1072 * @param augs Additional information that may include infoset augmentations 1073 * 1074 * @throws XNIException Thrown by handler to signal an error. 1075 */ 1076 public void processingInstruction(String target, XMLString data, Augmentations augs) 1077 throws XNIException { 1078 1079 // call handlers 1080 if (fDocumentHandler != null) { 1081 fDocumentHandler.processingInstruction(target, data, augs); 1082 } 1083 1084 } // processingInstruction(String,XMLString) 1085 1086 /** 1087 * This method notifies the end of a general entity. 1088 * <p> 1089 * <strong>Note:</strong> This method is not called for entity references 1090 * appearing as part of attribute values. 1091 * 1092 * @param name The name of the entity. 1093 * @param augs Additional information that may include infoset augmentations 1094 * 1095 * @exception XNIException 1096 * Thrown by handler to signal an error. 1097 */ 1098 public void endGeneralEntity(String name, Augmentations augs) throws XNIException { 1099 1100 // call handlers 1101 fEntityRef = false; 1102 if (fDocumentHandler != null) { 1103 fDocumentHandler.endGeneralEntity(name, augs); 1104 } 1105 1106 } // endEntity(String) 1107 1108 // constants 1109 1110 static final int INITIAL_STACK_SIZE = 8; 1111 static final int INC_STACK_SIZE = 8; 1112 1113 // 1114 // Data 1115 // 1116 1117 // Schema Normalization 1118 1119 private static final boolean DEBUG_NORMALIZATION = false; 1120 // temporary empty string buffer. 1121 private final XMLString fEmptyXMLStr = new XMLString(null, 0, -1); 1122 // temporary character buffer, and empty string buffer. 1123 private static final int BUFFER_SIZE = 20; 1124 private final XMLString fNormalizedStr = new XMLString(); 1125 private boolean fFirstChunk = true; 1126 // got first chunk in characters() (SAX) 1127 private boolean fTrailing = false; // Previous chunk had a trailing space 1128 private short fWhiteSpace = -1; //whiteSpace: preserve/replace/collapse 1129 private boolean fUnionType = false; 1130 1131 /** Schema grammar resolver. */ 1132 private final XSGrammarBucket fGrammarBucket = new XSGrammarBucket(); 1133 private final SubstitutionGroupHandler fSubGroupHandler = new SubstitutionGroupHandler(fGrammarBucket); 1134 1135 /** the DV usd to convert xsi:type to a QName */ 1136 // REVISIT: in new simple type design, make things in DVs static, 1137 // so that we can QNameDV.getCompiledForm() 1138 private final XSSimpleType fQNameDV = 1139 (XSSimpleType) SchemaGrammar.SG_SchemaNS.getGlobalTypeDecl(SchemaSymbols.ATTVAL_QNAME); 1140 1141 private final CMNodeFactory nodeFactory = new CMNodeFactory(); 1142 /** used to build content models */ 1143 // REVISIT: create decl pool, and pass it to each traversers 1144 private final CMBuilder fCMBuilder = new CMBuilder(nodeFactory); 1145 1146 // Schema grammar loader 1147 private final XMLSchemaLoader fSchemaLoader = 1148 new XMLSchemaLoader( 1149 fXSIErrorReporter.fErrorReporter, 1150 fGrammarBucket, 1151 fSubGroupHandler, 1152 fCMBuilder); 1153 1154 // state 1155 1156 /** String representation of the validation root. */ 1157 // REVISIT: what do we store here? QName, XPATH, some ID? use rawname now. 1158 private String fValidationRoot; 1159 1160 /** Skip validation: anything below this level should be skipped */ 1161 private int fSkipValidationDepth; 1162 1163 /** anything above this level has validation_attempted != full */ 1164 private int fNFullValidationDepth; 1165 1166 /** anything above this level has validation_attempted != none */ 1167 private int fNNoneValidationDepth; 1168 1169 /** Element depth: -2: validator not in pipeline; >= -1 current depth. */ 1170 private int fElementDepth; 1171 1172 /** Seen sub elements. */ 1173 private boolean fSubElement; 1174 1175 /** Seen sub elements stack. */ 1176 private boolean[] fSubElementStack = new boolean[INITIAL_STACK_SIZE]; 1177 1178 /** Current element declaration. */ 1179 private XSElementDecl fCurrentElemDecl; 1180 1181 /** Element decl stack. */ 1182 private XSElementDecl[] fElemDeclStack = new XSElementDecl[INITIAL_STACK_SIZE]; 1183 1184 /** nil value of the current element */ 1185 private boolean fNil; 1186 1187 /** nil value stack */ 1188 private boolean[] fNilStack = new boolean[INITIAL_STACK_SIZE]; 1189 1190 /** notation value of the current element */ 1191 private XSNotationDecl fNotation; 1192 1193 /** notation stack */ 1194 private XSNotationDecl[] fNotationStack = new XSNotationDecl[INITIAL_STACK_SIZE]; 1195 1196 /** Current type. */ 1197 private XSTypeDefinition fCurrentType; 1198 1199 /** type stack. */ 1200 private XSTypeDefinition[] fTypeStack = new XSTypeDefinition[INITIAL_STACK_SIZE]; 1201 1202 /** Current content model. */ 1203 private XSCMValidator fCurrentCM; 1204 1205 /** Content model stack. */ 1206 private XSCMValidator[] fCMStack = new XSCMValidator[INITIAL_STACK_SIZE]; 1207 1208 /** the current state of the current content model */ 1209 private int[] fCurrCMState; 1210 1211 /** stack to hold content model states */ 1212 private int[][] fCMStateStack = new int[INITIAL_STACK_SIZE][]; 1213 1214 /** whether the curret element is strictly assessed */ 1215 private boolean fStrictAssess = true; 1216 1217 /** strict assess stack */ 1218 private boolean[] fStrictAssessStack = new boolean[INITIAL_STACK_SIZE]; 1219 1220 /** Temporary string buffers. */ 1221 private final StringBuffer fBuffer = new StringBuffer(); 1222 1223 /** Whether need to append characters to fBuffer */ 1224 private boolean fAppendBuffer = true; 1225 1226 /** Did we see any character data? */ 1227 private boolean fSawText = false; 1228 1229 /** stack to record if we saw character data */ 1230 private boolean[] fSawTextStack = new boolean[INITIAL_STACK_SIZE]; 1231 1232 /** Did we see non-whitespace character data? */ 1233 private boolean fSawCharacters = false; 1234 1235 /** Stack to record if we saw character data outside of element content*/ 1236 private boolean[] fStringContent = new boolean[INITIAL_STACK_SIZE]; 1237 1238 /** temporary qname */ 1239 private final QName fTempQName = new QName(); 1240 1241 /** temporary validated info */ 1242 private ValidatedInfo fValidatedInfo = new ValidatedInfo(); 1243 1244 // used to validate default/fixed values against xsi:type 1245 // only need to check facets, so we set extraChecking to false (in reset) 1246 private ValidationState fState4XsiType = new ValidationState(); 1247 1248 // used to apply default/fixed values 1249 // only need to check id/idref/entity, so we set checkFacets to false 1250 private ValidationState fState4ApplyDefault = new ValidationState(); 1251 1252 // identity constraint information 1253 1254 /** 1255 * Stack of active XPath matchers for identity constraints. All 1256 * active XPath matchers are notified of startElement 1257 * and endElement callbacks in order to perform their matches. 1258 * <p> 1259 * For each element with identity constraints, the selector of 1260 * each identity constraint is activated. When the selector matches 1261 * its XPath, then all the fields of the identity constraint are 1262 * activated. 1263 * <p> 1264 * <strong>Note:</strong> Once the activation scope is left, the 1265 * XPath matchers are automatically removed from the stack of 1266 * active matchers and no longer receive callbacks. 1267 */ 1268 protected XPathMatcherStack fMatcherStack = new XPathMatcherStack(); 1269 1270 /** Cache of value stores for identity constraint fields. */ 1271 protected ValueStoreCache fValueStoreCache = new ValueStoreCache(); 1272 1273 // 1274 // Constructors 1275 // 1276 1277 /** Default constructor. */ 1278 public XMLSchemaValidator() { 1279 fState4XsiType.setExtraChecking(false); 1280 fState4ApplyDefault.setFacetChecking(false); 1281 1282 } // <init>() 1283 1284 /* 1285 * Resets the component. The component can query the component manager 1286 * about any features and properties that affect the operation of the 1287 * component. 1288 * 1289 * @param componentManager The component manager. 1290 * 1291 * @throws SAXException Thrown by component on finitialization error. 1292 * For example, if a feature or property is 1293 * required for the operation of the component, the 1294 * component manager may throw a 1295 * SAXNotRecognizedException or a 1296 * SAXNotSupportedException. 1297 */ 1298 public void reset(XMLComponentManager componentManager) throws XMLConfigurationException { 1299 1300 1301 fIdConstraint = false; 1302 //reset XSDDescription 1303 fLocationPairs.clear(); 1304 1305 // cleanup id table 1306 fValidationState.resetIDTables(); 1307 1308 //pass the component manager to the factory.. 1309 nodeFactory.reset(componentManager); 1310 1311 // reset schema loader 1312 fSchemaLoader.reset(componentManager); 1313 1314 // initialize state 1315 fCurrentElemDecl = null; 1316 fCurrentCM = null; 1317 fCurrCMState = null; 1318 fSkipValidationDepth = -1; 1319 fNFullValidationDepth = -1; 1320 fNNoneValidationDepth = -1; 1321 fElementDepth = -1; 1322 fSubElement = false; 1323 fSchemaDynamicValidation = false; 1324 1325 // datatype normalization 1326 fEntityRef = false; 1327 fInCDATA = false; 1328 1329 fMatcherStack.clear(); 1330 1331 if (!fMayMatchFieldMap.isEmpty()) { 1332 // should only clear this if the last schema had identity constraints. 1333 fMayMatchFieldMap.clear(); 1334 } 1335 1336 // get error reporter 1337 fXSIErrorReporter.reset((XMLErrorReporter) componentManager.getProperty(ERROR_REPORTER)); 1338 1339 boolean parser_settings = componentManager.getFeature(PARSER_SETTINGS, true); 1340 1341 if (!parser_settings){ 1342 // parser settings have not been changed 1343 fValidationManager.addValidationState(fValidationState); 1344 // Re-parse external schema location properties. 1345 XMLSchemaLoader.processExternalHints( 1346 fExternalSchemas, 1347 fExternalNoNamespaceSchema, 1348 fLocationPairs, 1349 fXSIErrorReporter.fErrorReporter); 1350 return; 1351 } 1352 1353 1354 // get symbol table. if it's a new one, add symbols to it. 1355 SymbolTable symbolTable = (SymbolTable) componentManager.getProperty(SYMBOL_TABLE); 1356 if (symbolTable != fSymbolTable) { 1357 fSymbolTable = symbolTable; 1358 } 1359 1360 fNamespaceGrowth = componentManager.getFeature(NAMESPACE_GROWTH, false); 1361 fDynamicValidation = componentManager.getFeature(DYNAMIC_VALIDATION, false); 1362 1363 if (fDynamicValidation) { 1364 fDoValidation = true; 1365 } else { 1366 fDoValidation = componentManager.getFeature(VALIDATION, false); 1367 } 1368 1369 if (fDoValidation) { 1370 fDoValidation |= componentManager.getFeature(XMLSchemaValidator.SCHEMA_VALIDATION, false); 1371 } 1372 1373 fFullChecking = componentManager.getFeature(SCHEMA_FULL_CHECKING, false); 1374 fNormalizeData = componentManager.getFeature(NORMALIZE_DATA, false); 1375 fSchemaElementDefault = componentManager.getFeature(SCHEMA_ELEMENT_DEFAULT, false); 1376 1377 fAugPSVI = componentManager.getFeature(SCHEMA_AUGMENT_PSVI, true); 1378 1379 fSchemaType = 1380 (String) componentManager.getProperty( 1381 Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_LANGUAGE, null); 1382 1383 fUseGrammarPoolOnly = componentManager.getFeature(USE_GRAMMAR_POOL_ONLY, false); 1384 1385 fEntityResolver = (XMLEntityResolver) componentManager.getProperty(ENTITY_MANAGER); 1386 1387 fValidationManager = (ValidationManager) componentManager.getProperty(VALIDATION_MANAGER); 1388 fValidationManager.addValidationState(fValidationState); 1389 fValidationState.setSymbolTable(fSymbolTable); 1390 1391 1392 // get schema location properties 1393 try { 1394 fExternalSchemas = (String) componentManager.getProperty(SCHEMA_LOCATION); 1395 fExternalNoNamespaceSchema = 1396 (String) componentManager.getProperty(SCHEMA_NONS_LOCATION); 1397 } catch (XMLConfigurationException e) { 1398 fExternalSchemas = null; 1399 fExternalNoNamespaceSchema = null; 1400 } 1401 1402 // store the external schema locations. they are set when reset is called, 1403 // so any other schemaLocation declaration for the same namespace will be 1404 // effectively ignored. becuase we choose to take first location hint 1405 // available for a particular namespace. 1406 XMLSchemaLoader.processExternalHints( 1407 fExternalSchemas, 1408 fExternalNoNamespaceSchema, 1409 fLocationPairs, 1410 fXSIErrorReporter.fErrorReporter); 1411 1412 fJaxpSchemaSource = componentManager.getProperty(JAXP_SCHEMA_SOURCE, null); 1413 1414 // clear grammars, and put the one for schema namespace there 1415 fGrammarPool = (XMLGrammarPool) componentManager.getProperty(XMLGRAMMAR_POOL, null); 1416 1417 fState4XsiType.setSymbolTable(symbolTable); 1418 fState4ApplyDefault.setSymbolTable(symbolTable); 1419 1420 } // reset(XMLComponentManager) 1421 1422 // 1423 // FieldActivator methods 1424 // 1425 1426 /** 1427 * Start the value scope for the specified identity constraint. This 1428 * method is called when the selector matches in order to initialize 1429 * the value store. 1430 * 1431 * @param identityConstraint The identity constraint. 1432 */ 1433 public void startValueScopeFor(IdentityConstraint identityConstraint, int initialDepth) { 1434 1435 ValueStoreBase valueStore = 1436 fValueStoreCache.getValueStoreFor(identityConstraint, initialDepth); 1437 valueStore.startValueScope(); 1438 1439 } // startValueScopeFor(IdentityConstraint identityConstraint) 1440 1441 /** 1442 * Request to activate the specified field. This method returns the 1443 * matcher for the field. 1444 * 1445 * @param field The field to activate. 1446 */ 1447 public XPathMatcher activateField(Field field, int initialDepth) { 1448 ValueStore valueStore = 1449 fValueStoreCache.getValueStoreFor(field.getIdentityConstraint(), initialDepth); 1450 setMayMatch(field, Boolean.TRUE); 1451 XPathMatcher matcher = field.createMatcher(this, valueStore); 1452 fMatcherStack.addMatcher(matcher); 1453 matcher.startDocumentFragment(); 1454 return matcher; 1455 } // activateField(Field):XPathMatcher 1456 1457 /** 1458 * Ends the value scope for the specified identity constraint. 1459 * 1460 * @param identityConstraint The identity constraint. 1461 */ 1462 public void endValueScopeFor(IdentityConstraint identityConstraint, int initialDepth) { 1463 1464 ValueStoreBase valueStore = 1465 fValueStoreCache.getValueStoreFor(identityConstraint, initialDepth); 1466 valueStore.endValueScope(); 1467 1468 } // endValueScopeFor(IdentityConstraint) 1469 1470 /** 1471 * Sets whether the given field is permitted to match a value. 1472 * This should be used to catch instance documents that try 1473 * and match a field several times in the same scope. 1474 * 1475 * @param field The field that may be permitted to be matched. 1476 * @param state Boolean indiciating whether the field may be matched. 1477 */ 1478 public void setMayMatch(Field field, Boolean state) { 1479 fMayMatchFieldMap.put(field, state); 1480 } // setMayMatch(Field, Boolean) 1481 1482 /** 1483 * Returns whether the given field is permitted to match a value. 1484 * 1485 * @param field The field that may be permitted to be matched. 1486 * @return Boolean indicating whether the field may be matched. 1487 */ 1488 public Boolean mayMatch(Field field) { 1489 return (Boolean) fMayMatchFieldMap.get(field); 1490 } // mayMatch(Field):Boolean 1491 1492 // a utility method for Identity constraints 1493 private void activateSelectorFor(IdentityConstraint ic) { 1494 Selector selector = ic.getSelector(); 1495 FieldActivator activator = this; 1496 if (selector == null) 1497 return; 1498 XPathMatcher matcher = selector.createMatcher(activator, fElementDepth); 1499 fMatcherStack.addMatcher(matcher); 1500 matcher.startDocumentFragment(); 1501 } 1502 1503 // 1504 // Protected methods 1505 // 1506 1507 /** ensure element stack capacity */ 1508 void ensureStackCapacity() { 1509 1510 if (fElementDepth == fElemDeclStack.length) { 1511 int newSize = fElementDepth + INC_STACK_SIZE; 1512 boolean[] newArrayB = new boolean[newSize]; 1513 System.arraycopy(fSubElementStack, 0, newArrayB, 0, fElementDepth); 1514 fSubElementStack = newArrayB; 1515 1516 XSElementDecl[] newArrayE = new XSElementDecl[newSize]; 1517 System.arraycopy(fElemDeclStack, 0, newArrayE, 0, fElementDepth); 1518 fElemDeclStack = newArrayE; 1519 1520 newArrayB = new boolean[newSize]; 1521 System.arraycopy(fNilStack, 0, newArrayB, 0, fElementDepth); 1522 fNilStack = newArrayB; 1523 1524 XSNotationDecl[] newArrayN = new XSNotationDecl[newSize]; 1525 System.arraycopy(fNotationStack, 0, newArrayN, 0, fElementDepth); 1526 fNotationStack = newArrayN; 1527 1528 XSTypeDefinition[] newArrayT = new XSTypeDefinition[newSize]; 1529 System.arraycopy(fTypeStack, 0, newArrayT, 0, fElementDepth); 1530 fTypeStack = newArrayT; 1531 1532 XSCMValidator[] newArrayC = new XSCMValidator[newSize]; 1533 System.arraycopy(fCMStack, 0, newArrayC, 0, fElementDepth); 1534 fCMStack = newArrayC; 1535 1536 newArrayB = new boolean[newSize]; 1537 System.arraycopy(fSawTextStack, 0, newArrayB, 0, fElementDepth); 1538 fSawTextStack = newArrayB; 1539 1540 newArrayB = new boolean[newSize]; 1541 System.arraycopy(fStringContent, 0, newArrayB, 0, fElementDepth); 1542 fStringContent = newArrayB; 1543 1544 newArrayB = new boolean[newSize]; 1545 System.arraycopy(fStrictAssessStack, 0, newArrayB, 0, fElementDepth); 1546 fStrictAssessStack = newArrayB; 1547 1548 int[][] newArrayIA = new int[newSize][]; 1549 System.arraycopy(fCMStateStack, 0, newArrayIA, 0, fElementDepth); 1550 fCMStateStack = newArrayIA; 1551 } 1552 1553 } // ensureStackCapacity 1554 1555 // handle start document 1556 void handleStartDocument(XMLLocator locator, String encoding) { 1557 fValueStoreCache.startDocument(); 1558 if (fAugPSVI) { 1559 fCurrentPSVI.fGrammars = null; 1560 fCurrentPSVI.fSchemaInformation = null; 1561 } 1562 } // handleStartDocument(XMLLocator,String) 1563 1564 void handleEndDocument() { 1565 fValueStoreCache.endDocument(); 1566 } // handleEndDocument() 1567 1568 // handle character contents 1569 // returns the normalized string if possible, otherwise the original string 1570 XMLString handleCharacters(XMLString text) { 1571 1572 if (fSkipValidationDepth >= 0) 1573 return text; 1574 1575 fSawText = fSawText || text.length > 0; 1576 1577 // Note: data in EntityRef and CDATA is normalized as well 1578 // if whitespace == -1 skip normalization, because it is a complexType 1579 // or a union type. 1580 if (fNormalizeData && fWhiteSpace != -1 && fWhiteSpace != XSSimpleType.WS_PRESERVE) { 1581 // normalize data 1582 normalizeWhitespace(text, fWhiteSpace == XSSimpleType.WS_COLLAPSE); 1583 text = fNormalizedStr; 1584 } 1585 if (fAppendBuffer) 1586 fBuffer.append(text.ch, text.offset, text.length); 1587 1588 // When it's a complex type with element-only content, we need to 1589 // find out whether the content contains any non-whitespace character. 1590 fSawOnlyWhitespaceInElementContent = false; 1591 if (fCurrentType != null 1592 && fCurrentType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) { 1593 XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType; 1594 if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_ELEMENT) { 1595 // data outside of element content 1596 for (int i = text.offset; i < text.offset + text.length; i++) { 1597 if (!XMLChar.isSpace(text.ch[i])) { 1598 fSawCharacters = true; 1599 break; 1600 } 1601 fSawOnlyWhitespaceInElementContent = !fSawCharacters; 1602 } 1603 } 1604 } 1605 1606 return text; 1607 } // handleCharacters(XMLString) 1608 1609 /** 1610 * Normalize whitespace in an XMLString according to the rules defined 1611 * in XML Schema specifications. 1612 * @param value The string to normalize. 1613 * @param collapse replace or collapse 1614 */ 1615 private void normalizeWhitespace(XMLString value, boolean collapse) { 1616 boolean skipSpace = collapse; 1617 boolean sawNonWS = false; 1618 boolean leading = false; 1619 boolean trailing = false; 1620 char c; 1621 int size = value.offset + value.length; 1622 1623 // ensure the ch array is big enough 1624 if (fNormalizedStr.ch == null || fNormalizedStr.ch.length < value.length + 1) { 1625 fNormalizedStr.ch = new char[value.length + 1]; 1626 } 1627 // don't include the leading ' ' for now. might include it later. 1628 fNormalizedStr.offset = 1; 1629 fNormalizedStr.length = 1; 1630 1631 for (int i = value.offset; i < size; i++) { 1632 c = value.ch[i]; 1633 if (XMLChar.isSpace(c)) { 1634 if (!skipSpace) { 1635 // take the first whitespace as a space and skip the others 1636 fNormalizedStr.ch[fNormalizedStr.length++] = ' '; 1637 skipSpace = collapse; 1638 } 1639 if (!sawNonWS) { 1640 // this is a leading whitespace, record it 1641 leading = true; 1642 } 1643 } else { 1644 fNormalizedStr.ch[fNormalizedStr.length++] = c; 1645 skipSpace = false; 1646 sawNonWS = true; 1647 } 1648 } 1649 if (skipSpace) { 1650 if (fNormalizedStr.length > 1) { 1651 // if we finished on a space trim it but also record it 1652 fNormalizedStr.length--; 1653 trailing = true; 1654 } else if (leading && !fFirstChunk) { 1655 // if all we had was whitespace we skipped record it as 1656 // trailing whitespace as well 1657 trailing = true; 1658 } 1659 } 1660 1661 if (fNormalizedStr.length > 1) { 1662 if (!fFirstChunk && (fWhiteSpace == XSSimpleType.WS_COLLAPSE)) { 1663 if (fTrailing) { 1664 // previous chunk ended on whitespace 1665 // insert whitespace 1666 fNormalizedStr.offset = 0; 1667 fNormalizedStr.ch[0] = ' '; 1668 } else if (leading) { 1669 // previous chunk ended on character, 1670 // this chunk starts with whitespace 1671 fNormalizedStr.offset = 0; 1672 fNormalizedStr.ch[0] = ' '; 1673 } 1674 } 1675 } 1676 1677 // The length includes the leading ' '. Now removing it. 1678 fNormalizedStr.length -= fNormalizedStr.offset; 1679 1680 fTrailing = trailing; 1681 1682 if (trailing || sawNonWS) 1683 fFirstChunk = false; 1684 } 1685 1686 private void normalizeWhitespace(String value, boolean collapse) { 1687 boolean skipSpace = collapse; 1688 char c; 1689 int size = value.length(); 1690 1691 // ensure the ch array is big enough 1692 if (fNormalizedStr.ch == null || fNormalizedStr.ch.length < size) { 1693 fNormalizedStr.ch = new char[size]; 1694 } 1695 fNormalizedStr.offset = 0; 1696 fNormalizedStr.length = 0; 1697 1698 for (int i = 0; i < size; i++) { 1699 c = value.charAt(i); 1700 if (XMLChar.isSpace(c)) { 1701 if (!skipSpace) { 1702 // take the first whitespace as a space and skip the others 1703 fNormalizedStr.ch[fNormalizedStr.length++] = ' '; 1704 skipSpace = collapse; 1705 } 1706 } else { 1707 fNormalizedStr.ch[fNormalizedStr.length++] = c; 1708 skipSpace = false; 1709 } 1710 } 1711 if (skipSpace) { 1712 if (fNormalizedStr.length != 0) 1713 // if we finished on a space trim it but also record it 1714 fNormalizedStr.length--; 1715 } 1716 } 1717 1718 // handle ignorable whitespace 1719 void handleIgnorableWhitespace(XMLString text) { 1720 1721 if (fSkipValidationDepth >= 0) 1722 return; 1723 1724 // REVISIT: the same process needs to be performed as handleCharacters. 1725 // only it's simpler here: we know all characters are whitespaces. 1726 1727 } // handleIgnorableWhitespace(XMLString) 1728 1729 /** Handle element. */ 1730 Augmentations handleStartElement(QName element, XMLAttributes attributes, Augmentations augs) { 1731 1732 if (DEBUG) { 1733 System.out.println("==>handleStartElement: " + element); 1734 } 1735 1736 // root element 1737 if (fElementDepth == -1 && fValidationManager.isGrammarFound()) { 1738 if (fSchemaType == null) { 1739 // schemaType is not specified 1740 // if a DTD grammar is found, we do the same thing as Dynamic: 1741 // if a schema grammar is found, validation is performed; 1742 // otherwise, skip the whole document. 1743 fSchemaDynamicValidation = true; 1744 } else { 1745 // [1] Either schemaType is DTD, and in this case validate/schema is turned off 1746 // [2] Validating against XML Schemas only 1747 // [a] dynamic validation is false: report error if SchemaGrammar is not found 1748 // [b] dynamic validation is true: if grammar is not found ignore. 1749 } 1750 1751 } 1752 1753 // get xsi:schemaLocation and xsi:noNamespaceSchemaLocation attributes, 1754 // parse them to get the grammars 1755 1756 String sLocation = 1757 attributes.getValue(SchemaSymbols.URI_XSI, SchemaSymbols.XSI_SCHEMALOCATION); 1758 String nsLocation = 1759 attributes.getValue(SchemaSymbols.URI_XSI, SchemaSymbols.XSI_NONAMESPACESCHEMALOCATION); 1760 //store the location hints.. we need to do it so that we can defer the loading of grammar until 1761 //there is a reference to a component from that namespace. To provide location hints to the 1762 //application for a namespace 1763 storeLocations(sLocation, nsLocation); 1764 1765 // if we are in the content of "skip", then just skip this element 1766 // REVISIT: is this the correct behaviour for ID constraints? -NG 1767 if (fSkipValidationDepth >= 0) { 1768 fElementDepth++; 1769 if (fAugPSVI) 1770 augs = getEmptyAugs(augs); 1771 return augs; 1772 } 1773 1774 //try to find schema grammar by different means.. 1775 SchemaGrammar sGrammar = 1776 findSchemaGrammar( 1777 XSDDescription.CONTEXT_ELEMENT, 1778 element.uri, 1779 null, 1780 element, 1781 attributes); 1782 1783 // if we are not skipping this element, and there is a content model, 1784 // we try to find the corresponding decl object for this element. 1785 // the reason we move this part of code here is to make sure the 1786 // error reported here (if any) is stored within the parent element's 1787 // context, instead of that of the current element. 1788 Object decl = null; 1789 if (fCurrentCM != null) { 1790 decl = fCurrentCM.oneTransition(element, fCurrCMState, fSubGroupHandler); 1791 // it could be an element decl or a wildcard decl 1792 if (fCurrCMState[0] == XSCMValidator.FIRST_ERROR) { 1793 XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType; 1794 //REVISIT: is it the only case we will have particle = null? 1795 Vector next; 1796 if (ctype.fParticle != null 1797 && (next = fCurrentCM.whatCanGoHere(fCurrCMState)).size() > 0) { 1798 String expected = expectedStr(next); 1799 reportSchemaError( 1800 "cvc-complex-type.2.4.a", 1801 new Object[] { element.rawname, expected }); 1802 } else { 1803 reportSchemaError("cvc-complex-type.2.4.d", new Object[] { element.rawname }); 1804 } 1805 } 1806 } 1807 1808 // if it's not the root element, we push the current states in the stacks 1809 if (fElementDepth != -1) { 1810 ensureStackCapacity(); 1811 fSubElementStack[fElementDepth] = true; 1812 fSubElement = false; 1813 fElemDeclStack[fElementDepth] = fCurrentElemDecl; 1814 fNilStack[fElementDepth] = fNil; 1815 fNotationStack[fElementDepth] = fNotation; 1816 fTypeStack[fElementDepth] = fCurrentType; 1817 fStrictAssessStack[fElementDepth] = fStrictAssess; 1818 fCMStack[fElementDepth] = fCurrentCM; 1819 fCMStateStack[fElementDepth] = fCurrCMState; 1820 fSawTextStack[fElementDepth] = fSawText; 1821 fStringContent[fElementDepth] = fSawCharacters; 1822 } 1823 1824 // increase the element depth after we've saved 1825 // all states for the parent element 1826 fElementDepth++; 1827 fCurrentElemDecl = null; 1828 XSWildcardDecl wildcard = null; 1829 fCurrentType = null; 1830 fStrictAssess = true; 1831 fNil = false; 1832 fNotation = null; 1833 1834 // and the buffer to hold the value of the element 1835 fBuffer.setLength(0); 1836 fSawText = false; 1837 fSawCharacters = false; 1838 1839 // check what kind of declaration the "decl" from 1840 // oneTransition() maps to 1841 if (decl != null) { 1842 if (decl instanceof XSElementDecl) { 1843 fCurrentElemDecl = (XSElementDecl) decl; 1844 } else { 1845 wildcard = (XSWildcardDecl) decl; 1846 } 1847 } 1848 1849 // if the wildcard is skip, then return 1850 if (wildcard != null && wildcard.fProcessContents == XSWildcardDecl.PC_SKIP) { 1851 fSkipValidationDepth = fElementDepth; 1852 if (fAugPSVI) 1853 augs = getEmptyAugs(augs); 1854 return augs; 1855 } 1856 1857 // try again to get the element decl: 1858 // case 1: find declaration for root element 1859 // case 2: find declaration for element from another namespace 1860 if (fCurrentElemDecl == null) { 1861 if (sGrammar != null) { 1862 fCurrentElemDecl = sGrammar.getGlobalElementDecl(element.localpart); 1863 } 1864 } 1865 1866 if (fCurrentElemDecl != null) { 1867 // then get the type 1868 fCurrentType = fCurrentElemDecl.fType; 1869 } 1870 1871 // get type from xsi:type 1872 String xsiType = attributes.getValue(SchemaSymbols.URI_XSI, SchemaSymbols.XSI_TYPE); 1873 1874 // if no decl/type found for the current element 1875 if (fCurrentType == null && xsiType == null) { 1876 // if this is the validation root, report an error, because 1877 // we can't find eith decl or type for this element 1878 // REVISIT: should we report error, or warning? 1879 if (fElementDepth == 0) { 1880 // for dynamic validation, skip the whole content, 1881 // because no grammar was found. 1882 if (fDynamicValidation || fSchemaDynamicValidation) { 1883 // no schema grammar was found, but it's either dynamic 1884 // validation, or another kind of grammar was found (DTD, 1885 // for example). The intended behavior here is to skip 1886 // the whole document. To improve performance, we try to 1887 // remove the validator from the pipeline, since it's not 1888 // supposed to do anything. 1889 if (fDocumentSource != null) { 1890 fDocumentSource.setDocumentHandler(fDocumentHandler); 1891 if (fDocumentHandler != null) 1892 fDocumentHandler.setDocumentSource(fDocumentSource); 1893 // indicate that the validator was removed. 1894 fElementDepth = -2; 1895 return augs; 1896 } 1897 1898 fSkipValidationDepth = fElementDepth; 1899 if (fAugPSVI) 1900 augs = getEmptyAugs(augs); 1901 return augs; 1902 } 1903 // We don't call reportSchemaError here, because the spec 1904 // doesn't think it's invalid not to be able to find a 1905 // declaration or type definition for an element. Xerces is 1906 // reporting it as an error for historical reasons, but in 1907 // PSVI, we shouldn't mark this element as invalid because 1908 // of this. - SG 1909 fXSIErrorReporter.fErrorReporter.reportError( 1910 XSMessageFormatter.SCHEMA_DOMAIN, 1911 "cvc-elt.1", 1912 new Object[] { element.rawname }, 1913 XMLErrorReporter.SEVERITY_ERROR); 1914 } 1915 // if wildcard = strict, report error. 1916 // needs to be called before fXSIErrorReporter.pushContext() 1917 // so that the error belongs to the parent element. 1918 else if (wildcard != null && wildcard.fProcessContents == XSWildcardDecl.PC_STRICT) { 1919 // report error, because wilcard = strict 1920 reportSchemaError("cvc-complex-type.2.4.c", new Object[] { element.rawname }); 1921 } 1922 // no element decl or type found for this element. 1923 // Allowed by the spec, we can choose to either laxly assess this 1924 // element, or to skip it. Now we choose lax assessment. 1925 fCurrentType = SchemaGrammar.fAnyType; 1926 fStrictAssess = false; 1927 fNFullValidationDepth = fElementDepth; 1928 // any type has mixed content, so we don't need to append buffer 1929 fAppendBuffer = false; 1930 1931 // push error reporter context: record the current position 1932 // This has to happen after we process skip contents, 1933 // otherwise push and pop won't be correctly paired. 1934 fXSIErrorReporter.pushContext(); 1935 } else { 1936 // push error reporter context: record the current position 1937 // This has to happen after we process skip contents, 1938 // otherwise push and pop won't be correctly paired. 1939 fXSIErrorReporter.pushContext(); 1940 1941 // get xsi:type 1942 if (xsiType != null) { 1943 XSTypeDefinition oldType = fCurrentType; 1944 fCurrentType = getAndCheckXsiType(element, xsiType, attributes); 1945 // If it fails, use the old type. Use anyType if ther is no old type. 1946 if (fCurrentType == null) { 1947 if (oldType == null) 1948 fCurrentType = SchemaGrammar.fAnyType; 1949 else 1950 fCurrentType = oldType; 1951 } 1952 } 1953 1954 fNNoneValidationDepth = fElementDepth; 1955 // if the element has a fixed value constraint, we need to append 1956 if (fCurrentElemDecl != null 1957 && fCurrentElemDecl.getConstraintType() == XSConstants.VC_FIXED) { 1958 fAppendBuffer = true; 1959 } 1960 // if the type is simple, we need to append 1961 else if (fCurrentType.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) { 1962 fAppendBuffer = true; 1963 } else { 1964 // if the type is simple content complex type, we need to append 1965 XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType; 1966 fAppendBuffer = (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_SIMPLE); 1967 } 1968 } 1969 1970 // Element Locally Valid (Element) 1971 // 2 Its {abstract} must be false. 1972 if (fCurrentElemDecl != null && fCurrentElemDecl.getAbstract()) 1973 reportSchemaError("cvc-elt.2", new Object[] { element.rawname }); 1974 1975 // make the current element validation root 1976 if (fElementDepth == 0) { 1977 fValidationRoot = element.rawname; 1978 } 1979 1980 // update normalization flags 1981 if (fNormalizeData) { 1982 // reset values 1983 fFirstChunk = true; 1984 fTrailing = false; 1985 fUnionType = false; 1986 fWhiteSpace = -1; 1987 } 1988 1989 // Element Locally Valid (Type) 1990 // 2 Its {abstract} must be false. 1991 if (fCurrentType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) { 1992 XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType; 1993 if (ctype.getAbstract()) { 1994 reportSchemaError("cvc-type.2", new Object[] { element.rawname }); 1995 } 1996 if (fNormalizeData) { 1997 // find out if the content type is simple and if variety is union 1998 // to be able to do character normalization 1999 if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_SIMPLE) { 2000 if (ctype.fXSSimpleType.getVariety() == XSSimpleType.VARIETY_UNION) { 2001 fUnionType = true; 2002 } else { 2003 try { 2004 fWhiteSpace = ctype.fXSSimpleType.getWhitespace(); 2005 } catch (DatatypeException e) { 2006 // do nothing 2007 } 2008 } 2009 } 2010 } 2011 } 2012 // normalization: simple type 2013 else if (fNormalizeData) { 2014 // if !union type 2015 XSSimpleType dv = (XSSimpleType) fCurrentType; 2016 if (dv.getVariety() == XSSimpleType.VARIETY_UNION) { 2017 fUnionType = true; 2018 } else { 2019 try { 2020 fWhiteSpace = dv.getWhitespace(); 2021 } catch (DatatypeException e) { 2022 // do nothing 2023 } 2024 } 2025 } 2026 2027 // then try to get the content model 2028 fCurrentCM = null; 2029 if (fCurrentType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) { 2030 fCurrentCM = ((XSComplexTypeDecl) fCurrentType).getContentModel(fCMBuilder); 2031 } 2032 2033 // and get the initial content model state 2034 fCurrCMState = null; 2035 if (fCurrentCM != null) 2036 fCurrCMState = fCurrentCM.startContentModel(); 2037 2038 // get information about xsi:nil 2039 String xsiNil = attributes.getValue(SchemaSymbols.URI_XSI, SchemaSymbols.XSI_NIL); 2040 // only deal with xsi:nil when there is an element declaration 2041 if (xsiNil != null && fCurrentElemDecl != null) 2042 fNil = getXsiNil(element, xsiNil); 2043 2044 // now validate everything related with the attributes 2045 // first, get the attribute group 2046 XSAttributeGroupDecl attrGrp = null; 2047 if (fCurrentType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) { 2048 XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType; 2049 attrGrp = ctype.getAttrGrp(); 2050 } 2051 // activate identity constraints 2052 fValueStoreCache.startElement(); 2053 fMatcherStack.pushContext(); 2054 if (fCurrentElemDecl != null && fCurrentElemDecl.fIDCPos > 0) { 2055 fIdConstraint = true; 2056 // initialize when identity constrains are defined for the elem 2057 fValueStoreCache.initValueStoresFor(fCurrentElemDecl, this); 2058 } 2059 processAttributes(element, attributes, attrGrp); 2060 2061 // add default attributes 2062 if (attrGrp != null) { 2063 addDefaultAttributes(element, attributes, attrGrp); 2064 } 2065 2066 // call all active identity constraints 2067 int count = fMatcherStack.getMatcherCount(); 2068 for (int i = 0; i < count; i++) { 2069 XPathMatcher matcher = fMatcherStack.getMatcherAt(i); 2070 matcher.startElement( element, attributes); 2071 } 2072 2073 if (fAugPSVI) { 2074 augs = getEmptyAugs(augs); 2075 2076 // PSVI: add validation context 2077 fCurrentPSVI.fValidationContext = fValidationRoot; 2078 // PSVI: add element declaration 2079 fCurrentPSVI.fDeclaration = fCurrentElemDecl; 2080 // PSVI: add element type 2081 fCurrentPSVI.fTypeDecl = fCurrentType; 2082 // PSVI: add notation attribute 2083 fCurrentPSVI.fNotation = fNotation; 2084 } 2085 2086 return augs; 2087 2088 } // handleStartElement(QName,XMLAttributes,boolean) 2089 2090 /** 2091 * Handle end element. If there is not text content, and there is a 2092 * {value constraint} on the corresponding element decl, then 2093 * set the fDefaultValue XMLString representing the default value. 2094 */ 2095 Augmentations handleEndElement(QName element, Augmentations augs) { 2096 2097 if (DEBUG) { 2098 System.out.println("==>handleEndElement:" + element); 2099 } 2100 // if we are skipping, return 2101 if (fSkipValidationDepth >= 0) { 2102 // but if this is the top element that we are skipping, 2103 // restore the states. 2104 if (fSkipValidationDepth == fElementDepth && fSkipValidationDepth > 0) { 2105 // set the partial validation depth to the depth of parent 2106 fNFullValidationDepth = fSkipValidationDepth - 1; 2107 fSkipValidationDepth = -1; 2108 fElementDepth--; 2109 fSubElement = fSubElementStack[fElementDepth]; 2110 fCurrentElemDecl = fElemDeclStack[fElementDepth]; 2111 fNil = fNilStack[fElementDepth]; 2112 fNotation = fNotationStack[fElementDepth]; 2113 fCurrentType = fTypeStack[fElementDepth]; 2114 fCurrentCM = fCMStack[fElementDepth]; 2115 fStrictAssess = fStrictAssessStack[fElementDepth]; 2116 fCurrCMState = fCMStateStack[fElementDepth]; 2117 fSawText = fSawTextStack[fElementDepth]; 2118 fSawCharacters = fStringContent[fElementDepth]; 2119 } 2120 else { 2121 fElementDepth--; 2122 } 2123 2124 // PSVI: validation attempted: 2125 // use default values in psvi item for 2126 // validation attempted, validity, and error codes 2127 2128 // check extra schema constraints on root element 2129 if (fElementDepth == -1 && fFullChecking) { 2130 XSConstraints.fullSchemaChecking( 2131 fGrammarBucket, 2132 fSubGroupHandler, 2133 fCMBuilder, 2134 fXSIErrorReporter.fErrorReporter); 2135 } 2136 2137 if (fAugPSVI) 2138 augs = getEmptyAugs(augs); 2139 return augs; 2140 } 2141 2142 // now validate the content of the element 2143 processElementContent(element); 2144 2145 // Element Locally Valid (Element) 2146 // 6 The element information item must be valid with respect to each of the {identity-constraint definitions} as per Identity-constraint Satisfied (3.11.4). 2147 2148 // call matchers and de-activate context 2149 int oldCount = fMatcherStack.getMatcherCount(); 2150 for (int i = oldCount - 1; i >= 0; i--) { 2151 XPathMatcher matcher = fMatcherStack.getMatcherAt(i); 2152 if (fCurrentElemDecl == null) 2153 matcher.endElement(element, null, false, fValidatedInfo.actualValue, fValidatedInfo.actualValueType, fValidatedInfo.itemValueTypes); 2154 2155 else 2156 matcher.endElement( 2157 element, 2158 fCurrentType, 2159 fCurrentElemDecl.getNillable(), 2160 fDefaultValue == null 2161 ? fValidatedInfo.actualValue 2162 : fCurrentElemDecl.fDefault.actualValue, 2163 fDefaultValue == null 2164 ? fValidatedInfo.actualValueType 2165 : fCurrentElemDecl.fDefault.actualValueType, 2166 fDefaultValue == null 2167 ? fValidatedInfo.itemValueTypes 2168 : fCurrentElemDecl.fDefault.itemValueTypes); 2169 } 2170 2171 if (fMatcherStack.size() > 0) { 2172 fMatcherStack.popContext(); 2173 } 2174 2175 int newCount = fMatcherStack.getMatcherCount(); 2176 // handle everything *but* keyref's. 2177 for (int i = oldCount - 1; i >= newCount; i--) { 2178 XPathMatcher matcher = fMatcherStack.getMatcherAt(i); 2179 if (matcher instanceof Selector.Matcher) { 2180 Selector.Matcher selMatcher = (Selector.Matcher) matcher; 2181 IdentityConstraint id; 2182 if ((id = selMatcher.getIdentityConstraint()) != null 2183 && id.getCategory() != IdentityConstraint.IC_KEYREF) { 2184 fValueStoreCache.transplant(id, selMatcher.getInitialDepth()); 2185 } 2186 } 2187 } 2188 2189 // now handle keyref's/... 2190 for (int i = oldCount - 1; i >= newCount; i--) { 2191 XPathMatcher matcher = fMatcherStack.getMatcherAt(i); 2192 if (matcher instanceof Selector.Matcher) { 2193 Selector.Matcher selMatcher = (Selector.Matcher) matcher; 2194 IdentityConstraint id; 2195 if ((id = selMatcher.getIdentityConstraint()) != null 2196 && id.getCategory() == IdentityConstraint.IC_KEYREF) { 2197 ValueStoreBase values = 2198 fValueStoreCache.getValueStoreFor(id, selMatcher.getInitialDepth()); 2199 if (values != null) // nothing to do if nothing matched! 2200 values.endDocumentFragment(); 2201 } 2202 } 2203 } 2204 fValueStoreCache.endElement(); 2205 2206 SchemaGrammar[] grammars = null; 2207 // have we reached the end tag of the validation root? 2208 if (fElementDepth == 0) { 2209 // 7 If the element information item is the validation root, it must be valid per Validation Root Valid (ID/IDREF) (3.3.4). 2210 String invIdRef = fValidationState.checkIDRefID(); 2211 fValidationState.resetIDTables(); 2212 if (invIdRef != null) { 2213 reportSchemaError("cvc-id.1", new Object[] { invIdRef }); 2214 } 2215 // check extra schema constraints 2216 if (fFullChecking) { 2217 XSConstraints.fullSchemaChecking( 2218 fGrammarBucket, 2219 fSubGroupHandler, 2220 fCMBuilder, 2221 fXSIErrorReporter.fErrorReporter); 2222 } 2223 2224 grammars = fGrammarBucket.getGrammars(); 2225 // return the final set of grammars validator ended up with 2226 if (fGrammarPool != null) { 2227 // Set grammars as immutable 2228 for (int k=0; k < grammars.length; k++) { 2229 grammars[k].setImmutable(true); 2230 } 2231 fGrammarPool.cacheGrammars(XMLGrammarDescription.XML_SCHEMA, grammars); 2232 } 2233 augs = endElementPSVI(true, grammars, augs); 2234 } else { 2235 augs = endElementPSVI(false, grammars, augs); 2236 2237 // decrease element depth and restore states 2238 fElementDepth--; 2239 2240 // get the states for the parent element. 2241 fSubElement = fSubElementStack[fElementDepth]; 2242 fCurrentElemDecl = fElemDeclStack[fElementDepth]; 2243 fNil = fNilStack[fElementDepth]; 2244 fNotation = fNotationStack[fElementDepth]; 2245 fCurrentType = fTypeStack[fElementDepth]; 2246 fCurrentCM = fCMStack[fElementDepth]; 2247 fStrictAssess = fStrictAssessStack[fElementDepth]; 2248 fCurrCMState = fCMStateStack[fElementDepth]; 2249 fSawText = fSawTextStack[fElementDepth]; 2250 fSawCharacters = fStringContent[fElementDepth]; 2251 2252 // We should have a stack for whitespace value, and pop it up here. 2253 // But when fWhiteSpace != -1, and we see a sub-element, it must be 2254 // an error (at least for Schema 1.0). So for valid documents, the 2255 // only value we are going to push/pop in the stack is -1. 2256 // Here we just mimic the effect of popping -1. -SG 2257 fWhiteSpace = -1; 2258 // Same for append buffer. Simple types and elements with fixed 2259 // value constraint don't allow sub-elements. -SG 2260 fAppendBuffer = false; 2261 // same here. 2262 fUnionType = false; 2263 } 2264 2265 return augs; 2266 } // handleEndElement(QName,boolean)*/ 2267 2268 final Augmentations endElementPSVI( 2269 boolean root, 2270 SchemaGrammar[] grammars, 2271 Augmentations augs) { 2272 2273 if (fAugPSVI) { 2274 augs = getEmptyAugs(augs); 2275 2276 // the 4 properties sent on startElement calls 2277 fCurrentPSVI.fDeclaration = this.fCurrentElemDecl; 2278 fCurrentPSVI.fTypeDecl = this.fCurrentType; 2279 fCurrentPSVI.fNotation = this.fNotation; 2280 fCurrentPSVI.fValidationContext = this.fValidationRoot; 2281 // PSVI: validation attempted 2282 // nothing below or at the same level has none or partial 2283 // (which means this level is strictly assessed, and all chidren 2284 // are full), so this one has full 2285 if (fElementDepth > fNFullValidationDepth) { 2286 fCurrentPSVI.fValidationAttempted = ElementPSVI.VALIDATION_FULL; 2287 } 2288 // nothing below or at the same level has full or partial 2289 // (which means this level is not strictly assessed, and all chidren 2290 // are none), so this one has none 2291 else if (fElementDepth > fNNoneValidationDepth) { 2292 fCurrentPSVI.fValidationAttempted = ElementPSVI.VALIDATION_NONE; 2293 } 2294 // otherwise partial, and anything above this level will be partial 2295 else { 2296 fCurrentPSVI.fValidationAttempted = ElementPSVI.VALIDATION_PARTIAL; 2297 fNFullValidationDepth = fNNoneValidationDepth = fElementDepth - 1; 2298 } 2299 2300 if (fDefaultValue != null) 2301 fCurrentPSVI.fSpecified = true; 2302 fCurrentPSVI.fNil = fNil; 2303 fCurrentPSVI.fMemberType = fValidatedInfo.memberType; 2304 fCurrentPSVI.fNormalizedValue = fValidatedInfo.normalizedValue; 2305 fCurrentPSVI.fActualValue = fValidatedInfo.actualValue; 2306 fCurrentPSVI.fActualValueType = fValidatedInfo.actualValueType; 2307 fCurrentPSVI.fItemValueTypes = fValidatedInfo.itemValueTypes; 2308 2309 if (fStrictAssess) { 2310 // get all errors for the current element, its attribute, 2311 // and subelements (if they were strictly assessed). 2312 // any error would make this element invalid. 2313 // and we merge these errors to the parent element. 2314 String[] errors = fXSIErrorReporter.mergeContext(); 2315 2316 // PSVI: error codes 2317 fCurrentPSVI.fErrorCodes = errors; 2318 // PSVI: validity 2319 fCurrentPSVI.fValidity = 2320 (errors == null) ? ElementPSVI.VALIDITY_VALID : ElementPSVI.VALIDITY_INVALID; 2321 } else { 2322 // PSVI: validity 2323 fCurrentPSVI.fValidity = ElementPSVI.VALIDITY_NOTKNOWN; 2324 // Discard the current context: ignore any error happened within 2325 // the sub-elements/attributes of this element, because those 2326 // errors won't affect the validity of the parent elements. 2327 fXSIErrorReporter.popContext(); 2328 } 2329 2330 if (root) { 2331 // store [schema information] in the PSVI 2332 fCurrentPSVI.fGrammars = grammars; 2333 fCurrentPSVI.fSchemaInformation = null; 2334 } 2335 } 2336 2337 return augs; 2338 2339 } 2340 2341 Augmentations getEmptyAugs(Augmentations augs) { 2342 if (augs == null) { 2343 augs = fAugmentations; 2344 augs.removeAllItems(); 2345 } 2346 augs.putItem(Constants.ELEMENT_PSVI, fCurrentPSVI); 2347 fCurrentPSVI.reset(); 2348 2349 return augs; 2350 } 2351 2352 void storeLocations(String sLocation, String nsLocation) { 2353 if (sLocation != null) { 2354 if (!XMLSchemaLoader.tokenizeSchemaLocationStr(sLocation, fLocationPairs)) { 2355 // error! 2356 fXSIErrorReporter.reportError( 2357 XSMessageFormatter.SCHEMA_DOMAIN, 2358 "SchemaLocation", 2359 new Object[] { sLocation }, 2360 XMLErrorReporter.SEVERITY_WARNING); 2361 } 2362 } 2363 if (nsLocation != null) { 2364 XMLSchemaLoader.LocationArray la = 2365 ((XMLSchemaLoader.LocationArray) fLocationPairs.get(XMLSymbols.EMPTY_STRING)); 2366 if (la == null) { 2367 la = new XMLSchemaLoader.LocationArray(); 2368 fLocationPairs.put(XMLSymbols.EMPTY_STRING, la); 2369 } 2370 la.addLocation(nsLocation); 2371 } 2372 2373 } //storeLocations 2374 2375 //this is the function where logic of retrieving grammar is written , parser first tries to get the grammar from 2376 //the local pool, if not in local pool, it gives chance to application to be able to retrieve the grammar, then it 2377 //tries to parse the grammar using location hints from the give namespace. 2378 SchemaGrammar findSchemaGrammar( 2379 short contextType, 2380 String namespace, 2381 QName enclosingElement, 2382 QName triggeringComponet, 2383 XMLAttributes attributes) { 2384 SchemaGrammar grammar = null; 2385 //get the grammar from local pool... 2386 grammar = fGrammarBucket.getGrammar(namespace); 2387 2388 if (grammar == null) { 2389 fXSDDescription.setNamespace(namespace); 2390 // give a chance to application to be able to retreive the grammar. 2391 if (fGrammarPool != null) { 2392 grammar = (SchemaGrammar) fGrammarPool.retrieveGrammar(fXSDDescription); 2393 if (grammar != null) { 2394 // put this grammar into the bucket, along with grammars 2395 // imported by it (directly or indirectly) 2396 if (!fGrammarBucket.putGrammar(grammar, true, fNamespaceGrowth)) { 2397 // REVISIT: a conflict between new grammar(s) and grammars 2398 // in the bucket. What to do? A warning? An exception? 2399 fXSIErrorReporter.fErrorReporter.reportError( 2400 XSMessageFormatter.SCHEMA_DOMAIN, 2401 "GrammarConflict", 2402 null, 2403 XMLErrorReporter.SEVERITY_WARNING); 2404 grammar = null; 2405 } 2406 } 2407 } 2408 } 2409 if ((grammar == null && !fUseGrammarPoolOnly) || fNamespaceGrowth) { 2410 fXSDDescription.reset(); 2411 fXSDDescription.fContextType = contextType; 2412 fXSDDescription.setNamespace(namespace); 2413 fXSDDescription.fEnclosedElementName = enclosingElement; 2414 fXSDDescription.fTriggeringComponent = triggeringComponet; 2415 fXSDDescription.fAttributes = attributes; 2416 if (fLocator != null) { 2417 fXSDDescription.setBaseSystemId(fLocator.getExpandedSystemId()); 2418 } 2419 2420 Hashtable locationPairs = fLocationPairs; 2421 Object locationArray = 2422 locationPairs.get(namespace == null ? XMLSymbols.EMPTY_STRING : namespace); 2423 if (locationArray != null) { 2424 String[] temp = ((XMLSchemaLoader.LocationArray) locationArray).getLocationArray(); 2425 if (temp.length != 0) { 2426 setLocationHints(fXSDDescription, temp, grammar); 2427 } 2428 } 2429 2430 if (grammar == null || fXSDDescription.fLocationHints != null) { 2431 boolean toParseSchema = true; 2432 if (grammar != null) { 2433 // use location hints instead 2434 locationPairs = EMPTY_TABLE; 2435 } 2436 2437 // try to parse the grammar using location hints from that namespace.. 2438 try { 2439 XMLInputSource xis = 2440 XMLSchemaLoader.resolveDocument( 2441 fXSDDescription, 2442 locationPairs, 2443 fEntityResolver); 2444 if (grammar != null && fNamespaceGrowth) { 2445 try { 2446 // if we are dealing with a different schema location, then include the new schema 2447 // into the existing grammar 2448 if (grammar.getDocumentLocations().contains(XMLEntityManager.expandSystemId(xis.getSystemId(), xis.getBaseSystemId(), false))) { 2449 toParseSchema = false; 2450 } 2451 } 2452 catch (MalformedURIException e) { 2453 } 2454 } 2455 if (toParseSchema) { 2456 grammar = fSchemaLoader.loadSchema(fXSDDescription, xis, fLocationPairs); 2457 } 2458 } catch (IOException ex) { 2459 final String [] locationHints = fXSDDescription.getLocationHints(); 2460 fXSIErrorReporter.fErrorReporter.reportError( 2461 XSMessageFormatter.SCHEMA_DOMAIN, 2462 "schema_reference.4", 2463 new Object[] { locationHints != null ? locationHints[0] : XMLSymbols.EMPTY_STRING }, 2464 XMLErrorReporter.SEVERITY_WARNING); 2465 } 2466 } 2467 } 2468 2469 return grammar; 2470 2471 } //findSchemaGrammar 2472 private void setLocationHints(XSDDescription desc, String[] locations, SchemaGrammar grammar) { 2473 int length = locations.length; 2474 if (grammar == null) { 2475 fXSDDescription.fLocationHints = new String[length]; 2476 System.arraycopy(locations, 0, fXSDDescription.fLocationHints, 0, length); 2477 } 2478 else { 2479 setLocationHints(desc, locations, grammar.getDocumentLocations()); 2480 } 2481 } 2482 2483 private void setLocationHints(XSDDescription desc, String[] locations, StringList docLocations) { 2484 int length = locations.length; 2485 String[] hints = new String[length]; 2486 int counter = 0; 2487 2488 for (int i=0; i<length; i++) { 2489 try { 2490 String id = XMLEntityManager.expandSystemId(locations[i], desc.getBaseSystemId(), false); 2491 if (!docLocations.contains(id)) { 2492 hints[counter++] = locations[i]; 2493 } 2494 } 2495 catch (MalformedURIException e) { 2496 } 2497 } 2498 2499 if (counter > 0) { 2500 if (counter == length) { 2501 fXSDDescription.fLocationHints = hints; 2502 } 2503 else { 2504 fXSDDescription.fLocationHints = new String[counter]; 2505 System.arraycopy(hints, 0, fXSDDescription.fLocationHints, 0, counter); 2506 } 2507 } 2508 } 2509 2510 2511 XSTypeDefinition getAndCheckXsiType(QName element, String xsiType, XMLAttributes attributes) { 2512 // This method also deals with clause 1.2.1.2 of the constraint 2513 // Validation Rule: Schema-Validity Assessment (Element) 2514 2515 // Element Locally Valid (Element) 2516 // 4 If there is an attribute information item among the element information item's [attributes] whose [namespace name] is identical to http://www.w3.org/2001/XMLSchema-instance and whose [local name] is type, then all of the following must be true: 2517 // 4.1 The normalized value of that attribute information item must be valid with respect to the built-in QName simple type, as defined by String Valid (3.14.4); 2518 QName typeName = null; 2519 try { 2520 typeName = (QName) fQNameDV.validate(xsiType, fValidationState, null); 2521 } catch (InvalidDatatypeValueException e) { 2522 reportSchemaError(e.getKey(), e.getArgs()); 2523 reportSchemaError( 2524 "cvc-elt.4.1", 2525 new Object[] { 2526 element.rawname, 2527 SchemaSymbols.URI_XSI + "," + SchemaSymbols.XSI_TYPE, 2528 xsiType }); 2529 return null; 2530 } 2531 2532 // 4.2 The local name and namespace name (as defined in QName Interpretation (3.15.3)), of the actual value of that attribute information item must resolve to a type definition, as defined in QName resolution (Instance) (3.15.4) 2533 XSTypeDefinition type = null; 2534 // if the namespace is schema namespace, first try built-in types 2535 if (typeName.uri == SchemaSymbols.URI_SCHEMAFORSCHEMA) { 2536 type = SchemaGrammar.SG_SchemaNS.getGlobalTypeDecl(typeName.localpart); 2537 } 2538 // if it's not schema built-in types, then try to get a grammar 2539 if (type == null) { 2540 //try to find schema grammar by different means.... 2541 SchemaGrammar grammar = 2542 findSchemaGrammar( 2543 XSDDescription.CONTEXT_XSITYPE, 2544 typeName.uri, 2545 element, 2546 typeName, 2547 attributes); 2548 2549 if (grammar != null) 2550 type = grammar.getGlobalTypeDecl(typeName.localpart); 2551 } 2552 // still couldn't find the type, report an error 2553 if (type == null) { 2554 reportSchemaError("cvc-elt.4.2", new Object[] { element.rawname, xsiType }); 2555 return null; 2556 } 2557 2558 // if there is no current type, set this one as current. 2559 // and we don't need to do extra checking 2560 if (fCurrentType != null) { 2561 // 4.3 The local type definition must be validly derived from the {type definition} given the union of the {disallowed substitutions} and the {type definition}'s {prohibited substitutions}, as defined in Type Derivation OK (Complex) (3.4.6) (if it is a complex type definition), or given {disallowed substitutions} as defined in Type Derivation OK (Simple) (3.14.6) (if it is a simple type definition). 2562 short block = fCurrentElemDecl.fBlock; 2563 if (fCurrentType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) 2564 block |= ((XSComplexTypeDecl) fCurrentType).fBlock; 2565 if (!XSConstraints.checkTypeDerivationOk(type, fCurrentType, block)) 2566 reportSchemaError( 2567 "cvc-elt.4.3", 2568 new Object[] { element.rawname, xsiType, fCurrentType.getName()}); 2569 } 2570 2571 return type; 2572 } //getAndCheckXsiType 2573 2574 boolean getXsiNil(QName element, String xsiNil) { 2575 // Element Locally Valid (Element) 2576 // 3 The appropriate case among the following must be true: 2577 // 3.1 If {nillable} is false, then there must be no attribute information item among the element information item's [attributes] whose [namespace name] is identical to http://www.w3.org/2001/XMLSchema-instance and whose [local name] is nil. 2578 if (fCurrentElemDecl != null && !fCurrentElemDecl.getNillable()) { 2579 reportSchemaError( 2580 "cvc-elt.3.1", 2581 new Object[] { 2582 element.rawname, 2583 SchemaSymbols.URI_XSI + "," + SchemaSymbols.XSI_NIL }); 2584 } 2585 // 3.2 If {nillable} is true and there is such an attribute information item and its actual value is true , then all of the following must be true: 2586 // 3.2.2 There must be no fixed {value constraint}. 2587 else { 2588 String value = XMLChar.trim(xsiNil); 2589 if (value.equals(SchemaSymbols.ATTVAL_TRUE) 2590 || value.equals(SchemaSymbols.ATTVAL_TRUE_1)) { 2591 if (fCurrentElemDecl != null 2592 && fCurrentElemDecl.getConstraintType() == XSConstants.VC_FIXED) { 2593 reportSchemaError( 2594 "cvc-elt.3.2.2", 2595 new Object[] { 2596 element.rawname, 2597 SchemaSymbols.URI_XSI + "," + SchemaSymbols.XSI_NIL }); 2598 } 2599 return true; 2600 } 2601 } 2602 return false; 2603 } 2604 2605 void processAttributes(QName element, XMLAttributes attributes, XSAttributeGroupDecl attrGrp) { 2606 2607 if (DEBUG) { 2608 System.out.println("==>processAttributes: " + attributes.getLength()); 2609 } 2610 2611 // whether we have seen a Wildcard ID. 2612 String wildcardIDName = null; 2613 2614 // for each present attribute 2615 int attCount = attributes.getLength(); 2616 2617 Augmentations augs = null; 2618 AttributePSVImpl attrPSVI = null; 2619 2620 boolean isSimple = 2621 fCurrentType == null || fCurrentType.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE; 2622 2623 XSObjectList attrUses = null; 2624 int useCount = 0; 2625 XSWildcardDecl attrWildcard = null; 2626 if (!isSimple) { 2627 attrUses = attrGrp.getAttributeUses(); 2628 useCount = attrUses.getLength(); 2629 attrWildcard = attrGrp.fAttributeWC; 2630 } 2631 2632 // Element Locally Valid (Complex Type) 2633 // 3 For each attribute information item in the element information item's [attributes] excepting those whose [namespace name] is identical to http://www.w3.org/2001/XMLSchema-instance and whose [local name] is one of type, nil, schemaLocation or noNamespaceSchemaLocation, the appropriate case among the following must be true: 2634 // get the corresponding attribute decl 2635 for (int index = 0; index < attCount; index++) { 2636 2637 attributes.getName(index, fTempQName); 2638 2639 if (DEBUG) { 2640 System.out.println("==>process attribute: " + fTempQName); 2641 } 2642 2643 if (fAugPSVI || fIdConstraint) { 2644 augs = attributes.getAugmentations(index); 2645 attrPSVI = (AttributePSVImpl) augs.getItem(Constants.ATTRIBUTE_PSVI); 2646 if (attrPSVI != null) { 2647 attrPSVI.reset(); 2648 } else { 2649 attrPSVI = new AttributePSVImpl(); 2650 augs.putItem(Constants.ATTRIBUTE_PSVI, attrPSVI); 2651 } 2652 // PSVI attribute: validation context 2653 attrPSVI.fValidationContext = fValidationRoot; 2654 } 2655 2656 // Element Locally Valid (Type) 2657 // 3.1.1 The element information item's [attributes] must be empty, excepting those 2658 // whose [namespace name] is identical to http://www.w3.org/2001/XMLSchema-instance and 2659 // whose [local name] is one of type, nil, schemaLocation or noNamespaceSchemaLocation. 2660 2661 // for the 4 xsi attributes, get appropriate decl, and validate 2662 if (fTempQName.uri == SchemaSymbols.URI_XSI) { 2663 XSAttributeDecl attrDecl = null; 2664 if (fTempQName.localpart == SchemaSymbols.XSI_SCHEMALOCATION) 2665 attrDecl = 2666 SchemaGrammar.SG_XSI.getGlobalAttributeDecl( 2667 SchemaSymbols.XSI_SCHEMALOCATION); 2668 else if (fTempQName.localpart == SchemaSymbols.XSI_NONAMESPACESCHEMALOCATION) 2669 attrDecl = 2670 SchemaGrammar.SG_XSI.getGlobalAttributeDecl( 2671 SchemaSymbols.XSI_NONAMESPACESCHEMALOCATION); 2672 else if (fTempQName.localpart == SchemaSymbols.XSI_NIL) 2673 attrDecl = SchemaGrammar.SG_XSI.getGlobalAttributeDecl(SchemaSymbols.XSI_NIL); 2674 else if (fTempQName.localpart == SchemaSymbols.XSI_TYPE) 2675 attrDecl = SchemaGrammar.SG_XSI.getGlobalAttributeDecl(SchemaSymbols.XSI_TYPE); 2676 if (attrDecl != null) { 2677 processOneAttribute(element, attributes, index, attrDecl, null, attrPSVI); 2678 continue; 2679 } 2680 } 2681 2682 // for namespace attributes, no_validation/unknow_validity 2683 if (fTempQName.rawname == XMLSymbols.PREFIX_XMLNS 2684 || fTempQName.rawname.startsWith("xmlns:")) { 2685 continue; 2686 } 2687 2688 // simple type doesn't allow any other attributes 2689 if (isSimple) { 2690 reportSchemaError( 2691 "cvc-type.3.1.1", 2692 new Object[] { element.rawname, fTempQName.rawname }); 2693 continue; 2694 } 2695 2696 // it's not xmlns, and not xsi, then we need to find a decl for it 2697 XSAttributeUseImpl currUse = null, oneUse; 2698 for (int i = 0; i < useCount; i++) { 2699 oneUse = (XSAttributeUseImpl) attrUses.item(i); 2700 if (oneUse.fAttrDecl.fName == fTempQName.localpart 2701 && oneUse.fAttrDecl.fTargetNamespace == fTempQName.uri) { 2702 currUse = oneUse; 2703 break; 2704 } 2705 } 2706 2707 // 3.2 otherwise all of the following must be true: 2708 // 3.2.1 There must be an {attribute wildcard}. 2709 // 3.2.2 The attribute information item must be valid with respect to it as defined in Item Valid (Wildcard) (3.10.4). 2710 2711 // if failed, get it from wildcard 2712 if (currUse == null) { 2713 //if (attrWildcard == null) 2714 // reportSchemaError("cvc-complex-type.3.2.1", new Object[]{element.rawname, fTempQName.rawname}); 2715 if (attrWildcard == null || !attrWildcard.allowNamespace(fTempQName.uri)) { 2716 // so this attribute is not allowed 2717 reportSchemaError( 2718 "cvc-complex-type.3.2.2", 2719 new Object[] { element.rawname, fTempQName.rawname }); 2720 continue; 2721 } 2722 } 2723 2724 XSAttributeDecl currDecl = null; 2725 if (currUse != null) { 2726 currDecl = currUse.fAttrDecl; 2727 } else { 2728 // which means it matches a wildcard 2729 // skip it if processContents is skip 2730 if (attrWildcard.fProcessContents == XSWildcardDecl.PC_SKIP) 2731 continue; 2732 2733 //try to find grammar by different means... 2734 SchemaGrammar grammar = 2735 findSchemaGrammar( 2736 XSDDescription.CONTEXT_ATTRIBUTE, 2737 fTempQName.uri, 2738 element, 2739 fTempQName, 2740 attributes); 2741 2742 if (grammar != null) { 2743 currDecl = grammar.getGlobalAttributeDecl(fTempQName.localpart); 2744 } 2745 2746 // if can't find 2747 if (currDecl == null) { 2748 // if strict, report error 2749 if (attrWildcard.fProcessContents == XSWildcardDecl.PC_STRICT) { 2750 reportSchemaError( 2751 "cvc-complex-type.3.2.2", 2752 new Object[] { element.rawname, fTempQName.rawname }); 2753 } 2754 2755 // then continue to the next attribute 2756 continue; 2757 } else { 2758 // 5 Let [Definition:] the wild IDs be the set of all attribute information item to which clause 3.2 applied and whose validation resulted in a context-determined declaration of mustFind or no context-determined declaration at all, and whose [local name] and [namespace name] resolve (as defined by QName resolution (Instance) (3.15.4)) to an attribute declaration whose {type definition} is or is derived from ID. Then all of the following must be true: 2759 // 5.1 There must be no more than one item in wild IDs. 2760 if (currDecl.fType.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE 2761 && ((XSSimpleType) currDecl.fType).isIDType()) { 2762 if (wildcardIDName != null) { 2763 reportSchemaError( 2764 "cvc-complex-type.5.1", 2765 new Object[] { element.rawname, currDecl.fName, wildcardIDName }); 2766 } else 2767 wildcardIDName = currDecl.fName; 2768 } 2769 } 2770 } 2771 2772 processOneAttribute(element, attributes, index, currDecl, currUse, attrPSVI); 2773 } // end of for (all attributes) 2774 2775 // 5.2 If wild IDs is non-empty, there must not be any attribute uses among the {attribute uses} whose {attribute declaration}'s {type definition} is or is derived from ID. 2776 if (!isSimple && attrGrp.fIDAttrName != null && wildcardIDName != null) { 2777 reportSchemaError( 2778 "cvc-complex-type.5.2", 2779 new Object[] { element.rawname, wildcardIDName, attrGrp.fIDAttrName }); 2780 } 2781 2782 } //processAttributes 2783 2784 void processOneAttribute( 2785 QName element, 2786 XMLAttributes attributes, 2787 int index, 2788 XSAttributeDecl currDecl, 2789 XSAttributeUseImpl currUse, 2790 AttributePSVImpl attrPSVI) { 2791 2792 String attrValue = attributes.getValue(index); 2793 fXSIErrorReporter.pushContext(); 2794 2795 // Attribute Locally Valid 2796 // For an attribute information item to be locally valid with respect to an attribute declaration all of the following must be true: 2797 // 1 The declaration must not be absent (see Missing Sub-components (5.3) for how this can fail to be the case). 2798 // 2 Its {type definition} must not be absent. 2799 // 3 The item's normalized value must be locally valid with respect to that {type definition} as per String Valid (3.14.4). 2800 // get simple type 2801 XSSimpleType attDV = currDecl.fType; 2802 2803 Object actualValue = null; 2804 try { 2805 actualValue = attDV.validate(attrValue, fValidationState, fValidatedInfo); 2806 // store the normalized value 2807 if (fNormalizeData) 2808 attributes.setValue(index, fValidatedInfo.normalizedValue); 2809 if (attributes instanceof XMLAttributesImpl) { 2810 XMLAttributesImpl attrs = (XMLAttributesImpl) attributes; 2811 boolean schemaId = 2812 fValidatedInfo.memberType != null 2813 ? fValidatedInfo.memberType.isIDType() 2814 : attDV.isIDType(); 2815 attrs.setSchemaId(index, schemaId); 2816 } 2817 2818 // PSVI: element notation 2819 if (attDV.getVariety() == XSSimpleType.VARIETY_ATOMIC 2820 && attDV.getPrimitiveKind() == XSSimpleType.PRIMITIVE_NOTATION) { 2821 QName qName = (QName) actualValue; 2822 SchemaGrammar grammar = fGrammarBucket.getGrammar(qName.uri); 2823 2824 //REVISIT: is it possible for the notation to be in different namespace than the attribute 2825 //with which it is associated, CHECK !! <fof n1:att1 = "n2:notation1" ..> 2826 // should we give chance to the application to be able to retrieve a grammar - nb 2827 //REVISIT: what would be the triggering component here.. if it is attribute value that 2828 // triggered the loading of grammar ?? -nb 2829 2830 if (grammar != null) { 2831 fNotation = grammar.getGlobalNotationDecl(qName.localpart); 2832 } 2833 } 2834 } catch (InvalidDatatypeValueException idve) { 2835 reportSchemaError(idve.getKey(), idve.getArgs()); 2836 reportSchemaError( 2837 "cvc-attribute.3", 2838 new Object[] { element.rawname, fTempQName.rawname, attrValue, attDV.getName()}); 2839 } 2840 2841 // get the value constraint from use or decl 2842 // 4 The item's actual value must match the value of the {value constraint}, if it is present and fixed. // now check the value against the simpleType 2843 if (actualValue != null && currDecl.getConstraintType() == XSConstants.VC_FIXED) { 2844 if (!isComparable(fValidatedInfo, currDecl.fDefault) || !actualValue.equals(currDecl.fDefault.actualValue)) { 2845 reportSchemaError( 2846 "cvc-attribute.4", 2847 new Object[] { 2848 element.rawname, 2849 fTempQName.rawname, 2850 attrValue, 2851 currDecl.fDefault.stringValue()}); 2852 } 2853 } 2854 2855 // 3.1 If there is among the {attribute uses} an attribute use with an {attribute declaration} whose {name} matches the attribute information item's [local name] and whose {target namespace} is identical to the attribute information item's [namespace name] (where an absent {target namespace} is taken to be identical to a [namespace name] with no value), then the attribute information must be valid with respect to that attribute use as per Attribute Locally Valid (Use) (3.5.4). In this case the {attribute declaration} of that attribute use is the context-determined declaration for the attribute information item with respect to Schema-Validity Assessment (Attribute) (3.2.4) and Assessment Outcome (Attribute) (3.2.5). 2856 if (actualValue != null 2857 && currUse != null 2858 && currUse.fConstraintType == XSConstants.VC_FIXED) { 2859 if (!isComparable(fValidatedInfo, currUse.fDefault) || !actualValue.equals(currUse.fDefault.actualValue)) { 2860 reportSchemaError( 2861 "cvc-complex-type.3.1", 2862 new Object[] { 2863 element.rawname, 2864 fTempQName.rawname, 2865 attrValue, 2866 currUse.fDefault.stringValue()}); 2867 } 2868 } 2869 if (fIdConstraint) { 2870 attrPSVI.fActualValue = actualValue; 2871 } 2872 2873 if (fAugPSVI) { 2874 // PSVI: attribute declaration 2875 attrPSVI.fDeclaration = currDecl; 2876 // PSVI: attribute type 2877 attrPSVI.fTypeDecl = attDV; 2878 2879 // PSVI: attribute memberType 2880 attrPSVI.fMemberType = fValidatedInfo.memberType; 2881 // PSVI: attribute normalized value 2882 // NOTE: we always store the normalized value, even if it's invlid, 2883 // because it might still be useful to the user. But when the it's 2884 // not valid, the normalized value is not trustable. 2885 attrPSVI.fNormalizedValue = fValidatedInfo.normalizedValue; 2886 attrPSVI.fActualValue = fValidatedInfo.actualValue; 2887 attrPSVI.fActualValueType = fValidatedInfo.actualValueType; 2888 attrPSVI.fItemValueTypes = fValidatedInfo.itemValueTypes; 2889 2890 2891 2892 // PSVI: validation attempted: 2893 attrPSVI.fValidationAttempted = AttributePSVI.VALIDATION_FULL; 2894 2895 String[] errors = fXSIErrorReporter.mergeContext(); 2896 // PSVI: error codes 2897 attrPSVI.fErrorCodes = errors; 2898 // PSVI: validity 2899 attrPSVI.fValidity = 2900 (errors == null) ? AttributePSVI.VALIDITY_VALID : AttributePSVI.VALIDITY_INVALID; 2901 } 2902 } 2903 2904 void addDefaultAttributes( 2905 QName element, 2906 XMLAttributes attributes, 2907 XSAttributeGroupDecl attrGrp) { 2908 // Check after all specified attrs are scanned 2909 // (1) report error for REQUIRED attrs that are missing (V_TAGc) 2910 // REVISIT: should we check prohibited attributes? 2911 // (2) report error for PROHIBITED attrs that are present (V_TAGc) 2912 // (3) add default attrs (FIXED and NOT_FIXED) 2913 // 2914 if (DEBUG) { 2915 System.out.println("==>addDefaultAttributes: " + element); 2916 } 2917 XSObjectList attrUses = attrGrp.getAttributeUses(); 2918 int useCount = attrUses.getLength(); 2919 XSAttributeUseImpl currUse; 2920 XSAttributeDecl currDecl; 2921 short constType; 2922 ValidatedInfo defaultValue; 2923 boolean isSpecified; 2924 QName attName; 2925 // for each attribute use 2926 for (int i = 0; i < useCount; i++) { 2927 2928 currUse = (XSAttributeUseImpl) attrUses.item(i); 2929 currDecl = currUse.fAttrDecl; 2930 // get value constraint 2931 constType = currUse.fConstraintType; 2932 defaultValue = currUse.fDefault; 2933 if (constType == XSConstants.VC_NONE) { 2934 constType = currDecl.getConstraintType(); 2935 defaultValue = currDecl.fDefault; 2936 } 2937 // whether this attribute is specified 2938 isSpecified = attributes.getValue(currDecl.fTargetNamespace, currDecl.fName) != null; 2939 2940 // Element Locally Valid (Complex Type) 2941 // 4 The {attribute declaration} of each attribute use in the {attribute uses} whose 2942 // {required} is true matches one of the attribute information items in the element 2943 // information item's [attributes] as per clause 3.1 above. 2944 if (currUse.fUse == SchemaSymbols.USE_REQUIRED) { 2945 if (!isSpecified) 2946 reportSchemaError( 2947 "cvc-complex-type.4", 2948 new Object[] { element.rawname, currDecl.fName }); 2949 } 2950 // if the attribute is not specified, then apply the value constraint 2951 if (!isSpecified && constType != XSConstants.VC_NONE) { 2952 attName = 2953 new QName(null, currDecl.fName, currDecl.fName, currDecl.fTargetNamespace); 2954 String normalized = (defaultValue != null) ? defaultValue.stringValue() : ""; 2955 int attrIndex = attributes.addAttribute(attName, "CDATA", normalized); 2956 if (attributes instanceof XMLAttributesImpl) { 2957 XMLAttributesImpl attrs = (XMLAttributesImpl) attributes; 2958 boolean schemaId = 2959 defaultValue != null 2960 && defaultValue.memberType != null 2961 ? defaultValue.memberType.isIDType() 2962 : currDecl.fType.isIDType(); 2963 attrs.setSchemaId(attrIndex, schemaId); 2964 } 2965 2966 if (fAugPSVI) { 2967 2968 // PSVI: attribute is "schema" specified 2969 Augmentations augs = attributes.getAugmentations(attrIndex); 2970 AttributePSVImpl attrPSVI = new AttributePSVImpl(); 2971 augs.putItem(Constants.ATTRIBUTE_PSVI, attrPSVI); 2972 2973 attrPSVI.fDeclaration = currDecl; 2974 attrPSVI.fTypeDecl = currDecl.fType; 2975 attrPSVI.fMemberType = defaultValue.memberType; 2976 attrPSVI.fNormalizedValue = normalized; 2977 attrPSVI.fActualValue = defaultValue.actualValue; 2978 attrPSVI.fActualValueType = defaultValue.actualValueType; 2979 attrPSVI.fItemValueTypes = defaultValue.itemValueTypes; 2980 attrPSVI.fValidationContext = fValidationRoot; 2981 attrPSVI.fValidity = AttributePSVI.VALIDITY_VALID; 2982 attrPSVI.fValidationAttempted = AttributePSVI.VALIDATION_FULL; 2983 attrPSVI.fSpecified = true; 2984 } 2985 } 2986 2987 } // for 2988 } // addDefaultAttributes 2989 2990 /** 2991 * If there is not text content, and there is a 2992 * {value constraint} on the corresponding element decl, then return 2993 * an XMLString representing the default value. 2994 */ 2995 void processElementContent(QName element) { 2996 // 1 If the item is ?valid? with respect to an element declaration as per Element Locally Valid (Element) (?3.3.4) and the {value constraint} is present, but clause 3.2 of Element Locally Valid (Element) (?3.3.4) above is not satisfied and the item has no element or character information item [children], then schema. Furthermore, the post-schema-validation infoset has the canonical lexical representation of the {value constraint} value as the item's [schema normalized value] property. 2997 if (fCurrentElemDecl != null 2998 && fCurrentElemDecl.fDefault != null 2999 && !fSawText 3000 && !fSubElement 3001 && !fNil) { 3002 3003 String strv = fCurrentElemDecl.fDefault.stringValue(); 3004 int bufLen = strv.length(); 3005 if (fNormalizedStr.ch == null || fNormalizedStr.ch.length < bufLen) { 3006 fNormalizedStr.ch = new char[bufLen]; 3007 } 3008 strv.getChars(0, bufLen, fNormalizedStr.ch, 0); 3009 fNormalizedStr.offset = 0; 3010 fNormalizedStr.length = bufLen; 3011 fDefaultValue = fNormalizedStr; 3012 } 3013 // fixed values are handled later, after xsi:type determined. 3014 3015 fValidatedInfo.normalizedValue = null; 3016 3017 // Element Locally Valid (Element) 3018 // 3.2.1 The element information item must have no character or element information item [children]. 3019 if (fNil) { 3020 if (fSubElement || fSawText) { 3021 reportSchemaError( 3022 "cvc-elt.3.2.1", 3023 new Object[] { 3024 element.rawname, 3025 SchemaSymbols.URI_XSI + "," + SchemaSymbols.XSI_NIL }); 3026 } 3027 } 3028 3029 this.fValidatedInfo.reset(); 3030 3031 // 5 The appropriate case among the following must be true: 3032 // 5.1 If the declaration has a {value constraint}, the item has neither element nor character [children] and clause 3.2 has not applied, then all of the following must be true: 3033 if (fCurrentElemDecl != null 3034 && fCurrentElemDecl.getConstraintType() != XSConstants.VC_NONE 3035 && !fSubElement 3036 && !fSawText 3037 && !fNil) { 3038 // 5.1.1 If the actual type definition is a local type definition then the canonical lexical representation of the {value constraint} value must be a valid default for the actual type definition as defined in Element Default Valid (Immediate) (3.3.6). 3039 if (fCurrentType != fCurrentElemDecl.fType) { 3040 //REVISIT:we should pass ValidatedInfo here. 3041 if (XSConstraints 3042 .ElementDefaultValidImmediate( 3043 fCurrentType, 3044 fCurrentElemDecl.fDefault.stringValue(), 3045 fState4XsiType, 3046 null) 3047 == null) 3048 reportSchemaError( 3049 "cvc-elt.5.1.1", 3050 new Object[] { 3051 element.rawname, 3052 fCurrentType.getName(), 3053 fCurrentElemDecl.fDefault.stringValue()}); 3054 } 3055 // 5.1.2 The element information item with the canonical lexical representation of the {value constraint} value used as its normalized value must be valid with respect to the actual type definition as defined by Element Locally Valid (Type) (3.3.4). 3056 // REVISIT: don't use toString, but validateActualValue instead 3057 // use the fState4ApplyDefault 3058 elementLocallyValidType(element, fCurrentElemDecl.fDefault.stringValue()); 3059 } else { 3060 // The following method call also deal with clause 1.2.2 of the constraint 3061 // Validation Rule: Schema-Validity Assessment (Element) 3062 3063 // 5.2 If the declaration has no {value constraint} or the item has either element or character [children] or clause 3.2 has applied, then all of the following must be true: 3064 // 5.2.1 The element information item must be valid with respect to the actual type definition as defined by Element Locally Valid (Type) (3.3.4). 3065 Object actualValue = elementLocallyValidType(element, fBuffer); 3066 // 5.2.2 If there is a fixed {value constraint} and clause 3.2 has not applied, all of the following must be true: 3067 if (fCurrentElemDecl != null 3068 && fCurrentElemDecl.getConstraintType() == XSConstants.VC_FIXED 3069 && !fNil) { 3070 String content = fBuffer.toString(); 3071 // 5.2.2.1 The element information item must have no element information item [children]. 3072 if (fSubElement) 3073 reportSchemaError("cvc-elt.5.2.2.1", new Object[] { element.rawname }); 3074 // 5.2.2.2 The appropriate case among the following must be true: 3075 if (fCurrentType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) { 3076 XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType; 3077 // 5.2.2.2.1 If the {content type} of the actual type definition is mixed, then the initial value of the item must match the canonical lexical representation of the {value constraint} value. 3078 if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_MIXED) { 3079 // REVISIT: how to get the initial value, does whiteSpace count? 3080 if (!fCurrentElemDecl.fDefault.normalizedValue.equals(content)) 3081 reportSchemaError( 3082 "cvc-elt.5.2.2.2.1", 3083 new Object[] { 3084 element.rawname, 3085 content, 3086 fCurrentElemDecl.fDefault.normalizedValue }); 3087 } 3088 // 5.2.2.2.2 If the {content type} of the actual type definition is a simple type definition, then the actual value of the item must match the canonical lexical representation of the {value constraint} value. 3089 else if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_SIMPLE) { 3090 if (actualValue != null && (!isComparable(fValidatedInfo, fCurrentElemDecl.fDefault) 3091 || !actualValue.equals(fCurrentElemDecl.fDefault.actualValue))) { 3092 reportSchemaError( 3093 "cvc-elt.5.2.2.2.2", 3094 new Object[] { 3095 element.rawname, 3096 content, 3097 fCurrentElemDecl.fDefault.stringValue()}); 3098 } 3099 } 3100 } else if (fCurrentType.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) { 3101 if (actualValue != null && (!isComparable(fValidatedInfo, fCurrentElemDecl.fDefault) 3102 || !actualValue.equals(fCurrentElemDecl.fDefault.actualValue))) { 3103 // REVISIT: the spec didn't mention this case: fixed 3104 // value with simple type 3105 reportSchemaError( 3106 "cvc-elt.5.2.2.2.2", 3107 new Object[] { 3108 element.rawname, 3109 content, 3110 fCurrentElemDecl.fDefault.stringValue()}); 3111 } 3112 } 3113 } 3114 } 3115 3116 if (fDefaultValue == null && fNormalizeData && fDocumentHandler != null && fUnionType) { 3117 // for union types we need to send data because we delayed sending 3118 // this data when we received it in the characters() call. 3119 String content = fValidatedInfo.normalizedValue; 3120 if (content == null) 3121 content = fBuffer.toString(); 3122 3123 int bufLen = content.length(); 3124 if (fNormalizedStr.ch == null || fNormalizedStr.ch.length < bufLen) { 3125 fNormalizedStr.ch = new char[bufLen]; 3126 } 3127 content.getChars(0, bufLen, fNormalizedStr.ch, 0); 3128 fNormalizedStr.offset = 0; 3129 fNormalizedStr.length = bufLen; 3130 fDocumentHandler.characters(fNormalizedStr, null); 3131 } 3132 } // processElementContent 3133 3134 Object elementLocallyValidType(QName element, Object textContent) { 3135 if (fCurrentType == null) 3136 return null; 3137 3138 Object retValue = null; 3139 // Element Locally Valid (Type) 3140 // 3 The appropriate case among the following must be true: 3141 // 3.1 If the type definition is a simple type definition, then all of the following must be true: 3142 if (fCurrentType.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) { 3143 // 3.1.2 The element information item must have no element information item [children]. 3144 if (fSubElement) 3145 reportSchemaError("cvc-type.3.1.2", new Object[] { element.rawname }); 3146 // 3.1.3 If clause 3.2 of Element Locally Valid (Element) (3.3.4) did not apply, then the normalized value must be valid with respect to the type definition as defined by String Valid (3.14.4). 3147 if (!fNil) { 3148 XSSimpleType dv = (XSSimpleType) fCurrentType; 3149 try { 3150 if (!fNormalizeData || fUnionType) { 3151 fValidationState.setNormalizationRequired(true); 3152 } 3153 retValue = dv.validate(textContent, fValidationState, fValidatedInfo); 3154 } catch (InvalidDatatypeValueException e) { 3155 reportSchemaError(e.getKey(), e.getArgs()); 3156 reportSchemaError( 3157 "cvc-type.3.1.3", 3158 new Object[] { element.rawname, textContent }); 3159 } 3160 } 3161 } else { 3162 // 3.2 If the type definition is a complex type definition, then the element information item must be valid with respect to the type definition as per Element Locally Valid (Complex Type) (3.4.4); 3163 retValue = elementLocallyValidComplexType(element, textContent); 3164 } 3165 3166 return retValue; 3167 } // elementLocallyValidType 3168 3169 Object elementLocallyValidComplexType(QName element, Object textContent) { 3170 Object actualValue = null; 3171 XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType; 3172 3173 // Element Locally Valid (Complex Type) 3174 // For an element information item to be locally valid with respect to a complex type definition all of the following must be true: 3175 // 1 {abstract} is false. 3176 // 2 If clause 3.2 of Element Locally Valid (Element) (3.3.4) did not apply, then the appropriate case among the following must be true: 3177 if (!fNil) { 3178 // 2.1 If the {content type} is empty, then the element information item has no character or element information item [children]. 3179 if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_EMPTY 3180 && (fSubElement || fSawText)) { 3181 reportSchemaError("cvc-complex-type.2.1", new Object[] { element.rawname }); 3182 } 3183 // 2.2 If the {content type} is a simple type definition, then the element information item has no element information item [children], and the normalized value of the element information item is valid with respect to that simple type definition as defined by String Valid (3.14.4). 3184 else if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_SIMPLE) { 3185 if (fSubElement) 3186 reportSchemaError("cvc-complex-type.2.2", new Object[] { element.rawname }); 3187 XSSimpleType dv = ctype.fXSSimpleType; 3188 try { 3189 if (!fNormalizeData || fUnionType) { 3190 fValidationState.setNormalizationRequired(true); 3191 } 3192 actualValue = dv.validate(textContent, fValidationState, fValidatedInfo); 3193 } catch (InvalidDatatypeValueException e) { 3194 reportSchemaError(e.getKey(), e.getArgs()); 3195 reportSchemaError("cvc-complex-type.2.2", new Object[] { element.rawname }); 3196 } 3197 // REVISIT: eventually, this method should return the same actualValue as elementLocallyValidType... 3198 // obviously it'll return null when the content is complex. 3199 } 3200 // 2.3 If the {content type} is element-only, then the element information item has no character information item [children] other than those whose [character code] is defined as a white space in [XML 1.0 (Second Edition)]. 3201 else if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_ELEMENT) { 3202 if (fSawCharacters) { 3203 reportSchemaError("cvc-complex-type.2.3", new Object[] { element.rawname }); 3204 } 3205 } 3206 // 2.4 If the {content type} is element-only or mixed, then the sequence of the element information item's element information item [children], if any, taken in order, is valid with respect to the {content type}'s particle, as defined in Element Sequence Locally Valid (Particle) (3.9.4). 3207 if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_ELEMENT 3208 || ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_MIXED) { 3209 // if the current state is a valid state, check whether 3210 // it's one of the final states. 3211 if (DEBUG) { 3212 System.out.println(fCurrCMState); 3213 } 3214 if (fCurrCMState[0] >= 0 && !fCurrentCM.endContentModel(fCurrCMState)) { 3215 String expected = expectedStr(fCurrentCM.whatCanGoHere(fCurrCMState)); 3216 reportSchemaError( 3217 "cvc-complex-type.2.4.b", 3218 new Object[] { element.rawname, expected }); 3219 } else { 3220 // Constant space algorithm for a{n,m} for n > 1 and m <= unbounded 3221 // After the DFA has completed, check minOccurs and maxOccurs 3222 // for all elements and wildcards in this content model where 3223 // a{n,m} is subsumed to a* or a+ 3224 ArrayList errors = fCurrentCM.checkMinMaxBounds(); 3225 if (errors != null) { 3226 for (int i = 0; i < errors.size(); i += 2) { 3227 reportSchemaError( 3228 (String) errors.get(i), 3229 new Object[] { element.rawname, errors.get(i + 1) }); 3230 } 3231 } 3232 } 3233 } 3234 } 3235 return actualValue; 3236 } // elementLocallyValidComplexType 3237 3238 void reportSchemaError(String key, Object[] arguments) { 3239 if (fDoValidation) 3240 fXSIErrorReporter.reportError( 3241 XSMessageFormatter.SCHEMA_DOMAIN, 3242 key, 3243 arguments, 3244 XMLErrorReporter.SEVERITY_ERROR); 3245 } 3246 3247 /** Returns true if the two ValidatedInfo objects can be compared in the same value space. **/ 3248 private boolean isComparable(ValidatedInfo info1, ValidatedInfo info2) { 3249 final short primitiveType1 = convertToPrimitiveKind(info1.actualValueType); 3250 final short primitiveType2 = convertToPrimitiveKind(info2.actualValueType); 3251 if (primitiveType1 != primitiveType2) { 3252 return (primitiveType1 == XSConstants.ANYSIMPLETYPE_DT && primitiveType2 == XSConstants.STRING_DT || 3253 primitiveType1 == XSConstants.STRING_DT && primitiveType2 == XSConstants.ANYSIMPLETYPE_DT); 3254 } 3255 else if (primitiveType1 == XSConstants.LIST_DT || primitiveType1 == XSConstants.LISTOFUNION_DT) { 3256 final ShortList typeList1 = info1.itemValueTypes; 3257 final ShortList typeList2 = info2.itemValueTypes; 3258 final int typeList1Length = typeList1 != null ? typeList1.getLength() : 0; 3259 final int typeList2Length = typeList2 != null ? typeList2.getLength() : 0; 3260 if (typeList1Length != typeList2Length) { 3261 return false; 3262 } 3263 for (int i = 0; i < typeList1Length; ++i) { 3264 final short primitiveItem1 = convertToPrimitiveKind(typeList1.item(i)); 3265 final short primitiveItem2 = convertToPrimitiveKind(typeList2.item(i)); 3266 if (primitiveItem1 != primitiveItem2) { 3267 if (primitiveItem1 == XSConstants.ANYSIMPLETYPE_DT && primitiveItem2 == XSConstants.STRING_DT || 3268 primitiveItem1 == XSConstants.STRING_DT && primitiveItem2 == XSConstants.ANYSIMPLETYPE_DT) { 3269 continue; 3270 } 3271 return false; 3272 } 3273 } 3274 } 3275 return true; 3276 } 3277 3278 private short convertToPrimitiveKind(short valueType) { 3279 /** Primitive datatypes. */ 3280 if (valueType <= XSConstants.NOTATION_DT) { 3281 return valueType; 3282 } 3283 /** Types derived from string. */ 3284 if (valueType <= XSConstants.ENTITY_DT) { 3285 return XSConstants.STRING_DT; 3286 } 3287 /** Types derived from decimal. */ 3288 if (valueType <= XSConstants.POSITIVEINTEGER_DT) { 3289 return XSConstants.DECIMAL_DT; 3290 } 3291 /** Other types. */ 3292 return valueType; 3293 } 3294 3295 private String expectedStr(Vector expected) { 3296 StringBuffer ret = new StringBuffer("{"); 3297 int size = expected.size(); 3298 for (int i = 0; i < size; i++) { 3299 if (i > 0) 3300 ret.append(", "); 3301 ret.append(expected.elementAt(i).toString()); 3302 } 3303 ret.append('}'); 3304 return ret.toString(); 3305 } 3306 3307 /**********************************/ 3308 3309 // xpath matcher information 3310 3311 /** 3312 * Stack of XPath matchers for identity constraints. 3313 * 3314 * @author Andy Clark, IBM 3315 */ 3316 protected static class XPathMatcherStack { 3317 3318 // 3319 // Data 3320 // 3321 3322 /** Active matchers. */ 3323 protected XPathMatcher[] fMatchers = new XPathMatcher[4]; 3324 3325 /** Count of active matchers. */ 3326 protected int fMatchersCount; 3327 3328 /** Offset stack for contexts. */ 3329 protected IntStack fContextStack = new IntStack(); 3330 3331 // 3332 // Constructors 3333 // 3334 3335 public XPathMatcherStack() { 3336 } // <init>() 3337 3338 // 3339 // Public methods 3340 // 3341 3342 /** Resets the XPath matcher stack. */ 3343 public void clear() { 3344 for (int i = 0; i < fMatchersCount; i++) { 3345 fMatchers[i] = null; 3346 } 3347 fMatchersCount = 0; 3348 fContextStack.clear(); 3349 } // clear() 3350 3351 /** Returns the size of the stack. */ 3352 public int size() { 3353 return fContextStack.size(); 3354 } // size():int 3355 3356 /** Returns the count of XPath matchers. */ 3357 public int getMatcherCount() { 3358 return fMatchersCount; 3359 } // getMatcherCount():int 3360 3361 /** Adds a matcher. */ 3362 public void addMatcher(XPathMatcher matcher) { 3363 ensureMatcherCapacity(); 3364 fMatchers[fMatchersCount++] = matcher; 3365 } // addMatcher(XPathMatcher) 3366 3367 /** Returns the XPath matcher at the specified index. */ 3368 public XPathMatcher getMatcherAt(int index) { 3369 return fMatchers[index]; 3370 } // getMatcherAt(index):XPathMatcher 3371 3372 /** Pushes a new context onto the stack. */ 3373 public void pushContext() { 3374 fContextStack.push(fMatchersCount); 3375 } // pushContext() 3376 3377 /** Pops a context off of the stack. */ 3378 public void popContext() { 3379 fMatchersCount = fContextStack.pop(); 3380 } // popContext() 3381 3382 // 3383 // Private methods 3384 // 3385 3386 /** Ensures the size of the matchers array. */ 3387 private void ensureMatcherCapacity() { 3388 if (fMatchersCount == fMatchers.length) { 3389 XPathMatcher[] array = new XPathMatcher[fMatchers.length * 2]; 3390 System.arraycopy(fMatchers, 0, array, 0, fMatchers.length); 3391 fMatchers = array; 3392 } 3393 } // ensureMatcherCapacity() 3394 3395 } // class XPathMatcherStack 3396 3397 // value store implementations 3398 3399 /** 3400 * Value store implementation base class. There are specific subclasses 3401 * for handling unique, key, and keyref. 3402 * 3403 * @author Andy Clark, IBM 3404 */ 3405 protected abstract class ValueStoreBase implements ValueStore { 3406 3407 // 3408 // Data 3409 // 3410 3411 /** Identity constraint. */ 3412 protected IdentityConstraint fIdentityConstraint; 3413 protected int fFieldCount = 0; 3414 protected Field[] fFields = null; 3415 /** current data */ 3416 protected Object[] fLocalValues = null; 3417 protected short[] fLocalValueTypes = null; 3418 protected ShortList[] fLocalItemValueTypes = null; 3419 3420 /** Current data value count. */ 3421 protected int fValuesCount; 3422 3423 /** global data */ 3424 public final Vector fValues = new Vector(); 3425 public ShortVector fValueTypes = null; 3426 public Vector fItemValueTypes = null; 3427 3428 private boolean fUseValueTypeVector = false; 3429 private int fValueTypesLength = 0; 3430 private short fValueType = 0; 3431 3432 private boolean fUseItemValueTypeVector = false; 3433 private int fItemValueTypesLength = 0; 3434 private ShortList fItemValueType = null; 3435 3436 /** buffer for error messages */ 3437 final StringBuffer fTempBuffer = new StringBuffer(); 3438 3439 // 3440 // Constructors 3441 // 3442 3443 /** Constructs a value store for the specified identity constraint. */ 3444 protected ValueStoreBase(IdentityConstraint identityConstraint) { 3445 fIdentityConstraint = identityConstraint; 3446 fFieldCount = fIdentityConstraint.getFieldCount(); 3447 fFields = new Field[fFieldCount]; 3448 fLocalValues = new Object[fFieldCount]; 3449 fLocalValueTypes = new short[fFieldCount]; 3450 fLocalItemValueTypes = new ShortList[fFieldCount]; 3451 for (int i = 0; i < fFieldCount; i++) { 3452 fFields[i] = fIdentityConstraint.getFieldAt(i); 3453 } 3454 } // <init>(IdentityConstraint) 3455 3456 // 3457 // Public methods 3458 // 3459 3460 // destroys this ValueStore; useful when, for instance, a 3461 // locally-scoped ID constraint is involved. 3462 public void clear() { 3463 fValuesCount = 0; 3464 fUseValueTypeVector = false; 3465 fValueTypesLength = 0; 3466 fValueType = 0; 3467 fUseItemValueTypeVector = false; 3468 fItemValueTypesLength = 0; 3469 fItemValueType = null; 3470 fValues.setSize(0); 3471 if (fValueTypes != null) { 3472 fValueTypes.clear(); 3473 } 3474 if (fItemValueTypes != null) { 3475 fItemValueTypes.setSize(0); 3476 } 3477 } // end clear():void 3478 3479 // appends the contents of one ValueStore to those of us. 3480 public void append(ValueStoreBase newVal) { 3481 for (int i = 0; i < newVal.fValues.size(); i++) { 3482 fValues.addElement(newVal.fValues.elementAt(i)); 3483 } 3484 } // append(ValueStoreBase) 3485 3486 /** Start scope for value store. */ 3487 public void startValueScope() { 3488 fValuesCount = 0; 3489 for (int i = 0; i < fFieldCount; i++) { 3490 fLocalValues[i] = null; 3491 fLocalValueTypes[i] = 0; 3492 fLocalItemValueTypes[i] = null; 3493 } 3494 } // startValueScope() 3495 3496 /** Ends scope for value store. */ 3497 public void endValueScope() { 3498 3499 if (fValuesCount == 0) { 3500 if (fIdentityConstraint.getCategory() == IdentityConstraint.IC_KEY) { 3501 String code = "AbsentKeyValue"; 3502 String eName = fIdentityConstraint.getElementName(); 3503 String cName = fIdentityConstraint.getIdentityConstraintName(); 3504 reportSchemaError(code, new Object[] { eName, cName }); 3505 } 3506 return; 3507 } 3508 3509 // Validation Rule: Identity-constraint Satisfied 3510 // 4.2 If the {identity-constraint category} is key, then all of the following must be true: 3511 // 4.2.1 The target node set and the qualified node set are equal, that is, every member of the 3512 // target node set is also a member of the qualified node set and vice versa. 3513 // 3514 // If the IDC is a key check whether we have all the fields. 3515 if (fValuesCount != fFieldCount) { 3516 if (fIdentityConstraint.getCategory() == IdentityConstraint.IC_KEY) { 3517 String code = "KeyNotEnoughValues"; 3518 UniqueOrKey key = (UniqueOrKey) fIdentityConstraint; 3519 String eName = fIdentityConstraint.getElementName(); 3520 String cName = key.getIdentityConstraintName(); 3521 reportSchemaError(code, new Object[] { eName, cName }); 3522 } 3523 return; 3524 } 3525 3526 } // endValueScope() 3527 3528 // This is needed to allow keyref's to look for matched keys 3529 // in the correct scope. Unique and Key may also need to 3530 // override this method for purposes of their own. 3531 // This method is called whenever the DocumentFragment 3532 // of an ID Constraint goes out of scope. 3533 public void endDocumentFragment() { 3534 } // endDocumentFragment():void 3535 3536 /** 3537 * Signals the end of the document. This is where the specific 3538 * instances of value stores can verify the integrity of the 3539 * identity constraints. 3540 */ 3541 public void endDocument() { 3542 } // endDocument() 3543 3544 // 3545 // ValueStore methods 3546 // 3547 3548 /* reports an error if an element is matched 3549 * has nillable true and is matched by a key. 3550 */ 3551 3552 public void reportError(String key, Object[] args) { 3553 reportSchemaError(key, args); 3554 } // reportError(String,Object[]) 3555 3556 /** 3557 * Adds the specified value to the value store. 3558 * 3559 * @param field The field associated to the value. This reference 3560 * is used to ensure that each field only adds a value 3561 * once within a selection scope. 3562 * @param actualValue The value to add. 3563 */ 3564 public void addValue(Field field, Object actualValue, short valueType, ShortList itemValueType) { 3565 int i; 3566 for (i = fFieldCount - 1; i > -1; i--) { 3567 if (fFields[i] == field) { 3568 break; 3569 } 3570 } 3571 // do we even know this field? 3572 if (i == -1) { 3573 String code = "UnknownField"; 3574 String eName = fIdentityConstraint.getElementName(); 3575 String cName = fIdentityConstraint.getIdentityConstraintName(); 3576 reportSchemaError(code, new Object[] { field.toString(), eName, cName }); 3577 return; 3578 } 3579 if (Boolean.TRUE != mayMatch(field)) { 3580 String code = "FieldMultipleMatch"; 3581 String cName = fIdentityConstraint.getIdentityConstraintName(); 3582 reportSchemaError(code, new Object[] { field.toString(), cName }); 3583 } else { 3584 fValuesCount++; 3585 } 3586 fLocalValues[i] = actualValue; 3587 fLocalValueTypes[i] = valueType; 3588 fLocalItemValueTypes[i] = itemValueType; 3589 if (fValuesCount == fFieldCount) { 3590 checkDuplicateValues(); 3591 // store values 3592 for (i = 0; i < fFieldCount; i++) { 3593 fValues.addElement(fLocalValues[i]); 3594 addValueType(fLocalValueTypes[i]); 3595 addItemValueType(fLocalItemValueTypes[i]); 3596 } 3597 } 3598 } // addValue(String,Field) 3599 3600 /** 3601 * Returns true if this value store contains the locally scoped value stores 3602 */ 3603 public boolean contains() { 3604 // REVISIT: we can improve performance by using hash codes, instead of 3605 // traversing global vector that could be quite large. 3606 int next = 0; 3607 final int size = fValues.size(); 3608 LOOP : for (int i = 0; i < size; i = next) { 3609 next = i + fFieldCount; 3610 for (int j = 0; j < fFieldCount; j++) { 3611 Object value1 = fLocalValues[j]; 3612 Object value2 = fValues.elementAt(i); 3613 short valueType1 = fLocalValueTypes[j]; 3614 short valueType2 = getValueTypeAt(i); 3615 if (value1 == null || value2 == null || valueType1 != valueType2 || !(value1.equals(value2))) { 3616 continue LOOP; 3617 } 3618 else if(valueType1 == XSConstants.LIST_DT || valueType1 == XSConstants.LISTOFUNION_DT) { 3619 ShortList list1 = fLocalItemValueTypes[j]; 3620 ShortList list2 = getItemValueTypeAt(i); 3621 if(list1 == null || list2 == null || !list1.equals(list2)) 3622 continue LOOP; 3623 } 3624 i++; 3625 } 3626 // found it 3627 return true; 3628 } 3629 // didn't find it 3630 return false; 3631 } // contains():boolean 3632 3633 /** 3634 * Returns -1 if this value store contains the specified 3635 * values, otherwise the index of the first field in the 3636 * key sequence. 3637 */ 3638 public int contains(ValueStoreBase vsb) { 3639 3640 final Vector values = vsb.fValues; 3641 final int size1 = values.size(); 3642 if (fFieldCount <= 1) { 3643 for (int i = 0; i < size1; ++i) { 3644 short val = vsb.getValueTypeAt(i); 3645 if (!valueTypeContains(val) || !fValues.contains(values.elementAt(i))) { 3646 return i; 3647 } 3648 else if(val == XSConstants.LIST_DT || val == XSConstants.LISTOFUNION_DT) { 3649 ShortList list1 = vsb.getItemValueTypeAt(i); 3650 if (!itemValueTypeContains(list1)) { 3651 return i; 3652 } 3653 } 3654 } 3655 } 3656 /** Handle n-tuples. **/ 3657 else { 3658 final int size2 = fValues.size(); 3659 /** Iterate over each set of fields. **/ 3660 OUTER: for (int i = 0; i < size1; i += fFieldCount) { 3661 /** Check whether this set is contained in the value store. **/ 3662 INNER: for (int j = 0; j < size2; j += fFieldCount) { 3663 for (int k = 0; k < fFieldCount; ++k) { 3664 final Object value1 = values.elementAt(i+k); 3665 final Object value2 = fValues.elementAt(j+k); 3666 final short valueType1 = vsb.getValueTypeAt(i+k); 3667 final short valueType2 = getValueTypeAt(j+k); 3668 if (value1 != value2 && (valueType1 != valueType2 || value1 == null || !value1.equals(value2))) { 3669 continue INNER; 3670 } 3671 else if(valueType1 == XSConstants.LIST_DT || valueType1 == XSConstants.LISTOFUNION_DT) { 3672 ShortList list1 = vsb.getItemValueTypeAt(i+k); 3673 ShortList list2 = getItemValueTypeAt(j+k); 3674 if (list1 == null || list2 == null || !list1.equals(list2)) { 3675 continue INNER; 3676 } 3677 } 3678 } 3679 continue OUTER; 3680 } 3681 return i; 3682 } 3683 } 3684 return -1; 3685 3686 } // contains(Vector):Object 3687 3688 // 3689 // Protected methods 3690 // 3691 3692 protected void checkDuplicateValues() { 3693 // no-op 3694 } // duplicateValue(Hashtable) 3695 3696 /** Returns a string of the specified values. */ 3697 protected String toString(Object[] values) { 3698 3699 // no values 3700 int size = values.length; 3701 if (size == 0) { 3702 return ""; 3703 } 3704 3705 fTempBuffer.setLength(0); 3706 3707 // construct value string 3708 for (int i = 0; i < size; i++) { 3709 if (i > 0) { 3710 fTempBuffer.append(','); 3711 } 3712 fTempBuffer.append(values[i]); 3713 } 3714 return fTempBuffer.toString(); 3715 3716 } // toString(Object[]):String 3717 3718 /** Returns a string of the specified values. */ 3719 protected String toString(Vector values, int start, int length) { 3720 3721 // no values 3722 if (length == 0) { 3723 return ""; 3724 } 3725 3726 // one value 3727 if (length == 1) { 3728 return String.valueOf(values.elementAt(start)); 3729 } 3730 3731 // construct value string 3732 StringBuffer str = new StringBuffer(); 3733 for (int i = 0; i < length; i++) { 3734 if (i > 0) { 3735 str.append(','); 3736 } 3737 str.append(values.elementAt(start + i)); 3738 } 3739 return str.toString(); 3740 3741 } // toString(Vector,int,int):String 3742 3743 // 3744 // Object methods 3745 // 3746 3747 /** Returns a string representation of this object. */ 3748 public String toString() { 3749 String s = super.toString(); 3750 int index1 = s.lastIndexOf('$'); 3751 if (index1 != -1) { 3752 s = s.substring(index1 + 1); 3753 } 3754 int index2 = s.lastIndexOf('.'); 3755 if (index2 != -1) { 3756 s = s.substring(index2 + 1); 3757 } 3758 return s + '[' + fIdentityConstraint + ']'; 3759 } // toString():String 3760 3761 // 3762 // Private methods 3763 // 3764 3765 private void addValueType(short type) { 3766 if (fUseValueTypeVector) { 3767 fValueTypes.add(type); 3768 } 3769 else if (fValueTypesLength++ == 0) { 3770 fValueType = type; 3771 } 3772 else if (fValueType != type) { 3773 fUseValueTypeVector = true; 3774 if (fValueTypes == null) { 3775 fValueTypes = new ShortVector(fValueTypesLength * 2); 3776 } 3777 for (int i = 1; i < fValueTypesLength; ++i) { 3778 fValueTypes.add(fValueType); 3779 } 3780 fValueTypes.add(type); 3781 } 3782 } 3783 3784 private short getValueTypeAt(int index) { 3785 if (fUseValueTypeVector) { 3786 return fValueTypes.valueAt(index); 3787 } 3788 return fValueType; 3789 } 3790 3791 private boolean valueTypeContains(short value) { 3792 if (fUseValueTypeVector) { 3793 return fValueTypes.contains(value); 3794 } 3795 return fValueType == value; 3796 } 3797 3798 private void addItemValueType(ShortList itemValueType) { 3799 if (fUseItemValueTypeVector) { 3800 fItemValueTypes.add(itemValueType); 3801 } 3802 else if (fItemValueTypesLength++ == 0) { 3803 fItemValueType = itemValueType; 3804 } 3805 else if (!(fItemValueType == itemValueType || 3806 (fItemValueType != null && fItemValueType.equals(itemValueType)))) { 3807 fUseItemValueTypeVector = true; 3808 if (fItemValueTypes == null) { 3809 fItemValueTypes = new Vector(fItemValueTypesLength * 2); 3810 } 3811 for (int i = 1; i < fItemValueTypesLength; ++i) { 3812 fItemValueTypes.add(fItemValueType); 3813 } 3814 fItemValueTypes.add(itemValueType); 3815 } 3816 } 3817 3818 private ShortList getItemValueTypeAt(int index) { 3819 if (fUseItemValueTypeVector) { 3820 return (ShortList) fItemValueTypes.elementAt(index); 3821 } 3822 return fItemValueType; 3823 } 3824 3825 private boolean itemValueTypeContains(ShortList value) { 3826 if (fUseItemValueTypeVector) { 3827 return fItemValueTypes.contains(value); 3828 } 3829 return fItemValueType == value || 3830 (fItemValueType != null && fItemValueType.equals(value)); 3831 } 3832 3833 } // class ValueStoreBase 3834 3835 /** 3836 * Unique value store. 3837 * 3838 * @author Andy Clark, IBM 3839 */ 3840 protected class UniqueValueStore extends ValueStoreBase { 3841 3842 // 3843 // Constructors 3844 // 3845 3846 /** Constructs a unique value store. */ 3847 public UniqueValueStore(UniqueOrKey unique) { 3848 super(unique); 3849 } // <init>(Unique) 3850 3851 // 3852 // ValueStoreBase protected methods 3853 // 3854 3855 /** 3856 * Called when a duplicate value is added. 3857 */ 3858 protected void checkDuplicateValues() { 3859 // is this value as a group duplicated? 3860 if (contains()) { 3861 String code = "DuplicateUnique"; 3862 String value = toString(fLocalValues); 3863 String eName = fIdentityConstraint.getElementName(); 3864 String cName = fIdentityConstraint.getIdentityConstraintName(); 3865 reportSchemaError(code, new Object[] { value, eName, cName }); 3866 } 3867 } // duplicateValue(Hashtable) 3868 3869 } // class UniqueValueStore 3870 3871 /** 3872 * Key value store. 3873 * 3874 * @author Andy Clark, IBM 3875 */ 3876 protected class KeyValueStore extends ValueStoreBase { 3877 3878 // REVISIT: Implement a more efficient storage mechanism. -Ac 3879 3880 // 3881 // Constructors 3882 // 3883 3884 /** Constructs a key value store. */ 3885 public KeyValueStore(UniqueOrKey key) { 3886 super(key); 3887 } // <init>(Key) 3888 3889 // 3890 // ValueStoreBase protected methods 3891 // 3892 3893 /** 3894 * Called when a duplicate value is added. 3895 */ 3896 protected void checkDuplicateValues() { 3897 if (contains()) { 3898 String code = "DuplicateKey"; 3899 String value = toString(fLocalValues); 3900 String eName = fIdentityConstraint.getElementName(); 3901 String cName = fIdentityConstraint.getIdentityConstraintName(); 3902 reportSchemaError(code, new Object[] { value, eName, cName }); 3903 } 3904 } // duplicateValue(Hashtable) 3905 3906 } // class KeyValueStore 3907 3908 /** 3909 * Key reference value store. 3910 * 3911 * @author Andy Clark, IBM 3912 */ 3913 protected class KeyRefValueStore extends ValueStoreBase { 3914 3915 // 3916 // Data 3917 // 3918 3919 /** Key value store. */ 3920 protected ValueStoreBase fKeyValueStore; 3921 3922 // 3923 // Constructors 3924 // 3925 3926 /** Constructs a key value store. */ 3927 public KeyRefValueStore(KeyRef keyRef, KeyValueStore keyValueStore) { 3928 super(keyRef); 3929 fKeyValueStore = keyValueStore; 3930 } // <init>(KeyRef) 3931 3932 // 3933 // ValueStoreBase methods 3934 // 3935 3936 // end the value Scope; here's where we have to tie 3937 // up keyRef loose ends. 3938 public void endDocumentFragment() { 3939 3940 // do all the necessary management... 3941 super.endDocumentFragment(); 3942 3943 // verify references 3944 // get the key store corresponding (if it exists): 3945 fKeyValueStore = 3946 (ValueStoreBase) fValueStoreCache.fGlobalIDConstraintMap.get( 3947 ((KeyRef) fIdentityConstraint).getKey()); 3948 3949 if (fKeyValueStore == null) { 3950 // report error 3951 String code = "KeyRefOutOfScope"; 3952 String value = fIdentityConstraint.toString(); 3953 reportSchemaError(code, new Object[] { value }); 3954 return; 3955 } 3956 int errorIndex = fKeyValueStore.contains(this); 3957 if (errorIndex != -1) { 3958 String code = "KeyNotFound"; 3959 String values = toString(fValues, errorIndex, fFieldCount); 3960 String element = fIdentityConstraint.getElementName(); 3961 String name = fIdentityConstraint.getName(); 3962 reportSchemaError(code, new Object[] { name, values, element }); 3963 } 3964 3965 } // endDocumentFragment() 3966 3967 /** End document. */ 3968 public void endDocument() { 3969 super.endDocument(); 3970 3971 } // endDocument() 3972 3973 } // class KeyRefValueStore 3974 3975 // value store management 3976 3977 /** 3978 * Value store cache. This class is used to store the values for 3979 * identity constraints. 3980 * 3981 * @author Andy Clark, IBM 3982 */ 3983 protected class ValueStoreCache { 3984 3985 // 3986 // Data 3987 // 3988 final LocalIDKey fLocalId = new LocalIDKey(); 3989 // values stores 3990 3991 /** stores all global Values stores. */ 3992 protected final Vector fValueStores = new Vector(); 3993 3994 /** 3995 * Values stores associated to specific identity constraints. 3996 * This hashtable maps IdentityConstraints and 3997 * the 0-based element on which their selectors first matched to 3998 * a corresponding ValueStore. This should take care 3999 * of all cases, including where ID constraints with 4000 * descendant-or-self axes occur on recursively-defined 4001 * elements. 4002 */ 4003 protected final Hashtable fIdentityConstraint2ValueStoreMap = new Hashtable(); 4004 4005 // sketch of algorithm: 4006 // - when a constraint is first encountered, its 4007 // values are stored in the (local) fIdentityConstraint2ValueStoreMap; 4008 // - Once it is validated (i.e., when it goes out of scope), 4009 // its values are merged into the fGlobalIDConstraintMap; 4010 // - as we encounter keyref's, we look at the global table to 4011 // validate them. 4012 // 4013 // The fGlobalIDMapStack has the following structure: 4014 // - validation always occurs against the fGlobalIDConstraintMap 4015 // (which comprises all the "eligible" id constraints); 4016 // When an endElement is found, this Hashtable is merged with the one 4017 // below in the stack. 4018 // When a start tag is encountered, we create a new 4019 // fGlobalIDConstraintMap. 4020 // i.e., the top of the fGlobalIDMapStack always contains 4021 // the preceding siblings' eligible id constraints; 4022 // the fGlobalIDConstraintMap contains descendants+self. 4023 // keyrefs can only match descendants+self. 4024 protected final Stack fGlobalMapStack = new Stack(); 4025 protected final Hashtable fGlobalIDConstraintMap = new Hashtable(); 4026 4027 // 4028 // Constructors 4029 // 4030 4031 /** Default constructor. */ 4032 public ValueStoreCache() { 4033 } // <init>() 4034 4035 // 4036 // Public methods 4037 // 4038 4039 /** Resets the identity constraint cache. */ 4040 public void startDocument() { 4041 fValueStores.removeAllElements(); 4042 fIdentityConstraint2ValueStoreMap.clear(); 4043 fGlobalIDConstraintMap.clear(); 4044 fGlobalMapStack.removeAllElements(); 4045 } // startDocument() 4046 4047 // startElement: pushes the current fGlobalIDConstraintMap 4048 // onto fGlobalMapStack and clears fGlobalIDConstraint map. 4049 public void startElement() { 4050 // only clone the hashtable when there are elements 4051 if (fGlobalIDConstraintMap.size() > 0) 4052 fGlobalMapStack.push(fGlobalIDConstraintMap.clone()); 4053 else 4054 fGlobalMapStack.push(null); 4055 fGlobalIDConstraintMap.clear(); 4056 } // startElement(void) 4057 4058 /** endElement(): merges contents of fGlobalIDConstraintMap with the 4059 * top of fGlobalMapStack into fGlobalIDConstraintMap. 4060 */ 4061 public void endElement() { 4062 if (fGlobalMapStack.isEmpty()) { 4063 return; // must be an invalid doc! 4064 } 4065 Hashtable oldMap = (Hashtable) fGlobalMapStack.pop(); 4066 // return if there is no element 4067 if (oldMap == null) { 4068 return; 4069 } 4070 4071 Iterator entries = oldMap.entrySet().iterator(); 4072 while (entries.hasNext()) { 4073 Map.Entry entry = (Map.Entry) entries.next(); 4074 IdentityConstraint id = (IdentityConstraint) entry.getKey(); 4075 ValueStoreBase oldVal = (ValueStoreBase) entry.getValue(); 4076 if (oldVal != null) { 4077 ValueStoreBase currVal = (ValueStoreBase) fGlobalIDConstraintMap.get(id); 4078 if (currVal == null) { 4079 fGlobalIDConstraintMap.put(id, oldVal); 4080 } 4081 else if (currVal != oldVal) { 4082 currVal.append(oldVal); 4083 } 4084 } 4085 } 4086 } // endElement() 4087 4088 /** 4089 * Initializes the value stores for the specified element 4090 * declaration. 4091 */ 4092 public void initValueStoresFor(XSElementDecl eDecl, FieldActivator activator) { 4093 // initialize value stores for unique fields 4094 IdentityConstraint[] icArray = eDecl.fIDConstraints; 4095 int icCount = eDecl.fIDCPos; 4096 for (int i = 0; i < icCount; i++) { 4097 switch (icArray[i].getCategory()) { 4098 case (IdentityConstraint.IC_UNIQUE) : 4099 // initialize value stores for unique fields 4100 UniqueOrKey unique = (UniqueOrKey) icArray[i]; 4101 LocalIDKey toHash = new LocalIDKey(unique, fElementDepth); 4102 UniqueValueStore uniqueValueStore = 4103 (UniqueValueStore) fIdentityConstraint2ValueStoreMap.get(toHash); 4104 if (uniqueValueStore == null) { 4105 uniqueValueStore = new UniqueValueStore(unique); 4106 fIdentityConstraint2ValueStoreMap.put(toHash, uniqueValueStore); 4107 } else { 4108 uniqueValueStore.clear(); 4109 } 4110 fValueStores.addElement(uniqueValueStore); 4111 activateSelectorFor(icArray[i]); 4112 break; 4113 case (IdentityConstraint.IC_KEY) : 4114 // initialize value stores for key fields 4115 UniqueOrKey key = (UniqueOrKey) icArray[i]; 4116 toHash = new LocalIDKey(key, fElementDepth); 4117 KeyValueStore keyValueStore = 4118 (KeyValueStore) fIdentityConstraint2ValueStoreMap.get(toHash); 4119 if (keyValueStore == null) { 4120 keyValueStore = new KeyValueStore(key); 4121 fIdentityConstraint2ValueStoreMap.put(toHash, keyValueStore); 4122 } else { 4123 keyValueStore.clear(); 4124 } 4125 fValueStores.addElement(keyValueStore); 4126 activateSelectorFor(icArray[i]); 4127 break; 4128 case (IdentityConstraint.IC_KEYREF) : 4129 // initialize value stores for keyRef fields 4130 KeyRef keyRef = (KeyRef) icArray[i]; 4131 toHash = new LocalIDKey(keyRef, fElementDepth); 4132 KeyRefValueStore keyRefValueStore = 4133 (KeyRefValueStore) fIdentityConstraint2ValueStoreMap.get(toHash); 4134 if (keyRefValueStore == null) { 4135 keyRefValueStore = new KeyRefValueStore(keyRef, null); 4136 fIdentityConstraint2ValueStoreMap.put(toHash, keyRefValueStore); 4137 } else { 4138 keyRefValueStore.clear(); 4139 } 4140 fValueStores.addElement(keyRefValueStore); 4141 activateSelectorFor(icArray[i]); 4142 break; 4143 } 4144 } 4145 } // initValueStoresFor(XSElementDecl) 4146 4147 /** Returns the value store associated to the specified IdentityConstraint. */ 4148 public ValueStoreBase getValueStoreFor(IdentityConstraint id, int initialDepth) { 4149 fLocalId.fDepth = initialDepth; 4150 fLocalId.fId = id; 4151 return (ValueStoreBase) fIdentityConstraint2ValueStoreMap.get(fLocalId); 4152 } // getValueStoreFor(IdentityConstraint, int):ValueStoreBase 4153 4154 /** Returns the global value store associated to the specified IdentityConstraint. */ 4155 public ValueStoreBase getGlobalValueStoreFor(IdentityConstraint id) { 4156 return (ValueStoreBase) fGlobalIDConstraintMap.get(id); 4157 } // getValueStoreFor(IdentityConstraint):ValueStoreBase 4158 4159 // This method takes the contents of the (local) ValueStore 4160 // associated with id and moves them into the global 4161 // hashtable, if id is a <unique> or a <key>. 4162 // If it's a <keyRef>, then we leave it for later. 4163 public void transplant(IdentityConstraint id, int initialDepth) { 4164 fLocalId.fDepth = initialDepth; 4165 fLocalId.fId = id; 4166 ValueStoreBase newVals = 4167 (ValueStoreBase) fIdentityConstraint2ValueStoreMap.get(fLocalId); 4168 if (id.getCategory() == IdentityConstraint.IC_KEYREF) 4169 return; 4170 ValueStoreBase currVals = (ValueStoreBase) fGlobalIDConstraintMap.get(id); 4171 if (currVals != null) { 4172 currVals.append(newVals); 4173 fGlobalIDConstraintMap.put(id, currVals); 4174 } else 4175 fGlobalIDConstraintMap.put(id, newVals); 4176 4177 } // transplant(id) 4178 4179 /** Check identity constraints. */ 4180 public void endDocument() { 4181 4182 int count = fValueStores.size(); 4183 for (int i = 0; i < count; i++) { 4184 ValueStoreBase valueStore = (ValueStoreBase) fValueStores.elementAt(i); 4185 valueStore.endDocument(); 4186 } 4187 4188 } // endDocument() 4189 4190 // 4191 // Object methods 4192 // 4193 4194 /** Returns a string representation of this object. */ 4195 public String toString() { 4196 String s = super.toString(); 4197 int index1 = s.lastIndexOf('$'); 4198 if (index1 != -1) { 4199 return s.substring(index1 + 1); 4200 } 4201 int index2 = s.lastIndexOf('.'); 4202 if (index2 != -1) { 4203 return s.substring(index2 + 1); 4204 } 4205 return s; 4206 } // toString():String 4207 4208 } // class ValueStoreCache 4209 4210 // the purpose of this class is to enable IdentityConstraint,int 4211 // pairs to be used easily as keys in Hashtables. 4212 protected class LocalIDKey { 4213 4214 public IdentityConstraint fId; 4215 public int fDepth; 4216 4217 public LocalIDKey() { 4218 } 4219 4220 public LocalIDKey(IdentityConstraint id, int depth) { 4221 fId = id; 4222 fDepth = depth; 4223 } // init(IdentityConstraint, int) 4224 4225 // object method 4226 public int hashCode() { 4227 return fId.hashCode() + fDepth; 4228 } 4229 4230 public boolean equals(Object localIDKey) { 4231 if (localIDKey instanceof LocalIDKey) { 4232 LocalIDKey lIDKey = (LocalIDKey) localIDKey; 4233 return (lIDKey.fId == fId && lIDKey.fDepth == fDepth); 4234 } 4235 return false; 4236 } 4237 } // class LocalIDKey 4238 4239 /** 4240 * A simple vector for <code>short</code>s. 4241 */ 4242 protected static final class ShortVector { 4243 4244 // 4245 // Data 4246 // 4247 4248 /** Current length. */ 4249 private int fLength; 4250 4251 /** Data. */ 4252 private short[] fData; 4253 4254 // 4255 // Constructors 4256 // 4257 4258 public ShortVector() {} 4259 4260 public ShortVector(int initialCapacity) { 4261 fData = new short[initialCapacity]; 4262 } 4263 4264 // 4265 // Public methods 4266 // 4267 4268 /** Returns the length of the vector. */ 4269 public int length() { 4270 return fLength; 4271 } 4272 4273 /** Adds the value to the vector. */ 4274 public void add(short value) { 4275 ensureCapacity(fLength + 1); 4276 fData[fLength++] = value; 4277 } 4278 4279 /** Returns the short value at the specified position in the vector. */ 4280 public short valueAt(int position) { 4281 return fData[position]; 4282 } 4283 4284 /** Clears the vector. */ 4285 public void clear() { 4286 fLength = 0; 4287 } 4288 4289 /** Returns whether the short is contained in the vector. */ 4290 public boolean contains(short value) { 4291 for (int i = 0; i < fLength; ++i) { 4292 if (fData[i] == value) { 4293 return true; 4294 } 4295 } 4296 return false; 4297 } 4298 4299 // 4300 // Private methods 4301 // 4302 4303 /** Ensures capacity. */ 4304 private void ensureCapacity(int size) { 4305 if (fData == null) { 4306 fData = new short[8]; 4307 } 4308 else if (fData.length <= size) { 4309 short[] newdata = new short[fData.length * 2]; 4310 System.arraycopy(fData, 0, newdata, 0, fData.length); 4311 fData = newdata; 4312 } 4313 } 4314 } 4315 4316 } // class SchemaValidator