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