2
* Licensed to the Apache Software Foundation (ASF) under one or more
3
* contributor license agreements. See the NOTICE file distributed with
4
* this work for additional information regarding copyright ownership.
5
* The ASF licenses this file to You under the Apache License, Version 2.0
6
* (the "License"); you may not use this file except in compliance with
7
* the License. You may obtain a copy of the License at
9
* http://www.apache.org/licenses/LICENSE-2.0
11
* Unless required by applicable law or agreed to in writing, software
12
* distributed under the License is distributed on an "AS IS" BASIS,
13
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
* See the License for the specific language governing permissions and
15
* limitations under the License.
18
package org.apache.xerces.impl.xs.traversers;
20
import java.io.IOException;
21
import java.io.StringReader;
22
import java.util.ArrayList;
23
import java.util.Hashtable;
24
import java.util.Stack;
25
import java.util.Vector;
27
import org.apache.xerces.impl.Constants;
28
import org.apache.xerces.impl.XMLEntityManager;
29
import org.apache.xerces.impl.XMLErrorReporter;
30
import org.apache.xerces.impl.xs.SchemaGrammar;
31
import org.apache.xerces.impl.xs.SchemaNamespaceSupport;
32
import org.apache.xerces.impl.xs.SchemaSymbols;
33
import org.apache.xerces.impl.xs.XMLSchemaException;
34
import org.apache.xerces.impl.xs.XMLSchemaLoader;
35
import org.apache.xerces.impl.xs.XSComplexTypeDecl;
36
import org.apache.xerces.impl.xs.XSDDescription;
37
import org.apache.xerces.impl.xs.XSDeclarationPool;
38
import org.apache.xerces.impl.xs.XSElementDecl;
39
import org.apache.xerces.impl.xs.XSGrammarBucket;
40
import org.apache.xerces.impl.xs.XSGroupDecl;
41
import org.apache.xerces.impl.xs.XSMessageFormatter;
42
import org.apache.xerces.impl.xs.XSModelGroupImpl;
43
import org.apache.xerces.impl.xs.XSParticleDecl;
44
import org.apache.xerces.impl.xs.opti.ElementImpl;
45
import org.apache.xerces.impl.xs.opti.SchemaDOMParser;
46
import org.apache.xerces.impl.xs.opti.SchemaParsingConfig;
47
import org.apache.xerces.impl.xs.util.SimpleLocator;
49
import org.apache.xerces.util.DOMUtil;
50
import org.apache.xerces.parsers.SAXParser;
51
import org.apache.xerces.parsers.XML11Configuration;
52
import org.apache.xerces.util.DOMInputSource;
53
import org.apache.xerces.util.DefaultErrorHandler;
54
import org.apache.xerces.util.SAXInputSource;
55
import org.apache.xerces.util.SymbolTable;
56
import org.apache.xerces.util.XMLSymbols;
57
import org.apache.xerces.util.URI.MalformedURIException;
58
import org.apache.xerces.xni.QName;
59
import org.apache.xerces.xni.grammars.Grammar;
60
import org.apache.xerces.xni.grammars.XMLGrammarDescription;
61
import org.apache.xerces.xni.grammars.XMLGrammarPool;
62
import org.apache.xerces.xni.grammars.XMLSchemaDescription;
63
import org.apache.xerces.xni.parser.XMLComponentManager;
64
import org.apache.xerces.xni.parser.XMLConfigurationException;
65
import org.apache.xerces.xni.parser.XMLEntityResolver;
66
import org.apache.xerces.xni.parser.XMLErrorHandler;
67
import org.apache.xerces.xni.parser.XMLInputSource;
68
import org.apache.xerces.xs.XSObject;
69
import org.apache.xerces.xs.XSParticle;
70
import org.w3c.dom.Document;
71
import org.w3c.dom.Element;
72
import org.w3c.dom.Node;
73
import org.xml.sax.InputSource;
74
import org.xml.sax.SAXException;
75
import org.xml.sax.XMLReader;
76
import org.xml.sax.helpers.XMLReaderFactory;
80
* The purpose of this class is to co-ordinate the construction of a
81
* grammar object corresponding to a schema. To do this, it must be
82
* prepared to parse several schema documents (for instance if the
83
* schema document originally referred to contains <include> or
84
* <redefined> information items). If any of the schemas imports a
85
* schema, other grammars may be constructed as a side-effect.
89
* @author Neil Graham, IBM
90
* @author Pavani Mukthipudi, Sun Microsystems
92
* @version $Id: XSDHandler.java,v 1.2 2009/12/10 03:18:40 matthewoliver Exp $
94
public class XSDHandler {
96
/** Feature identifier: validation. */
97
protected static final String VALIDATION =
98
Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE;
100
/** feature identifier: XML Schema validation */
101
protected static final String XMLSCHEMA_VALIDATION =
102
Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE;
104
/** Feature identifier: allow java encodings */
105
protected static final String ALLOW_JAVA_ENCODINGS =
106
Constants.XERCES_FEATURE_PREFIX + Constants.ALLOW_JAVA_ENCODINGS_FEATURE;
108
/** Feature identifier: continue after fatal error */
109
protected static final String CONTINUE_AFTER_FATAL_ERROR =
110
Constants.XERCES_FEATURE_PREFIX + Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE;
112
/** Feature identifier: allow java encodings */
113
protected static final String STANDARD_URI_CONFORMANT_FEATURE =
114
Constants.XERCES_FEATURE_PREFIX + Constants.STANDARD_URI_CONFORMANT_FEATURE;
116
/** Feature: disallow doctype*/
117
protected static final String DISALLOW_DOCTYPE =
118
Constants.XERCES_FEATURE_PREFIX + Constants.DISALLOW_DOCTYPE_DECL_FEATURE;
120
/** Feature: generate synthetic annotations */
121
protected static final String GENERATE_SYNTHETIC_ANNOTATIONS =
122
Constants.XERCES_FEATURE_PREFIX + Constants.GENERATE_SYNTHETIC_ANNOTATIONS_FEATURE;
124
/** Feature identifier: validate annotations. */
125
protected static final String VALIDATE_ANNOTATIONS =
126
Constants.XERCES_FEATURE_PREFIX + Constants.VALIDATE_ANNOTATIONS_FEATURE;
128
/** Feature identifier: honour all schemaLocations */
129
protected static final String HONOUR_ALL_SCHEMALOCATIONS =
130
Constants.XERCES_FEATURE_PREFIX + Constants.HONOUR_ALL_SCHEMALOCATIONS_FEATURE;
132
/** Feature identifier: namespace prefixes. */
133
private static final String NAMESPACE_PREFIXES =
134
Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACE_PREFIXES_FEATURE;
136
/** Feature identifier: string interning. */
137
protected static final String STRING_INTERNING =
138
Constants.SAX_FEATURE_PREFIX + Constants.STRING_INTERNING_FEATURE;
140
/** Property identifier: error handler. */
141
protected static final String ERROR_HANDLER =
142
Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY;
144
/** Property identifier: JAXP schema source. */
145
protected static final String JAXP_SCHEMA_SOURCE =
146
Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_SOURCE;
148
/** Property identifier: entity resolver. */
149
public static final String ENTITY_RESOLVER =
150
Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY;
151
/** Property identifier: entity manager. */
152
protected static final String ENTITY_MANAGER =
153
Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY;
155
/** Property identifier: error reporter. */
156
public static final String ERROR_REPORTER =
157
Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;
159
/** Property identifier: grammar pool. */
160
public static final String XMLGRAMMAR_POOL =
161
Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY;
163
/** Property identifier: symbol table. */
164
public static final String SYMBOL_TABLE =
165
Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
167
/** Property identifier: security manager. */
168
protected static final String SECURITY_MANAGER =
169
Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY;
171
protected static final boolean DEBUG_NODE_POOL = false;
175
// different sorts of declarations; should make lookup and
176
// traverser calling more efficient/less bulky.
177
final static int ATTRIBUTE_TYPE = 1;
178
final static int ATTRIBUTEGROUP_TYPE = 2;
179
final static int ELEMENT_TYPE = 3;
180
final static int GROUP_TYPE = 4;
181
final static int IDENTITYCONSTRAINT_TYPE = 5;
182
final static int NOTATION_TYPE = 6;
183
final static int TYPEDECL_TYPE = 7;
185
// this string gets appended to redefined names; it's purpose is to be
186
// as unlikely as possible to cause collisions.
187
public final static String REDEF_IDENTIFIER = "_fn3dktizrknc9pi";
190
//protected data that can be accessable by any traverser
191
// stores <notation> decl
192
protected Hashtable fNotationRegistry = new Hashtable();
194
protected XSDeclarationPool fDeclPool = null;
197
// These tables correspond to the symbol spaces defined in the
199
// They are keyed with a QName (that is, String("URI,localpart) and
200
// their values are nodes corresponding to the given name's decl.
201
// By asking the node for its ownerDocument and looking in
202
// XSDocumentInfoRegistry we can easily get the corresponding
203
// XSDocumentInfo object.
204
private Hashtable fUnparsedAttributeRegistry = new Hashtable();
205
private Hashtable fUnparsedAttributeGroupRegistry = new Hashtable();
206
private Hashtable fUnparsedElementRegistry = new Hashtable();
207
private Hashtable fUnparsedGroupRegistry = new Hashtable();
208
private Hashtable fUnparsedIdentityConstraintRegistry = new Hashtable();
209
private Hashtable fUnparsedNotationRegistry = new Hashtable();
210
private Hashtable fUnparsedTypeRegistry = new Hashtable();
211
// Compensation for the above hashtables to locate XSDocumentInfo,
212
// Since we may take Schema Element directly, so can not get the
213
// corresponding XSDocumentInfo object just using above hashtables.
214
private Hashtable fUnparsedAttributeRegistrySub = new Hashtable();
215
private Hashtable fUnparsedAttributeGroupRegistrySub = new Hashtable();
216
private Hashtable fUnparsedElementRegistrySub = new Hashtable();
217
private Hashtable fUnparsedGroupRegistrySub = new Hashtable();
218
private Hashtable fUnparsedIdentityConstraintRegistrySub = new Hashtable();
219
private Hashtable fUnparsedNotationRegistrySub = new Hashtable();
220
private Hashtable fUnparsedTypeRegistrySub = new Hashtable();
222
// this is keyed with a documentNode (or the schemaRoot nodes
223
// contained in the XSDocumentInfo objects) and its value is the
224
// XSDocumentInfo object corresponding to that document.
225
// Basically, the function of this registry is to be a link
226
// between the nodes we fetch from calls to the fUnparsed*
227
// arrays and the XSDocumentInfos they live in.
228
private Hashtable fXSDocumentInfoRegistry = new Hashtable();
230
// this hashtable is keyed on by XSDocumentInfo objects. Its values
231
// are Vectors containing the XSDocumentInfo objects <include>d,
232
// <import>ed or <redefine>d by the key XSDocumentInfo.
233
private Hashtable fDependencyMap = new Hashtable();
235
// this hashtable is keyed on by a target namespace. Its values
236
// are Vectors containing namespaces imported by schema documents
237
// with the key target namespace.
238
// if an imprted schema has absent namespace, the value "null" is stored.
239
private Hashtable fImportMap = new Hashtable();
240
// all namespaces that imports other namespaces
241
// if the importing schema has absent namespace, empty string is stored.
242
// (because the key of a hashtable can't be null.)
243
private Vector fAllTNSs = new Vector();
244
// stores instance document mappings between namespaces and schema hints
245
private Hashtable fLocationPairs = null;
246
private static final Hashtable EMPTY_TABLE = new Hashtable();
248
// Records which nodes are hidden when the input is a DOMInputSource.
249
Hashtable fHiddenNodes = null;
251
// convenience methods
252
private String null2EmptyString(String ns) {
253
return ns == null ? XMLSymbols.EMPTY_STRING : ns;
255
private String emptyString2Null(String ns) {
256
return ns == XMLSymbols.EMPTY_STRING ? null : ns;
258
// use Schema Element to lookup the SystemId.
259
private String doc2SystemId(Element ele) {
260
String documentURI = null;
262
* REVISIT: Casting until DOM Level 3 interfaces are available. -- mrglavas
264
if(ele.getOwnerDocument() instanceof org.apache.xerces.impl.xs.opti.SchemaDOM){
265
documentURI = ((org.apache.xerces.impl.xs.opti.SchemaDOM) ele.getOwnerDocument()).getDocumentURI();
267
return documentURI != null ? documentURI : (String) fDoc2SystemId.get(ele);
270
// This vector stores strings which are combinations of the
271
// publicId and systemId of the inputSource corresponding to a
272
// schema document. This combination is used so that the user's
273
// EntityResolver can provide a consistent way of identifying a
274
// schema document that is included in multiple other schemas.
275
private Hashtable fTraversed = new Hashtable();
277
// this hashtable contains a mapping from Schema Element to its systemId
278
// this is useful to resolve a uri relative to the referring document
279
private Hashtable fDoc2SystemId = new Hashtable();
281
// the primary XSDocumentInfo we were called to parse
282
private XSDocumentInfo fRoot = null;
284
// This hashtable's job is to act as a link between the Schema Element and its
285
// XSDocumentInfo object.
286
private Hashtable fDoc2XSDocumentMap = new Hashtable();
288
// map between <redefine> elements and the XSDocumentInfo
289
// objects that correspond to the documents being redefined.
290
private Hashtable fRedefine2XSDMap = new Hashtable();
292
// map between <redefine> elements and the namespace support
293
private Hashtable fRedefine2NSSupport = new Hashtable();
295
// these objects store a mapping between the names of redefining
296
// groups/attributeGroups and the groups/AttributeGroups which
297
// they redefine by restriction (implicitly). It is up to the
298
// Group and AttributeGroup traversers to check these restrictions for
300
private Hashtable fRedefinedRestrictedAttributeGroupRegistry = new Hashtable();
301
private Hashtable fRedefinedRestrictedGroupRegistry = new Hashtable();
303
// a variable storing whether the last schema document
304
// processed (by getSchema) was a duplicate.
305
private boolean fLastSchemaWasDuplicate;
307
// validate annotations feature
308
private boolean fValidateAnnotations = false;
310
//handle multiple import feature
311
private boolean fHonourAllSchemaLocations = false;
313
// the XMLErrorReporter
314
private XMLErrorReporter fErrorReporter;
315
private XMLEntityResolver fEntityResolver;
317
// the XSAttributeChecker
318
private XSAttributeChecker fAttributeChecker;
321
private SymbolTable fSymbolTable;
323
// the GrammarResolver
324
private XSGrammarBucket fGrammarBucket;
326
// the Grammar description
327
private XSDDescription fSchemaGrammarDescription;
330
private XMLGrammarPool fGrammarPool;
332
//************ Traversers **********
333
XSDAttributeGroupTraverser fAttributeGroupTraverser;
334
XSDAttributeTraverser fAttributeTraverser;
335
XSDComplexTypeTraverser fComplexTypeTraverser;
336
XSDElementTraverser fElementTraverser;
337
XSDGroupTraverser fGroupTraverser;
338
XSDKeyrefTraverser fKeyrefTraverser;
339
XSDNotationTraverser fNotationTraverser;
340
XSDSimpleTypeTraverser fSimpleTypeTraverser;
341
XSDUniqueOrKeyTraverser fUniqueOrKeyTraverser;
342
XSDWildcardTraverser fWildCardTraverser;
344
SchemaDOMParser fSchemaParser;
345
SchemaContentHandler fXSContentHandler;
346
XML11Configuration fAnnotationValidator;
347
XSAnnotationGrammarPool fGrammarBucketAdapter;
349
// these data members are needed for the deferred traversal
350
// of local elements.
352
// the initial size of the array to store deferred local elements
353
private static final int INIT_STACK_SIZE = 30;
354
// the incremental size of the array to store deferred local elements
355
private static final int INC_STACK_SIZE = 10;
356
// current position of the array (# of deferred local elements)
357
private int fLocalElemStackPos = 0;
359
private XSParticleDecl[] fParticle = new XSParticleDecl[INIT_STACK_SIZE];
360
private Element[] fLocalElementDecl = new Element[INIT_STACK_SIZE];
361
private XSDocumentInfo[] fLocalElementDecl_schema = new XSDocumentInfo[INIT_STACK_SIZE]; //JACK
362
private int[] fAllContext = new int[INIT_STACK_SIZE];
363
private XSObject[] fParent = new XSObject[INIT_STACK_SIZE];
364
private String [][] fLocalElemNamespaceContext = new String [INIT_STACK_SIZE][1];
366
// these data members are needed for the deferred traversal
369
// the initial size of the array to store deferred keyrefs
370
private static final int INIT_KEYREF_STACK = 2;
371
// the incremental size of the array to store deferred keyrefs
372
private static final int INC_KEYREF_STACK_AMOUNT = 2;
373
// current position of the array (# of deferred keyrefs)
374
private int fKeyrefStackPos = 0;
376
private Element [] fKeyrefs = new Element[INIT_KEYREF_STACK];
377
private XSDocumentInfo [] fKeyrefsMapXSDocumentInfo = new XSDocumentInfo[INIT_KEYREF_STACK];
378
private XSElementDecl [] fKeyrefElems = new XSElementDecl [INIT_KEYREF_STACK];
379
private String [][] fKeyrefNamespaceContext = new String[INIT_KEYREF_STACK][1];
383
fHiddenNodes = new Hashtable();
384
fSchemaParser = new SchemaDOMParser(new SchemaParsingConfig());
387
// it should be possible to use the same XSDHandler to parse
388
// multiple schema documents; this will allow one to be
390
public XSDHandler (XSGrammarBucket gBucket) {
392
fGrammarBucket = gBucket;
394
// Note: don't use SchemaConfiguration internally
395
// we will get stack overflaw because
396
// XMLSchemaValidator will be instantiating XSDHandler...
397
fSchemaGrammarDescription = new XSDDescription();
401
* This method initiates the parse of a schema. It will likely be
402
* called from the Validator and it will make the
403
* resulting grammar available; it returns a reference to this object just
404
* in case. A reset(XMLComponentManager) must be called before this methods is called.
407
* @param locationPairs
408
* @return the SchemaGrammar
409
* @throws IOException
411
public SchemaGrammar parseSchema(XMLInputSource is, XSDDescription desc,
412
Hashtable locationPairs)
414
fLocationPairs = locationPairs;
415
fSchemaParser.resetNodePool();
416
SchemaGrammar grammar = null;
417
String schemaNamespace = null;
418
short referType = desc.getContextType();
419
// if loading using JAXP schemaSource property, or using grammar caching loadGrammar
420
// the desc.targetNamespace is always null.
421
// Therefore we should not attempt to find out if
422
// the schema is already in the bucket, since in the case we have
423
// no namespace schema in the bucket, findGrammar will always return the
424
// no namespace schema.
425
if (referType != XSDDescription.CONTEXT_PREPARSE){
426
// first try to find it in the bucket/pool, return if one is found
427
if(fHonourAllSchemaLocations && referType == XSDDescription.CONTEXT_IMPORT && isExistingGrammar(desc)) {
428
grammar = fGrammarBucket.getGrammar(desc.getTargetNamespace());
431
grammar = findGrammar(desc);
435
schemaNamespace = desc.getTargetNamespace();
436
// handle empty string URI as null
437
if (schemaNamespace != null) {
438
schemaNamespace = fSymbolTable.addSymbol(schemaNamespace);
442
// before parsing a schema, need to clear registries associated with
446
Document schemaRootDoc = null;
447
Element schemaRoot = null;
448
// first phase: construct trees.
449
if (is instanceof DOMInputSource) {
450
//clean up the field fHiddenNodes, used for DOMInputSource
451
fHiddenNodes.clear();
452
Node domNode = ((DOMInputSource)is).getNode();
454
if (domNode instanceof Document) {
455
schemaRootDoc = (Document)domNode;
456
schemaRoot = DOMUtil.getRoot(schemaRootDoc);
458
else if (domNode instanceof Element) {
459
schemaRoot = (Element)domNode;
465
else if (is instanceof SAXInputSource) {
466
XMLReader parser = ((SAXInputSource)is).getXMLReader();
467
InputSource inputSource = ((SAXInputSource)is).getInputSource();
468
boolean namespacePrefixes = false;
469
if (parser != null) {
471
namespacePrefixes = parser.getFeature(NAMESPACE_PREFIXES);
473
catch (SAXException se) {}
477
parser = XMLReaderFactory.createXMLReader();
479
// If something went wrong with the factory
480
// just use our own SAX parser.
481
catch (SAXException se) {
482
parser = new SAXParser();
485
parser.setFeature(NAMESPACE_PREFIXES, true);
486
namespacePrefixes = true;
488
catch (SAXException se) {}
490
// If XML names and Namespace URIs are already internalized we
491
// can avoid running them through the SymbolTable.
492
boolean stringsInternalized = false;
494
stringsInternalized = parser.getFeature(STRING_INTERNING);
496
catch (SAXException exc) {
497
// The feature isn't recognized or getting it is not supported.
498
// In either case, assume that strings are not internalized.
500
if (fXSContentHandler == null) {
501
fXSContentHandler = new SchemaContentHandler();
503
fXSContentHandler.reset(fSchemaParser, fSymbolTable,
504
namespacePrefixes, stringsInternalized);
505
parser.setContentHandler(fXSContentHandler);
506
parser.setErrorHandler(fErrorReporter.getSAXErrorHandler());
508
parser.parse(inputSource);
510
catch (SAXException se) {
513
schemaRootDoc = fXSContentHandler.getDocument();
514
if (schemaRootDoc == null) {
515
// something went wrong right off the hop
518
schemaRoot = DOMUtil.getRoot(schemaRootDoc);
521
schemaRoot = getSchemaDocument(schemaNamespace, is,
522
referType == XSDDescription.CONTEXT_PREPARSE,
525
}//is instanceof XMLInputSource
527
if(schemaRoot == null){
528
// something went wrong right off the hop
532
if ( referType == XSDDescription.CONTEXT_PREPARSE) {
533
Element schemaElem = schemaRoot;
534
schemaNamespace = DOMUtil.getAttrValue(schemaElem, SchemaSymbols.ATT_TARGETNAMESPACE);
535
if(schemaNamespace != null && schemaNamespace.length() > 0) {
536
// Since now we've discovered a namespace, we need to update xsd key
537
// and store this schema in traversed schemas bucket
538
schemaNamespace = fSymbolTable.addSymbol(schemaNamespace);
539
desc.setTargetNamespace(schemaNamespace);
542
schemaNamespace = null;
544
grammar = findGrammar(desc);
547
String schemaId = XMLEntityManager.expandSystemId(is.getSystemId(), is.getBaseSystemId(), false);
548
XSDKey key = new XSDKey(schemaId, referType, schemaNamespace);
549
fTraversed.put(key, schemaRoot);
550
if (schemaId != null) {
551
fDoc2SystemId.put(schemaRoot, schemaId);
555
// before constructing trees and traversing a schema, need to reset
556
// all traversers and clear all registries
557
prepareForTraverse();
559
fRoot = constructTrees(schemaRoot, is.getSystemId(), desc);
564
// second phase: fill global registries.
565
buildGlobalNameRegistries();
567
// third phase: call traversers
568
ArrayList annotationInfo = fValidateAnnotations ? new ArrayList() : null;
569
traverseSchemas(annotationInfo);
571
// fourth phase: handle local element decls
572
traverseLocalElements();
574
// fifth phase: handle Keyrefs
577
// sixth phase: validate attribute of non-schema namespaces
578
// REVISIT: skip this for now. we really don't want to do it.
579
//fAttributeChecker.checkNonSchemaAttributes(fGrammarBucket);
581
// seventh phase: store imported grammars
582
// for all grammars with <import>s
583
for (int i = fAllTNSs.size() - 1; i >= 0; i--) {
584
// get its target namespace
585
String tns = (String)fAllTNSs.elementAt(i);
586
// get all namespaces it imports
587
Vector ins = (Vector)fImportMap.get(tns);
589
SchemaGrammar sg = fGrammarBucket.getGrammar(emptyString2Null(tns));
593
// for imported namespace
595
for (int j = 0; j < ins.size(); j++) {
596
// get imported grammar
597
isg = fGrammarBucket.getGrammar((String)ins.elementAt(j));
598
// reuse the same vector
600
ins.setElementAt(isg, count++);
603
// set the imported grammars
604
sg.setImportedGrammars(ins);
607
/** validate annotations **/
608
if (fValidateAnnotations && annotationInfo.size() > 0) {
609
validateAnnotations(annotationInfo);
613
return fGrammarBucket.getGrammar(fRoot.fTargetNamespace);
616
private void validateAnnotations(ArrayList annotationInfo) {
617
if (fAnnotationValidator == null) {
618
createAnnotationValidator();
620
final int size = annotationInfo.size();
621
final XMLInputSource src = new XMLInputSource(null, null, null);
622
fGrammarBucketAdapter.refreshGrammars(fGrammarBucket);
623
for (int i = 0; i < size; i += 2) {
624
src.setSystemId((String) annotationInfo.get(i));
625
XSAnnotationInfo annotation = (XSAnnotationInfo) annotationInfo.get(i+1);
626
while (annotation != null) {
627
src.setCharacterStream(new StringReader(annotation.fAnnotation));
629
fAnnotationValidator.parse(src);
631
catch (IOException exc) {}
632
annotation = annotation.next;
637
private void createAnnotationValidator() {
638
fAnnotationValidator = new XML11Configuration();
639
fGrammarBucketAdapter = new XSAnnotationGrammarPool();
640
fAnnotationValidator.setFeature(VALIDATION, true);
641
fAnnotationValidator.setFeature(XMLSCHEMA_VALIDATION, true);
642
fAnnotationValidator.setProperty(XMLGRAMMAR_POOL, fGrammarBucketAdapter);
643
/** Set error handler. **/
644
XMLErrorHandler errorHandler = fErrorReporter.getErrorHandler();
645
fAnnotationValidator.setProperty(ERROR_HANDLER, (errorHandler != null) ? errorHandler : new DefaultErrorHandler());
649
* Pull the grammar out of the bucket simply using
652
SchemaGrammar getGrammar(String tns) {
653
return fGrammarBucket.getGrammar(tns);
657
* First try to find a grammar in the bucket, if failed, consult the
658
* grammar pool. If a grammar is found in the pool, then add it (and all
659
* imported ones) into the bucket.
661
protected SchemaGrammar findGrammar(XSDDescription desc) {
662
SchemaGrammar sg = fGrammarBucket.getGrammar(desc.getTargetNamespace());
664
if (fGrammarPool != null) {
665
sg = (SchemaGrammar)fGrammarPool.retrieveGrammar(desc);
667
// put this grammar into the bucket, along with grammars
668
// imported by it (directly or indirectly)
669
if (!fGrammarBucket.putGrammar(sg, true)) {
670
// REVISIT: a conflict between new grammar(s) and grammars
671
// in the bucket. What to do? A warning? An exception?
672
reportSchemaWarning("GrammarConflict", null, null);
681
// may wish to have setter methods for ErrorHandler,
684
private static final String[][] NS_ERROR_CODES = {
685
{"src-include.2.1", "src-include.2.1"},
686
{"src-redefine.3.1", "src-redefine.3.1"},
687
{"src-import.3.1", "src-import.3.2"},
689
{"TargetNamespace.1", "TargetNamespace.2"},
690
{"TargetNamespace.1", "TargetNamespace.2"},
691
{"TargetNamespace.1", "TargetNamespace.2"},
692
{"TargetNamespace.1", "TargetNamespace.2"}
695
private static final String[] ELE_ERROR_CODES = {
696
"src-include.1", "src-redefine.2", "src-import.2", "schema_reference.4",
697
"schema_reference.4", "schema_reference.4", "schema_reference.4", "schema_reference.4"
700
// This method does several things:
701
// It constructs an instance of an XSDocumentInfo object using the
702
// schemaRoot node. Then, for each <include>,
703
// <redefine>, and <import> children, it attempts to resolve the
704
// requested schema document, initiates a DOM parse, and calls
705
// itself recursively on that document's root. It also records in
706
// the DependencyMap object what XSDocumentInfo objects its XSDocumentInfo
708
// It also makes sure the targetNamespace of the schema it was
709
// called to parse is correct.
710
protected XSDocumentInfo constructTrees(Element schemaRoot, String locationHint, XSDDescription desc) {
711
if (schemaRoot == null) return null;
712
String callerTNS = desc.getTargetNamespace();
713
short referType = desc.getContextType();
715
XSDocumentInfo currSchemaInfo = null;
717
// note that attributes are freed at end of traverseSchemas()
718
currSchemaInfo = new XSDocumentInfo(schemaRoot, fAttributeChecker, fSymbolTable);
719
} catch (XMLSchemaException se) {
720
reportSchemaError(ELE_ERROR_CODES[referType],
721
new Object[]{locationHint},
725
// targetNamespace="" is not valid, issue a warning, and ignore it
726
if (currSchemaInfo.fTargetNamespace != null &&
727
currSchemaInfo.fTargetNamespace.length() == 0) {
728
reportSchemaWarning("EmptyTargetNamespace",
729
new Object[]{locationHint},
731
currSchemaInfo.fTargetNamespace = null;
734
if (callerTNS != null) {
735
// the second index to the NS_ERROR_CODES array
736
// if the caller/expected NS is not absent, we use the first column
738
// for include and redefine
739
if (referType == XSDDescription.CONTEXT_INCLUDE ||
740
referType == XSDDescription.CONTEXT_REDEFINE) {
741
// if the referred document has no targetNamespace,
742
// it's a chameleon schema
743
if (currSchemaInfo.fTargetNamespace == null) {
744
currSchemaInfo.fTargetNamespace = callerTNS;
745
currSchemaInfo.fIsChameleonSchema = true;
747
// if the referred document has a target namespace differing
748
// from the caller, it's an error
749
else if (callerTNS != currSchemaInfo.fTargetNamespace) {
750
reportSchemaError(NS_ERROR_CODES[referType][secondIdx],
751
new Object [] {callerTNS, currSchemaInfo.fTargetNamespace},
756
// for instance and import, the two NS's must be the same
757
else if (referType != XSDDescription.CONTEXT_PREPARSE && callerTNS != currSchemaInfo.fTargetNamespace) {
758
reportSchemaError(NS_ERROR_CODES[referType][secondIdx],
759
new Object [] {callerTNS, currSchemaInfo.fTargetNamespace},
764
// now there is no caller/expected NS, it's an error for the referred
765
// document to have a target namespace, unless we are preparsing a schema
766
else if (currSchemaInfo.fTargetNamespace != null) {
767
// set the target namespace of the description
768
if (referType == XSDDescription.CONTEXT_PREPARSE) {
769
desc.setTargetNamespace(currSchemaInfo.fTargetNamespace);
770
callerTNS = currSchemaInfo.fTargetNamespace;
773
// the second index to the NS_ERROR_CODES array
774
// if the caller/expected NS is absent, we use the second column
776
reportSchemaError(NS_ERROR_CODES[referType][secondIdx],
777
new Object [] {callerTNS, currSchemaInfo.fTargetNamespace},
782
// the other cases (callerTNS == currSchemaInfo.fTargetNamespce == null)
785
// a schema document can always access it's own target namespace
786
currSchemaInfo.addAllowedNS(currSchemaInfo.fTargetNamespace);
788
SchemaGrammar sg = null;
790
if (referType == XSDDescription.CONTEXT_INCLUDE ||
791
referType == XSDDescription.CONTEXT_REDEFINE) {
792
sg = fGrammarBucket.getGrammar(currSchemaInfo.fTargetNamespace);
794
else if(fHonourAllSchemaLocations && referType == XSDDescription.CONTEXT_IMPORT) {
795
sg = findGrammar(desc);
797
sg = new SchemaGrammar(currSchemaInfo.fTargetNamespace, desc.makeClone(), fSymbolTable);
798
fGrammarBucket.putGrammar(sg);
802
sg = new SchemaGrammar(currSchemaInfo.fTargetNamespace, desc.makeClone(), fSymbolTable);
803
fGrammarBucket.putGrammar(sg);
806
// store the document and its location
807
// REVISIT: don't expose the DOM tree
808
sg.addDocument(null, (String)fDoc2SystemId.get(currSchemaInfo.fSchemaElement));
810
fDoc2XSDocumentMap.put(schemaRoot, currSchemaInfo);
811
Vector dependencies = new Vector();
812
Element rootNode = schemaRoot;
814
Element newSchemaRoot = null;
815
for (Element child = DOMUtil.getFirstChildElement(rootNode);
817
child = DOMUtil.getNextSiblingElement(child)) {
818
String schemaNamespace=null;
819
String schemaHint=null;
820
String localName = DOMUtil.getLocalName(child);
824
if (localName.equals(SchemaSymbols.ELT_ANNOTATION))
826
else if (localName.equals(SchemaSymbols.ELT_IMPORT)) {
827
refType = XSDDescription.CONTEXT_IMPORT;
828
// have to handle some validation here too!
829
// call XSAttributeChecker to fill in attrs
830
Object[] importAttrs = fAttributeChecker.checkAttributes(child, true, currSchemaInfo);
831
schemaHint = (String)importAttrs[XSAttributeChecker.ATTIDX_SCHEMALOCATION];
832
schemaNamespace = (String)importAttrs[XSAttributeChecker.ATTIDX_NAMESPACE];
833
if (schemaNamespace != null)
834
schemaNamespace = fSymbolTable.addSymbol(schemaNamespace);
835
// a document can't import another document with the same namespace
836
if (schemaNamespace == currSchemaInfo.fTargetNamespace) {
837
reportSchemaError(schemaNamespace != null ?
838
"src-import.1.1" : "src-import.1.2", new Object [] {schemaNamespace}, child);
841
// check contents and process optional annotations
842
Element importChild = DOMUtil.getFirstChildElement(child);
843
if(importChild != null ) {
844
String importComponentType = DOMUtil.getLocalName(importChild);
845
if (importComponentType.equals(SchemaSymbols.ELT_ANNOTATION)) {
846
// promoting annotations to parent component
848
fElementTraverser.traverseAnnotationDecl(importChild, importAttrs, true, currSchemaInfo));
850
reportSchemaError("s4s-elt-must-match.1", new Object [] {localName, "annotation?", importComponentType}, child);
852
if(DOMUtil.getNextSiblingElement(importChild) != null) {
853
reportSchemaError("s4s-elt-must-match.1", new Object [] {localName, "annotation?", DOMUtil.getLocalName(DOMUtil.getNextSiblingElement(importChild))}, child);
857
String text = DOMUtil.getSyntheticAnnotation(child);
859
sg.addAnnotation(fElementTraverser.traverseSyntheticAnnotation(child, text, importAttrs, true, currSchemaInfo));
862
fAttributeChecker.returnAttrArray(importAttrs, currSchemaInfo);
864
// if this namespace has not been imported by this document,
865
// then import if multiple imports support is enabled.
866
if(currSchemaInfo.isAllowedNS(schemaNamespace)) {
867
if(!fHonourAllSchemaLocations)
871
currSchemaInfo.addAllowedNS(schemaNamespace);
873
// also record the fact that one namespace imports another one
874
// convert null to ""
875
String tns = null2EmptyString(currSchemaInfo.fTargetNamespace);
876
// get all namespaces imported by this one
877
Vector ins = (Vector)fImportMap.get(tns);
878
// if no namespace was imported, create new Vector
880
// record that this one imports other(s)
881
fAllTNSs.addElement(tns);
883
fImportMap.put(tns, ins);
884
ins.addElement(schemaNamespace);
886
else if (!ins.contains(schemaNamespace)){
887
ins.addElement(schemaNamespace);
890
fSchemaGrammarDescription.reset();
891
fSchemaGrammarDescription.setContextType(XSDDescription.CONTEXT_IMPORT);
892
fSchemaGrammarDescription.setBaseSystemId(doc2SystemId(schemaRoot));
893
fSchemaGrammarDescription.setLocationHints(new String[]{schemaHint});
894
fSchemaGrammarDescription.setTargetNamespace(schemaNamespace);
896
// if a grammar with the same namespace and location exists (or being
897
// built), ignore this one (don't traverse it).
898
if ((!fHonourAllSchemaLocations && findGrammar(fSchemaGrammarDescription) != null) || isExistingGrammar(fSchemaGrammarDescription))
900
// If "findGrammar" returns a grammar, then this is not the
901
// the first time we see a location for a given namespace.
902
// Don't consult the location pair hashtable in this case,
903
// otherwise the location will be ignored because it'll get
904
// resolved to the same location as the first hint.
905
newSchemaRoot = resolveSchema(fSchemaGrammarDescription, false, child,
906
findGrammar(fSchemaGrammarDescription) == null);
908
else if ((localName.equals(SchemaSymbols.ELT_INCLUDE)) ||
909
(localName.equals(SchemaSymbols.ELT_REDEFINE))) {
910
// validation for redefine/include will be the same here; just
911
// make sure TNS is right (don't care about redef contents
913
Object[] includeAttrs = fAttributeChecker.checkAttributes(child, true, currSchemaInfo);
914
schemaHint = (String)includeAttrs[XSAttributeChecker.ATTIDX_SCHEMALOCATION];
915
// store the namespace decls of the redefine element
916
if (localName.equals(SchemaSymbols.ELT_REDEFINE)) {
917
fRedefine2NSSupport.put(child, new SchemaNamespaceSupport(currSchemaInfo.fNamespaceSupport));
920
// check annotations. Must do this here to avoid having to
921
// re-parse attributes later
922
if(localName.equals(SchemaSymbols.ELT_INCLUDE)) {
923
Element includeChild = DOMUtil.getFirstChildElement(child);
924
if(includeChild != null ) {
925
String includeComponentType = DOMUtil.getLocalName(includeChild);
926
if (includeComponentType.equals(SchemaSymbols.ELT_ANNOTATION)) {
927
// promoting annotations to parent component
929
fElementTraverser.traverseAnnotationDecl(includeChild, includeAttrs, true, currSchemaInfo));
931
reportSchemaError("s4s-elt-must-match.1", new Object [] {localName, "annotation?", includeComponentType}, child);
933
if(DOMUtil.getNextSiblingElement(includeChild) != null) {
934
reportSchemaError("s4s-elt-must-match.1", new Object [] {localName, "annotation?", DOMUtil.getLocalName(DOMUtil.getNextSiblingElement(includeChild))}, child);
938
String text = DOMUtil.getSyntheticAnnotation(child);
940
sg.addAnnotation(fElementTraverser.traverseSyntheticAnnotation(child, text, includeAttrs, true, currSchemaInfo));
945
for (Element redefinedChild = DOMUtil.getFirstChildElement(child);
946
redefinedChild != null;
947
redefinedChild = DOMUtil.getNextSiblingElement(redefinedChild)) {
948
String redefinedComponentType = DOMUtil.getLocalName(redefinedChild);
949
if (redefinedComponentType.equals(SchemaSymbols.ELT_ANNOTATION)) {
950
// promoting annotations to parent component
952
fElementTraverser.traverseAnnotationDecl(redefinedChild, includeAttrs, true, currSchemaInfo));
953
DOMUtil.setHidden(redefinedChild, fHiddenNodes);
956
String text = DOMUtil.getSyntheticAnnotation(child);
958
sg.addAnnotation(fElementTraverser.traverseSyntheticAnnotation(child, text, includeAttrs, true, currSchemaInfo));
961
// catch all other content errors later
964
fAttributeChecker.returnAttrArray(includeAttrs, currSchemaInfo);
965
// schemaLocation is required on <include> and <redefine>
966
if (schemaHint == null) {
967
reportSchemaError("s4s-att-must-appear", new Object [] {
968
"<include> or <redefine>", "schemaLocation"},
971
// pass the systemId of the current document as the base systemId
972
boolean mustResolve = false;
973
refType = XSDDescription.CONTEXT_INCLUDE;
974
if(localName.equals(SchemaSymbols.ELT_REDEFINE)) {
975
mustResolve = nonAnnotationContent(child);
976
refType = XSDDescription.CONTEXT_REDEFINE;
978
fSchemaGrammarDescription.reset();
979
fSchemaGrammarDescription.setContextType(refType);
980
fSchemaGrammarDescription.setBaseSystemId(doc2SystemId(schemaRoot));
981
fSchemaGrammarDescription.setLocationHints(new String[]{schemaHint});
982
fSchemaGrammarDescription.setTargetNamespace(callerTNS);
983
newSchemaRoot = resolveSchema(fSchemaGrammarDescription, mustResolve, child, true);
984
schemaNamespace = currSchemaInfo.fTargetNamespace;
987
// no more possibility of schema references in well-formed
992
// If the schema is duplicate, we needn't call constructTrees() again.
993
// To handle mutual <include>s
994
XSDocumentInfo newSchemaInfo = null;
995
if (fLastSchemaWasDuplicate) {
996
newSchemaInfo = newSchemaRoot == null ? null : (XSDocumentInfo)fDoc2XSDocumentMap.get(newSchemaRoot);
999
newSchemaInfo = constructTrees(newSchemaRoot, schemaHint, fSchemaGrammarDescription);
1002
if (localName.equals(SchemaSymbols.ELT_REDEFINE) &&
1003
newSchemaInfo != null) {
1004
// must record which schema we're redefining so that we can
1005
// rename the right things later!
1006
fRedefine2XSDMap.put(child, newSchemaInfo);
1008
if (newSchemaRoot != null) {
1009
if (newSchemaInfo != null)
1010
dependencies.addElement(newSchemaInfo);
1011
newSchemaRoot = null;
1015
fDependencyMap.put(currSchemaInfo, dependencies);
1016
return currSchemaInfo;
1017
} // end constructTrees
1019
private boolean isExistingGrammar(XSDDescription desc) {
1020
SchemaGrammar sg = fGrammarBucket.getGrammar(desc.getTargetNamespace());
1022
return findGrammar(desc) != null;
1026
return sg.getDocumentLocations().contains(XMLEntityManager.expandSystemId(desc.getLiteralSystemId(), desc.getBaseSystemId(), false));
1027
} catch (MalformedURIException e) {
1033
// This method builds registries for all globally-referenceable
1034
// names. A registry will be built for each symbol space defined
1035
// by the spec. It is also this method's job to rename redefined
1036
// components, and to record which components redefine others (so
1037
// that implicit redefinitions of groups and attributeGroups can be handled).
1038
protected void buildGlobalNameRegistries() {
1041
// Starting with fRoot, we examine each child of the schema
1042
// element. Skipping all imports and includes, we record the names
1043
// of all other global components (and children of <redefine>). We
1044
// also put <redefine> names in a registry that we look through in
1045
// case something needs renaming. Once we're done with a schema we
1046
// set its Document node to hidden so that we don't try to traverse
1047
// it again; then we look to its Dependency map entry. We keep a
1048
// stack of schemas that we haven't yet finished processing; this
1049
// is a depth-first traversal.
1051
Stack schemasToProcess = new Stack();
1052
schemasToProcess.push(fRoot);
1054
while (!schemasToProcess.empty()) {
1055
XSDocumentInfo currSchemaDoc =
1056
(XSDocumentInfo)schemasToProcess.pop();
1057
Element currDoc = currSchemaDoc.fSchemaElement;
1058
if(DOMUtil.isHidden(currDoc, fHiddenNodes)){
1059
// must have processed this already!
1063
Element currRoot = currDoc;
1064
// process this schema's global decls
1065
boolean dependenciesCanOccur = true;
1066
for (Element globalComp =
1067
DOMUtil.getFirstChildElement(currRoot);
1069
globalComp = DOMUtil.getNextSiblingElement(globalComp)) {
1070
// this loop makes sure the <schema> element ordering is
1072
if (DOMUtil.getLocalName(globalComp).equals(SchemaSymbols.ELT_ANNOTATION)) {
1073
//skip it; traverse it later
1076
else if (DOMUtil.getLocalName(globalComp).equals(SchemaSymbols.ELT_INCLUDE) ||
1077
DOMUtil.getLocalName(globalComp).equals(SchemaSymbols.ELT_IMPORT)) {
1078
if (!dependenciesCanOccur) {
1079
reportSchemaError("s4s-elt-invalid-content.3", new Object [] {DOMUtil.getLocalName(globalComp)}, globalComp);
1081
DOMUtil.setHidden(globalComp, fHiddenNodes);
1083
else if (DOMUtil.getLocalName(globalComp).equals(SchemaSymbols.ELT_REDEFINE)) {
1084
if (!dependenciesCanOccur) {
1085
reportSchemaError("s4s-elt-invalid-content.3", new Object [] {DOMUtil.getLocalName(globalComp)}, globalComp);
1087
for (Element redefineComp = DOMUtil.getFirstChildElement(globalComp);
1088
redefineComp != null;
1089
redefineComp = DOMUtil.getNextSiblingElement(redefineComp)) {
1090
String lName = DOMUtil.getAttrValue(redefineComp, SchemaSymbols.ATT_NAME);
1091
if (lName.length() == 0) // an error we'll catch later
1093
String qName = currSchemaDoc.fTargetNamespace == null ?
1095
currSchemaDoc.fTargetNamespace +","+lName;
1096
String componentType = DOMUtil.getLocalName(redefineComp);
1097
if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) {
1098
checkForDuplicateNames(qName, fUnparsedAttributeGroupRegistry, fUnparsedAttributeGroupRegistrySub, redefineComp, currSchemaDoc);
1099
// the check will have changed our name;
1100
String targetLName = DOMUtil.getAttrValue(redefineComp, SchemaSymbols.ATT_NAME)+REDEF_IDENTIFIER;
1101
// and all we need to do is error-check+rename our kkids:
1102
renameRedefiningComponents(currSchemaDoc, redefineComp, SchemaSymbols.ELT_ATTRIBUTEGROUP,
1103
lName, targetLName);
1105
else if ((componentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) ||
1106
(componentType.equals(SchemaSymbols.ELT_SIMPLETYPE))) {
1107
checkForDuplicateNames(qName, fUnparsedTypeRegistry, fUnparsedTypeRegistrySub, redefineComp, currSchemaDoc);
1108
// the check will have changed our name;
1109
String targetLName = DOMUtil.getAttrValue(redefineComp, SchemaSymbols.ATT_NAME) + REDEF_IDENTIFIER;
1110
// and all we need to do is error-check+rename our kkids:
1111
if (componentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) {
1112
renameRedefiningComponents(currSchemaDoc, redefineComp, SchemaSymbols.ELT_COMPLEXTYPE,
1113
lName, targetLName);
1115
else { // must be simpleType
1116
renameRedefiningComponents(currSchemaDoc, redefineComp, SchemaSymbols.ELT_SIMPLETYPE,
1117
lName, targetLName);
1120
else if (componentType.equals(SchemaSymbols.ELT_GROUP)) {
1121
checkForDuplicateNames(qName, fUnparsedGroupRegistry, fUnparsedGroupRegistrySub, redefineComp, currSchemaDoc);
1122
// the check will have changed our name;
1123
String targetLName = DOMUtil.getAttrValue(redefineComp, SchemaSymbols.ATT_NAME)+REDEF_IDENTIFIER;
1124
// and all we need to do is error-check+rename our kids:
1125
renameRedefiningComponents(currSchemaDoc, redefineComp, SchemaSymbols.ELT_GROUP,
1126
lName, targetLName);
1128
} // end march through <redefine> children
1129
// and now set as traversed
1130
//DOMUtil.setHidden(globalComp);
1133
dependenciesCanOccur = false;
1134
String lName = DOMUtil.getAttrValue(globalComp, SchemaSymbols.ATT_NAME);
1135
if (lName.length() == 0) // an error we'll catch later
1137
String qName = currSchemaDoc.fTargetNamespace == null?
1139
currSchemaDoc.fTargetNamespace +","+lName;
1140
String componentType = DOMUtil.getLocalName(globalComp);
1141
if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTE)) {
1142
checkForDuplicateNames(qName, fUnparsedAttributeRegistry, fUnparsedAttributeRegistrySub, globalComp, currSchemaDoc);
1144
else if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) {
1145
checkForDuplicateNames(qName, fUnparsedAttributeGroupRegistry, fUnparsedAttributeGroupRegistrySub, globalComp, currSchemaDoc);
1147
else if ((componentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) ||
1148
(componentType.equals(SchemaSymbols.ELT_SIMPLETYPE))) {
1149
checkForDuplicateNames(qName, fUnparsedTypeRegistry, fUnparsedTypeRegistrySub, globalComp, currSchemaDoc);
1151
else if (componentType.equals(SchemaSymbols.ELT_ELEMENT)) {
1152
checkForDuplicateNames(qName, fUnparsedElementRegistry, fUnparsedElementRegistrySub, globalComp, currSchemaDoc);
1154
else if (componentType.equals(SchemaSymbols.ELT_GROUP)) {
1155
checkForDuplicateNames(qName, fUnparsedGroupRegistry, fUnparsedGroupRegistrySub, globalComp, currSchemaDoc);
1157
else if (componentType.equals(SchemaSymbols.ELT_NOTATION)) {
1158
checkForDuplicateNames(qName, fUnparsedNotationRegistry, fUnparsedNotationRegistrySub, globalComp, currSchemaDoc);
1163
// now we're done with this one!
1164
DOMUtil.setHidden(currDoc, fHiddenNodes);
1165
// now add the schemas this guy depends on
1166
Vector currSchemaDepends = (Vector)fDependencyMap.get(currSchemaDoc);
1167
for (int i = 0; i < currSchemaDepends.size(); i++) {
1168
schemasToProcess.push(currSchemaDepends.elementAt(i));
1172
} // end buildGlobalNameRegistries
1174
// Beginning at the first schema processing was requested for
1175
// (fRoot), this method
1176
// examines each child (global schema information item) of each
1177
// schema document (and of each <redefine> element)
1178
// corresponding to an XSDocumentInfo object. If the
1179
// readOnly field on that node has not been set, it calls an
1180
// appropriate traverser to traverse it. Once all global decls in
1181
// an XSDocumentInfo object have been traversed, it marks that object
1182
// as traversed (or hidden) in order to avoid infinite loops. It completes
1183
// when it has visited all XSDocumentInfo objects in the
1184
// DependencyMap and marked them as traversed.
1185
protected void traverseSchemas(ArrayList annotationInfo) {
1186
// the process here is very similar to that in
1187
// buildGlobalRegistries, except we can't set our schemas as
1188
// hidden for a second time; so make them all visible again
1190
setSchemasVisible(fRoot);
1191
Stack schemasToProcess = new Stack();
1192
schemasToProcess.push(fRoot);
1193
while (!schemasToProcess.empty()) {
1194
XSDocumentInfo currSchemaDoc =
1195
(XSDocumentInfo)schemasToProcess.pop();
1196
Element currDoc = currSchemaDoc.fSchemaElement;
1198
SchemaGrammar currSG = fGrammarBucket.getGrammar(currSchemaDoc.fTargetNamespace);
1200
if(DOMUtil.isHidden(currDoc, fHiddenNodes)) {
1201
// must have processed this already!
1204
Element currRoot = currDoc;
1205
boolean sawAnnotation = false;
1206
// traverse this schema's global decls
1207
for (Element globalComp =
1208
DOMUtil.getFirstVisibleChildElement(currRoot, fHiddenNodes);
1210
globalComp = DOMUtil.getNextVisibleSiblingElement(globalComp, fHiddenNodes)) {
1211
DOMUtil.setHidden(globalComp, fHiddenNodes);
1212
String componentType = DOMUtil.getLocalName(globalComp);
1213
// includes and imports will not show up here!
1214
if (DOMUtil.getLocalName(globalComp).equals(SchemaSymbols.ELT_REDEFINE)) {
1215
// use the namespace decls for the redefine, instead of for the parent <schema>
1216
currSchemaDoc.backupNSSupport((SchemaNamespaceSupport)fRedefine2NSSupport.get(globalComp));
1217
for (Element redefinedComp = DOMUtil.getFirstVisibleChildElement(globalComp, fHiddenNodes);
1218
redefinedComp != null;
1219
redefinedComp = DOMUtil.getNextVisibleSiblingElement(redefinedComp, fHiddenNodes)) {
1220
String redefinedComponentType = DOMUtil.getLocalName(redefinedComp);
1221
DOMUtil.setHidden(redefinedComp, fHiddenNodes);
1222
if (redefinedComponentType.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) {
1223
fAttributeGroupTraverser.traverseGlobal(redefinedComp, currSchemaDoc, currSG);
1225
else if (redefinedComponentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) {
1226
fComplexTypeTraverser.traverseGlobal(redefinedComp, currSchemaDoc, currSG);
1228
else if (redefinedComponentType.equals(SchemaSymbols.ELT_GROUP)) {
1229
fGroupTraverser.traverseGlobal(redefinedComp, currSchemaDoc, currSG);
1231
else if (redefinedComponentType.equals(SchemaSymbols.ELT_SIMPLETYPE)) {
1232
fSimpleTypeTraverser.traverseGlobal(redefinedComp, currSchemaDoc, currSG);
1234
// annotations will have been processed already; this is now
1236
//else if (redefinedComponentType.equals(SchemaSymbols.ELT_ANNOTATION)) {
1237
// fElementTraverser.traverseAnnotationDecl(redefinedComp, null, true, currSchemaDoc);
1240
reportSchemaError("s4s-elt-must-match.1", new Object [] {DOMUtil.getLocalName(globalComp), "(annotation | (simpleType | complexType | group | attributeGroup))*", redefinedComponentType}, redefinedComp);
1242
} // end march through <redefine> children
1243
currSchemaDoc.restoreNSSupport();
1245
else if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTE)) {
1246
fAttributeTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG);
1248
else if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) {
1249
fAttributeGroupTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG);
1251
else if (componentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) {
1252
fComplexTypeTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG);
1254
else if (componentType.equals(SchemaSymbols.ELT_ELEMENT)) {
1255
fElementTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG);
1257
else if (componentType.equals(SchemaSymbols.ELT_GROUP)) {
1258
fGroupTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG);
1260
else if (componentType.equals(SchemaSymbols.ELT_NOTATION)) {
1261
fNotationTraverser.traverse(globalComp, currSchemaDoc, currSG);
1263
else if (componentType.equals(SchemaSymbols.ELT_SIMPLETYPE)) {
1264
fSimpleTypeTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG);
1266
else if (componentType.equals(SchemaSymbols.ELT_ANNOTATION)) {
1267
currSG.addAnnotation(fElementTraverser.traverseAnnotationDecl(globalComp, currSchemaDoc.getSchemaAttrs(), true, currSchemaDoc));
1268
sawAnnotation = true;
1271
reportSchemaError("s4s-elt-invalid-content.1", new Object [] {SchemaSymbols.ELT_SCHEMA, DOMUtil.getLocalName(globalComp)}, globalComp);
1275
if (!sawAnnotation) {
1276
String text = DOMUtil.getSyntheticAnnotation(currRoot);
1278
currSG.addAnnotation(fElementTraverser.traverseSyntheticAnnotation(currRoot, text, currSchemaDoc.getSchemaAttrs(), true, currSchemaDoc));
1282
/** Collect annotation information for validation. **/
1283
if (annotationInfo != null) {
1284
XSAnnotationInfo info = currSchemaDoc.getAnnotations();
1285
/** Only add annotations to the list if there were any in this document. **/
1287
annotationInfo.add(doc2SystemId(currDoc));
1288
annotationInfo.add(info);
1291
// now we're done with this one!
1292
currSchemaDoc.returnSchemaAttrs();
1293
DOMUtil.setHidden(currDoc, fHiddenNodes);
1295
// now add the schemas this guy depends on
1296
Vector currSchemaDepends = (Vector)fDependencyMap.get(currSchemaDoc);
1297
for (int i = 0; i < currSchemaDepends.size(); i++) {
1298
schemasToProcess.push(currSchemaDepends.elementAt(i));
1301
} // end traverseSchemas
1303
// store whether we have reported an error about that no grammar
1304
// is found for the given namespace uri
1305
private Vector fReportedTNS = null;
1306
// check whether we need to report an error against the given uri.
1307
// if we have reported an error, then we don't need to report again;
1308
// otherwise we reported the error, and remember this fact.
1309
private final boolean needReportTNSError(String uri) {
1310
if (fReportedTNS == null)
1311
fReportedTNS = new Vector();
1312
else if (fReportedTNS.contains(uri))
1314
fReportedTNS.addElement(uri);
1318
private static final String[] COMP_TYPE = {
1320
"attribute declaration",
1322
"element declaration",
1324
"identity constraint",
1329
private static final String[] CIRCULAR_CODES = {
1332
"src-attribute_group.3",
1333
"e-props-correct.6",
1334
"mg-props-correct.2",
1337
"st-props-correct.2", //or ct-props-correct.3
1340
// since it is forbidden for traversers to talk to each other
1341
// directly (except wen a traverser encounters a local declaration),
1342
// this provides a generic means for a traverser to call
1343
// for the traversal of some declaration. An XSDocumentInfo is
1344
// required because the XSDocumentInfo that the traverser is traversing
1345
// may bear no relation to the one the handler is operating on.
1346
// This method will:
1347
// 1. See if a global definition matching declToTraverse exists;
1348
// 2. if so, determine if there is a path from currSchema to the
1349
// schema document where declToTraverse lives (i.e., do a lookup
1350
// in DependencyMap);
1351
// 3. depending on declType (which will be relevant to step 1 as
1352
// well), call the appropriate traverser with the appropriate
1353
// XSDocumentInfo object.
1354
// This method returns whatever the traverser it called returned;
1355
// this will be an Object of some kind
1356
// that lives in the Grammar.
1357
protected Object getGlobalDecl(XSDocumentInfo currSchema,
1359
QName declToTraverse,
1362
if (DEBUG_NODE_POOL) {
1363
System.out.println("TRAVERSE_GL: "+declToTraverse.toString());
1365
// from the schema spec, all built-in types are present in all schemas,
1366
// so if the requested component is a type, and could be found in the
1367
// default schema grammar, we should return that type.
1368
// otherwise (since we would support user-defined schema grammar) we'll
1369
// use the normal way to get the decl
1370
if (declToTraverse.uri != null &&
1371
declToTraverse.uri == SchemaSymbols.URI_SCHEMAFORSCHEMA) {
1372
if (declType == TYPEDECL_TYPE) {
1373
Object retObj = SchemaGrammar.SG_SchemaNS.getGlobalTypeDecl(declToTraverse.localpart);
1379
// now check whether this document can access the requsted namespace
1380
if (!currSchema.isAllowedNS(declToTraverse.uri)) {
1381
// cannot get to this schema from the one containing the requesting decl
1382
if (currSchema.needReportTNSError(declToTraverse.uri)) {
1383
String code = declToTraverse.uri == null ? "src-resolve.4.1" : "src-resolve.4.2";
1384
reportSchemaError(code, new Object[]{fDoc2SystemId.get(currSchema.fSchemaElement), declToTraverse.uri, declToTraverse.rawname}, elmNode);
1389
// check whether there is grammar for the requested namespace
1390
SchemaGrammar sGrammar = fGrammarBucket.getGrammar(declToTraverse.uri);
1391
if (sGrammar == null) {
1392
if (needReportTNSError(declToTraverse.uri))
1393
reportSchemaError("src-resolve", new Object[]{declToTraverse.rawname, COMP_TYPE[declType]}, elmNode);
1397
// if there is such grammar, check whether the requested component is in the grammar
1398
Object retObj = null;
1400
case ATTRIBUTE_TYPE :
1401
retObj = sGrammar.getGlobalAttributeDecl(declToTraverse.localpart);
1403
case ATTRIBUTEGROUP_TYPE :
1404
retObj = sGrammar.getGlobalAttributeGroupDecl(declToTraverse.localpart);
1407
retObj = sGrammar.getGlobalElementDecl(declToTraverse.localpart);
1410
retObj = sGrammar.getGlobalGroupDecl(declToTraverse.localpart);
1412
case IDENTITYCONSTRAINT_TYPE :
1413
retObj = sGrammar.getIDConstraintDecl(declToTraverse.localpart);
1415
case NOTATION_TYPE :
1416
retObj = sGrammar.getGlobalNotationDecl(declToTraverse.localpart);
1418
case TYPEDECL_TYPE :
1419
retObj = sGrammar.getGlobalTypeDecl(declToTraverse.localpart);
1423
// if the component is parsed, return it
1427
XSDocumentInfo schemaWithDecl = null;
1428
Element decl = null;
1429
XSDocumentInfo declDoc = null;
1431
// the component is not parsed, try to find a DOM element for it
1432
String declKey = declToTraverse.uri == null? ","+declToTraverse.localpart:
1433
declToTraverse.uri+","+declToTraverse.localpart;
1435
case ATTRIBUTE_TYPE :
1436
decl = (Element)fUnparsedAttributeRegistry.get(declKey);
1437
declDoc = (XSDocumentInfo)fUnparsedAttributeRegistrySub.get(declKey);
1439
case ATTRIBUTEGROUP_TYPE :
1440
decl = (Element)fUnparsedAttributeGroupRegistry.get(declKey);
1441
declDoc = (XSDocumentInfo)fUnparsedAttributeGroupRegistrySub.get(declKey);
1444
decl = (Element)fUnparsedElementRegistry.get(declKey);
1445
declDoc = (XSDocumentInfo)fUnparsedElementRegistrySub.get(declKey);
1448
decl = (Element)fUnparsedGroupRegistry.get(declKey);
1449
declDoc = (XSDocumentInfo)fUnparsedGroupRegistrySub.get(declKey);
1451
case IDENTITYCONSTRAINT_TYPE :
1452
decl = (Element)fUnparsedIdentityConstraintRegistry.get(declKey);
1453
declDoc = (XSDocumentInfo)fUnparsedIdentityConstraintRegistrySub.get(declKey);
1455
case NOTATION_TYPE :
1456
decl = (Element)fUnparsedNotationRegistry.get(declKey);
1457
declDoc = (XSDocumentInfo)fUnparsedNotationRegistrySub.get(declKey);
1459
case TYPEDECL_TYPE :
1460
decl = (Element)fUnparsedTypeRegistry.get(declKey);
1461
declDoc = (XSDocumentInfo)fUnparsedTypeRegistrySub.get(declKey);
1464
reportSchemaError("Internal-Error", new Object [] {"XSDHandler asked to locate component of type " + declType + "; it does not recognize this type!"}, elmNode);
1467
// no DOM element found, so the component can't be located
1469
reportSchemaError("src-resolve", new Object[]{declToTraverse.rawname, COMP_TYPE[declType]}, elmNode);
1473
// get the schema doc containing the component to be parsed
1474
// it should always return non-null value, but since null-checking
1475
// comes for free, let's be safe and check again
1476
schemaWithDecl = findXSDocumentForDecl(currSchema, decl, declDoc);
1477
if (schemaWithDecl == null) {
1478
// cannot get to this schema from the one containing the requesting decl
1479
String code = declToTraverse.uri == null ? "src-resolve.4.1" : "src-resolve.4.2";
1480
reportSchemaError(code, new Object[]{fDoc2SystemId.get(currSchema.fSchemaElement), declToTraverse.uri, declToTraverse.rawname}, elmNode);
1483
// a component is hidden, meaning either it's traversed, or being traversed.
1484
// but we didn't find it in the grammar, so it's the latter case, and
1485
// a circular reference. error!
1486
if (DOMUtil.isHidden(decl, fHiddenNodes)) {
1487
String code = CIRCULAR_CODES[declType];
1488
if (declType == TYPEDECL_TYPE) {
1489
if (SchemaSymbols.ELT_COMPLEXTYPE.equals(DOMUtil.getLocalName(decl)))
1490
code = "ct-props-correct.3";
1492
// decl must not be null if we're here...
1493
reportSchemaError(code, new Object [] {declToTraverse.prefix+":"+declToTraverse.localpart}, elmNode);
1497
DOMUtil.setHidden(decl, fHiddenNodes);
1498
SchemaNamespaceSupport nsSupport = null;
1499
// if the parent is <redefine> use the namespace delcs for it.
1500
Element parent = DOMUtil.getParent(decl);
1501
if (DOMUtil.getLocalName(parent).equals(SchemaSymbols.ELT_REDEFINE))
1502
nsSupport = (SchemaNamespaceSupport)fRedefine2NSSupport.get(parent);
1503
// back up the current SchemaNamespaceSupport, because we need to provide
1504
// a fresh one to the traverseGlobal methods.
1505
schemaWithDecl.backupNSSupport(nsSupport);
1507
// traverse the referenced global component
1509
case ATTRIBUTE_TYPE :
1510
retObj = fAttributeTraverser.traverseGlobal(decl, schemaWithDecl, sGrammar);
1512
case ATTRIBUTEGROUP_TYPE :
1513
retObj = fAttributeGroupTraverser.traverseGlobal(decl, schemaWithDecl, sGrammar);
1516
retObj = fElementTraverser.traverseGlobal(decl, schemaWithDecl, sGrammar);
1519
retObj = fGroupTraverser.traverseGlobal(decl, schemaWithDecl, sGrammar);
1521
case IDENTITYCONSTRAINT_TYPE :
1522
// identity constraints should have been parsed already...
1523
// we should never get here
1526
case NOTATION_TYPE :
1527
retObj = fNotationTraverser.traverse(decl, schemaWithDecl, sGrammar);
1529
case TYPEDECL_TYPE :
1530
if (DOMUtil.getLocalName(decl).equals(SchemaSymbols.ELT_COMPLEXTYPE))
1531
retObj = fComplexTypeTraverser.traverseGlobal(decl, schemaWithDecl, sGrammar);
1533
retObj = fSimpleTypeTraverser.traverseGlobal(decl, schemaWithDecl, sGrammar);
1536
// restore the previous SchemaNamespaceSupport, so that the caller can get
1537
// proper namespace binding.
1538
schemaWithDecl.restoreNSSupport();
1541
} // getGlobalDecl(XSDocumentInfo, int, QName): Object
1543
// This method determines whether there is a group
1544
// (attributeGroup) which the given one has redefined by
1545
// restriction. If so, it returns it; else it returns null.
1546
// @param type: whether what's been redefined is an
1547
// attributeGroup or a group;
1548
// @param name: the QName of the component doing the redefining.
1549
// @param currSchema: schema doc in which the redefining component lives.
1550
// @return: Object representing decl redefined if present, null
1552
Object getGrpOrAttrGrpRedefinedByRestriction(int type, QName name, XSDocumentInfo currSchema, Element elmNode) {
1553
String realName = name.uri != null?name.uri+","+name.localpart:
1555
String nameToFind = null;
1557
case ATTRIBUTEGROUP_TYPE:
1558
nameToFind = (String)fRedefinedRestrictedAttributeGroupRegistry.get(realName);
1561
nameToFind = (String)fRedefinedRestrictedGroupRegistry.get(realName);
1566
if (nameToFind == null) return null;
1567
int commaPos = nameToFind.indexOf(",");
1568
QName qNameToFind = new QName(XMLSymbols.EMPTY_STRING, nameToFind.substring(commaPos+1),
1569
nameToFind.substring(commaPos), (commaPos == 0)? null : nameToFind.substring(0, commaPos));
1570
Object retObj = getGlobalDecl(currSchema, type, qNameToFind, elmNode);
1571
if(retObj == null) {
1573
case ATTRIBUTEGROUP_TYPE:
1574
reportSchemaError("src-redefine.7.2.1", new Object []{name.localpart}, elmNode);
1577
reportSchemaError("src-redefine.6.2.1", new Object []{name.localpart}, elmNode);
1583
} // getGrpOrAttrGrpRedefinedByRestriction(int, QName, XSDocumentInfo): Object
1585
// Since ID constraints can occur in local elements, unless we
1586
// wish to completely traverse all our DOM trees looking for ID
1587
// constraints while we're building our global name registries,
1588
// which seems terribly inefficient, we need to resolve keyrefs
1589
// after all parsing is complete. This we can simply do by running through
1590
// fIdentityConstraintRegistry and calling traverseKeyRef on all
1591
// of the KeyRef nodes. This unfortunately removes this knowledge
1592
// from the elementTraverser class (which must ignore keyrefs),
1593
// but there seems to be no efficient way around this...
1594
protected void resolveKeyRefs() {
1595
for (int i=0; i<fKeyrefStackPos; i++) {
1596
XSDocumentInfo keyrefSchemaDoc = fKeyrefsMapXSDocumentInfo[i];
1597
keyrefSchemaDoc.fNamespaceSupport.makeGlobal();
1598
keyrefSchemaDoc.fNamespaceSupport.setEffectiveContext( fKeyrefNamespaceContext[i] );
1599
SchemaGrammar keyrefGrammar = fGrammarBucket.getGrammar(keyrefSchemaDoc.fTargetNamespace);
1600
// need to set <keyref> to hidden before traversing it,
1601
// because it has global scope
1602
DOMUtil.setHidden(fKeyrefs[i], fHiddenNodes);
1603
fKeyrefTraverser.traverse(fKeyrefs[i], fKeyrefElems[i], keyrefSchemaDoc, keyrefGrammar);
1605
} // end resolveKeyRefs
1607
// an accessor method. Just makes sure callers
1608
// who want the Identity constraint registry vaguely know what they're about.
1609
protected Hashtable getIDRegistry() {
1610
return fUnparsedIdentityConstraintRegistry;
1612
// an accessor method.
1613
protected Hashtable getIDRegistry_sub() {
1614
return fUnparsedIdentityConstraintRegistrySub;
1619
// This method squirrels away <keyref> declarations--along with the element
1620
// decls and namespace bindings they might find handy.
1621
protected void storeKeyRef (Element keyrefToStore, XSDocumentInfo schemaDoc,
1622
XSElementDecl currElemDecl) {
1623
String keyrefName = DOMUtil.getAttrValue(keyrefToStore, SchemaSymbols.ATT_NAME);
1624
if (keyrefName.length() != 0) {
1625
String keyrefQName = schemaDoc.fTargetNamespace == null?
1626
"," + keyrefName: schemaDoc.fTargetNamespace+","+keyrefName;
1627
checkForDuplicateNames(keyrefQName, fUnparsedIdentityConstraintRegistry, fUnparsedIdentityConstraintRegistrySub, keyrefToStore, schemaDoc);
1629
// now set up all the registries we'll need...
1631
// check array sizes
1632
if (fKeyrefStackPos == fKeyrefs.length) {
1633
Element [] elemArray = new Element [fKeyrefStackPos + INC_KEYREF_STACK_AMOUNT];
1634
System.arraycopy(fKeyrefs, 0, elemArray, 0, fKeyrefStackPos);
1635
fKeyrefs = elemArray;
1636
XSElementDecl [] declArray = new XSElementDecl [fKeyrefStackPos + INC_KEYREF_STACK_AMOUNT];
1637
System.arraycopy(fKeyrefElems, 0, declArray, 0, fKeyrefStackPos);
1638
fKeyrefElems = declArray;
1639
String[][] stringArray = new String [fKeyrefStackPos + INC_KEYREF_STACK_AMOUNT][];
1640
System.arraycopy(fKeyrefNamespaceContext, 0, stringArray, 0, fKeyrefStackPos);
1641
fKeyrefNamespaceContext = stringArray;
1643
XSDocumentInfo [] xsDocumentInfo = new XSDocumentInfo [fKeyrefStackPos + INC_KEYREF_STACK_AMOUNT];
1644
System.arraycopy(fKeyrefsMapXSDocumentInfo, 0, xsDocumentInfo, 0, fKeyrefStackPos);
1645
fKeyrefsMapXSDocumentInfo = xsDocumentInfo;
1648
fKeyrefs[fKeyrefStackPos] = keyrefToStore;
1649
fKeyrefElems[fKeyrefStackPos] = currElemDecl;
1650
fKeyrefNamespaceContext[fKeyrefStackPos] = schemaDoc.fNamespaceSupport.getEffectiveLocalContext();
1652
fKeyrefsMapXSDocumentInfo[fKeyrefStackPos++] = schemaDoc;
1653
} // storeKeyref (Element, XSDocumentInfo, XSElementDecl): void
1657
* resolveSchema method is responsible for resolving location of the schema (using XMLEntityResolver),
1658
* and if it was succefully resolved getting the schema Document.
1660
* @param mustResolve
1661
* @param referElement
1662
* @return A schema Element or null.
1664
private Element resolveSchema(XSDDescription desc, boolean mustResolve,
1665
Element referElement, boolean usePairs) {
1666
XMLInputSource schemaSource = null;
1668
Hashtable pairs = usePairs ? fLocationPairs : EMPTY_TABLE;
1669
schemaSource = XMLSchemaLoader.resolveDocument(desc, pairs, fEntityResolver);
1671
catch (IOException ex) {
1673
reportSchemaError("schema_reference.4",
1674
new Object[]{desc.getLocationHints()[0]},
1678
reportSchemaWarning("schema_reference.4",
1679
new Object[]{desc.getLocationHints()[0]},
1683
if (schemaSource instanceof DOMInputSource) {
1684
fHiddenNodes.clear();
1685
Node node = ((DOMInputSource)schemaSource).getNode();
1687
if (node instanceof Document) {
1688
return DOMUtil.getRoot((Document) node);
1690
else if (node instanceof Element) {
1691
return (Element) node;
1697
else if (schemaSource instanceof SAXInputSource) {
1698
XMLReader parser = ((SAXInputSource)schemaSource).getXMLReader();
1699
InputSource inputSource = ((SAXInputSource)schemaSource).getInputSource();
1700
boolean namespacePrefixes = false;
1701
if (parser != null) {
1703
namespacePrefixes = parser.getFeature(NAMESPACE_PREFIXES);
1705
catch (SAXException se) {}
1709
parser = XMLReaderFactory.createXMLReader();
1711
// If something went wrong with the factory
1712
// just use our own SAX parser.
1713
catch (SAXException se) {
1714
parser = new SAXParser();
1717
parser.setFeature(NAMESPACE_PREFIXES, true);
1718
namespacePrefixes = true;
1720
catch (SAXException se) {}
1722
// If XML names and Namespace URIs are already internalized we
1723
// can avoid running them through the SymbolTable.
1724
boolean stringsInternalized = false;
1726
stringsInternalized = parser.getFeature(STRING_INTERNING);
1728
catch (SAXException exc) {
1729
// The feature isn't recognized or getting it is not supported.
1730
// In either case, assume that strings are not internalized.
1732
if (fXSContentHandler == null) {
1733
fXSContentHandler = new SchemaContentHandler();
1735
fXSContentHandler.reset(fSchemaParser, fSymbolTable,
1736
namespacePrefixes, stringsInternalized);
1737
parser.setContentHandler(fXSContentHandler);
1738
parser.setErrorHandler(fErrorReporter.getSAXErrorHandler());
1740
parser.parse(inputSource);
1742
catch (SAXException se) {
1745
catch (IOException ioe) {
1748
Document root = fXSContentHandler.getDocument();
1750
// something went wrong right off the hop
1753
return DOMUtil.getRoot(root);
1755
return getSchemaDocument(desc.getTargetNamespace(), schemaSource, mustResolve, desc.getContextType(), referElement);
1756
} // getSchema(String, String, String, boolean, short): Document
1759
* getSchemaDocument method uses XMLInputSource to parse a schema document.
1760
* @param schemaNamespace
1761
* @param schemaSource
1762
* @param mustResolve
1764
* @param referElement
1765
* @return A schema Element.
1767
private Element getSchemaDocument(String schemaNamespace, XMLInputSource schemaSource,
1768
boolean mustResolve, short referType, Element referElement) {
1770
boolean hasInput = true;
1771
// contents of this method will depend on the system we adopt for entity resolution--i.e., XMLEntityHandler, EntityHandler, etc.
1772
Element schemaElement = null;
1774
// when the system id and byte stream and character stream
1775
// of the input source are all null, it's
1776
// impossible to find the schema document. so we skip in
1777
// this case. otherwise we'll receive some NPE or
1778
// file not found errors. but schemaHint=="" is perfectly
1779
// legal for import.
1780
if (schemaSource != null &&
1781
(schemaSource.getSystemId() != null ||
1782
schemaSource.getByteStream() != null ||
1783
schemaSource.getCharacterStream() != null)) {
1785
// When the system id of the input source is used, first try to
1786
// expand it, and check whether the same document has been
1787
// parsed before. If so, return the document corresponding to
1790
String schemaId = null;
1791
if (referType != XSDDescription.CONTEXT_PREPARSE){
1792
schemaId = XMLEntityManager.expandSystemId(schemaSource.getSystemId(), schemaSource.getBaseSystemId(), false);
1793
key = new XSDKey(schemaId, referType, schemaNamespace);
1794
if((schemaElement = (Element)fTraversed.get(key)) != null) {
1795
fLastSchemaWasDuplicate = true;
1796
return schemaElement;
1800
fSchemaParser.parse(schemaSource);
1801
schemaElement = fSchemaParser.getDocument2() == null ? null: DOMUtil.getRoot(fSchemaParser.getDocument2());
1803
// now we need to store the mapping information from system id
1804
// to the document. also from the document to the system id.
1806
fTraversed.put(key, schemaElement );
1807
if (schemaId != null)
1808
fDoc2SystemId.put(schemaElement, schemaId );
1809
fLastSchemaWasDuplicate = false;
1810
return schemaElement;
1816
catch (IOException ex) {
1819
// either an error occured (exception), or empty input source was
1820
// returned, we need to report an error or a warning
1823
reportSchemaError("schema_reference.4",
1824
new Object[]{schemaSource.getSystemId()},
1828
reportSchemaError("schema_reference.4",
1829
new Object[]{schemaSource == null ? "" : schemaSource.getSystemId()},
1833
else if (hasInput) {
1834
reportSchemaWarning("schema_reference.4",
1835
new Object[]{schemaSource.getSystemId()},
1839
fLastSchemaWasDuplicate = false;
1841
} // getSchema(String, XMLInputSource, boolean, boolean): Document
1843
// initialize all the traversers.
1844
// this should only need to be called once during the construction
1845
// of this object; it creates the traversers that will be used to
1847
// construct schemaGrammars.
1848
private void createTraversers() {
1849
fAttributeChecker = new XSAttributeChecker(this);
1850
fAttributeGroupTraverser = new XSDAttributeGroupTraverser(this, fAttributeChecker);
1851
fAttributeTraverser = new XSDAttributeTraverser(this, fAttributeChecker);
1852
fComplexTypeTraverser = new XSDComplexTypeTraverser(this, fAttributeChecker);
1853
fElementTraverser = new XSDElementTraverser(this, fAttributeChecker);
1854
fGroupTraverser = new XSDGroupTraverser(this, fAttributeChecker);
1855
fKeyrefTraverser = new XSDKeyrefTraverser(this, fAttributeChecker);
1856
fNotationTraverser = new XSDNotationTraverser(this, fAttributeChecker);
1857
fSimpleTypeTraverser = new XSDSimpleTypeTraverser(this, fAttributeChecker);
1858
fUniqueOrKeyTraverser = new XSDUniqueOrKeyTraverser(this, fAttributeChecker);
1859
fWildCardTraverser = new XSDWildcardTraverser(this, fAttributeChecker);
1860
} // createTraversers()
1862
// before parsing a schema, need to clear registries associated with
1864
void prepareForParse() {
1866
fDoc2SystemId.clear();
1867
fHiddenNodes.clear();
1868
fLastSchemaWasDuplicate = false;
1871
// before traversing a schema's parse tree, need to reset all traversers and
1872
// clear all registries
1873
void prepareForTraverse() {
1874
fUnparsedAttributeRegistry.clear();
1875
fUnparsedAttributeGroupRegistry.clear();
1876
fUnparsedElementRegistry.clear();
1877
fUnparsedGroupRegistry.clear();
1878
fUnparsedIdentityConstraintRegistry.clear();
1879
fUnparsedNotationRegistry.clear();
1880
fUnparsedTypeRegistry.clear();
1882
fUnparsedAttributeRegistrySub.clear();
1883
fUnparsedAttributeGroupRegistrySub.clear();
1884
fUnparsedElementRegistrySub.clear();
1885
fUnparsedGroupRegistrySub.clear();
1886
fUnparsedIdentityConstraintRegistrySub.clear();
1887
fUnparsedNotationRegistrySub.clear();
1888
fUnparsedTypeRegistrySub.clear();
1890
fXSDocumentInfoRegistry.clear();
1891
fDependencyMap.clear();
1892
fDoc2XSDocumentMap.clear();
1893
fRedefine2XSDMap.clear();
1894
fRedefine2NSSupport.clear();
1895
fAllTNSs.removeAllElements();
1899
// clear local element stack
1900
for (int i = 0; i < fLocalElemStackPos; i++) {
1901
fParticle[i] = null;
1902
fLocalElementDecl[i] = null;
1903
fLocalElementDecl_schema[i] = null;
1904
fLocalElemNamespaceContext[i] = null;
1906
fLocalElemStackPos = 0;
1908
// and do same for keyrefs.
1909
for (int i = 0; i < fKeyrefStackPos; i++) {
1911
fKeyrefElems[i] = null;
1912
fKeyrefNamespaceContext[i] = null;
1913
fKeyrefsMapXSDocumentInfo[i] = null;
1915
fKeyrefStackPos = 0;
1917
// create traversers if necessary
1918
if (fAttributeChecker == null) {
1923
fAttributeChecker.reset(fSymbolTable);
1924
fAttributeGroupTraverser.reset(fSymbolTable, fValidateAnnotations);
1925
fAttributeTraverser.reset(fSymbolTable, fValidateAnnotations);
1926
fComplexTypeTraverser.reset(fSymbolTable, fValidateAnnotations);
1927
fElementTraverser.reset(fSymbolTable, fValidateAnnotations);
1928
fGroupTraverser.reset(fSymbolTable, fValidateAnnotations);
1929
fKeyrefTraverser.reset(fSymbolTable, fValidateAnnotations);
1930
fNotationTraverser.reset(fSymbolTable, fValidateAnnotations);
1931
fSimpleTypeTraverser.reset(fSymbolTable, fValidateAnnotations);
1932
fUniqueOrKeyTraverser.reset(fSymbolTable, fValidateAnnotations);
1933
fWildCardTraverser.reset(fSymbolTable, fValidateAnnotations);
1935
fRedefinedRestrictedAttributeGroupRegistry.clear();
1936
fRedefinedRestrictedGroupRegistry.clear();
1938
public void setDeclPool (XSDeclarationPool declPool){
1939
fDeclPool = declPool;
1942
public void reset(XMLComponentManager componentManager) {
1945
fSymbolTable = (SymbolTable) componentManager.getProperty(SYMBOL_TABLE);
1947
//set entity resolver
1948
fEntityResolver = (XMLEntityResolver) componentManager.getProperty(ENTITY_MANAGER);
1949
XMLEntityResolver er = (XMLEntityResolver)componentManager.getProperty(ENTITY_RESOLVER);
1951
fSchemaParser.setEntityResolver(er);
1953
// set error reporter
1955
(XMLErrorReporter) componentManager.getProperty(ERROR_REPORTER);
1957
XMLErrorHandler currErrorHandler = fErrorReporter.getErrorHandler();
1958
// Setting a parser property can be much more expensive
1959
// than checking its value. Don't set the ERROR_HANDLER
1960
// property unless it's actually changed.
1961
if (currErrorHandler != fSchemaParser.getProperty(ERROR_HANDLER)) {
1962
fSchemaParser.setProperty(ERROR_HANDLER, (currErrorHandler != null) ? currErrorHandler : new DefaultErrorHandler());
1963
if (fAnnotationValidator != null) {
1964
fAnnotationValidator.setProperty(ERROR_HANDLER, (currErrorHandler != null) ? currErrorHandler : new DefaultErrorHandler());
1967
} catch (XMLConfigurationException e) {
1971
fValidateAnnotations = componentManager.getFeature(VALIDATE_ANNOTATIONS);
1972
} catch (XMLConfigurationException e) {
1973
fValidateAnnotations = false;
1977
fHonourAllSchemaLocations = componentManager.getFeature(HONOUR_ALL_SCHEMALOCATIONS);
1978
} catch (XMLConfigurationException e) {
1979
fHonourAllSchemaLocations = false;
1983
fSchemaParser.setFeature(
1984
CONTINUE_AFTER_FATAL_ERROR,
1985
fErrorReporter.getFeature(CONTINUE_AFTER_FATAL_ERROR));
1986
} catch (XMLConfigurationException e) {
1990
fSchemaParser.setFeature(
1991
ALLOW_JAVA_ENCODINGS,
1992
componentManager.getFeature(ALLOW_JAVA_ENCODINGS));
1993
} catch (XMLConfigurationException e) {
1996
fSchemaParser.setFeature(
1997
STANDARD_URI_CONFORMANT_FEATURE,
1998
componentManager.getFeature(STANDARD_URI_CONFORMANT_FEATURE));
1999
} catch (XMLConfigurationException e) {
2004
(XMLGrammarPool) componentManager.getProperty(XMLGRAMMAR_POOL);
2005
} catch (XMLConfigurationException e) {
2006
fGrammarPool = null;
2008
// security features
2010
fSchemaParser.setFeature( DISALLOW_DOCTYPE,
2011
componentManager.getFeature(DISALLOW_DOCTYPE));
2012
} catch (XMLConfigurationException e) {
2015
Object security = componentManager.getProperty(SECURITY_MANAGER);
2016
if (security != null){
2017
fSchemaParser.setProperty(SECURITY_MANAGER, security);
2019
} catch (XMLConfigurationException e) {
2022
} // reset(XMLComponentManager)
2026
* Traverse all the deferred local elements. This method should be called
2027
* by traverseSchemas after we've done with all the global declarations.
2029
void traverseLocalElements() {
2030
fElementTraverser.fDeferTraversingLocalElements = false;
2032
for (int i = 0; i < fLocalElemStackPos; i++) {
2033
Element currElem = fLocalElementDecl[i];
2034
//XSDocumentInfo currSchema = (XSDocumentInfo)fDoc2XSDocumentMap.get(DOMUtil.getDocument(currElem));
2035
//XSDocumentInfo currSchema = (XSDocumentInfo)fDoc2XSDocumentMap.get(DOMUtil.getRoot(DOMUtil.getDocument(currElem)));
2036
XSDocumentInfo currSchema = fLocalElementDecl_schema[i];
2037
SchemaGrammar currGrammar = fGrammarBucket.getGrammar(currSchema.fTargetNamespace);
2038
fElementTraverser.traverseLocal (fParticle[i], currElem, currSchema, currGrammar, fAllContext[i], fParent[i], fLocalElemNamespaceContext[i]);
2039
// If it's an empty particle, remove it from the containing component.
2040
if (fParticle[i].fType == XSParticleDecl.PARTICLE_EMPTY) {
2041
XSModelGroupImpl group = null;
2042
if (fParent[i] instanceof XSComplexTypeDecl) {
2043
XSParticle p = ((XSComplexTypeDecl)fParent[i]).getParticle();
2045
group = (XSModelGroupImpl)p.getTerm();
2048
group = ((XSGroupDecl)fParent[i]).fModelGroup;
2051
removeParticle(group, fParticle[i]);
2056
private boolean removeParticle(XSModelGroupImpl group, XSParticleDecl particle) {
2057
XSParticleDecl member;
2058
for (int i = 0; i < group.fParticleCount; i++) {
2059
member = group.fParticles[i];
2060
if (member == particle) {
2061
for (int j = i; j < group.fParticleCount-1; j++)
2062
group.fParticles[j] = group.fParticles[j+1];
2063
group.fParticleCount--;
2066
if (member.fType == XSParticleDecl.PARTICLE_MODELGROUP) {
2067
if (removeParticle((XSModelGroupImpl)member.fValue, particle))
2074
// the purpose of this method is to keep up-to-date structures
2075
// we'll need for the feferred traversal of local elements.
2076
void fillInLocalElemInfo(Element elmDecl,
2077
XSDocumentInfo schemaDoc,
2078
int allContextFlags,
2080
XSParticleDecl particle) {
2082
// if the stack is full, increase the size
2083
if (fParticle.length == fLocalElemStackPos) {
2085
XSParticleDecl[] newStackP = new XSParticleDecl[fLocalElemStackPos+INC_STACK_SIZE];
2086
System.arraycopy(fParticle, 0, newStackP, 0, fLocalElemStackPos);
2087
fParticle = newStackP;
2088
Element[] newStackE = new Element[fLocalElemStackPos+INC_STACK_SIZE];
2089
System.arraycopy(fLocalElementDecl, 0, newStackE, 0, fLocalElemStackPos);
2090
fLocalElementDecl = newStackE;
2091
XSDocumentInfo [] newStackE_schema = new XSDocumentInfo[fLocalElemStackPos+INC_STACK_SIZE];
2092
System.arraycopy(fLocalElementDecl_schema, 0, newStackE_schema, 0, fLocalElemStackPos);
2093
fLocalElementDecl_schema = newStackE_schema;
2094
int[] newStackI = new int[fLocalElemStackPos+INC_STACK_SIZE];
2095
System.arraycopy(fAllContext, 0, newStackI, 0, fLocalElemStackPos);
2096
fAllContext = newStackI;
2097
XSObject[] newStackC = new XSObject[fLocalElemStackPos+INC_STACK_SIZE];
2098
System.arraycopy(fParent, 0, newStackC, 0, fLocalElemStackPos);
2099
fParent = newStackC;
2100
String [][] newStackN = new String [fLocalElemStackPos+INC_STACK_SIZE][];
2101
System.arraycopy(fLocalElemNamespaceContext, 0, newStackN, 0, fLocalElemStackPos);
2102
fLocalElemNamespaceContext = newStackN;
2105
fParticle[fLocalElemStackPos] = particle;
2106
fLocalElementDecl[fLocalElemStackPos] = elmDecl;
2107
fLocalElementDecl_schema[fLocalElemStackPos] = schemaDoc;
2108
fAllContext[fLocalElemStackPos] = allContextFlags;
2109
fParent[fLocalElemStackPos] = parent;
2110
fLocalElemNamespaceContext[fLocalElemStackPos++] = schemaDoc.fNamespaceSupport.getEffectiveLocalContext();
2111
} // end fillInLocalElemInfo(...)
2113
/** This method makes sure that
2114
* if this component is being redefined that it lives in the
2115
* right schema. It then renames the component correctly. If it
2116
* detects a collision--a duplicate definition--then it complains.
2117
* Note that redefines must be handled carefully: if there
2118
* is a collision, it may be because we're redefining something we know about
2119
* or because we've found the thing we're redefining.
2121
void checkForDuplicateNames(String qName,
2122
Hashtable registry, Hashtable registry_sub, Element currComp,
2123
XSDocumentInfo currSchema) {
2124
Object objElem = null;
2125
// REVISIT: when we add derivation checking, we'll have to make
2126
// sure that ID constraint collisions don't necessarily result in error messages.
2127
if ((objElem = registry.get(qName)) == null) {
2129
registry.put(qName, currComp);
2130
registry_sub.put(qName, currSchema);
2134
Element collidingElem = (Element)objElem;
2135
XSDocumentInfo collidingElemSchema = (XSDocumentInfo)registry_sub.get(qName);
2136
if (collidingElem == currComp) return;
2137
Element elemParent = null;
2138
XSDocumentInfo redefinedSchema = null;
2139
// case where we've collided with a redefining element
2140
// (the parent of the colliding element is a redefine)
2141
boolean collidedWithRedefine = true;
2142
if ((DOMUtil.getLocalName((elemParent = DOMUtil.getParent(collidingElem))).equals(SchemaSymbols.ELT_REDEFINE))) {
2143
redefinedSchema = (XSDocumentInfo)(fRedefine2XSDMap.get(elemParent));
2144
// case where we're a redefining element.
2146
else if ((DOMUtil.getLocalName(DOMUtil.getParent(currComp)).equals(SchemaSymbols.ELT_REDEFINE))) {
2147
redefinedSchema = collidingElemSchema;
2148
collidedWithRedefine = false;
2150
if (redefinedSchema != null) { //redefinition involved somehow
2151
// If both components belong to the same document then
2152
// report an error and return.
2153
if(collidingElemSchema == currSchema){
2154
reportSchemaError("sch-props-correct.2", new Object[]{qName}, currComp);
2158
String newName = qName.substring(qName.lastIndexOf(',')+1)+REDEF_IDENTIFIER;
2159
if (redefinedSchema == currSchema) { // object comp. okay here
2160
// now have to do some renaming...
2161
currComp.setAttribute(SchemaSymbols.ATT_NAME, newName);
2162
if (currSchema.fTargetNamespace == null){
2163
registry.put(","+newName, currComp);
2164
registry_sub.put(","+newName, currSchema);
2167
registry.put(currSchema.fTargetNamespace+","+newName, currComp);
2168
registry_sub.put(currSchema.fTargetNamespace+","+newName, currSchema);
2170
// and take care of nested redefines by calling recursively:
2171
if (currSchema.fTargetNamespace == null)
2172
checkForDuplicateNames(","+newName, registry, registry_sub, currComp, currSchema);
2174
checkForDuplicateNames(currSchema.fTargetNamespace+","+newName, registry, registry_sub, currComp, currSchema);
2176
else { // we may be redefining the wrong schema
2177
if (collidedWithRedefine) {
2178
if (currSchema.fTargetNamespace == null)
2179
checkForDuplicateNames(","+newName, registry, registry_sub, currComp, currSchema);
2181
checkForDuplicateNames(currSchema.fTargetNamespace+","+newName, registry, registry_sub, currComp, currSchema);
2184
// error that redefined element in wrong schema
2185
reportSchemaError("sch-props-correct.2", new Object [] {qName}, currComp);
2190
// we've just got a flat-out collision
2191
reportSchemaError("sch-props-correct.2", new Object []{qName}, currComp);
2194
} // checkForDuplicateNames(String, Hashtable, Element, XSDocumentInfo):void
2196
// the purpose of this method is to take the component of the
2197
// specified type and rename references to itself so that they
2198
// refer to the object being redefined. It takes special care of
2199
// <group>s and <attributeGroup>s to ensure that information
2200
// relating to implicit restrictions is preserved for those
2202
private void renameRedefiningComponents(XSDocumentInfo currSchema,
2203
Element child, String componentType,
2204
String oldName, String newName) {
2205
if (componentType.equals(SchemaSymbols.ELT_SIMPLETYPE)) {
2206
Element grandKid = DOMUtil.getFirstChildElement(child);
2207
if (grandKid == null) {
2208
reportSchemaError("src-redefine.5.a.a", null, child);
2211
String grandKidName = DOMUtil.getLocalName(grandKid);
2212
if (grandKidName.equals(SchemaSymbols.ELT_ANNOTATION)) {
2213
grandKid = DOMUtil.getNextSiblingElement(grandKid);
2215
if (grandKid == null) {
2216
reportSchemaError("src-redefine.5.a.a", null, child);
2219
grandKidName = DOMUtil.getLocalName(grandKid);
2220
if (!grandKidName.equals(SchemaSymbols.ELT_RESTRICTION)) {
2221
reportSchemaError("src-redefine.5.a.b", new Object[]{grandKidName}, child);
2224
Object[] attrs = fAttributeChecker.checkAttributes(grandKid, false, currSchema);
2225
QName derivedBase = (QName)attrs[XSAttributeChecker.ATTIDX_BASE];
2226
if (derivedBase == null ||
2227
derivedBase.uri != currSchema.fTargetNamespace ||
2228
!derivedBase.localpart.equals(oldName)) {
2229
reportSchemaError("src-redefine.5.a.c",
2230
new Object[]{grandKidName,
2231
(currSchema.fTargetNamespace==null?"":currSchema.fTargetNamespace)
2236
// now we have to do the renaming...
2237
if (derivedBase.prefix != null && derivedBase.prefix.length() > 0)
2238
grandKid.setAttribute( SchemaSymbols.ATT_BASE,
2239
derivedBase.prefix + ":" + newName );
2241
grandKid.setAttribute( SchemaSymbols.ATT_BASE, newName );
2244
fAttributeChecker.returnAttrArray(attrs, currSchema);
2249
else if (componentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) {
2250
Element grandKid = DOMUtil.getFirstChildElement(child);
2251
if (grandKid == null) {
2252
reportSchemaError("src-redefine.5.b.a", null, child);
2255
if (DOMUtil.getLocalName(grandKid).equals(SchemaSymbols.ELT_ANNOTATION)) {
2256
grandKid = DOMUtil.getNextSiblingElement(grandKid);
2258
if (grandKid == null) {
2259
reportSchemaError("src-redefine.5.b.a", null, child);
2262
// have to go one more level down; let another pass worry whether complexType is valid.
2263
Element greatGrandKid = DOMUtil.getFirstChildElement(grandKid);
2264
if (greatGrandKid == null) {
2265
reportSchemaError("src-redefine.5.b.b", null, grandKid);
2268
String greatGrandKidName = DOMUtil.getLocalName(greatGrandKid);
2269
if (greatGrandKidName.equals(SchemaSymbols.ELT_ANNOTATION)) {
2270
greatGrandKid = DOMUtil.getNextSiblingElement(greatGrandKid);
2272
if (greatGrandKid == null) {
2273
reportSchemaError("src-redefine.5.b.b", null, grandKid);
2276
greatGrandKidName = DOMUtil.getLocalName(greatGrandKid);
2277
if (!greatGrandKidName.equals(SchemaSymbols.ELT_RESTRICTION) &&
2278
!greatGrandKidName.equals(SchemaSymbols.ELT_EXTENSION)) {
2279
reportSchemaError("src-redefine.5.b.c", new Object[]{greatGrandKidName}, greatGrandKid);
2282
Object[] attrs = fAttributeChecker.checkAttributes(greatGrandKid, false, currSchema);
2283
QName derivedBase = (QName)attrs[XSAttributeChecker.ATTIDX_BASE];
2284
if (derivedBase == null ||
2285
derivedBase.uri != currSchema.fTargetNamespace ||
2286
!derivedBase.localpart.equals(oldName)) {
2287
reportSchemaError("src-redefine.5.b.d",
2288
new Object[]{greatGrandKidName,
2289
(currSchema.fTargetNamespace==null?"":currSchema.fTargetNamespace)
2294
// now we have to do the renaming...
2295
if (derivedBase.prefix != null && derivedBase.prefix.length() > 0)
2296
greatGrandKid.setAttribute( SchemaSymbols.ATT_BASE,
2297
derivedBase.prefix + ":" + newName );
2299
greatGrandKid.setAttribute( SchemaSymbols.ATT_BASE,
2309
else if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) {
2310
String processedBaseName = (currSchema.fTargetNamespace == null)?
2311
","+oldName:currSchema.fTargetNamespace+","+oldName;
2312
int attGroupRefsCount = changeRedefineGroup(processedBaseName, componentType, newName, child, currSchema);
2313
if (attGroupRefsCount > 1) {
2314
reportSchemaError("src-redefine.7.1", new Object []{new Integer(attGroupRefsCount)}, child);
2316
else if (attGroupRefsCount == 1) {
2320
if (currSchema.fTargetNamespace == null)
2321
fRedefinedRestrictedAttributeGroupRegistry.put(processedBaseName, ","+newName);
2323
fRedefinedRestrictedAttributeGroupRegistry.put(processedBaseName, currSchema.fTargetNamespace+","+newName);
2325
else if (componentType.equals(SchemaSymbols.ELT_GROUP)) {
2326
String processedBaseName = (currSchema.fTargetNamespace == null)?
2327
","+oldName:currSchema.fTargetNamespace+","+oldName;
2328
int groupRefsCount = changeRedefineGroup(processedBaseName, componentType, newName, child, currSchema);
2329
if (groupRefsCount > 1) {
2330
reportSchemaError("src-redefine.6.1.1", new Object []{new Integer(groupRefsCount)}, child);
2332
else if (groupRefsCount == 1) {
2336
if (currSchema.fTargetNamespace == null)
2337
fRedefinedRestrictedGroupRegistry.put(processedBaseName, ","+newName);
2339
fRedefinedRestrictedGroupRegistry.put(processedBaseName, currSchema.fTargetNamespace+","+newName);
2343
reportSchemaError("Internal-Error", new Object [] {"could not handle this particular <redefine>; please submit your schemas and instance document in a bug report!"}, child);
2345
// if we get here then we must have reported an error and failed somewhere...
2347
} // renameRedefiningComponents(XSDocumentInfo, Element, String, String, String):void
2349
// this method takes a name of the form a:b, determines the URI mapped
2350
// to by a in the current SchemaNamespaceSupport object, and returns this
2351
// information in the form (nsURI,b) suitable for lookups in the global
2353
// REVISIT: should have it return QName, instead of String. this would
2354
// save lots of string concatenation time. we can use
2355
// QName#equals() to compare two QNames, and use QName directly
2356
// as a key to the SymbolHash.
2357
// And when the DV's are ready to return compiled values from
2358
// validate() method, we should just call QNameDV.validate()
2360
private String findQName(String name, XSDocumentInfo schemaDoc) {
2361
SchemaNamespaceSupport currNSMap = schemaDoc.fNamespaceSupport;
2362
int colonPtr = name.indexOf(':');
2363
String prefix = XMLSymbols.EMPTY_STRING;
2365
prefix = name.substring(0, colonPtr);
2366
String uri = currNSMap.getURI(fSymbolTable.addSymbol(prefix));
2367
String localpart = (colonPtr == 0)?name:name.substring(colonPtr+1);
2368
if (prefix == XMLSymbols.EMPTY_STRING && uri == null && schemaDoc.fIsChameleonSchema)
2369
uri = schemaDoc.fTargetNamespace;
2371
return ","+localpart;
2372
return uri+","+localpart;
2373
} // findQName(String, XSDocumentInfo): String
2375
// This function looks among the children of curr for an element of type elementSought.
2376
// If it finds one, it evaluates whether its ref attribute contains a reference
2377
// to originalQName. If it does, it returns 1 + the value returned by
2378
// calls to itself on all other children. In all other cases it returns 0 plus
2379
// the sum of the values returned by calls to itself on curr's children.
2380
// It also resets the value of ref so that it will refer to the renamed type from the schema
2382
private int changeRedefineGroup(String originalQName, String elementSought,
2383
String newName, Element curr, XSDocumentInfo schemaDoc) {
2385
for (Element child = DOMUtil.getFirstChildElement(curr);
2386
child != null; child = DOMUtil.getNextSiblingElement(child)) {
2387
String name = DOMUtil.getLocalName(child);
2388
if (!name.equals(elementSought))
2389
result += changeRedefineGroup(originalQName, elementSought, newName, child, schemaDoc);
2391
String ref = child.getAttribute( SchemaSymbols.ATT_REF );
2392
if (ref.length() != 0) {
2393
String processedRef = findQName(ref, schemaDoc);
2394
if (originalQName.equals(processedRef)) {
2395
String prefix = XMLSymbols.EMPTY_STRING;
2396
int colonptr = ref.indexOf(":");
2398
prefix = ref.substring(0,colonptr);
2399
child.setAttribute(SchemaSymbols.ATT_REF, prefix + ":" + newName);
2402
child.setAttribute(SchemaSymbols.ATT_REF, newName);
2404
if (elementSought.equals(SchemaSymbols.ELT_GROUP)) {
2405
String minOccurs = child.getAttribute( SchemaSymbols.ATT_MINOCCURS );
2406
String maxOccurs = child.getAttribute( SchemaSymbols.ATT_MAXOCCURS );
2407
if (!((maxOccurs.length() == 0 || maxOccurs.equals("1"))
2408
&& (minOccurs.length() == 0 || minOccurs.equals("1")))) {
2409
reportSchemaError("src-redefine.6.1.2", new Object [] {ref}, child);
2413
} // if ref was null some other stage of processing will flag the error
2417
} // changeRedefineGroup
2419
// this method returns the XSDocumentInfo object that contains the
2420
// component corresponding to decl. If components from this
2421
// document cannot be referred to from those of currSchema, this
2422
// method returns null; it's up to the caller to throw an error.
2423
// @param: currSchema: the XSDocumentInfo object containing the
2425
// @param: decl: the declaration being ref'd.
2426
// this method is superficial now. ---Jack
2427
private XSDocumentInfo findXSDocumentForDecl(XSDocumentInfo currSchema,
2428
Element decl, XSDocumentInfo decl_Doc) {
2430
if (DEBUG_NODE_POOL) {
2431
System.out.println("DOCUMENT NS:"+ currSchema.fTargetNamespace+" hashcode:"+ ((Object)currSchema.fSchemaElement).hashCode());
2433
Object temp = decl_Doc;
2435
// something went badly wrong; we don't know this doc?
2438
XSDocumentInfo declDocInfo = (XSDocumentInfo)temp;
2441
Logic here is unnecessary after schema WG's recent decision to allow
2442
schema components from one document to refer to components of any other,
2443
so long as there's some include/import/redefine path amongst them.
2444
If they rver reverse this decision the code's right here though... - neilg
2445
// now look in fDependencyMap to see if this is reachable
2446
if(((Vector)fDependencyMap.get(currSchema)).contains(declDocInfo)) {
2449
// obviously the requesting doc didn't include, redefine or
2450
// import the one containing decl...
2453
} // findXSDocumentForDecl(XSDocumentInfo, Element): XSDocumentInfo
2455
// returns whether more than <annotation>s occur in children of elem
2456
private boolean nonAnnotationContent(Element elem) {
2457
for(Element child = DOMUtil.getFirstChildElement(elem); child != null; child = DOMUtil.getNextSiblingElement(child)) {
2458
if(!(DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION))) return true;
2461
} // nonAnnotationContent(Element): boolean
2463
private void setSchemasVisible(XSDocumentInfo startSchema) {
2464
if (DOMUtil.isHidden(startSchema.fSchemaElement, fHiddenNodes)) {
2466
DOMUtil.setVisible(startSchema.fSchemaElement, fHiddenNodes);
2467
Vector dependingSchemas = (Vector)fDependencyMap.get(startSchema);
2468
for (int i = 0; i < dependingSchemas.size(); i++) {
2469
setSchemasVisible((XSDocumentInfo)dependingSchemas.elementAt(i));
2472
// if it's visible already than so must be its children
2473
} // setSchemasVisible(XSDocumentInfo): void
2475
private SimpleLocator xl = new SimpleLocator();
2478
* Extract location information from an Element node, and create a
2479
* new SimpleLocator object from such information. Returning null means
2480
* no information can be retrieved from the element.
2482
public SimpleLocator element2Locator(Element e) {
2483
if (!( e instanceof ElementImpl))
2486
SimpleLocator l = new SimpleLocator();
2487
return element2Locator(e, l) ? l : null;
2491
* Extract location information from an Element node, store such
2492
* information in the passed-in SimpleLocator object, then return
2493
* true. Returning false means can't extract or store such information.
2495
public boolean element2Locator(Element e, SimpleLocator l) {
2498
if (e instanceof ElementImpl) {
2499
ElementImpl ele = (ElementImpl)e;
2500
// get system id from document object
2501
Document doc = ele.getOwnerDocument();
2502
String sid = (String)fDoc2SystemId.get(DOMUtil.getRoot(doc));
2503
// line/column numbers are stored in the element node
2504
int line = ele.getLineNumber();
2505
int column = ele.getColumnNumber();
2506
l.setValues(sid, sid, line, column, ele.getCharacterOffset());
2512
void reportSchemaError(String key, Object[] args, Element ele) {
2513
if (element2Locator(ele, xl)) {
2514
fErrorReporter.reportError(xl, XSMessageFormatter.SCHEMA_DOMAIN,
2515
key, args, XMLErrorReporter.SEVERITY_ERROR);
2518
fErrorReporter.reportError(XSMessageFormatter.SCHEMA_DOMAIN,
2519
key, args, XMLErrorReporter.SEVERITY_ERROR);
2523
void reportSchemaWarning(String key, Object[] args, Element ele) {
2524
if (element2Locator(ele, xl)) {
2525
fErrorReporter.reportError(xl, XSMessageFormatter.SCHEMA_DOMAIN,
2526
key, args, XMLErrorReporter.SEVERITY_WARNING);
2529
fErrorReporter.reportError(XSMessageFormatter.SCHEMA_DOMAIN,
2530
key, args, XMLErrorReporter.SEVERITY_WARNING);
2535
* Grammar pool used for validating annotations. This will return all of the
2536
* grammars from the grammar bucket. It will also return an object for the
2537
* schema for schemas which will contain at least the relevant declarations
2540
private static class XSAnnotationGrammarPool implements XMLGrammarPool {
2542
private XSGrammarBucket fGrammarBucket;
2543
private Grammar [] fInitialGrammarSet;
2545
public Grammar[] retrieveInitialGrammarSet(String grammarType) {
2546
if (grammarType == XMLGrammarDescription.XML_SCHEMA) {
2547
if (fInitialGrammarSet == null) {
2548
if (fGrammarBucket == null) {
2549
fInitialGrammarSet = new Grammar [] {SchemaGrammar.SG_Schema4Annotations};
2552
SchemaGrammar [] schemaGrammars = fGrammarBucket.getGrammars();
2554
* If the grammar bucket already contains the schema for schemas
2555
* then we already have the definitions for the parts relevant
2558
for (int i = 0; i < schemaGrammars.length; ++i) {
2559
if (SchemaSymbols.URI_SCHEMAFORSCHEMA.equals(schemaGrammars[i].getTargetNamespace())) {
2560
fInitialGrammarSet = schemaGrammars;
2561
return fInitialGrammarSet;
2564
Grammar [] grammars = new Grammar[schemaGrammars.length + 1];
2565
System.arraycopy(schemaGrammars, 0, grammars, 0, schemaGrammars.length);
2566
grammars[grammars.length - 1] = SchemaGrammar.SG_Schema4Annotations;
2567
fInitialGrammarSet = grammars;
2570
return fInitialGrammarSet;
2572
return new Grammar[0];
2575
public void cacheGrammars(String grammarType, Grammar[] grammars) {
2579
public Grammar retrieveGrammar(XMLGrammarDescription desc) {
2580
if (desc.getGrammarType() == XMLGrammarDescription.XML_SCHEMA) {
2581
final String tns = ((XMLSchemaDescription) desc).getTargetNamespace();
2582
if (fGrammarBucket != null) {
2583
Grammar grammar = fGrammarBucket.getGrammar(tns);
2584
if (grammar != null) {
2588
if (SchemaSymbols.URI_SCHEMAFORSCHEMA.equals(tns)) {
2589
return SchemaGrammar.SG_Schema4Annotations;
2595
public void refreshGrammars(XSGrammarBucket gBucket) {
2596
fGrammarBucket = gBucket;
2597
fInitialGrammarSet = null;
2600
public void lockPool() {}
2602
public void unlockPool() {}
2604
public void clear() {}
2608
* used to identify a reference to a schema document
2609
* if the same document is referenced twice with the same key, then
2610
* we only need to parse it once.
2612
* When 2 XSDKey's are compared, the following table can be used to
2613
* determine whether they are equal:
2614
* inc red imp pre ins
2615
* inc N/L ? N/L N/L N/L
2617
* imp N/L ? N/P N/P N/P
2618
* pre N/L ? N/P N/P N/P
2619
* ins N/L ? N/P N/P N/P
2621
* Where: N/L: duplicate when they have the same namespace and location.
2622
* ? : not clear from the spec.
2623
* REVISIT: to simplify the process, also considering
2624
* it's very rare, we treat them as not duplicate.
2625
* N/P: not possible. imp/pre/ins are referenced by namespace.
2626
* when the first time we encounter a schema document for a
2627
* namespace, we create a grammar and store it in the grammar
2628
* bucket. when we see another reference to the same namespace,
2629
* we first check whether a grammar with the same namespace is
2630
* already in the bucket, which is true in this case, so we
2631
* won't create another XSDKey.
2633
* Conclusion from the table: two XSDKey's are duplicate only when all of
2634
* the following are true:
2635
* 1. They are both "redefine", or neither is "redefine";
2636
* 2. They have the same namespace;
2637
* 3. They have the same non-null location.
2639
* About 3: if neither has a non-null location, then it's the case where
2640
* 2 input streams are provided, but no system ID is provided. We can't tell
2641
* whether the 2 streams have the same content, so we treat them as not
2644
private static class XSDKey {
2647
// for inclue/redefine, this is the enclosing namespace
2648
// for import/preparse/instance, this is the target namespace
2651
XSDKey(String systemId, short referType, String referNS) {
2652
this.systemId = systemId;
2653
this.referType = referType;
2654
this.referNS = referNS;
2657
public int hashCode() {
2658
// according to the description at the beginning of this class,
2659
// we use the hashcode of the namespace as the hashcoe of this key.
2660
return referNS == null ? 0 : referNS.hashCode();
2663
public boolean equals(Object obj) {
2664
if (!(obj instanceof XSDKey)) {
2667
XSDKey key = (XSDKey)obj;
2669
// condition 1: both are redefine
2670
/** if (referType == XSDDescription.CONTEXT_REDEFINE ||
2671
key.referType == XSDDescription.CONTEXT_REDEFINE) {
2672
if (referType != key.referType)
2676
// condition 2: same namespace
2677
if (referNS != key.referNS)
2680
// condition 3: same non-null location
2681
if (systemId == null || !systemId.equals(key.systemId)) {
2692
public void setGenerateSyntheticAnnotations(boolean state) {
2693
fSchemaParser.setFeature(GENERATE_SYNTHETIC_ANNOTATIONS, state);