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