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