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