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