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