| /* |
| * The Apache Software License, Version 1.1 |
| * |
| * |
| * Copyright (c) 1999 The Apache Software Foundation. All rights |
| * reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. The end-user documentation included with the redistribution, |
| * if any, must include the following acknowledgment: |
| * "This product includes software developed by the |
| * Apache Software Foundation (http://www.apache.org/)." |
| * Alternately, this acknowledgment may appear in the software itself, |
| * if and wherever such third-party acknowledgments normally appear. |
| * |
| * 4. The names "Xerces" and "Apache Software Foundation" must |
| * not be used to endorse or promote products derived from this |
| * software without prior written permission. For written |
| * permission, please contact apache@apache.org. |
| * |
| * 5. Products derived from this software may not be called "Apache", |
| * nor may "Apache" appear in their name, without prior written |
| * permission of the Apache Software Foundation. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation and was |
| * originally based on software copyright (c) 1999, International |
| * Business Machines, Inc., http://www.apache.org. For more |
| * information on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| */ |
| |
| package org.apache.xerces.impl.xs.traversers; |
| |
| import org.apache.xerces.impl.xs.XSGrammarResolver; |
| import org.apache.xerces.impl.xs.XSParticleDecl; |
| import org.apache.xerces.impl.xs.XSElementDecl; |
| import org.apache.xerces.impl.xs.SchemaNamespaceSupport; |
| import org.apache.xerces.impl.xs.SchemaGrammar; |
| import org.apache.xerces.impl.xs.XSComplexTypeDecl; |
| import org.apache.xerces.impl.xs.SchemaSymbols; |
| import org.apache.xerces.impl.xs.XSMessageFormatter; |
| import org.apache.xerces.impl.xs.XMLSchemaValidator; |
| import org.apache.xerces.parsers.StandardParserConfiguration; |
| import org.apache.xerces.impl.XMLErrorReporter; |
| import org.apache.xerces.impl.XMLEntityManager; |
| import org.apache.xerces.parsers.DOMParser; |
| import org.apache.xerces.xni.QName; |
| import org.apache.xerces.xni.parser.XMLEntityResolver; |
| import org.apache.xerces.xni.parser.XMLInputSource; |
| import org.apache.xerces.util.SymbolTable; |
| import org.apache.xerces.util.SymbolHash; |
| import org.apache.xerces.util.DOMUtil; |
| |
| import org.w3c.dom.Document; |
| import org.apache.xerces.dom.DocumentImpl; |
| import org.w3c.dom.Attr; |
| import org.w3c.dom.Element; |
| |
| import java.util.Hashtable; |
| import java.util.Stack; |
| import java.util.Vector; |
| import java.util.StringTokenizer; |
| import java.io.IOException; |
| |
| /** |
| * The purpose of this class is to co-ordinate the construction of a |
| * grammar object corresponding to a schema. To do this, it must be |
| * prepared to parse several schema documents (for instance if the |
| * schema document originally referred to contains <include> or |
| * <redefined> information items). If any of the schemas imports a |
| * schema, other grammars may be constructed as a side-effect. |
| * |
| * @author Neil Graham, IBM |
| * @version $Id$ |
| */ |
| |
| public class XSDHandler { |
| |
| // data |
| |
| // different sorts of declarations; should make lookup and |
| // traverser calling more efficient/less bulky. |
| final static int ATTRIBUTE_TYPE = 1; |
| final static int ATTRIBUTEGROUP_TYPE = 2; |
| final static int ELEMENT_TYPE = 3; |
| final static int GROUP_TYPE = 4; |
| final static int IDENTITYCONSTRAINT_TYPE = 5; |
| final static int NOTATION_TYPE = 6; |
| final static int TYPEDECL_TYPE = 7; |
| |
| // this string gets appended to redefined names; it's purpose is to be |
| // as unlikely as possible to cause collisions. |
| public final static String REDEF_IDENTIFIER = "_fn3dktizrknc9pi"; |
| |
| // please note the difference between SchemaHandler.EMPTY_STRING and |
| // SchemaSymbols.EMPTY_STRING: |
| // the one in SchemaHandler is only for namespace binding purpose, it's |
| // used as a legal prefix, and it's added to the current symbol table; |
| // while the one in SchemaSymbols is for general purpose: just empty. |
| public String EMPTY_STRING; |
| |
| // |
| //protected data that can be accessable by any traverser |
| // stores <notation> decl |
| protected Hashtable fNotationRegistry = new Hashtable(); |
| |
| // These tables correspond to the symbol spaces defined in the |
| // spec. |
| // They are keyed with a QName (that is, String("URI,localpart) and |
| // their values are nodes corresponding to the given name's decl. |
| // By asking the node for its ownerDocument and looking in |
| // XSDocumentInfoRegistry we can easily get the corresponding |
| // XSDocumentInfo object. |
| private Hashtable fUnparsedAttributeRegistry = new Hashtable(); |
| private Hashtable fUnparsedAttributeGroupRegistry = new Hashtable(); |
| private Hashtable fUnparsedElementRegistry = new Hashtable(); |
| private Hashtable fUnparsedGroupRegistry = new Hashtable(); |
| private Hashtable fUnparsedIdentityConstraintRegistry = new Hashtable(); |
| private Hashtable fUnparsedNotationRegistry = new Hashtable(); |
| private Hashtable fUnparsedTypeRegistry = new Hashtable(); |
| // this is keyed with a documentNode (or the schemaRoot nodes |
| // contained in the XSDocumentInfo objects) and its value is the |
| // XSDocumentInfo object corresponding to that document. |
| // Basically, the function of this registry is to be a link |
| // between the nodes we fetch from calls to the fUnparsed* |
| // arrays and the XSDocumentInfos they live in. |
| private Hashtable fXSDocumentInfoRegistry = new Hashtable(); |
| |
| // this hashtable is keyed on by XSDocumentInfo objects. Its values |
| // are Vectors containing the XSDocumentInfo objects <include>d, |
| // <import>ed or <redefine>d by the key XSDocumentInfo. |
| private Hashtable fDependencyMap = new Hashtable(); |
| |
| // This vector stores strings which are combinations of the |
| // publicId and systemId of the inputSource corresponding to a |
| // schema document. This combination is used so that the user's |
| // EntityResolver can provide a consistent way of identifying a |
| // schema document that is included in multiple other schemas. |
| private SymbolHash fTraversed = new SymbolHash(); |
| |
| // this hashtable contains a mapping from Document to its systemId |
| // this is useful to resolve a uri relative to the referring document |
| private Hashtable fDoc2SystemId = new Hashtable(); |
| |
| // the primary XSDocumentInfo we were called to parse |
| private XSDocumentInfo fRoot = null; |
| |
| // This hashtable's job is to act as a link between the document |
| // node at the root of the parsed schema's tree and its |
| // XSDocumentInfo object. |
| private Hashtable fDoc2XSDocumentMap = new Hashtable(); |
| |
| // map between <redefine> elements and the XSDocumentInfo |
| // objects that correspond to the documents being redefined. |
| private Hashtable fRedefine2XSDMap = new Hashtable(); |
| |
| // these objects store a mapping between the names of redefining |
| // groups/attributeGroups and the groups/AttributeGroups which |
| // they redefine by restriction (implicitly). It is up to the |
| // Group and AttributeGroup traversers to check these restrictions for |
| // validity. |
| private Hashtable fRedefinedRestrictedAttributeGroupRegistry = new Hashtable(); |
| private Hashtable fRedefinedRestrictedGroupRegistry = new Hashtable(); |
| |
| // a variable storing whether the last schema document |
| // processed (by getSchema) was a duplicate. |
| private boolean fLastSchemaWasDuplicate; |
| |
| // the XMLErrorReporter |
| private XMLErrorReporter fErrorReporter; |
| |
| // the XSAttributeChecker |
| private XSAttributeChecker fAttributeChecker; |
| |
| // this class is to make use of the schema location property values. |
| // we store the namespace/location pairs in a hashtable (use "" as the |
| // namespace of absent namespace). when resolving an entity, we first try |
| // to find in the hashtable whether there is a value for that namespace, |
| // if so, pass that location value to the user-defined entity resolver. |
| protected class LocationResolver { |
| // the user-defined entity resolver |
| public XMLEntityResolver fExternalResolver = null; |
| // namespace/location pairs |
| public Hashtable fLocationPairs = new Hashtable(); |
| |
| public void reset(XMLEntityResolver entityResolver, |
| String sLocation, String nsLocation) { |
| fLocationPairs.clear(); |
| fExternalResolver = entityResolver; |
| |
| if (sLocation != null) { |
| StringTokenizer t = new StringTokenizer(sLocation, " \n\t\r"); |
| String namespace, location; |
| while (t.hasMoreTokens()) { |
| namespace = t.nextToken (); |
| if (!t.hasMoreTokens()) { |
| break; |
| } |
| location = t.nextToken(); |
| fLocationPairs.put(namespace, location); |
| } |
| } |
| if (nsLocation != null) { |
| fLocationPairs.put(EMPTY_STRING, nsLocation); |
| } |
| } |
| |
| public XMLInputSource resolveEntity(String namespace, String location, String base, boolean useProperties) throws IOException { |
| if (fExternalResolver == null) |
| return null; |
| |
| String loc = null; |
| // we consider the schema location properties for import |
| if (useProperties) { |
| // use empty string as the key for absent namespace |
| String ns = namespace == null ? EMPTY_STRING : namespace; |
| // get the location hint for that namespace |
| loc = (String)fLocationPairs.get(ns); |
| } |
| |
| // if it's not import, or if the target namespace is not set |
| // in the schema location properties, use location hint |
| if (loc == null) |
| loc = location; |
| |
| // REVISIT: resolve the entity. passing null as public id, instead |
| // of passing namespace value. -SG |
| return fExternalResolver.resolveEntity(null, loc, base); |
| } |
| } |
| |
| // the schema location resolver |
| private LocationResolver fLocationResolver = new LocationResolver(); |
| |
| // the symbol table |
| private SymbolTable fSymbolTable; |
| |
| // the GrammarResolver |
| private XSGrammarResolver fGrammarResolver; |
| |
| //************ Traversers ********** |
| XSDAttributeGroupTraverser fAttributeGroupTraverser; |
| XSDAttributeTraverser fAttributeTraverser; |
| XSDComplexTypeTraverser fComplexTypeTraverser; |
| XSDElementTraverser fElementTraverser; |
| XSDGroupTraverser fGroupTraverser; |
| XSDKeyrefTraverser fKeyrefTraverser; |
| XSDNotationTraverser fNotationTraverser; |
| XSDSimpleTypeTraverser fSimpleTypeTraverser; |
| XSDUniqueOrKeyTraverser fUniqueOrKeyTraverser; |
| XSDWildcardTraverser fWildCardTraverser; |
| |
| DOMParser fSchemaParser; |
| |
| // these data members are needed for the deferred traversal |
| // of local elements. |
| |
| // the initial size of the array to store deferred local elements |
| private static final int INIT_STACK_SIZE = 30; |
| // the incremental size of the array to store deferred local elements |
| private static final int INC_STACK_SIZE = 10; |
| // current position of the array (# of deferred local elements) |
| private int fLocalElemStackPos; |
| |
| private XSParticleDecl[] fParticle; |
| private Element[] fLocalElementDecl; |
| private int[] fAllContext; |
| private String [][] fLocalElemNamespaceContext; |
| |
| // these data members are needed for the deferred traversal |
| // of keyrefs. |
| |
| // the initial size of the array to store deferred keyrefs |
| private static final int INIT_KEYREF_STACK = 2; |
| // the incremental size of the array to store deferred keyrefs |
| private static final int INC_KEYREF_STACK_AMOUNT = 2; |
| // current position of the array (# of deferred keyrefs) |
| private int fKeyrefStackPos; |
| |
| private Element [] fKeyrefs; |
| private XSElementDecl [] fKeyrefElems; |
| private String [][] fKeyrefNamespaceContext; |
| |
| // Constructors |
| |
| // it should be possible to use the same XSDHandler to parse |
| // multiple schema documents; this will allow one to be |
| // constructed. |
| public XSDHandler (XSGrammarResolver gResolver) { |
| fGrammarResolver = gResolver; |
| |
| // REVISIT: do we use shadowed or synchronized symbol table of |
| // SchemaSymbols.fSymbolTable? |
| // REVISIT: don't use SchemaConfiguration internally |
| // we will get stack overflaw because |
| // XMLSchemaValidator will be instantiating XSDHandler... |
| fSchemaParser = new DOMParser(new StandardParserConfiguration(new SchemaSymbols.SchemaSymbolTable())); |
| // set ErrorHandler and EntityResolver (doesn't seem that |
| // XMLErrorHandler or XMLEntityResolver will work with |
| // standard DOMParser... |
| //REVISIT: disable deferred dom expansion. there are bugs. |
| try { |
| fSchemaParser.setFeature("http://apache.org/xml/features/dom/defer-node-expansion", false); |
| } |
| catch (Exception e) { |
| } |
| |
| createTraversers(); |
| } // end constructor |
| |
| // This method initiates the parse of a schema. It will likely be |
| // called from the Validator and it will make the |
| // resulting grammar available; it returns a reference to this object just |
| // in case. An ErrorHandler, EntityResolver, GrammarPool and SymbolTable must |
| // already have been set; the last thing this method does is reset |
| // this object (i.e., clean the registries, etc.). |
| public SchemaGrammar parseSchema(String schemaNamespace, |
| String schemaHint) { |
| |
| // first phase: construct trees. |
| Document schemaRoot = getSchema(schemaNamespace, schemaHint, null, true, true); |
| if (schemaRoot == null) { |
| // something went wrong right off the hop |
| reportGenericSchemaError("Could not locate a schema document corresponding to grammar " + schemaNamespace); |
| return null; |
| } |
| // handle empty string URI as null |
| if (schemaNamespace != null) { |
| schemaNamespace = fSymbolTable.addSymbol(schemaNamespace); |
| } |
| fRoot = constructTrees(schemaRoot, schemaNamespace); |
| if (fRoot == null) { |
| // REVISIT: something went wrong; print error about no schema found |
| reportGenericSchemaError("Could not locate a schema document"); |
| return null; |
| } |
| |
| // second phase: fill global registries. |
| buildGlobalNameRegistries(); |
| |
| // third phase: call traversers |
| traverseSchemas(); |
| |
| // fourth phase: handle local element decls |
| traverseLocalElements(); |
| |
| // fifth phase: handle Keyrefs |
| resolveKeyRefs(); |
| |
| // sixth phase: validate attribute of non-schema namespaces |
| // REVISIT: skip this for now. we reall don't want to do it. |
| //fAttributeChecker.checkNonSchemaAttributes(fGrammarResolver); |
| |
| // and return. |
| return fGrammarResolver.getGrammar(schemaNamespace); |
| } // end parseSchema |
| |
| // may wish to have setter methods for ErrorHandler, |
| // EntityResolver... |
| |
| // This method does several things: |
| // It constructs an instance of an XSDocumentInfo object using the |
| // schemaRoot node. Then, for each <include>, |
| // <redefine>, and <import> children, it attempts to resolve the |
| // requested schema document, initiates a DOM parse, and calls |
| // itself recursively on that document's root. It also records in |
| // the DependencyMap object what XSDocumentInfo objects its XSDocumentInfo |
| // depends on. |
| // It also makes sure the targetNamespace of the schema it was |
| // called to parse is correct. |
| protected XSDocumentInfo constructTrees(Document schemaRoot, String callerTNS) { |
| if (schemaRoot == null) return null; |
| XSDocumentInfo currSchemaInfo = new XSDocumentInfo(schemaRoot, fAttributeChecker, fSymbolTable); |
| |
| // Modified by Pavani Mukthipudi, Sun Microsystems Inc. |
| fDoc2XSDocumentMap.put(schemaRoot, currSchemaInfo); |
| |
| if (callerTNS != null) { |
| // only set if we were included or redefined in. |
| if (currSchemaInfo.fTargetNamespace == null) { |
| currSchemaInfo.fTargetNamespace = callerTNS; |
| currSchemaInfo.fIsChameleonSchema = true; |
| } |
| else if (callerTNS != currSchemaInfo.fTargetNamespace) { |
| reportSchemaError("src-include.2", new Object [] {callerTNS, currSchemaInfo.fTargetNamespace}); |
| } |
| } |
| SchemaGrammar sg = null; |
| if ((sg = fGrammarResolver.getGrammar(currSchemaInfo.fTargetNamespace)) == null) { |
| sg = new SchemaGrammar(fSymbolTable, currSchemaInfo.fTargetNamespace); |
| fGrammarResolver.putGrammar(sg); |
| } |
| |
| Vector dependencies = new Vector(); |
| Element rootNode = DOMUtil.getRoot(schemaRoot); |
| |
| Document newSchemaRoot = null; |
| for (Element child = DOMUtil.getFirstChildElement(rootNode); |
| child != null; |
| child = DOMUtil.getNextSiblingElement(child)) { |
| String schemaNamespace=null; |
| String schemaHint=null; |
| String localName = DOMUtil.getLocalName(child); |
| if (localName.equals(SchemaSymbols.ELT_ANNOTATION)) |
| continue; |
| else if (localName.equals(SchemaSymbols.ELT_IMPORT)) { |
| // have to handle some validation here too! |
| // call XSAttributeChecker to fill in attrs |
| Object[] includeAttrs = fAttributeChecker.checkAttributes(child, true, currSchemaInfo); |
| schemaHint = (String)includeAttrs[XSAttributeChecker.ATTIDX_SCHEMALOCATION]; |
| schemaNamespace = (String)includeAttrs[XSAttributeChecker.ATTIDX_NAMESPACE]; |
| if (schemaNamespace != null) |
| schemaNamespace = fSymbolTable.addSymbol(schemaNamespace); |
| if (schemaNamespace == currSchemaInfo.fTargetNamespace) { |
| reportSchemaError("src-import.1.1", new Object [] {schemaNamespace}); |
| } |
| fAttributeChecker.returnAttrArray(includeAttrs, currSchemaInfo); |
| // consciously throw away whether was a duplicate; don't care. |
| // pass the systemId of the current document as the base systemId |
| newSchemaRoot = getSchema(schemaNamespace, schemaHint, (String)fDoc2SystemId.get(schemaRoot), false, true); |
| } |
| else if ((localName.equals(SchemaSymbols.ELT_INCLUDE)) || |
| (localName.equals(SchemaSymbols.ELT_REDEFINE))) { |
| // validation for redefine/include will be the same here; just |
| // make sure TNS is right (don't care about redef contents |
| // yet). |
| Object[] includeAttrs = fAttributeChecker.checkAttributes(child, true, currSchemaInfo); |
| schemaHint = (String)includeAttrs[XSAttributeChecker.ATTIDX_SCHEMALOCATION]; |
| fAttributeChecker.returnAttrArray(includeAttrs, currSchemaInfo); |
| // schemaLocation is required on <include> and <redefine> |
| if (schemaHint == null) |
| reportGenericSchemaError("schemaLocation attribute must appear in <include> and <redefine>"); |
| // pass the systemId of the current document as the base systemId |
| boolean mustResolve = false; |
| if(localName.equals(SchemaSymbols.ELT_REDEFINE)) { |
| mustResolve = nonAnnotationContent(child); |
| } |
| newSchemaRoot = getSchema(null, schemaHint, (String)fDoc2SystemId.get(schemaRoot), mustResolve, false); |
| schemaNamespace = currSchemaInfo.fTargetNamespace; |
| } |
| else { |
| // no more possibility of schema references in well-formed |
| // schema... |
| break; |
| } |
| |
| // If the schema is duplicate, we needn't call constructTrees() again. |
| // To handle mutual <include>s |
| |
| // REVISIT: this creates a bug if the same document is both |
| // imported and included. then only the first one takes |
| // effect. |
| |
| XSDocumentInfo newSchemaInfo = null; |
| if (fLastSchemaWasDuplicate) { |
| newSchemaInfo = (XSDocumentInfo)fDoc2XSDocumentMap.get(newSchemaRoot); |
| } |
| else { |
| newSchemaInfo = constructTrees(newSchemaRoot, schemaNamespace); |
| } |
| if (localName.equals(SchemaSymbols.ELT_REDEFINE) && |
| newSchemaInfo != null) { |
| // must record which schema we're redefining so that we can |
| // rename the right things later! |
| fRedefine2XSDMap.put(child, newSchemaInfo); |
| } |
| if (newSchemaRoot != null) { |
| dependencies.addElement(newSchemaInfo); |
| newSchemaRoot = null; |
| } |
| } |
| fDependencyMap.put(currSchemaInfo, dependencies); |
| return currSchemaInfo; |
| } // end constructTrees |
| |
| // This method builds registries for all globally-referenceable |
| // names. A registry will be built for each symbol space defined |
| // by the spec. It is also this method's job to rename redefined |
| // components, and to record which components redefine others (so |
| // that implicit redefinitions of groups and attributeGroups can be handled). |
| protected void buildGlobalNameRegistries() { |
| /* Starting with fRoot, we examine each child of the schema |
| * element. Skipping all imports and includes, we record the names |
| * of all other global components (and children of <redefine>). We |
| * also put <redefine> names in a registry that we look through in |
| * case something needs renaming. Once we're done with a schema we |
| * set its Document node to hidden so that we don't try to traverse |
| * it again; then we look to its Dependency map entry. We keep a |
| * stack of schemas that we haven't yet finished processing; this |
| * is a depth-first traversal. |
| */ |
| Stack schemasToProcess = new Stack(); |
| schemasToProcess.push(fRoot); |
| while (!schemasToProcess.empty()) { |
| XSDocumentInfo currSchemaDoc = |
| (XSDocumentInfo)schemasToProcess.pop(); |
| Document currDoc = currSchemaDoc.fSchemaDoc; |
| if (DOMUtil.isHidden(currDoc)) { |
| // must have processed this already! |
| continue; |
| } |
| Element currRoot = DOMUtil.getRoot(currDoc); |
| |
| // process this schema's global decls |
| boolean dependenciesCanOccur = true; |
| for (Element globalComp = |
| DOMUtil.getFirstChildElement(currRoot); |
| globalComp != null; |
| globalComp = DOMUtil.getNextSiblingElement(globalComp)) { |
| // this loop makes sure the <schema> element ordering is |
| // also valid. |
| if (DOMUtil.getLocalName(globalComp).equals(SchemaSymbols.ELT_ANNOTATION)) { |
| //skip it; traverse it later |
| continue; |
| } |
| else if (DOMUtil.getLocalName(globalComp).equals(SchemaSymbols.ELT_INCLUDE) || |
| DOMUtil.getLocalName(globalComp).equals(SchemaSymbols.ELT_IMPORT)) { |
| if (!dependenciesCanOccur) { |
| reportSchemaError("sch-props-correct.1", new Object [] {DOMUtil.getLocalName(globalComp)}); |
| } |
| // we've dealt with this; mark as traversed |
| DOMUtil.setHidden(globalComp); |
| } |
| else if (DOMUtil.getLocalName(globalComp).equals(SchemaSymbols.ELT_REDEFINE)) { |
| if (!dependenciesCanOccur) { |
| reportSchemaError("sch-props-correct.1", new Object [] {DOMUtil.getLocalName(globalComp)}); |
| } |
| for (Element redefineComp = DOMUtil.getFirstChildElement(globalComp); |
| redefineComp != null; |
| redefineComp = DOMUtil.getNextSiblingElement(redefineComp)) { |
| String lName = DOMUtil.getAttrValue(redefineComp, SchemaSymbols.ATT_NAME); |
| if (lName.length() == 0) // an error we'll catch later |
| continue; |
| String qName = currSchemaDoc.fTargetNamespace == null ? |
| ","+lName: |
| currSchemaDoc.fTargetNamespace +","+lName; |
| String componentType = DOMUtil.getLocalName(redefineComp); |
| if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) { |
| checkForDuplicateNames(qName, fUnparsedAttributeGroupRegistry, redefineComp, currSchemaDoc); |
| // the check will have changed our name; |
| String targetLName = DOMUtil.getAttrValue(redefineComp, SchemaSymbols.ATT_NAME)+REDEF_IDENTIFIER; |
| // and all we need to do is error-check+rename our kkids: |
| renameRedefiningComponents(currSchemaDoc, redefineComp, SchemaSymbols.ELT_ATTRIBUTEGROUP, |
| lName, targetLName); |
| } |
| else if ((componentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) || |
| (componentType.equals(SchemaSymbols.ELT_SIMPLETYPE))) { |
| checkForDuplicateNames(qName, fUnparsedTypeRegistry, redefineComp, currSchemaDoc); |
| // the check will have changed our name; |
| String targetLName = DOMUtil.getAttrValue(redefineComp, SchemaSymbols.ATT_NAME) + REDEF_IDENTIFIER; |
| // and all we need to do is error-check+rename our kkids: |
| if (componentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) { |
| renameRedefiningComponents(currSchemaDoc, redefineComp, SchemaSymbols.ELT_COMPLEXTYPE, |
| lName, targetLName); |
| } |
| else { // must be simpleType |
| renameRedefiningComponents(currSchemaDoc, redefineComp, SchemaSymbols.ELT_SIMPLETYPE, |
| lName, targetLName); |
| } |
| } |
| else if (componentType.equals(SchemaSymbols.ELT_GROUP)) { |
| checkForDuplicateNames(qName, fUnparsedGroupRegistry, redefineComp, currSchemaDoc); |
| // the check will have changed our name; |
| String targetLName = DOMUtil.getAttrValue(redefineComp, SchemaSymbols.ATT_NAME)+REDEF_IDENTIFIER; |
| // and all we need to do is error-check+rename our kids: |
| renameRedefiningComponents(currSchemaDoc, redefineComp, SchemaSymbols.ELT_GROUP, |
| lName, targetLName); |
| } |
| } // end march through <redefine> children |
| // and now set as traversed |
| //DOMUtil.setHidden(globalComp); |
| } |
| else { |
| dependenciesCanOccur = false; |
| String lName = DOMUtil.getAttrValue(globalComp, SchemaSymbols.ATT_NAME); |
| if (lName.length() == 0) // an error we'll catch later |
| continue; |
| String qName = currSchemaDoc.fTargetNamespace == null? |
| ","+lName: |
| currSchemaDoc.fTargetNamespace +","+lName; |
| String componentType = DOMUtil.getLocalName(globalComp); |
| if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTE)) { |
| checkForDuplicateNames(qName, fUnparsedAttributeRegistry, globalComp, currSchemaDoc); |
| } |
| else if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) { |
| checkForDuplicateNames(qName, fUnparsedAttributeGroupRegistry, globalComp, currSchemaDoc); |
| } |
| else if ((componentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) || |
| (componentType.equals(SchemaSymbols.ELT_SIMPLETYPE))) { |
| checkForDuplicateNames(qName, fUnparsedTypeRegistry, globalComp, currSchemaDoc); |
| } |
| else if (componentType.equals(SchemaSymbols.ELT_ELEMENT)) { |
| checkForDuplicateNames(qName, fUnparsedElementRegistry, globalComp, currSchemaDoc); |
| } |
| else if (componentType.equals(SchemaSymbols.ELT_GROUP)) { |
| checkForDuplicateNames(qName, fUnparsedGroupRegistry, globalComp, currSchemaDoc); |
| } |
| else if (componentType.equals(SchemaSymbols.ELT_NOTATION)) { |
| checkForDuplicateNames(qName, fUnparsedNotationRegistry, globalComp, currSchemaDoc); |
| } |
| } |
| } // end for |
| |
| // now we're done with this one! |
| DOMUtil.setHidden(currDoc); |
| // now add the schemas this guy depends on |
| Vector currSchemaDepends = (Vector)fDependencyMap.get(currSchemaDoc); |
| for (int i = 0; i < currSchemaDepends.size(); i++) { |
| schemasToProcess.push(currSchemaDepends.elementAt(i)); |
| } |
| } // while |
| } // end buildGlobalNameRegistries |
| |
| // Beginning at the first schema processing was requested for |
| // (fRoot), this method |
| // examines each child (global schema information item) of each |
| // schema document (and of each <redefine> element) |
| // corresponding to an XSDocumentInfo object. If the |
| // readOnly field on that node has not been set, it calls an |
| // appropriate traverser to traverse it. Once all global decls in |
| // an XSDocumentInfo object have been traversed, it marks that object |
| // as traversed (or hidden) in order to avoid infinite loops. It completes |
| // when it has visited all XSDocumentInfo objects in the |
| // DependencyMap and marked them as traversed. |
| protected void traverseSchemas() { |
| // the process here is very similar to that in |
| // buildGlobalRegistries, except we can't set our schemas as |
| // hidden for a second time; so make them all visible again |
| // first! |
| setSchemasVisible(fRoot); |
| Stack schemasToProcess = new Stack(); |
| schemasToProcess.push(fRoot); |
| while (!schemasToProcess.empty()) { |
| XSDocumentInfo currSchemaDoc = |
| (XSDocumentInfo)schemasToProcess.pop(); |
| Document currDoc = currSchemaDoc.fSchemaDoc; |
| SchemaGrammar currSG = fGrammarResolver.getGrammar(currSchemaDoc.fTargetNamespace); |
| if (DOMUtil.isHidden(currDoc)) { |
| // must have processed this already! |
| continue; |
| } |
| Element currRoot = DOMUtil.getRoot(currDoc); |
| |
| // traverse this schema's global decls |
| for (Element globalComp = |
| DOMUtil.getFirstVisibleChildElement(currRoot); |
| globalComp != null; |
| globalComp = DOMUtil.getNextVisibleSiblingElement(globalComp)) { |
| // We'll always want to set this as hidden! |
| DOMUtil.setHidden(globalComp); |
| String componentType = DOMUtil.getLocalName(globalComp); |
| // includes and imports will not show up here! |
| if (DOMUtil.getLocalName(globalComp).equals(SchemaSymbols.ELT_REDEFINE)) { |
| for (Element redefinedComp = DOMUtil.getFirstVisibleChildElement(globalComp); |
| redefinedComp != null; |
| redefinedComp = DOMUtil.getNextVisibleSiblingElement(redefinedComp)) { |
| String redefinedComponentType = DOMUtil.getLocalName(redefinedComp); |
| DOMUtil.setHidden(redefinedComp); |
| if (redefinedComponentType.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) { |
| fAttributeGroupTraverser.traverseGlobal(redefinedComp, currSchemaDoc, currSG); |
| } |
| else if (redefinedComponentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) { |
| fComplexTypeTraverser.traverseGlobal(redefinedComp, currSchemaDoc, currSG); |
| } |
| else if (redefinedComponentType.equals(SchemaSymbols.ELT_GROUP)) { |
| fGroupTraverser.traverseGlobal(redefinedComp, currSchemaDoc, currSG); |
| } |
| else if (redefinedComponentType.equals(SchemaSymbols.ELT_SIMPLETYPE)) { |
| fSimpleTypeTraverser.traverseGlobal(redefinedComp, currSchemaDoc, currSG); |
| } |
| else if (redefinedComponentType.equals(SchemaSymbols.ELT_ANNOTATION)) { |
| // REVISIT: according to 3.13.2 the PSVI needs the parent's attributes; |
| // thus this should be done in buildGlobalNameRegistries not here... |
| fElementTraverser.traverseAnnotationDecl(redefinedComp, null, true, currSchemaDoc); |
| } |
| else { |
| reportSchemaError("src-redefine", new Object [] {componentType}); |
| } |
| } // end march through <redefine> children |
| } |
| else if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTE)) { |
| fAttributeTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG); |
| } |
| else if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) { |
| fAttributeGroupTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG); |
| } |
| else if (componentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) { |
| fComplexTypeTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG); |
| } |
| else if (componentType.equals(SchemaSymbols.ELT_ELEMENT)) { |
| fElementTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG); |
| } |
| else if (componentType.equals(SchemaSymbols.ELT_GROUP)) { |
| fGroupTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG); |
| } |
| else if (componentType.equals(SchemaSymbols.ELT_NOTATION)) { |
| fNotationTraverser.traverse(globalComp, currSchemaDoc, currSG); |
| } |
| else if (componentType.equals(SchemaSymbols.ELT_SIMPLETYPE)) { |
| fSimpleTypeTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG); |
| } |
| else if (componentType.equals(SchemaSymbols.ELT_ANNOTATION)) { |
| // REVISIT: according to 3.13.2 the PSVI needs the parent's attributes; |
| // thus this should be done in buildGlobalNameRegistries not here... |
| fElementTraverser.traverseAnnotationDecl(globalComp, null, true, currSchemaDoc); |
| } |
| else { |
| reportSchemaError("sch-props-correct.1", new Object [] {DOMUtil.getLocalName(globalComp)}); |
| } |
| } // end for |
| |
| // now we're done with this one! |
| DOMUtil.setHidden(currDoc); |
| // now add the schemas this guy depends on |
| Vector currSchemaDepends = (Vector)fDependencyMap.get(currSchemaDoc); |
| for (int i = 0; i < currSchemaDepends.size(); i++) { |
| schemasToProcess.push(currSchemaDepends.elementAt(i)); |
| } |
| } // while |
| } // end traverseSchemas |
| |
| private static final String[] COMP_TYPE = { |
| null, // index 0 |
| "attribute declaration", |
| "attribute group", |
| "elment declaration", |
| "group", |
| "identity constraint", |
| "notation", |
| "type definition", |
| }; |
| |
| // since it is forbidden for traversers to talk to each other |
| // directly (except wen a traverser encounters a local declaration), |
| // this provides a generic means for a traverser to call |
| // for the traversal of some declaration. An XSDocumentInfo is |
| // required because the XSDocumentInfo that the traverser is traversing |
| // may bear no relation to the one the handler is operating on. |
| // This method will: |
| // 1. See if a global definition matching declToTraverse exists; |
| // 2. if so, determine if there is a path from currSchema to the |
| // schema document where declToTraverse lives (i.e., do a lookup |
| // in DependencyMap); |
| // 3. depending on declType (which will be relevant to step 1 as |
| // well), call the appropriate traverser with the appropriate |
| // XSDocumentInfo object. |
| // This method returns whatever the traverser it called returned; |
| // this will be an Object of some kind |
| // that lives in the Grammar. |
| protected Object getGlobalDecl(XSDocumentInfo currSchema, |
| int declType, |
| QName declToTraverse) { |
| |
| // from the schema spec, all built-in types are present in all schemas, |
| // so if the requested component is a type, and could be found in the |
| // default schema grammar, we should return that type. |
| // otherwise (since we would support user-defined schema grammar) we'll |
| // use the normal way to get the decl |
| if (declToTraverse.uri != null && |
| declToTraverse.uri == SchemaSymbols.URI_SCHEMAFORSCHEMA) { |
| if (declType == TYPEDECL_TYPE) { |
| Object retObj = SchemaGrammar.SG_SchemaNS.getGlobalTypeDecl(declToTraverse.localpart); |
| if (retObj != null) |
| return retObj; |
| } |
| } |
| |
| XSDocumentInfo schemaWithDecl = null; |
| Element decl = null; |
| |
| String declKey = declToTraverse.uri == null? ","+declToTraverse.localpart: |
| declToTraverse.uri+","+declToTraverse.localpart; |
| switch (declType) { |
| case ATTRIBUTE_TYPE : |
| decl = (Element)fUnparsedAttributeRegistry.get(declKey); |
| break; |
| case ATTRIBUTEGROUP_TYPE : |
| decl = (Element)fUnparsedAttributeGroupRegistry.get(declKey); |
| break; |
| case ELEMENT_TYPE : |
| decl = (Element)fUnparsedElementRegistry.get(declKey); |
| break; |
| case GROUP_TYPE : |
| decl = (Element)fUnparsedGroupRegistry.get(declKey); |
| break; |
| case IDENTITYCONSTRAINT_TYPE : |
| decl = (Element)fUnparsedIdentityConstraintRegistry.get(declKey); |
| break; |
| case NOTATION_TYPE : |
| decl = (Element)fUnparsedNotationRegistry.get(declKey); |
| break; |
| case TYPEDECL_TYPE : |
| decl = (Element)fUnparsedTypeRegistry.get(declKey); |
| break; |
| default: |
| // REVISIT: report internal error... |
| reportGenericSchemaError("XSDHandler asked to locate component of type " + declType + "; it does not recognize this type (internal error!)"); |
| } |
| if (decl != null) |
| schemaWithDecl = findXSDocumentForDecl(currSchema, decl); |
| else { |
| reportSchemaError("src-resolve", new Object[]{declToTraverse.rawname, COMP_TYPE[declType]}); |
| return null; |
| } |
| |
| if (schemaWithDecl == null) { |
| // cannot get to this schema from the one containing the requesting decl |
| reportSchemaError("src-resolve.4", new Object[]{currSchema, declToTraverse.uri}); |
| return null; |
| } |
| SchemaGrammar sGrammar = fGrammarResolver.getGrammar(schemaWithDecl.fTargetNamespace); |
| |
| Object retObj = null; |
| switch (declType) { |
| case ATTRIBUTE_TYPE : |
| retObj = sGrammar.getGlobalAttributeDecl(declToTraverse.localpart); |
| break; |
| case ATTRIBUTEGROUP_TYPE : |
| retObj = sGrammar.getGlobalAttributeGroupDecl(declToTraverse.localpart); |
| break; |
| case ELEMENT_TYPE : |
| retObj = sGrammar.getGlobalElementDecl(declToTraverse.localpart); |
| break; |
| case GROUP_TYPE : |
| retObj = sGrammar.getGlobalGroupDecl(declToTraverse.localpart); |
| break; |
| case IDENTITYCONSTRAINT_TYPE : |
| retObj = sGrammar.getIDConstraintDecl(declToTraverse.localpart); |
| break; |
| case NOTATION_TYPE : |
| retObj = sGrammar.getNotationDecl(declToTraverse.localpart); |
| break; |
| case TYPEDECL_TYPE : |
| retObj = sGrammar.getGlobalTypeDecl(declToTraverse.localpart); |
| break; |
| } |
| |
| if (retObj != null) |
| return retObj; |
| |
| if (DOMUtil.isHidden(decl)) { |
| // decl must not be null if we're here... |
| //REVISIT: report an error: circular reference |
| reportGenericSchemaError("Circular reference detected in schema component named " + declToTraverse.prefix+":"+declToTraverse.localpart); |
| return null; |
| } |
| |
| DOMUtil.setHidden(decl); |
| |
| // back up the current SchemaNamespaceSupport, because we need to provide |
| // a fresh one to the traverseGlobal methods. |
| schemaWithDecl.backupNSSupport(); |
| |
| switch (declType) { |
| case ATTRIBUTE_TYPE : |
| retObj = fAttributeTraverser.traverseGlobal(decl, schemaWithDecl, sGrammar); |
| break; |
| case ATTRIBUTEGROUP_TYPE : |
| retObj = fAttributeGroupTraverser.traverseGlobal(decl, schemaWithDecl, sGrammar); |
| break; |
| case ELEMENT_TYPE : |
| retObj = fElementTraverser.traverseGlobal(decl, schemaWithDecl, sGrammar); |
| break; |
| case GROUP_TYPE : |
| retObj = fGroupTraverser.traverseGlobal(decl, schemaWithDecl, sGrammar); |
| break; |
| case IDENTITYCONSTRAINT_TYPE : |
| // identity constraints should have been parsed already... |
| // we should never get here |
| retObj = null; |
| break; |
| case NOTATION_TYPE : |
| retObj = fNotationTraverser.traverse(decl, schemaWithDecl, sGrammar); |
| break; |
| case TYPEDECL_TYPE : |
| if (DOMUtil.getLocalName(decl).equals(SchemaSymbols.ELT_COMPLEXTYPE)) |
| retObj = fComplexTypeTraverser.traverseGlobal(decl, schemaWithDecl, sGrammar); |
| else |
| retObj = fSimpleTypeTraverser.traverseGlobal(decl, schemaWithDecl, sGrammar); |
| } |
| |
| // restore the previous SchemaNamespaceSupport, so that the caller can get |
| // proper namespace binding. |
| schemaWithDecl.restoreNSSupport(); |
| |
| return retObj; |
| } // getGlobalDecl(XSDocumentInfo, int, QName): Object |
| |
| // This method determines whether there is a group |
| // (attributeGroup) which the given one has redefined by |
| // restriction. If so, it returns it; else it returns null. |
| // @param type: whether what's been redefined is an |
| // attributeGroup or a group; |
| // @param name: the QName of the component doing the redefining. |
| // @param currSchema: schema doc in which the redefining component lives. |
| // @return: Object representing decl redefined if present, null |
| // otherwise. |
| Object getGrpOrAttrGrpRedefinedByRestriction(int type, QName name, XSDocumentInfo currSchema) { |
| String realName = name.uri != null?name.uri+","+name.localpart: |
| ","+name.localpart; |
| String nameToFind = null; |
| switch (type) { |
| case ATTRIBUTEGROUP_TYPE: |
| nameToFind = (String)fRedefinedRestrictedAttributeGroupRegistry.get(realName); |
| break; |
| case GROUP_TYPE: |
| nameToFind = (String)fRedefinedRestrictedGroupRegistry.get(realName); |
| break; |
| default: |
| return null; |
| } |
| if (nameToFind == null) return null; |
| int commaPos = nameToFind.indexOf(","); |
| QName qNameToFind = new QName(EMPTY_STRING, nameToFind.substring(commaPos+1), |
| nameToFind.substring(commaPos), (commaPos == 0)? null : nameToFind.substring(0, commaPos)); |
| Object retObj = getGlobalDecl(currSchema, type, qNameToFind); |
| if(retObj == null) { |
| switch (type) { |
| case ATTRIBUTEGROUP_TYPE: |
| reportSchemaError("src-redefine.7.2.1", new Object []{name.localpart}); |
| break; |
| case GROUP_TYPE: |
| reportSchemaError("src-redefine.6.2.1", new Object []{name.localpart}); |
| break; |
| } |
| return null; |
| } |
| return retObj; |
| } // getGrpOrAttrGrpRedefinedByRestriction(int, QName, XSDocumentInfo): Object |
| |
| // Since ID constraints can occur in local elements, unless we |
| // wish to completely traverse all our DOM trees looking for ID |
| // constraints while we're building our global name registries, |
| // which seems terribly inefficient, we need to resolve keyrefs |
| // after all parsing is complete. This we can simply do by running through |
| // fIdentityConstraintRegistry and calling traverseKeyRef on all |
| // of the KeyRef nodes. This unfortunately removes this knowledge |
| // from the elementTraverser class (which must ignore keyrefs), |
| // but there seems to be no efficient way around this... |
| protected void resolveKeyRefs() { |
| for (int i=0; i<fKeyrefStackPos; i++) { |
| Document keyrefDoc = DOMUtil.getDocument(fKeyrefs[i]); |
| XSDocumentInfo keyrefSchemaDoc = (XSDocumentInfo)fDoc2XSDocumentMap.get(keyrefDoc); |
| keyrefSchemaDoc.fNamespaceSupport.makeGlobal(); |
| keyrefSchemaDoc.fNamespaceSupport.setEffectiveContext( fKeyrefNamespaceContext[i] ); |
| SchemaGrammar keyrefGrammar = fGrammarResolver.getGrammar(keyrefSchemaDoc.fTargetNamespace); |
| // need to set <keyref> to hidden before traversing it, |
| // because it has global scope |
| DOMUtil.setHidden(fKeyrefs[i]); |
| fKeyrefTraverser.traverse(fKeyrefs[i], fKeyrefElems[i], keyrefSchemaDoc, keyrefGrammar); |
| } |
| } // end resolveKeyRefs |
| |
| // an accessor method. Just makes sure callers |
| // who want the Identity constraint registry vaguely know what they're about. |
| protected Hashtable getIDRegistry() { |
| return fUnparsedIdentityConstraintRegistry; |
| } |
| |
| // This method squirrels away <keyref> declarations--along with the element |
| // decls and namespace bindings they might find handy. |
| protected void storeKeyRef (Element keyrefToStore, XSDocumentInfo schemaDoc, |
| XSElementDecl currElemDecl) { |
| String keyrefName = DOMUtil.getAttrValue(keyrefToStore, SchemaSymbols.ATT_NAME); |
| if (keyrefName.length() != 0) { |
| String keyrefQName = schemaDoc.fTargetNamespace == null? |
| "," + keyrefName: schemaDoc.fTargetNamespace+","+keyrefName; |
| checkForDuplicateNames(keyrefQName, fUnparsedIdentityConstraintRegistry, keyrefToStore, schemaDoc); |
| } |
| // now set up all the registries we'll need... |
| |
| // check array sizes |
| if (fKeyrefStackPos == fKeyrefs.length) { |
| Element [] elemArray = new Element [fKeyrefStackPos + INC_KEYREF_STACK_AMOUNT]; |
| System.arraycopy(fKeyrefs, 0, elemArray, 0, fKeyrefStackPos); |
| fKeyrefs = elemArray; |
| XSElementDecl [] declArray = new XSElementDecl [fKeyrefStackPos + INC_KEYREF_STACK_AMOUNT]; |
| System.arraycopy(fKeyrefElems, 0, declArray, 0, fKeyrefStackPos); |
| fKeyrefElems = declArray; |
| String[][] stringArray = new String [fKeyrefStackPos + INC_KEYREF_STACK_AMOUNT][]; |
| System.arraycopy(fKeyrefNamespaceContext, 0, stringArray, 0, fKeyrefStackPos); |
| fKeyrefNamespaceContext = stringArray; |
| } |
| fKeyrefs[fKeyrefStackPos] = keyrefToStore; |
| fKeyrefElems[fKeyrefStackPos] = currElemDecl; |
| fKeyrefNamespaceContext[fKeyrefStackPos++] = schemaDoc.fNamespaceSupport.getEffectiveLocalContext(); |
| } // storeKeyref (Element, XSDocumentInfo, XSElementDecl): void |
| |
| // This method is responsible for schema resolution. If it finds |
| // a schema document that the XMLEntityResolver resolves to with |
| // the given namespace and hint, it returns it. It returns true |
| // if this is the first time it's seen this document, false |
| // otherwise. schemaDoc is null if and only if no schema document |
| // was resolved to. |
| private Document getSchema(String schemaNamespace, String schemaHint, |
| String baseSystemId, boolean mustResolve, boolean useProperties) { |
| // contents of this method will depend on the system we adopt for entity resolution--i.e., XMLEntityHandler, EntityHandler, etc. |
| XMLInputSource schemaSource=null; |
| Document schemaDoc = null; |
| try { |
| schemaSource = fLocationResolver.resolveEntity(schemaNamespace, schemaHint, baseSystemId, useProperties); |
| // REVISIT: when the system id and byte stream and character stream |
| // of the input source are all null, it's |
| // impossible to find the schema document. so we skip in |
| // this case. otherwise we'll receive some NPE or |
| // file not found errors. but schemaHint=="" is perfectly |
| // legal for import. |
| if (schemaSource != null && |
| (schemaSource.getSystemId() != null || |
| schemaSource.getByteStream() != null || |
| schemaSource.getCharacterStream() != null)) { |
| |
| // When the system id of the input source is used, first try to |
| // expand it, and check whether the same document has been |
| // parsed before. If so, return the document corresponding to |
| // that system id. |
| String schemaId = null; |
| if (schemaSource.getByteStream() == null && |
| schemaSource.getCharacterStream() == null) { |
| schemaId = XMLEntityManager.expandSystemId(schemaSource.getSystemId(), schemaSource.getBaseSystemId()); |
| if (fTraversed.get(schemaId) != null) { |
| fLastSchemaWasDuplicate = true; |
| return(Document)(fTraversed.get(schemaId)); |
| } |
| } |
| fSchemaParser.reset(); |
| fSchemaParser.parse(schemaSource); |
| schemaDoc = fSchemaParser.getDocument(); |
| // now we need to store the mapping information from system id |
| // to the document. also from the document to the system id. |
| if (schemaId != null) { |
| fTraversed.put(schemaId, schemaDoc ); |
| fDoc2SystemId.put(schemaDoc, schemaId ); |
| } |
| fLastSchemaWasDuplicate = false; |
| return schemaDoc; |
| } |
| |
| } |
| catch (java.io.FileNotFoundException ex) { |
| // REVISIT: how to report an error for missing files |
| fErrorReporter.reportError(XSMessageFormatter.SCHEMA_DOMAIN, |
| "General", |
| new Object[]{"file not found: " + schemaHint}, |
| // when using namespace, then hint is optional, |
| // and it's not an error if the file is not found |
| // but if not using namespace (include), |
| // it's a warning if the file is not found. |
| mustResolve ? |
| XMLErrorReporter.SEVERITY_ERROR: |
| XMLErrorReporter.SEVERITY_WARNING); |
| } |
| catch (IOException ex) { |
| // REVISIT: report an error! |
| reportGenericSchemaError("error reading schema document: " + schemaHint); |
| } |
| |
| schemaDoc = null; |
| fLastSchemaWasDuplicate = false; |
| return null; |
| } // getSchema(String, String, String, boolean, boolean): Document |
| |
| // initialize all the traversers. |
| // this should only need to be called once during the construction |
| // of this object; it creates the traversers that will be used to |
| |
| // construct schemaGrammars. |
| private void createTraversers() { |
| fAttributeChecker = new XSAttributeChecker(this); |
| fAttributeGroupTraverser = new XSDAttributeGroupTraverser(this, fAttributeChecker); |
| fAttributeTraverser = new XSDAttributeTraverser(this, fAttributeChecker); |
| fComplexTypeTraverser = new XSDComplexTypeTraverser(this, fAttributeChecker); |
| fElementTraverser = new XSDElementTraverser(this, fAttributeChecker); |
| fGroupTraverser = new XSDGroupTraverser(this, fAttributeChecker); |
| fKeyrefTraverser = new XSDKeyrefTraverser(this, fAttributeChecker); |
| fNotationTraverser = new XSDNotationTraverser(this, fAttributeChecker); |
| fSimpleTypeTraverser = new XSDSimpleTypeTraverser(this, fAttributeChecker); |
| fUniqueOrKeyTraverser = new XSDUniqueOrKeyTraverser(this, fAttributeChecker); |
| fWildCardTraverser = new XSDWildcardTraverser(this, fAttributeChecker); |
| } // createTraversers() |
| |
| // this method clears all the global structs of this object |
| // (except those passed in via the constructor). |
| public void reset(XMLErrorReporter errorReporter, |
| XMLEntityResolver entityResolver, |
| SymbolTable symbolTable, |
| String externalSchemaLocation, |
| String externalNoNSSchemaLocation) { |
| |
| fErrorReporter = errorReporter; |
| fSymbolTable = symbolTable; |
| |
| EMPTY_STRING = fSymbolTable.addSymbol(SchemaSymbols.EMPTY_STRING); |
| |
| fLocationResolver.reset(entityResolver, externalSchemaLocation, externalNoNSSchemaLocation); |
| |
| try { |
| fSchemaParser.setProperty(XMLSchemaValidator.ERROR_REPORTER, fErrorReporter); |
| } |
| catch (Exception e) { |
| } |
| |
| fUnparsedAttributeRegistry.clear(); |
| fUnparsedAttributeGroupRegistry.clear(); |
| fUnparsedElementRegistry.clear(); |
| fUnparsedGroupRegistry.clear(); |
| fUnparsedIdentityConstraintRegistry.clear(); |
| fUnparsedNotationRegistry.clear(); |
| fUnparsedTypeRegistry.clear(); |
| |
| fXSDocumentInfoRegistry.clear(); |
| fDependencyMap.clear(); |
| fTraversed.clear(); |
| fDoc2SystemId.clear(); |
| fDoc2XSDocumentMap.clear(); |
| fRedefine2XSDMap.clear(); |
| fRoot = null; |
| fLastSchemaWasDuplicate = false; |
| |
| fLocalElemStackPos = 0; |
| fParticle = new XSParticleDecl[INIT_STACK_SIZE]; |
| fLocalElementDecl = new Element[INIT_STACK_SIZE]; |
| fAllContext = new int[INIT_STACK_SIZE]; |
| // err on the small side for num. of local namespaces declared... |
| fLocalElemNamespaceContext = new String [INIT_STACK_SIZE][1]; |
| |
| // and do same for keyrefs. |
| fKeyrefStackPos = 0; |
| fKeyrefs = new Element[INIT_KEYREF_STACK]; |
| fKeyrefElems = new XSElementDecl [INIT_KEYREF_STACK]; |
| fKeyrefNamespaceContext = new String[INIT_KEYREF_STACK][1]; |
| |
| // reset traversers |
| fAttributeChecker.reset(fErrorReporter, fSymbolTable); |
| fAttributeGroupTraverser.reset(fErrorReporter, fSymbolTable); |
| fAttributeTraverser.reset(fErrorReporter, fSymbolTable); |
| fComplexTypeTraverser.reset(fErrorReporter, fSymbolTable); |
| fElementTraverser.reset(fErrorReporter, fSymbolTable); |
| fGroupTraverser.reset(fErrorReporter, fSymbolTable); |
| fKeyrefTraverser.reset(fErrorReporter, fSymbolTable); |
| fNotationTraverser.reset(fErrorReporter, fSymbolTable); |
| fSimpleTypeTraverser.reset(fErrorReporter, fSymbolTable); |
| fUniqueOrKeyTraverser.reset(fErrorReporter, fSymbolTable); |
| fWildCardTraverser.reset(fErrorReporter, fSymbolTable); |
| |
| fRedefinedRestrictedAttributeGroupRegistry.clear(); |
| fRedefinedRestrictedGroupRegistry.clear(); |
| } // reset(ErrorReporter, EntityResolver, SymbolTable) |
| |
| /** |
| * Traverse all the deferred local elements. This method should be called |
| * by traverseSchemas after we've done with all the global declarations. |
| */ |
| void traverseLocalElements() { |
| fElementTraverser.fDeferTraversingLocalElements = false; |
| |
| for (int i = 0; i < fLocalElemStackPos; i++) { |
| Element currElem = fLocalElementDecl[i]; |
| XSDocumentInfo currSchema = (XSDocumentInfo)fDoc2XSDocumentMap.get(DOMUtil.getDocument(currElem)); |
| SchemaGrammar currGrammar = fGrammarResolver.getGrammar(currSchema.fTargetNamespace); |
| fElementTraverser.traverseLocal (fParticle[i], currElem, currSchema, currGrammar, fAllContext[i]); |
| } |
| } |
| |
| // the purpose of this method is to keep up-to-date structures |
| // we'll need for the feferred traversal of local elements. |
| void fillInLocalElemInfo(Element elmDecl, |
| XSDocumentInfo schemaDoc, |
| int allContextFlags, |
| XSParticleDecl particle) { |
| |
| // if the stack is full, increase the size |
| if (fParticle.length == fLocalElemStackPos) { |
| // increase size |
| XSParticleDecl[] newStackP = new XSParticleDecl[fLocalElemStackPos+INC_STACK_SIZE]; |
| System.arraycopy(fParticle, 0, newStackP, 0, fLocalElemStackPos); |
| fParticle = newStackP; |
| Element[] newStackE = new Element[fLocalElemStackPos+INC_STACK_SIZE]; |
| System.arraycopy(fLocalElementDecl, 0, newStackE, 0, fLocalElemStackPos); |
| fLocalElementDecl = newStackE; |
| int[] newStackI = new int[fLocalElemStackPos+INC_STACK_SIZE]; |
| System.arraycopy(fAllContext, 0, newStackI, 0, fLocalElemStackPos); |
| fAllContext = newStackI; |
| String [][] newStackN = new String [fLocalElemStackPos+INC_STACK_SIZE][]; |
| System.arraycopy(fLocalElemNamespaceContext, 0, newStackN, 0, fLocalElemStackPos); |
| fLocalElemNamespaceContext = newStackN; |
| } |
| |
| fParticle[fLocalElemStackPos] = particle; |
| fLocalElementDecl[fLocalElemStackPos] = elmDecl; |
| fAllContext[fLocalElemStackPos] = allContextFlags; |
| fLocalElemNamespaceContext[fLocalElemStackPos++] = schemaDoc.fNamespaceSupport.getEffectiveLocalContext(); |
| } // end fillInLocalElemInfo(...) |
| |
| /** This method makes sure that |
| * if this component is being redefined that it lives in the |
| * right schema. It then renames the component correctly. If it |
| * detects a collision--a duplicate definition--then it complains. |
| * Note that redefines must be handled carefully: if there |
| * is a collision, it may be because we're redefining something we know about |
| * or because we've found the thing we're redefining. |
| */ |
| void checkForDuplicateNames(String qName, |
| Hashtable registry, Element currComp, |
| XSDocumentInfo currSchema) { |
| Object objElem = null; |
| // REVISIT: when we add derivation checking, we'll have to make |
| // sure that ID constraint collisions don't necessarily result in error messages. |
| if ((objElem = registry.get(qName)) == null) { |
| // just add it in! |
| registry.put(qName, currComp); |
| } |
| else { |
| Element collidingElem = (Element)objElem; |
| if (collidingElem == currComp) return; |
| Element elemParent = null; |
| XSDocumentInfo redefinedSchema = null; |
| // case where we've collided with a redefining element |
| // (the parent of the colliding element is a redefine) |
| boolean collidedWithRedefine = true; |
| if ((DOMUtil.getLocalName((elemParent = DOMUtil.getParent(collidingElem))).equals(SchemaSymbols.ELT_REDEFINE))) { |
| redefinedSchema = (XSDocumentInfo)(fRedefine2XSDMap.get(elemParent)); |
| // case where we're a redefining element. |
| } |
| else if ((DOMUtil.getLocalName(DOMUtil.getParent(currComp)).equals(SchemaSymbols.ELT_REDEFINE))) { |
| redefinedSchema = (XSDocumentInfo)(fDoc2XSDocumentMap.get(DOMUtil.getDocument(collidingElem))); |
| collidedWithRedefine = false; |
| } |
| if (redefinedSchema != null) { //redefinition involved somehow |
| String newName = qName.substring(qName.lastIndexOf(',')+1)+REDEF_IDENTIFIER; |
| if (redefinedSchema == currSchema) { // object comp. okay here |
| // now have to do some renaming... |
| currComp.setAttribute(SchemaSymbols.ATT_NAME, newName); |
| if (currSchema.fTargetNamespace == null) |
| registry.put(","+newName, currComp); |
| else |
| registry.put(currSchema.fTargetNamespace+","+newName, currComp); |
| // and take care of nested redefines by calling recursively: |
| if (currSchema.fTargetNamespace == null) |
| checkForDuplicateNames(","+newName, registry, currComp, currSchema); |
| else |
| checkForDuplicateNames(currSchema.fTargetNamespace+","+newName, registry, currComp, currSchema); |
| } |
| else { // we may be redefining the wrong schema |
| if (collidedWithRedefine) { |
| if (currSchema.fTargetNamespace == null) |
| checkForDuplicateNames(","+newName, registry, currComp, currSchema); |
| else |
| checkForDuplicateNames(currSchema.fTargetNamespace+","+newName, registry, currComp, currSchema); |
| } |
| else { |
| // REVISIT: error that redefined element in wrong schema |
| reportSchemaError("src-redefine.1", new Object [] {qName}); |
| } |
| } |
| } |
| else { // we've just got a flat-out collision |
| reportSchemaError("sch-props-correct.2", new Object []{qName}); |
| } |
| } |
| } // checkForDuplicateNames(String, Hashtable, Element, XSDocumentInfo):void |
| |
| |
| // |
| //!!!!!!!!!!!!!!!! IMPLEMENT the following functions !!!!!!!!!! |
| // |
| //REVISIT: implement namescope support!!! |
| protected String resolvePrefixToURI (String prefix) { |
| //String uriStr = fStringPool.toString(fNamespacesScope.getNamespaceForPrefix(fStringPool.addSymbol(prefix))); |
| //if (uriStr.length() == 0 && prefix.length() > 0) { |
| // REVISIT: Localize |
| //// REVISIT: reportGenericSchemaError("prefix : [" + prefix +"] cannot be resolved to a URI"); |
| //return ""; |
| //} |
| |
| return null; |
| } |
| |
| // the purpose of this method is to take the component of the |
| // specified type and rename references to itself so that they |
| // refer to the object being redefined. It takes special care of |
| // <group>s and <attributeGroup>s to ensure that information |
| // relating to implicit restrictions is preserved for those |
| // traversers. |
| private void renameRedefiningComponents(XSDocumentInfo currSchema, |
| Element child, String componentType, |
| String oldName, String newName) { |
| |
| SchemaNamespaceSupport currNSMap = currSchema.fNamespaceSupport; |
| if (componentType.equals(SchemaSymbols.ELT_SIMPLETYPE)) { |
| String processedTypeName = currSchema.fTargetNamespace == null? |
| ","+oldName:currSchema.fTargetNamespace+","+oldName; |
| Element grandKid = DOMUtil.getFirstChildElement(child); |
| if (grandKid == null) { |
| // fRedefineSucceeded = false; |
| reportSchemaError("src-redefine.5", null); |
| } |
| else { |
| String grandKidName = grandKid.getLocalName(); |
| if (grandKidName.equals(SchemaSymbols.ELT_ANNOTATION)) { |
| grandKid = DOMUtil.getNextSiblingElement(grandKid); |
| grandKidName = grandKid.getLocalName(); |
| } |
| if (grandKid == null) { |
| // fRedefineSucceeded = false; |
| reportSchemaError("src-redefine.5", null); |
| } |
| else if (!grandKidName.equals(SchemaSymbols.ELT_RESTRICTION)) { |
| // fRedefineSucceeded = false; |
| reportSchemaError("src-redefine.5", null); |
| } |
| else { |
| String derivedBase = grandKid.getAttribute( SchemaSymbols.ATT_BASE ); |
| String processedDerivedBase = findQName(derivedBase, currSchema); |
| if (!processedTypeName.equals(processedDerivedBase)) { |
| // fRedefineSucceeded = false; |
| reportSchemaError("src-redefine.5", null); |
| } |
| else { |
| // now we have to do the renaming... |
| int colonptr = derivedBase.indexOf(":"); |
| if (colonptr > 0) |
| grandKid.setAttribute( SchemaSymbols.ATT_BASE, |
| derivedBase.substring(0,colonptr) + ":" + newName ); |
| else |
| grandKid.setAttribute( SchemaSymbols.ATT_BASE, newName ); |
| // return true; |
| } |
| } |
| } |
| } |
| else if (componentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) { |
| String processedTypeName = currSchema.fTargetNamespace == null? |
| ","+oldName:currSchema.fTargetNamespace+","+oldName; |
| Element grandKid = DOMUtil.getFirstChildElement(child); |
| if (grandKid == null) { |
| // fRedefineSucceeded = false; |
| reportSchemaError("src-redefine.5", null); |
| } |
| else { |
| if (grandKid.getLocalName().equals(SchemaSymbols.ELT_ANNOTATION)) { |
| grandKid = DOMUtil.getNextSiblingElement(grandKid); |
| } |
| if (grandKid == null) { |
| // fRedefineSucceeded = false; |
| reportSchemaError("src-redefine.5", null); |
| } |
| else { |
| // have to go one more level down; let another pass worry whether complexType is valid. |
| Element greatGrandKid = DOMUtil.getFirstChildElement(grandKid); |
| if (greatGrandKid == null) { |
| // fRedefineSucceeded = false; |
| reportSchemaError("src-redefine.5", null); |
| } |
| else { |
| String greatGrandKidName = greatGrandKid.getLocalName(); |
| if (greatGrandKidName.equals(SchemaSymbols.ELT_ANNOTATION)) { |
| greatGrandKid = DOMUtil.getNextSiblingElement(greatGrandKid); |
| greatGrandKidName = greatGrandKid.getLocalName(); |
| } |
| if (greatGrandKid == null) { |
| // fRedefineSucceeded = false; |
| reportSchemaError("src-redefine.5", null); |
| } |
| else if (!greatGrandKidName.equals(SchemaSymbols.ELT_RESTRICTION) && |
| !greatGrandKidName.equals(SchemaSymbols.ELT_EXTENSION)) { |
| // fRedefineSucceeded = false; |
| reportSchemaError("src-redefine.5", null); |
| } |
| else { |
| String derivedBase = greatGrandKid.getAttribute( SchemaSymbols.ATT_BASE ); |
| String processedDerivedBase = findQName(derivedBase, currSchema); |
| if (!processedTypeName.equals(processedDerivedBase)) { |
| // fRedefineSucceeded = false; |
| reportSchemaError("src-redefine.5", null); |
| } |
| else { |
| // now we have to do the renaming... |
| int colonptr = derivedBase.indexOf(":"); |
| if (colonptr > 0) |
| greatGrandKid.setAttribute( SchemaSymbols.ATT_BASE, |
| derivedBase.substring(0,colonptr) + ":" + newName ); |
| else |
| greatGrandKid.setAttribute( SchemaSymbols.ATT_BASE, |
| newName ); |
| // return true; |
| } |
| } |
| } |
| } |
| } |
| } |
| else if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) { |
| String processedBaseName = (currSchema.fTargetNamespace == null)? |
| ","+oldName:currSchema.fTargetNamespace+","+oldName; |
| int attGroupRefsCount = changeRedefineGroup(processedBaseName, componentType, newName, child, currSchema); |
| if (attGroupRefsCount > 1) { |
| // fRedefineSucceeded = false; |
| reportSchemaError("src-redefine.7.1", new Object []{new Integer(attGroupRefsCount)}); |
| } |
| else if (attGroupRefsCount == 1) { |
| // return true; |
| } |
| else |
| if (currSchema.fTargetNamespace == null) |
| fRedefinedRestrictedAttributeGroupRegistry.put(processedBaseName, ","+newName); |
| else |
| fRedefinedRestrictedAttributeGroupRegistry.put(processedBaseName, currSchema.fTargetNamespace+","+newName); |
| } |
| else if (componentType.equals(SchemaSymbols.ELT_GROUP)) { |
| String processedBaseName = (currSchema.fTargetNamespace == null)? |
| ","+oldName:currSchema.fTargetNamespace+","+oldName; |
| int groupRefsCount = changeRedefineGroup(processedBaseName, componentType, newName, child, currSchema); |
| if (groupRefsCount > 1) { |
| // fRedefineSucceeded = false; |
| reportSchemaError("src-redefine.6.1.1", new Object []{new Integer(groupRefsCount)}); |
| } |
| else if (groupRefsCount == 1) { |
| // return true; |
| } |
| else { |
| if (currSchema.fTargetNamespace == null) |
| fRedefinedRestrictedGroupRegistry.put(processedBaseName, ","+newName); |
| else |
| fRedefinedRestrictedGroupRegistry.put(processedBaseName, currSchema.fTargetNamespace+","+newName); |
| } |
| } |
| else { |
| // fRedefineSucceeded = false; |
| // REVISIT: Localize |
| reportGenericSchemaError("internal Xerces error; please submit a bug with schema as testcase"); |
| } |
| // if we get here then we must have reported an error and failed somewhere... |
| // return false; |
| } // renameRedefiningComponents(XSDocumentInfo, Element, String, String, String):void |
| |
| // this method takes a name of the form a:b, determines the URI mapped |
| // to by a in the current SchemaNamespaceSupport object, and returns this |
| // information in the form (nsURI,b) suitable for lookups in the global |
| // decl Hashtables. |
| // REVISIT: should have it return QName, instead of String. this would |
| // save lots of string concatenation time. we can use |
| // QName#equals() to compare two QNames, and use QName directly |
| // as a key to the SymbolHash. |
| // And when the DV's are ready to return compiled values from |
| // validate() method, we should just call QNameDV.validate() |
| // in this method. |
| private String findQName(String name, XSDocumentInfo schemaDoc) { |
| SchemaNamespaceSupport currNSMap = schemaDoc.fNamespaceSupport; |
| int colonPtr = name.indexOf(':'); |
| String prefix = EMPTY_STRING; |
| if (colonPtr > 0) |
| prefix = name.substring(0, colonPtr); |
| String uri = currNSMap.getURI(fSymbolTable.addSymbol(prefix)); |
| String localpart = (colonPtr == 0)?name:name.substring(colonPtr+1); |
| if (prefix == this.EMPTY_STRING && uri == null && schemaDoc.fIsChameleonSchema) |
| uri = schemaDoc.fTargetNamespace; |
| if (uri == null) |
| return ","+localpart; |
| return uri+","+localpart; |
| } // findQName(String, XSDocumentInfo): String |
| |
| // This function looks among the children of curr for an element of type elementSought. |
| // If it finds one, it evaluates whether its ref attribute contains a reference |
| // to originalQName. If it does, it returns 1 + the value returned by |
| // calls to itself on all other children. In all other cases it returns 0 plus |
| // the sum of the values returned by calls to itself on curr's children. |
| // It also resets the value of ref so that it will refer to the renamed type from the schema |
| // being redefined. |
| private int changeRedefineGroup(String originalQName, String elementSought, |
| String newName, Element curr, XSDocumentInfo schemaDoc) { |
| SchemaNamespaceSupport currNSMap = schemaDoc.fNamespaceSupport; |
| int result = 0; |
| for (Element child = DOMUtil.getFirstChildElement(curr); |
| child != null; child = DOMUtil.getNextSiblingElement(child)) { |
| String name = child.getLocalName(); |
| if (!name.equals(elementSought)) |
| result += changeRedefineGroup(originalQName, elementSought, newName, child, schemaDoc); |
| else { |
| String ref = child.getAttribute( SchemaSymbols.ATT_REF ); |
| if (ref.length() != 0) { |
| String processedRef = findQName(ref, schemaDoc); |
| if (originalQName.equals(processedRef)) { |
| String prefix = EMPTY_STRING; |
| String localpart = ref; |
| int colonptr = ref.indexOf(":"); |
| if (colonptr > 0) { |
| prefix = ref.substring(0,colonptr); |
| child.setAttribute(SchemaSymbols.ATT_REF, prefix + ":" + newName); |
| } |
| else |
| child.setAttribute(SchemaSymbols.ATT_REF, newName); |
| result++; |
| if (elementSought.equals(SchemaSymbols.ELT_GROUP)) { |
| String minOccurs = child.getAttribute( SchemaSymbols.ATT_MINOCCURS ); |
| String maxOccurs = child.getAttribute( SchemaSymbols.ATT_MAXOCCURS ); |
| if (!((maxOccurs.length() == 0 || maxOccurs.equals("1")) |
| && (minOccurs.length() == 0 || minOccurs.equals("1")))) { |
| reportSchemaError("src-redefine.6.1.2", new Object [] {ref}); |
| } |
| } |
| } |
| } // if ref was null some other stage of processing will flag the error |
| } |
| } |
| return result; |
| } // changeRedefineGroup |
| |
| // this method returns the XSDocumentInfo object that contains the |
| // component corresponding to decl. If components from this |
| // document cannot be referred to from those of currSchema, this |
| // method returns null; it's up to the caller to throw an error. |
| // @param: currSchema: the XSDocumentInfo object containing the |
| // decl ref'ing us. |
| // @param: decl: the declaration being ref'd. |
| private XSDocumentInfo findXSDocumentForDecl(XSDocumentInfo currSchema, |
| Element decl) { |
| Document declDoc = DOMUtil.getDocument(decl); |
| Object temp = fDoc2XSDocumentMap.get(declDoc); |
| if (temp == null) { |
| // something went badly wrong; we don't know this doc? |
| return null; |
| } |
| XSDocumentInfo declDocInfo = (XSDocumentInfo)temp; |
| return declDocInfo; |
| /********* |
| Logic here is unnecessary after schema WG's recent decision to allow |
| schema components from one document to refer to components of any other, |
| so long as there's some include/import/redefine path amongst them. |
| If they rver reverse this decision the code's right here though... - neilg |
| // now look in fDependencyMap to see if this is reachable |
| if(((Vector)fDependencyMap.get(currSchema)).contains(declDocInfo)) { |
| return declDocInfo; |
| } |
| // obviously the requesting doc didn't include, redefine or |
| // import the one containing decl... |
| return null; |
| **********/ |
| } // findXSDocumentForDecl(XSDocumentInfo, Element): XSDocumentInfo |
| |
| // returns whether more than <annotation>s occur in children of elem |
| private boolean nonAnnotationContent(Element elem) { |
| for(Element child = DOMUtil.getFirstChildElement(elem); child != null; child = DOMUtil.getNextSiblingElement(child)) { |
| if(!(DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION))) return true; |
| } |
| return false; |
| } // nonAnnotationContent(Element): boolean |
| |
| private void setSchemasVisible(XSDocumentInfo startSchema) { |
| if (DOMUtil.isHidden(startSchema.fSchemaDoc)) { |
| // make it visible |
| DOMUtil.setVisible(startSchema.fSchemaDoc); |
| Vector dependingSchemas = (Vector)fDependencyMap.get(startSchema); |
| for (int i = 0; i < dependingSchemas.size(); i++) { |
| setSchemasVisible((XSDocumentInfo)dependingSchemas.elementAt(i)); |
| } |
| } |
| // if it's visible already than so must be its children |
| } // setSchemasVisible(XSDocumentInfo): void |
| |
| // report schema error |
| void reportSchemaError (String key, Object[] args) { |
| fErrorReporter.reportError(XSMessageFormatter.SCHEMA_DOMAIN, |
| key, args, |
| XMLErrorReporter.SEVERITY_ERROR); |
| } |
| |
| // REVISIT: is it how we want to handle error reporting? |
| void reportGenericSchemaError (String error) { |
| fErrorReporter.reportError(XSMessageFormatter.SCHEMA_DOMAIN, |
| "General", |
| new Object[]{error}, |
| XMLErrorReporter.SEVERITY_ERROR); |
| } |
| |
| } // XSDHandler |