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