| |
| /* |
| * The Apache Software License, Version 1.1 |
| * |
| * |
| * Copyright (c) 2000 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.validators.schema; |
| |
| import org.apache.xerces.framework.XMLErrorReporter; |
| import org.apache.xerces.validators.common.Grammar; |
| import org.apache.xerces.validators.common.GrammarResolver; |
| import org.apache.xerces.validators.common.GrammarResolverImpl; |
| import org.apache.xerces.validators.common.XMLElementDecl; |
| import org.apache.xerces.validators.common.XMLAttributeDecl; |
| import org.apache.xerces.validators.schema.SchemaSymbols; |
| import org.apache.xerces.validators.schema.XUtil; |
| import org.apache.xerces.validators.datatype.DatatypeValidator; |
| import org.apache.xerces.validators.datatype.DatatypeValidatorFactoryImpl; |
| import org.apache.xerces.validators.datatype.InvalidDatatypeValueException; |
| import org.apache.xerces.utils.StringPool; |
| import org.w3c.dom.Element; |
| |
| //REVISIT: for now, import everything in the DOM package |
| import org.w3c.dom.*; |
| import java.util.*; |
| import java.net.URL; |
| import java.net.MalformedURLException; |
| |
| //Unit Test |
| import org.apache.xerces.parsers.DOMParser; |
| import org.apache.xerces.validators.common.XMLValidator; |
| import org.apache.xerces.validators.datatype.DatatypeValidator.*; |
| import org.apache.xerces.validators.datatype.InvalidDatatypeValueException; |
| import org.apache.xerces.framework.XMLContentSpec; |
| import org.apache.xerces.utils.QName; |
| import org.apache.xerces.utils.NamespacesScope; |
| import org.apache.xerces.parsers.SAXParser; |
| import org.apache.xerces.framework.XMLParser; |
| import org.apache.xerces.framework.XMLDocumentScanner; |
| |
| import org.xml.sax.InputSource; |
| import org.xml.sax.SAXParseException; |
| import org.xml.sax.EntityResolver; |
| import org.xml.sax.ErrorHandler; |
| import org.xml.sax.SAXException; |
| import java.io.IOException; |
| import org.w3c.dom.Document; |
| import org.apache.xml.serialize.OutputFormat; |
| import org.apache.xml.serialize.XMLSerializer; |
| import org.apache.xerces.validators.schema.SchemaSymbols; |
| |
| |
| |
| |
| /** |
| * Instances of this class get delegated to Traverse the Schema and |
| * to populate the Grammar internal representation by |
| * instances of Grammar objects. |
| * Traverse a Schema Grammar: |
| * As of April 07, 2000 the following is the |
| * XML Representation of Schemas and Schema components, |
| * Chapter 4 of W3C Working Draft. |
| * <schema |
| * attributeFormDefault = qualified | unqualified |
| * blockDefault = #all or (possibly empty) subset of {equivClass, extension, restriction} |
| * elementFormDefault = qualified | unqualified |
| * finalDefault = #all or (possibly empty) subset of {extension, restriction} |
| * id = ID |
| * targetNamespace = uriReference |
| * version = string> |
| * Content: ((include | import | annotation)* , ((simpleType | complexType | element | group | attribute | attributeGroup | notation) , annotation*)+) |
| * </schema> |
| * |
| * |
| * <attribute |
| * form = qualified | unqualified |
| * id = ID |
| * name = NCName |
| * ref = QName |
| * type = QName |
| * use = default | fixed | optional | prohibited | required |
| * value = string> |
| * Content: (annotation? , simpleType?) |
| * </> |
| * |
| * <element |
| * abstract = boolean |
| * block = #all or (possibly empty) subset of {equivClass, extension, restriction} |
| * default = string |
| * equivClass = QName |
| * final = #all or (possibly empty) subset of {extension, restriction} |
| * fixed = string |
| * form = qualified | unqualified |
| * id = ID |
| * maxOccurs = string |
| * minOccurs = nonNegativeInteger |
| * name = NCName |
| * nullable = boolean |
| * ref = QName |
| * type = QName> |
| * Content: (annotation? , (simpleType | complexType)? , (unique | key | keyref)*) |
| * </> |
| * |
| * |
| * <complexType |
| * abstract = boolean |
| * base = QName |
| * block = #all or (possibly empty) subset of {extension, restriction} |
| * content = elementOnly | empty | mixed | textOnly |
| * derivedBy = extension | restriction |
| * final = #all or (possibly empty) subset of {extension, restriction} |
| * id = ID |
| * name = NCName> |
| * Content: (annotation? , (((minExclusive | minInclusive | maxExclusive | maxInclusive | precision | scale | length | minLength | maxLength | encoding | period | duration | enumeration | pattern)* | (element | group | all | choice | sequence | any)*) , ((attribute | attributeGroup)* , anyAttribute?))) |
| * </> |
| * |
| * |
| * <attributeGroup |
| * id = ID |
| * name = NCName |
| * ref = QName> |
| * Content: (annotation?, (attribute|attributeGroup), anyAttribute?) |
| * </> |
| * |
| * <anyAttribute |
| * id = ID |
| * namespace = ##any | ##other | ##local | list of {uri, ##targetNamespace}> |
| * Content: (annotation?) |
| * </anyAttribute> |
| * |
| * <group |
| * id = ID |
| * maxOccurs = string |
| * minOccurs = nonNegativeInteger |
| * name = NCName |
| * ref = QName> |
| * Content: (annotation? , (element | group | all | choice | sequence | any)*) |
| * </> |
| * |
| * <all |
| * id = ID |
| * maxOccurs = string |
| * minOccurs = nonNegativeInteger> |
| * Content: (annotation? , (element | group | choice | sequence | any)*) |
| * </all> |
| * |
| * <choice |
| * id = ID |
| * maxOccurs = string |
| * minOccurs = nonNegativeInteger> |
| * Content: (annotation? , (element | group | choice | sequence | any)*) |
| * </choice> |
| * |
| * <sequence |
| * id = ID |
| * maxOccurs = string |
| * minOccurs = nonNegativeInteger> |
| * Content: (annotation? , (element | group | choice | sequence | any)*) |
| * </sequence> |
| * |
| * |
| * <any |
| * id = ID |
| * maxOccurs = string |
| * minOccurs = nonNegativeInteger |
| * namespace = ##any | ##other | ##local | list of {uri, ##targetNamespace} |
| * processContents = lax | skip | strict> |
| * Content: (annotation?) |
| * </any> |
| * |
| * <unique |
| * id = ID |
| * name = NCName> |
| * Content: (annotation? , (selector , field+)) |
| * </unique> |
| * |
| * <key |
| * id = ID |
| * name = NCName> |
| * Content: (annotation? , (selector , field+)) |
| * </key> |
| * |
| * <keyref |
| * id = ID |
| * name = NCName |
| * refer = QName> |
| * Content: (annotation? , (selector , field+)) |
| * </keyref> |
| * |
| * <selector> |
| * Content: XPathExprApprox : An XPath expression |
| * </selector> |
| * |
| * <field> |
| * Content: XPathExprApprox : An XPath expression |
| * </field> |
| * |
| * |
| * <notation |
| * id = ID |
| * name = NCName |
| * public = A public identifier, per ISO 8879 |
| * system = uriReference> |
| * Content: (annotation?) |
| * </notation> |
| * |
| * <annotation> |
| * Content: (appinfo | documentation)* |
| * </annotation> |
| * |
| * <include |
| * id = ID |
| * schemaLocation = uriReference> |
| * Content: (annotation?) |
| * </include> |
| * |
| * <import |
| * id = ID |
| * namespace = uriReference |
| * schemaLocation = uriReference> |
| * Content: (annotation?) |
| * </import> |
| * |
| * <simpleType |
| * abstract = boolean |
| * base = QName |
| * derivedBy = | list | restriction : restriction |
| * id = ID |
| * name = NCName> |
| * Content: ( annotation? , ( minExclusive | minInclusive | maxExclusive | maxInclusive | precision | scale | length | minLength | maxLength | encoding | period | duration | enumeration | pattern )* ) |
| * </simpleType> |
| * |
| * <length |
| * id = ID |
| * value = nonNegativeInteger> |
| * Content: ( annotation? ) |
| * </length> |
| * |
| * <minLength |
| * id = ID |
| * value = nonNegativeInteger> |
| * Content: ( annotation? ) |
| * </minLength> |
| * |
| * <maxLength |
| * id = ID |
| * value = nonNegativeInteger> |
| * Content: ( annotation? ) |
| * </maxLength> |
| * |
| * |
| * <pattern |
| * id = ID |
| * value = string> |
| * Content: ( annotation? ) |
| * </pattern> |
| * |
| * |
| * <enumeration |
| * id = ID |
| * value = string> |
| * Content: ( annotation? ) |
| * </enumeration> |
| * |
| * <maxInclusive |
| * id = ID |
| * value = string> |
| * Content: ( annotation? ) |
| * </maxInclusive> |
| * |
| * <maxExclusive |
| * id = ID |
| * value = string> |
| * Content: ( annotation? ) |
| * </maxExclusive> |
| * |
| * <minInclusive |
| * id = ID |
| * value = string> |
| * Content: ( annotation? ) |
| * </minInclusive> |
| * |
| * |
| * <minExclusive |
| * id = ID |
| * value = string> |
| * Content: ( annotation? ) |
| * </minExclusive> |
| * |
| * <precision |
| * id = ID |
| * value = nonNegativeInteger> |
| * Content: ( annotation? ) |
| * </precision> |
| * |
| * <scale |
| * id = ID |
| * value = nonNegativeInteger> |
| * Content: ( annotation? ) |
| * </scale> |
| * |
| * <encoding |
| * id = ID |
| * value = | hex | base64 > |
| * Content: ( annotation? ) |
| * </encoding> |
| * |
| * |
| * <duration |
| * id = ID |
| * value = timeDuration> |
| * Content: ( annotation? ) |
| * </duration> |
| * |
| * <period |
| * id = ID |
| * value = timeDuration> |
| * Content: ( annotation? ) |
| * </period> |
| * |
| * |
| * @author Eric Ye, Jeffrey Rodriguez, Andy Clark |
| * |
| * @see org.apache.xerces.validators.common.Grammar |
| * |
| * @version $Id$ |
| */ |
| |
| public class TraverseSchema implements |
| NamespacesScope.NamespacesHandler{ |
| |
| |
| //CONSTANTS |
| private static final int TOP_LEVEL_SCOPE = -1; |
| |
| //debuggin |
| private static boolean DEBUGGING = false; |
| |
| //private data members |
| |
| |
| private XMLErrorReporter fErrorReporter = null; |
| private StringPool fStringPool = null; |
| |
| private GrammarResolver fGrammarResolver = null; |
| private SchemaGrammar fSchemaGrammar = null; |
| |
| private Element fSchemaRootElement; |
| |
| private DatatypeValidatorFactoryImpl fDatatypeRegistry = |
| DatatypeValidatorFactoryImpl.getDatatypeRegistry(); |
| |
| private Hashtable fComplexTypeRegistry = new Hashtable(); |
| private Hashtable fAttributeDeclRegistry = new Hashtable(); |
| |
| private Vector fIncludeLocations = new Vector(); |
| private Vector fImportLocations = new Vector(); |
| |
| |
| private int fAnonTypeCount =0; |
| private int fScopeCount=0; |
| private int fCurrentScope=TOP_LEVEL_SCOPE; |
| private int fSimpleTypeAnonCount = 0; |
| private Stack fCurrentTypeNameStack = new Stack(); |
| private Hashtable fElementRecurseComplex = new Hashtable(); |
| |
| private boolean fElementDefaultQualified = false; |
| private boolean fAttributeDefaultQualified = false; |
| |
| private int fTargetNSURI; |
| private String fTargetNSURIString = ""; |
| private NamespacesScope fNamespacesScope = null; |
| private String fCurrentSchemaURL = ""; |
| |
| private XMLAttributeDecl fTempAttributeDecl = new XMLAttributeDecl(); |
| private XMLElementDecl fTempElementDecl = new XMLElementDecl(); |
| |
| // REVISIT: maybe need to be moved into SchemaGrammar class |
| public class ComplexTypeInfo { |
| public String typeName; |
| |
| public DatatypeValidator baseDataTypeValidator; |
| public ComplexTypeInfo baseComplexTypeInfo; |
| |
| public int derivedBy = 0; |
| public int blockSet = 0; |
| public int finalSet = 0; |
| |
| public boolean isAbstract = false; |
| |
| public int scopeDefined = -1; |
| |
| public int contentType; |
| public int contentSpecHandle = -1; |
| public int templateElementIndex = -1; |
| public int attlistHead = -1; |
| public DatatypeValidator datatypeValidator; |
| } |
| |
| |
| //REVISIT: verify the URI. |
| public final static String SchemaForSchemaURI = "http://www.w3.org/TR-1/Schema"; |
| |
| private TraverseSchema( ) { |
| // new TraverseSchema() is forbidden; |
| } |
| |
| |
| public void setGrammarResolver(GrammarResolver grammarResolver){ |
| fGrammarResolver = grammarResolver; |
| } |
| public void startNamespaceDeclScope(int prefix, int uri){ |
| //TO DO |
| } |
| public void endNamespaceDeclScope(int prefix){ |
| //TO DO, do we need to do anything here? |
| } |
| |
| |
| |
| private String resolvePrefixToURI (String prefix) throws Exception { |
| String uriStr = fStringPool.toString(fNamespacesScope.getNamespaceForPrefix(fStringPool.addSymbol(prefix))); |
| if (uriStr == null) { |
| // REVISIT: Localize |
| reportGenericSchemaError("prefix : [" + prefix +"] can not be resolved to a URI"); |
| return ""; |
| } |
| |
| //REVISIT, !!!! a hack: needs to be updated later, cause now we only use localpart to key build-in datatype. |
| if ( prefix.length()==0 && uriStr.equals(SchemaSymbols.URI_SCHEMAFORSCHEMA) |
| && fTargetNSURIString.length() == 0) { |
| uriStr = ""; |
| } |
| |
| return uriStr; |
| } |
| |
| public TraverseSchema(Element root, StringPool stringPool, |
| SchemaGrammar schemaGrammar, |
| GrammarResolver grammarResolver, |
| XMLErrorReporter errorReporter, |
| String schemaURL |
| ) throws Exception { |
| fErrorReporter = errorReporter; |
| fCurrentSchemaURL = schemaURL; |
| doTraverseSchema(root, stringPool, schemaGrammar, grammarResolver); |
| } |
| |
| public TraverseSchema(Element root, StringPool stringPool, |
| SchemaGrammar schemaGrammar, |
| GrammarResolver grammarResolver |
| ) throws Exception { |
| doTraverseSchema(root, stringPool, schemaGrammar, grammarResolver); |
| } |
| |
| public void doTraverseSchema(Element root, StringPool stringPool, |
| SchemaGrammar schemaGrammar, |
| GrammarResolver grammarResolver) throws Exception { |
| |
| fNamespacesScope = new NamespacesScope(this); |
| |
| fSchemaRootElement = root; |
| fStringPool = stringPool; |
| fSchemaGrammar = schemaGrammar; |
| fGrammarResolver = grammarResolver; |
| |
| if (root == null) { |
| // REVISIT: Anything to do? |
| return; |
| } |
| |
| //Make sure namespace binding is defaulted |
| String rootPrefix = root.getPrefix(); |
| if( rootPrefix == null || rootPrefix.length() == 0 ){ |
| String xmlns = root.getAttribute("xmlns"); |
| if( xmlns.length() == 0 ) |
| root.setAttribute("xmlns", SchemaSymbols.URI_SCHEMAFORSCHEMA ); |
| } |
| |
| //Retrieve the targetnamespace URI information |
| fTargetNSURIString = root.getAttribute(SchemaSymbols.ATT_TARGETNAMESPACE); |
| if (fTargetNSURIString==null) { |
| fTargetNSURIString=""; |
| } |
| fTargetNSURI = fStringPool.addSymbol(fTargetNSURIString); |
| |
| if (fGrammarResolver == null) { |
| // REVISIT: Localize |
| reportGenericSchemaError("Internal error: don't have a GrammarResolver for TraverseSchema"); |
| } |
| else{ |
| fSchemaGrammar.setComplexTypeRegistry(fComplexTypeRegistry); |
| fSchemaGrammar.setDatatypeRegistry(fDatatypeRegistry); |
| fSchemaGrammar.setAttributeDeclRegistry(fAttributeDeclRegistry); |
| fSchemaGrammar.setNamespacesScope(fNamespacesScope); |
| fSchemaGrammar.setTargetNamespaceURI(fTargetNSURIString); |
| fGrammarResolver.putGrammar(fTargetNSURIString, fSchemaGrammar); |
| } |
| |
| |
| |
| // Retrived the Namespace mapping from the schema element. |
| NamedNodeMap schemaEltAttrs = root.getAttributes(); |
| int i = 0; |
| Attr sattr = null; |
| |
| boolean seenXMLNS = false; |
| while ((sattr = (Attr)schemaEltAttrs.item(i++)) != null) { |
| String attName = sattr.getName(); |
| if (attName.startsWith("xmlns:")) { |
| String attValue = sattr.getValue(); |
| String prefix = attName.substring(attName.indexOf(":")+1); |
| fNamespacesScope.setNamespaceForPrefix( fStringPool.addSymbol(prefix), |
| fStringPool.addSymbol(attValue) ); |
| } |
| if (attName.equals("xmlns")) { |
| |
| String attValue = sattr.getValue(); |
| fNamespacesScope.setNamespaceForPrefix( fStringPool.addSymbol(""), |
| fStringPool.addSymbol(attValue) ); |
| seenXMLNS = true; |
| } |
| |
| } |
| if (!seenXMLNS && fTargetNSURIString.length() == 0 ) { |
| fNamespacesScope.setNamespaceForPrefix( fStringPool.addSymbol(""), |
| fStringPool.addSymbol("") ); |
| } |
| |
| fElementDefaultQualified = |
| root.getAttribute(SchemaSymbols.ATT_ELEMENTFORMDEFAULT).equals(SchemaSymbols.ATTVAL_QUALIFIED); |
| fAttributeDefaultQualified = |
| root.getAttribute(SchemaSymbols.ATT_ATTRIBUTEFORMDEFAULT).equals(SchemaSymbols.ATTVAL_QUALIFIED); |
| |
| //REVISIT, really sticky when noTargetNamesapce, for now, we assume everyting is in the same name space); |
| if (fTargetNSURI == StringPool.EMPTY_STRING) { |
| fElementDefaultQualified = true; |
| //fAttributeDefaultQualified = true; |
| } |
| |
| |
| //fScopeCount++; |
| fCurrentScope = -1; |
| |
| |
| checkTopLevelDuplicateNames(root); |
| |
| //extract all top-level attribute, attributeGroup, and group Decls and put them in the 3 hasn table in the SchemaGrammar. |
| extractTopLevel3Components(root); |
| |
| for (Element child = XUtil.getFirstChildElement(root); child != null; |
| child = XUtil.getNextSiblingElement(child)) { |
| |
| String name = child.getNodeName(); |
| |
| if (name.equals(SchemaSymbols.ELT_ANNOTATION) ) { |
| traverseAnnotationDecl(child); |
| } else if (name.equals(SchemaSymbols.ELT_SIMPLETYPE )) { |
| traverseSimpleTypeDecl(child); |
| } else if (name.equals(SchemaSymbols.ELT_COMPLEXTYPE )) { |
| traverseComplexTypeDecl(child); |
| } else if (name.equals(SchemaSymbols.ELT_ELEMENT )) { |
| traverseElementDecl(child); |
| } else if (name.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) { |
| //traverseAttributeGroupDecl(child); |
| } else if (name.equals( SchemaSymbols.ELT_ATTRIBUTE ) ) { |
| traverseAttributeDecl( child, null ); |
| } else if (name.equals( SchemaSymbols.ELT_WILDCARD) ) { |
| traverseWildcardDecl( child); |
| } else if (name.equals(SchemaSymbols.ELT_GROUP) && child.getAttribute(SchemaSymbols.ATT_REF).equals("")) { |
| //traverseGroupDecl(child); |
| } else if (name.equals(SchemaSymbols.ELT_NOTATION)) { |
| ; //TO DO |
| } |
| else if (name.equals(SchemaSymbols.ELT_INCLUDE)) { |
| traverseInclude(child); |
| } |
| else if (name.equals(SchemaSymbols.ELT_IMPORT)) { |
| traverseImport(child); |
| } |
| } // for each child node |
| |
| } // traverseSchema(Element) |
| |
| private void checkTopLevelDuplicateNames(Element root) { |
| //TO DO : !!! |
| } |
| |
| private void extractTopLevel3Components(Element root){ |
| |
| for (Element child = XUtil.getFirstChildElement(root); child != null; |
| child = XUtil.getNextSiblingElement(child)) { |
| |
| String name = child.getNodeName(); |
| |
| if (name.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) { |
| fSchemaGrammar.topLevelAttrGrpDecls.put(name, child); |
| } else if (name.equals( SchemaSymbols.ELT_ATTRIBUTE ) ) { |
| fSchemaGrammar.topLevelAttrDecls.put(name, child); |
| } else if (name.equals(SchemaSymbols.ELT_GROUP) && child.getAttribute(SchemaSymbols.ATT_REF).equals("")) { |
| fSchemaGrammar.topLevelGroupDecls.put(name, child); |
| } |
| } // for each child node |
| } |
| |
| /** |
| * Expands a system id and returns the system id as a URL, if |
| * it can be expanded. A return value of null means that the |
| * identifier is already expanded. An exception thrown |
| * indicates a failure to expand the id. |
| * |
| * @param systemId The systemId to be expanded. |
| * |
| * @return Returns the URL object representing the expanded system |
| * identifier. A null value indicates that the given |
| * system identifier is already expanded. |
| * |
| */ |
| private String expandSystemId(String systemId, String currentSystemId) throws Exception{ |
| String id = systemId; |
| |
| // check for bad parameters id |
| if (id == null || id.length() == 0) { |
| return systemId; |
| } |
| |
| // if id already expanded, return |
| try { |
| URL url = new URL(id); |
| if (url != null) { |
| return systemId; |
| } |
| } |
| catch (MalformedURLException e) { |
| // continue on... |
| } |
| |
| // normalize id |
| id = fixURI(id); |
| |
| // normalize base |
| URL base = null; |
| URL url = null; |
| try { |
| if (currentSystemId == null) { |
| String dir; |
| try { |
| dir = fixURI(System.getProperty("user.dir")); |
| } |
| catch (SecurityException se) { |
| dir = ""; |
| } |
| if (!dir.endsWith("/")) { |
| dir = dir + "/"; |
| } |
| base = new URL("file", "", dir); |
| } |
| else { |
| base = new URL(currentSystemId); |
| } |
| |
| // expand id |
| url = new URL(base, id); |
| } |
| catch (Exception e) { |
| // let it go through |
| } |
| if (url == null) { |
| return systemId; |
| } |
| return url.toString(); |
| } |
| /** |
| * Fixes a platform dependent filename to standard URI form. |
| * |
| * @param str The string to fix. |
| * |
| * @return Returns the fixed URI string. |
| */ |
| private static String fixURI(String str) { |
| |
| // handle platform dependent strings |
| str = str.replace(java.io.File.separatorChar, '/'); |
| |
| // Windows fix |
| if (str.length() >= 2) { |
| char ch1 = str.charAt(1); |
| if (ch1 == ':') { |
| char ch0 = Character.toUpperCase(str.charAt(0)); |
| if (ch0 >= 'A' && ch0 <= 'Z') { |
| str = "/" + str; |
| } |
| } |
| } |
| |
| // done |
| return str; |
| } |
| |
| |
| private void traverseInclude(Element includeDecl) throws Exception { |
| |
| //TO DO: !!!!! location needs to be resolved first. |
| |
| String location = includeDecl.getAttribute(SchemaSymbols.ATT_SCHEMALOCATION); |
| location = expandSystemId(location, fCurrentSchemaURL); |
| |
| if (fIncludeLocations.contains((Object)location)) { |
| return; |
| } |
| fIncludeLocations.addElement((Object)location); |
| |
| DOMParser parser = new DOMParser() { |
| public void ignorableWhitespace(char ch[], int start, int length) {} |
| public void ignorableWhitespace(int dataIdx) {} |
| }; |
| parser.setEntityResolver( new Resolver() ); |
| parser.setErrorHandler( new ErrorHandler() ); |
| |
| try { |
| parser.setFeature("http://xml.org/sax/features/validation", false); |
| parser.setFeature("http://xml.org/sax/features/namespaces", true); |
| parser.setFeature("http://apache.org/xml/features/dom/defer-node-expansion", false); |
| }catch( org.xml.sax.SAXNotRecognizedException e ) { |
| e.printStackTrace(); |
| }catch( org.xml.sax.SAXNotSupportedException e ) { |
| e.printStackTrace(); |
| } |
| |
| try { |
| parser.parse( location); |
| }catch( IOException e ) { |
| e.printStackTrace(); |
| }catch( SAXException e ) { |
| //e.printStackTrace(); |
| } |
| |
| Document document = parser.getDocument(); //Our Grammar |
| Element root = null; |
| if (document != null) { |
| root = document.getDocumentElement(); |
| } |
| |
| if (root != null) { |
| String targetNSURI = root.getAttribute(SchemaSymbols.ATT_TARGETNAMESPACE); |
| if (targetNSURI.length() > 0 && !targetNSURI.equals(fTargetNSURIString) ) { |
| // REVISIT: Localize |
| reportGenericSchemaError("included schema '"+location+"' has a different targetNameSpace '" |
| +targetNSURI+"'"); |
| } |
| else { |
| boolean saveElementDefaultQualified = fElementDefaultQualified; |
| boolean saveAttributeDefaultQualified = fAttributeDefaultQualified; |
| int saveScope = fCurrentScope; |
| String savedSchemaURL = fCurrentSchemaURL; |
| Element saveRoot = fSchemaRootElement; |
| fSchemaRootElement = root; |
| fCurrentSchemaURL = location; |
| traverseIncludedSchema(root); |
| fCurrentSchemaURL = savedSchemaURL; |
| fCurrentScope = saveScope; |
| fElementDefaultQualified = saveElementDefaultQualified; |
| fAttributeDefaultQualified = saveAttributeDefaultQualified; |
| fSchemaRootElement = saveRoot; |
| } |
| |
| } |
| |
| } |
| |
| private void traverseIncludedSchema(Element root) throws Exception { |
| // Retrived the Namespace mapping from the schema element. |
| NamedNodeMap schemaEltAttrs = root.getAttributes(); |
| int i = 0; |
| Attr sattr = null; |
| |
| boolean seenXMLNS = false; |
| while ((sattr = (Attr)schemaEltAttrs.item(i++)) != null) { |
| String attName = sattr.getName(); |
| if (attName.startsWith("xmlns:")) { |
| String attValue = sattr.getValue(); |
| String prefix = attName.substring(attName.indexOf(":")+1); |
| fNamespacesScope.setNamespaceForPrefix( fStringPool.addSymbol(prefix), |
| fStringPool.addSymbol(attValue) ); |
| } |
| if (attName.equals("xmlns")) { |
| |
| String attValue = sattr.getValue(); |
| fNamespacesScope.setNamespaceForPrefix( fStringPool.addSymbol(""), |
| fStringPool.addSymbol(attValue) ); |
| seenXMLNS = true; |
| } |
| |
| } |
| if (!seenXMLNS && fTargetNSURIString.length() == 0 ) { |
| fNamespacesScope.setNamespaceForPrefix( fStringPool.addSymbol(""), |
| fStringPool.addSymbol("") ); |
| } |
| |
| fElementDefaultQualified = |
| root.getAttribute(SchemaSymbols.ATT_ELEMENTFORMDEFAULT).equals(SchemaSymbols.ATTVAL_QUALIFIED); |
| fAttributeDefaultQualified = |
| root.getAttribute(SchemaSymbols.ATT_ATTRIBUTEFORMDEFAULT).equals(SchemaSymbols.ATTVAL_QUALIFIED); |
| |
| //REVISIT, really sticky when noTargetNamesapce, for now, we assume everyting is in the same name space); |
| if (fTargetNSURI == StringPool.EMPTY_STRING) { |
| fElementDefaultQualified = true; |
| //fAttributeDefaultQualified = true; |
| } |
| |
| //fScopeCount++; |
| fCurrentScope = -1; |
| |
| |
| checkTopLevelDuplicateNames(root); |
| |
| //extract all top-level attribute, attributeGroup, and group Decls and put them in the 3 hasn table in the SchemaGrammar. |
| extractTopLevel3Components(root); |
| |
| for (Element child = XUtil.getFirstChildElement(root); child != null; |
| child = XUtil.getNextSiblingElement(child)) { |
| |
| String name = child.getNodeName(); |
| |
| if (name.equals(SchemaSymbols.ELT_ANNOTATION) ) { |
| traverseAnnotationDecl(child); |
| } else if (name.equals(SchemaSymbols.ELT_SIMPLETYPE )) { |
| traverseSimpleTypeDecl(child); |
| } else if (name.equals(SchemaSymbols.ELT_COMPLEXTYPE )) { |
| traverseComplexTypeDecl(child); |
| } else if (name.equals(SchemaSymbols.ELT_ELEMENT )) { |
| traverseElementDecl(child); |
| } else if (name.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) { |
| //traverseAttributeGroupDecl(child); |
| } else if (name.equals( SchemaSymbols.ELT_ATTRIBUTE ) ) { |
| traverseAttributeDecl( child, null ); |
| } else if (name.equals( SchemaSymbols.ELT_WILDCARD) ) { |
| traverseWildcardDecl( child); |
| } else if (name.equals(SchemaSymbols.ELT_GROUP) && child.getAttribute(SchemaSymbols.ATT_REF).equals("")) { |
| //traverseGroupDecl(child); |
| } else if (name.equals(SchemaSymbols.ELT_NOTATION)) { |
| ; //TO DO |
| } |
| else if (name.equals(SchemaSymbols.ELT_INCLUDE)) { |
| traverseInclude(child); |
| } |
| else if (name.equals(SchemaSymbols.ELT_IMPORT)) { |
| traverseImport(child); |
| } |
| } // for each child node |
| |
| } |
| |
| private void traverseImport(Element importDecl) throws Exception { |
| String location = importDecl.getAttribute(SchemaSymbols.ATT_SCHEMALOCATION); |
| location = expandSystemId(location, fCurrentSchemaURL); |
| |
| |
| String namespaceString = importDecl.getAttribute(SchemaSymbols.ATT_NAMESPACE); |
| SchemaGrammar importedGrammar = new SchemaGrammar(); |
| if (fGrammarResolver.getGrammar(namespaceString) != null) { |
| importedGrammar = (SchemaGrammar) fGrammarResolver.getGrammar(namespaceString); |
| } |
| |
| if (fImportLocations.contains((Object)location)) { |
| return; |
| } |
| fImportLocations.addElement((Object)location); |
| |
| DOMParser parser = new DOMParser() { |
| public void ignorableWhitespace(char ch[], int start, int length) {} |
| public void ignorableWhitespace(int dataIdx) {} |
| }; |
| parser.setEntityResolver( new Resolver() ); |
| parser.setErrorHandler( new ErrorHandler() ); |
| |
| try { |
| parser.setFeature("http://xml.org/sax/features/validation", false); |
| parser.setFeature("http://xml.org/sax/features/namespaces", true); |
| parser.setFeature("http://apache.org/xml/features/dom/defer-node-expansion", false); |
| }catch( org.xml.sax.SAXNotRecognizedException e ) { |
| e.printStackTrace(); |
| }catch( org.xml.sax.SAXNotSupportedException e ) { |
| e.printStackTrace(); |
| } |
| |
| try { |
| parser.parse( location); |
| }catch( IOException e ) { |
| e.printStackTrace(); |
| }catch( SAXException e ) { |
| e.printStackTrace(); |
| } |
| |
| Document document = parser.getDocument(); //Our Grammar |
| Element root = null; |
| if (document != null) { |
| root = document.getDocumentElement(); |
| } |
| |
| if (root != null) { |
| String targetNSURI = root.getAttribute(SchemaSymbols.ATT_TARGETNAMESPACE); |
| if (!targetNSURI.equals(namespaceString) ) { |
| // REVISIT: Localize |
| reportGenericSchemaError("imported schema '"+location+"' has a different targetNameSpace '" |
| +targetNSURI+"' from what is declared '"+namespaceString+"'."); |
| } |
| else |
| new TraverseSchema(root, fStringPool, importedGrammar, fGrammarResolver, fErrorReporter, location); |
| } |
| else { |
| reportGenericSchemaError("Could not get the doc root for imported Schema file: "+location); |
| } |
| } |
| |
| /** |
| * No-op - Traverse Annotation Declaration |
| * |
| * @param comment |
| */ |
| private void traverseAnnotationDecl(Element comment) { |
| //TO DO |
| return ; |
| } |
| |
| /** |
| * Traverse SimpleType declaration: |
| * <simpleType |
| * abstract = boolean |
| * base = QName |
| * derivedBy = | list | restriction : restriction |
| * id = ID |
| * name = NCName> |
| * Content: ( annotation? , ( minExclusive | minInclusive | maxExclusive | maxInclusive | precision | scale | length | minLength | maxLength | encoding | period | duration | enumeration | pattern )* ) |
| * </simpleType> |
| * |
| * @param simpleTypeDecl |
| * @return |
| */ |
| private int traverseSimpleTypeDecl( Element simpleTypeDecl ) throws Exception { |
| |
| String varietyProperty = simpleTypeDecl.getAttribute( SchemaSymbols.ATT_DERIVEDBY ); |
| if (varietyProperty.length() == 0) { |
| varietyProperty = SchemaSymbols.ATTVAL_RESTRICTION; |
| } |
| String nameProperty = simpleTypeDecl.getAttribute( SchemaSymbols.ATT_NAME ); |
| String baseTypeQNameProperty = simpleTypeDecl.getAttribute( SchemaSymbols.ATT_BASE ); |
| String abstractProperty = simpleTypeDecl.getAttribute( SchemaSymbols.ATT_ABSTRACT ); |
| |
| int newSimpleTypeName = -1; |
| |
| |
| if ( nameProperty.equals("")) { // anonymous simpleType |
| newSimpleTypeName = fStringPool.addSymbol( |
| "#S#"+fSimpleTypeAnonCount++ ); |
| //"http://www.apache.org/xml/xerces/internalDatatype"+fSimpleTypeAnonCount++ ); |
| } else |
| newSimpleTypeName = fStringPool.addSymbol( nameProperty ); |
| |
| |
| int basetype; |
| DatatypeValidator baseValidator = null; |
| |
| if( baseTypeQNameProperty!= null ) { |
| basetype = fStringPool.addSymbol( baseTypeQNameProperty ); |
| String prefix = ""; |
| String localpart = baseTypeQNameProperty; |
| int colonptr = baseTypeQNameProperty.indexOf(":"); |
| if ( colonptr > 0) { |
| prefix = baseTypeQNameProperty.substring(0,colonptr); |
| localpart = baseTypeQNameProperty.substring(colonptr+1); |
| } |
| String uri = resolvePrefixToURI(prefix); |
| |
| baseValidator = getDatatypeValidator(uri, localpart); |
| |
| if (baseValidator == null) { |
| Element baseTypeNode = getTopLevelComponentByName(SchemaSymbols.ELT_SIMPLETYPE, localpart); |
| if (baseTypeNode != null) { |
| traverseSimpleTypeDecl( baseTypeNode ); |
| |
| baseValidator = getDatatypeValidator(uri, localpart); |
| |
| if (baseValidator == null) { |
| reportSchemaError(SchemaMessageProvider.UnknownBaseDatatype, |
| new Object [] { simpleTypeDecl.getAttribute( SchemaSymbols.ATT_BASE ), |
| simpleTypeDecl.getAttribute(SchemaSymbols.ATT_NAME) }); |
| return -1; |
| //reportGenericSchemaError("Base type could not be found : " + baseTypeQNameProperty); |
| } |
| |
| } |
| else { |
| reportSchemaError(SchemaMessageProvider.UnknownBaseDatatype, |
| new Object [] { simpleTypeDecl.getAttribute( SchemaSymbols.ATT_BASE ), |
| simpleTypeDecl.getAttribute(SchemaSymbols.ATT_NAME) }); |
| return -1; |
| //reportGenericSchemaError("Base type could not be found : " + baseTypeQNameProperty); |
| } |
| |
| } |
| } |
| // Any Children if so then check Content otherwise bail out |
| |
| Element content = XUtil.getFirstChildElement( simpleTypeDecl ); |
| int numFacets = 0; |
| Hashtable facetData = null; |
| |
| if( content != null ) { |
| |
| //Content follows: ( annotation? , facets* ) |
| |
| //annotation ? ( 0 or 1 ) |
| if( content.getNodeName().equals( SchemaSymbols.ELT_ANNOTATION ) ){ |
| traverseAnnotationDecl( content ); |
| content = XUtil.getNextSiblingElement(content); |
| } |
| |
| //TODO: If content is annotation again should raise validation error |
| // if( content.getNodeName().equal( SchemaSymbols.ELT_ANNOTATIO ) { |
| // throw ValidationException(); } |
| // |
| |
| //facets * ( 0 or more ) |
| |
| |
| int numEnumerationLiterals = 0; |
| facetData = new Hashtable(); |
| Vector enumData = new Vector(); |
| |
| while (content != null) { |
| if (content.getNodeType() == Node.ELEMENT_NODE) { |
| Element facetElt = (Element) content; |
| numFacets++; |
| if (facetElt.getNodeName().equals(SchemaSymbols.ELT_ENUMERATION)) { |
| numEnumerationLiterals++; |
| String enumVal = facetElt.getAttribute(SchemaSymbols.ATT_VALUE); |
| enumData.addElement(enumVal); |
| //Enumerations can have annotations ? ( 0 | 1 ) |
| Element enumContent = XUtil.getFirstChildElement( facetElt ); |
| if( enumContent != null && enumContent != null && enumContent.getNodeName().equals( SchemaSymbols.ELT_ANNOTATION ) ){ |
| traverseAnnotationDecl( content ); |
| } |
| //TODO: If enumContent is encounter again should raise validation error |
| // enumContent.getNextSibling(); |
| // if( enumContent.getNodeName().equal( SchemaSymbols.ELT_ANNOTATIO ) { |
| // throw ValidationException(); } |
| // |
| } else { |
| facetData.put(facetElt.getNodeName(),facetElt.getAttribute( SchemaSymbols.ATT_VALUE )); |
| } |
| } |
| //content = (Element) content.getNextSibling(); |
| content = XUtil.getNextSiblingElement(content); |
| } |
| if (numEnumerationLiterals > 0) { |
| facetData.put(SchemaSymbols.ELT_ENUMERATION, enumData); |
| } |
| } |
| |
| // create & register validator for "generated" type if it doesn't exist |
| |
| String nameOfType = fStringPool.toString( newSimpleTypeName); |
| if (fTargetNSURIString.length () != 0) { |
| nameOfType = fTargetNSURIString+","+nameOfType; |
| } |
| |
| |
| try { |
| |
| DatatypeValidator newValidator = |
| fDatatypeRegistry.getDatatypeValidator( nameOfType ); |
| |
| if( newValidator == null ) { // not previously registered |
| boolean derivedByList = |
| varietyProperty.equals( SchemaSymbols.ATTVAL_LIST ) ? true:false; |
| |
| fDatatypeRegistry.createDatatypeValidator( nameOfType, baseValidator, |
| facetData, derivedByList ); |
| |
| } |
| |
| } catch (Exception e) { |
| //e.printStackTrace(System.err); |
| reportSchemaError(SchemaMessageProvider.DatatypeError,new Object [] { e.getMessage() }); |
| } |
| return fStringPool.addSymbol(nameOfType); |
| } |
| |
| /* |
| * <any |
| * id = ID |
| * maxOccurs = string |
| * minOccurs = nonNegativeInteger |
| * namespace = ##any | ##other | ##local | list of {uri, ##targetNamespace} |
| * processContents = lax | skip | strict> |
| * Content: (annotation?) |
| * </any> |
| */ |
| private int traverseAny(Element child) throws Exception { |
| int anyIndex = -1; |
| String namespace = child.getAttribute(SchemaSymbols.ATT_NAMESPACE).trim(); |
| String processContents = child.getAttribute("processContents").trim(); |
| |
| int processContentsAny = XMLContentSpec.CONTENTSPECNODE_ANY; |
| int processContentsAnyOther = XMLContentSpec.CONTENTSPECNODE_ANY_OTHER; |
| int processContentsAnyLocal = XMLContentSpec.CONTENTSPECNODE_ANY_LOCAL; |
| |
| if (processContents.length() > 0 && !processContents.equals("strict")) { |
| if (processContents.equals("lax")) { |
| processContentsAny = XMLContentSpec.CONTENTSPECNODE_ANY_LAX; |
| processContentsAnyOther = XMLContentSpec.CONTENTSPECNODE_ANY_OTHER_LAX; |
| processContentsAnyLocal = XMLContentSpec.CONTENTSPECNODE_ANY_LOCAL_LAX; |
| } |
| else if (processContents.equals("skip")) { |
| processContentsAny = XMLContentSpec.CONTENTSPECNODE_ANY_SKIP; |
| processContentsAnyOther = XMLContentSpec.CONTENTSPECNODE_ANY_OTHER_SKIP; |
| processContentsAnyLocal = XMLContentSpec.CONTENTSPECNODE_ANY_LOCAL_SKIP; |
| } |
| } |
| |
| if (namespace.length() == 0 || namespace.equals("##any")) { |
| anyIndex = fSchemaGrammar.addContentSpecNode(processContentsAny, -1, -1, false); |
| } |
| else if (namespace.equals("##other")) { |
| String uri = child.getOwnerDocument().getDocumentElement().getAttribute("targetNamespace"); |
| int uriIndex = fStringPool.addSymbol(uri); |
| anyIndex = fSchemaGrammar.addContentSpecNode(processContentsAnyOther, -1, uriIndex, false); |
| } |
| else if (namespace.equals("##local")) { |
| anyIndex = fSchemaGrammar.addContentSpecNode(processContentsAnyLocal, -1, -1, false); |
| } |
| else if (namespace.length() > 0) { |
| StringTokenizer tokenizer = new StringTokenizer(namespace); |
| Vector tokens = new Vector(); |
| while (tokenizer.hasMoreElements()) { |
| String token = tokenizer.nextToken(); |
| if (token.equals("##targetNamespace")) { |
| token = child.getOwnerDocument().getDocumentElement().getAttribute("targetNamespace"); |
| } |
| tokens.addElement(token); |
| } |
| String uri = (String)tokens.elementAt(0); |
| int uriIndex = fStringPool.addSymbol(uri); |
| int leafIndex = fSchemaGrammar.addContentSpecNode(processContentsAny, -1, uriIndex, false); |
| int valueIndex = leafIndex; |
| int count = tokens.size(); |
| if (count > 1) { |
| uri = (String)tokens.elementAt(1); |
| uriIndex = fStringPool.addSymbol(uri); |
| leafIndex = fSchemaGrammar.addContentSpecNode(processContentsAny, -1, uriIndex, false); |
| int otherValueIndex = leafIndex; |
| int choiceIndex = fSchemaGrammar.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_CHOICE, valueIndex, otherValueIndex, false); |
| for (int i = 2; i < count; i++) { |
| uri = (String)tokens.elementAt(i); |
| uriIndex = fStringPool.addSymbol(uri); |
| leafIndex = fSchemaGrammar.addContentSpecNode(processContentsAny, -1, uriIndex, false); |
| otherValueIndex = leafIndex; |
| choiceIndex = fSchemaGrammar.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_CHOICE, choiceIndex, otherValueIndex, false); |
| } |
| anyIndex = choiceIndex; |
| } |
| else { |
| anyIndex = leafIndex; |
| } |
| } |
| else { |
| // REVISIT: Localize |
| reportGenericSchemaError("Empty namespace attribute for any element"); |
| } |
| |
| return anyIndex; |
| } |
| |
| |
| public DatatypeValidator getDatatypeValidator(String uri, String localpart) { |
| |
| DatatypeValidator dv = null; |
| |
| if (uri.length()==0 || uri.equals(SchemaSymbols.URI_SCHEMAFORSCHEMA)) { |
| dv = fDatatypeRegistry.getDatatypeValidator( localpart ); |
| } |
| else { |
| dv = fDatatypeRegistry.getDatatypeValidator( uri+","+localpart ); |
| } |
| |
| return dv; |
| } |
| |
| /* |
| * <anyAttribute |
| * id = ID |
| * namespace = ##any | ##other | ##local | list of {uri, ##targetNamespace}> |
| * Content: (annotation?) |
| * </anyAttribute> |
| */ |
| private XMLAttributeDecl traverseAnyAttribute(Element anyAttributeDecl) throws Exception { |
| XMLAttributeDecl anyAttDecl = new XMLAttributeDecl(); |
| String processContents = anyAttributeDecl.getAttribute(SchemaSymbols.ATT_PROCESSCONTENTS).trim(); |
| String namespace = anyAttributeDecl.getAttribute(SchemaSymbols.ATT_NAMESPACE).trim(); |
| String curTargetUri = anyAttributeDecl.getOwnerDocument().getDocumentElement().getAttribute("targetNamespace"); |
| |
| if ( namespace.length() == 0 || namespace.equals(SchemaSymbols.ATTVAL_TWOPOUNDANY) ) { |
| anyAttDecl.type = XMLAttributeDecl.TYPE_ANY_ANY; |
| } |
| else if (namespace.equals(SchemaSymbols.ATTVAL_TWOPOUNDOTHER)) { |
| anyAttDecl.type = XMLAttributeDecl.TYPE_ANY_OTHER; |
| anyAttDecl.name.uri = fStringPool.addSymbol(curTargetUri); |
| } |
| else if (namespace.equals(SchemaSymbols.ATTVAL_TWOPOUNDLOCAL)) { |
| anyAttDecl.type = XMLAttributeDecl.TYPE_ANY_LOCAL; |
| } |
| else if (namespace.length() > 0){ |
| anyAttDecl.type = XMLAttributeDecl.TYPE_ANY_LIST; |
| |
| StringTokenizer tokenizer = new StringTokenizer(namespace); |
| int aStringList = fStringPool.startStringList(); |
| Vector tokens = new Vector(); |
| while (tokenizer.hasMoreElements()) { |
| String token = tokenizer.nextToken(); |
| if (token.equals("##targetNamespace")) { |
| token = curTargetUri; |
| } |
| if (!fStringPool.addStringToList(aStringList, fStringPool.addSymbol(token))){ |
| reportGenericSchemaError("Internal StringPool error when reading the "+ |
| "namespace attribute for anyattribute declaration"); |
| } |
| } |
| fStringPool.finishStringList(aStringList); |
| |
| anyAttDecl.enumeration = aStringList; |
| } |
| else { |
| // REVISIT: Localize |
| reportGenericSchemaError("Empty namespace attribute for anyattribute declaration"); |
| } |
| |
| // default processContents is "strict"; |
| anyAttDecl.defaultType = XMLAttributeDecl.PROCESSCONTENTS_STRICT; |
| |
| if (processContents.equals(SchemaSymbols.ATTVAL_SKIP)){ |
| anyAttDecl.defaultType = XMLAttributeDecl.PROCESSCONTENTS_SKIP; |
| } |
| else if (processContents.equals(SchemaSymbols.ATTVAL_LAX)) { |
| anyAttDecl.defaultType = XMLAttributeDecl.PROCESSCONTENTS_LAX; |
| } |
| |
| return anyAttDecl; |
| } |
| |
| private XMLAttributeDecl mergeTwoAnyAttribute(XMLAttributeDecl oneAny, XMLAttributeDecl anotherAny) { |
| if (oneAny.type == -1) { |
| return oneAny; |
| } |
| if (anotherAny.type == -1) { |
| return anotherAny; |
| } |
| |
| if (oneAny.type == XMLAttributeDecl.TYPE_ANY_ANY) { |
| return anotherAny; |
| } |
| |
| if (anotherAny.type == XMLAttributeDecl.TYPE_ANY_ANY) { |
| return oneAny; |
| } |
| |
| if (oneAny.type == XMLAttributeDecl.TYPE_ANY_OTHER) { |
| if (anotherAny.type == XMLAttributeDecl.TYPE_ANY_OTHER) { |
| |
| if ( anotherAny.name.uri == oneAny.name.uri ) { |
| return oneAny; |
| } |
| else { |
| oneAny.type = -1; |
| return oneAny; |
| } |
| |
| } |
| else if (anotherAny.type == XMLAttributeDecl.TYPE_ANY_LOCAL) { |
| return anotherAny; |
| } |
| else if (anotherAny.type == XMLAttributeDecl.TYPE_ANY_LIST) { |
| if (!fStringPool.stringInList(anotherAny.enumeration, oneAny.name.uri) ) { |
| return anotherAny; |
| } |
| else { |
| int[] anotherAnyURIs = fStringPool.stringListAsIntArray(anotherAny.enumeration); |
| int newList = fStringPool.startStringList(); |
| for (int i=0; i< anotherAnyURIs.length; i++) { |
| if (anotherAnyURIs[i] != oneAny.name.uri ) { |
| fStringPool.addStringToList(newList, anotherAnyURIs[i]); |
| } |
| } |
| fStringPool.finishStringList(newList); |
| anotherAny.enumeration = newList; |
| return anotherAny; |
| } |
| } |
| } |
| |
| if (oneAny.type == XMLAttributeDecl.TYPE_ANY_LOCAL) { |
| if ( anotherAny.type == XMLAttributeDecl.TYPE_ANY_OTHER |
| || anotherAny.type == XMLAttributeDecl.TYPE_ANY_LOCAL) { |
| return oneAny; |
| } |
| else if (anotherAny.type == XMLAttributeDecl.TYPE_ANY_LIST) { |
| oneAny.type = -1; |
| return oneAny; |
| } |
| } |
| |
| if (oneAny.type == XMLAttributeDecl.TYPE_ANY_LIST) { |
| if ( anotherAny.type == XMLAttributeDecl.TYPE_ANY_OTHER){ |
| if (!fStringPool.stringInList(oneAny.enumeration, anotherAny.name.uri) ) { |
| return oneAny; |
| } |
| else { |
| int[] oneAnyURIs = fStringPool.stringListAsIntArray(oneAny.enumeration); |
| int newList = fStringPool.startStringList(); |
| for (int i=0; i< oneAnyURIs.length; i++) { |
| if (oneAnyURIs[i] != anotherAny.name.uri ) { |
| fStringPool.addStringToList(newList, oneAnyURIs[i]); |
| } |
| } |
| fStringPool.finishStringList(newList); |
| oneAny.enumeration = newList; |
| return oneAny; |
| } |
| |
| } |
| else if ( anotherAny.type == XMLAttributeDecl.TYPE_ANY_LOCAL) { |
| oneAny.type = -1; |
| return oneAny; |
| } |
| else if (anotherAny.type == XMLAttributeDecl.TYPE_ANY_LIST) { |
| int[] result = intersect2sets( fStringPool.stringListAsIntArray(oneAny.enumeration), |
| fStringPool.stringListAsIntArray(anotherAny.enumeration)); |
| int newList = fStringPool.startStringList(); |
| for (int i=0; i<result.length; i++) { |
| fStringPool.addStringToList(newList, result[i]); |
| } |
| fStringPool.finishStringList(newList); |
| oneAny.enumeration = newList; |
| return oneAny; |
| } |
| } |
| |
| // should never go there; |
| return oneAny; |
| } |
| |
| int[] intersect2sets(int[] one, int[] theOther){ |
| int[] result = new int[(one.length>theOther.length?one.length:theOther.length)]; |
| |
| // simple implemention, |
| int count = 0; |
| for (int i=0; i<one.length; i++) { |
| for(int j=0; j<theOther.length; j++) { |
| if (one[i]==theOther[j]) { |
| result[count++] = one[i]; |
| } |
| } |
| } |
| |
| int[] result2 = new int[count]; |
| System.arraycopy(result, 0, result2, 0, count); |
| |
| return result2; |
| } |
| |
| /** |
| * Traverse ComplexType Declaration. |
| * |
| * <complexType |
| * abstract = boolean |
| * base = QName |
| * block = #all or (possibly empty) subset of {extension, restriction} |
| * content = elementOnly | empty | mixed | textOnly |
| * derivedBy = extension | restriction |
| * final = #all or (possibly empty) subset of {extension, restriction} |
| * id = ID |
| * name = NCName> |
| * Content: (annotation? , (((minExclusive | minInclusive | maxExclusive |
| * | maxInclusive | precision | scale | length | minLength |
| * | maxLength | encoding | period | duration | enumeration |
| * | pattern)* | (element | group | all | choice | sequence | any)*) , |
| * ((attribute | attributeGroup)* , anyAttribute?))) |
| * </complexType> |
| * @param complexTypeDecl |
| * @return |
| */ |
| |
| //REVISIT: TO DO, base and derivation ??? |
| private int traverseComplexTypeDecl( Element complexTypeDecl ) throws Exception { |
| String isAbstract = complexTypeDecl.getAttribute( SchemaSymbols.ATT_ABSTRACT ); |
| String base = complexTypeDecl.getAttribute(SchemaSymbols.ATT_BASE); |
| String blockSet = complexTypeDecl.getAttribute( SchemaSymbols.ATT_BLOCK ); |
| String content = complexTypeDecl.getAttribute(SchemaSymbols.ATT_CONTENT); |
| String derivedBy = complexTypeDecl.getAttribute( SchemaSymbols.ATT_DERIVEDBY ); |
| String finalSet = complexTypeDecl.getAttribute( SchemaSymbols.ATT_FINAL ); |
| String typeId = complexTypeDecl.getAttribute( SchemaSymbols.ATTVAL_ID ); |
| String typeName = complexTypeDecl.getAttribute(SchemaSymbols.ATT_NAME); |
| boolean isNamedType = false; |
| |
| if ( DEBUGGING ) |
| System.out.println("traversing complex Type : " + typeName +","+base+","+content+"."); |
| |
| if (typeName.equals("")) { // gensym a unique name |
| //typeName = "http://www.apache.org/xml/xerces/internalType"+fTypeCount++; |
| typeName = "#"+fAnonTypeCount++; |
| } |
| else { |
| fCurrentTypeNameStack.push(typeName); |
| isNamedType = true; |
| } |
| |
| if (isTopLevel(complexTypeDecl)) { |
| |
| String fullName = fTargetNSURIString+","+typeName; |
| ComplexTypeInfo temp = (ComplexTypeInfo) fComplexTypeRegistry.get(fullName); |
| if (temp != null ) { |
| return fStringPool.addSymbol(fullName); |
| } |
| } |
| |
| int scopeDefined = fScopeCount++; |
| int previousScope = fCurrentScope; |
| fCurrentScope = scopeDefined; |
| |
| Element child = null; |
| int contentSpecType = -1; |
| int csnType = 0; |
| int left = -2; |
| int right = -2; |
| |
| ComplexTypeInfo baseTypeInfo = null; //if base is a complexType; |
| DatatypeValidator baseTypeValidator = null; //if base is a simple type or a complex type derived from a simpleType |
| DatatypeValidator simpleTypeValidator = null; |
| int baseTypeSymbol = -1; |
| String fullBaseName = ""; |
| |
| boolean baseIsSimpleSimple = false; |
| boolean baseIsComplexSimple = false; |
| boolean baseFromAnotherSchema = false; |
| String baseTypeSchemaURI = null; |
| boolean derivedByRestriction = true; |
| boolean derivedByExtension = false; |
| int baseContentSpecHandle = -1; |
| Element baseTypeNode = null; |
| |
| |
| //int parsedderivedBy = parseComplexDerivedBy(derivedBy); |
| //handle the inhreitance here. |
| if (base.length()>0) { |
| |
| //first check if derivedBy is present |
| if (derivedBy.length() == 0) { |
| // REVISIT: Localize |
| reportGenericSchemaError("derivedBy must be present when base is present in " |
| +SchemaSymbols.ELT_COMPLEXTYPE |
| +" "+ typeName); |
| derivedBy = SchemaSymbols.ATTVAL_EXTENSION; |
| } |
| |
| if (derivedBy.equals(SchemaSymbols.ATTVAL_EXTENSION)) { |
| derivedByRestriction = false; |
| } |
| |
| String prefix = ""; |
| String localpart = base; |
| int colonptr = base.indexOf(":"); |
| if ( colonptr > 0) { |
| prefix = base.substring(0,colonptr); |
| localpart = base.substring(colonptr+1); |
| } |
| int localpartIndex = fStringPool.addSymbol(localpart); |
| String typeURI = resolvePrefixToURI(prefix); |
| |
| // check if the base type is from the same Schema; |
| if ( ! typeURI.equals(fTargetNSURIString) |
| && ! typeURI.equals(SchemaSymbols.URI_SCHEMAFORSCHEMA) |
| && typeURI.length() != 0 ) /*REVISIT, !!!! a hack: for schema that has no target namespace, e.g. personal-schema.xml*/{ |
| baseFromAnotherSchema = true; |
| baseTypeSchemaURI = typeURI; |
| baseTypeInfo = getTypeInfoFromNS(typeURI, localpart); |
| if (baseTypeInfo == null) { |
| baseTypeValidator = getTypeValidatorFromNS(typeURI, localpart); |
| if (baseTypeValidator == null) { |
| //TO DO: report error here; |
| System.out.println("Could not find base type " +localpart |
| + " in schema " + typeURI); |
| } |
| else{ |
| baseIsSimpleSimple = true; |
| } |
| } |
| } |
| else { |
| |
| fullBaseName = typeURI+","+localpart; |
| |
| // assume the base is a complexType and try to locate the base type first |
| baseTypeInfo = (ComplexTypeInfo) fComplexTypeRegistry.get(fullBaseName); |
| |
| // if not found, 2 possibilities: 1: ComplexType in question has not been compiled yet; |
| // 2: base is SimpleTYpe; |
| if (baseTypeInfo == null) { |
| baseTypeValidator = getDatatypeValidator(typeURI, localpart); |
| |
| if (baseTypeValidator == null) { |
| baseTypeNode = getTopLevelComponentByName(SchemaSymbols.ELT_COMPLEXTYPE,localpart); |
| if (baseTypeNode != null) { |
| baseTypeSymbol = traverseComplexTypeDecl( baseTypeNode ); |
| baseTypeInfo = (ComplexTypeInfo) |
| fComplexTypeRegistry.get(fStringPool.toString(baseTypeSymbol)); //REVISIT: should it be fullBaseName; |
| } |
| else { |
| baseTypeNode = getTopLevelComponentByName(SchemaSymbols.ELT_SIMPLETYPE, localpart); |
| if (baseTypeNode != null) { |
| baseTypeSymbol = traverseSimpleTypeDecl( baseTypeNode ); |
| simpleTypeValidator = baseTypeValidator = getDatatypeValidator(typeURI, localpart); |
| if (simpleTypeValidator == null) { |
| //TO DO: signal error here. |
| } |
| |
| baseIsSimpleSimple = true; |
| } |
| else { |
| // REVISIT: Localize |
| reportGenericSchemaError("Base type could not be found : " + base); |
| } |
| } |
| } |
| else { |
| simpleTypeValidator = baseTypeValidator; |
| baseIsSimpleSimple = true; |
| } |
| } |
| } |
| //Schema Spec : 5.11: Complex Type Definition Properties Correct : 2 |
| if (baseIsSimpleSimple && derivedByRestriction) { |
| // REVISIT: Localize |
| reportGenericSchemaError("base is a simpledType, can't derive by restriction in " + typeName); |
| } |
| |
| //if the base is a complexType |
| if (baseTypeInfo != null ) { |
| |
| //Schema Spec : 5.11: Derivation Valid ( Extension ) 1.1.1 |
| // 5.11: Derivation Valid ( Restriction, Complex ) 1.2.1 |
| if (derivedByRestriction) { |
| //REVISIT: check base Type's finalset does not include "restriction" |
| } |
| else { |
| //REVISIT: check base Type's finalset doest not include "extension" |
| } |
| |
| if ( baseTypeInfo.contentSpecHandle > -1) { |
| if (derivedByRestriction) { |
| //REVISIT: !!! really hairy staff to check the particle derivation OK in 5.10 |
| checkParticleDerivationOK(complexTypeDecl, baseTypeNode); |
| } |
| baseContentSpecHandle = baseTypeInfo.contentSpecHandle; |
| } |
| else if ( baseTypeInfo.datatypeValidator != null ) { |
| baseTypeValidator = baseTypeInfo.datatypeValidator; |
| baseIsComplexSimple = true; |
| } |
| } |
| |
| //Schema Spec : 5.11: Derivation Valid ( Extension ) 1.1.1 |
| if (baseIsComplexSimple && !derivedByRestriction ) { |
| // REVISIT: Localize |
| reportGenericSchemaError("base is ComplexSimple, can't derive by extension in " + typeName); |
| } |
| |
| |
| } // END of if (base.length() > 0) {} |
| |
| // skip refinement and annotations |
| child = null; |
| |
| if (baseIsComplexSimple) { |
| |
| contentSpecType = XMLElementDecl.TYPE_SIMPLE; |
| |
| int numEnumerationLiterals = 0; |
| int numFacets = 0; |
| Hashtable facetData = new Hashtable(); |
| Vector enumData = new Vector(); |
| |
| |
| //REVISIT: there is a better way to do this, |
| for (child = XUtil.getFirstChildElement(complexTypeDecl); |
| child != null && (child.getNodeName().equals(SchemaSymbols.ELT_MINEXCLUSIVE) || |
| child.getNodeName().equals(SchemaSymbols.ELT_MININCLUSIVE) || |
| child.getNodeName().equals(SchemaSymbols.ELT_MAXEXCLUSIVE) || |
| child.getNodeName().equals(SchemaSymbols.ELT_MAXINCLUSIVE) || |
| child.getNodeName().equals(SchemaSymbols.ELT_PRECISION) || |
| child.getNodeName().equals(SchemaSymbols.ELT_SCALE) || |
| child.getNodeName().equals(SchemaSymbols.ELT_LENGTH) || |
| child.getNodeName().equals(SchemaSymbols.ELT_MINLENGTH) || |
| child.getNodeName().equals(SchemaSymbols.ELT_MAXLENGTH) || |
| child.getNodeName().equals(SchemaSymbols.ELT_ENCODING) || |
| child.getNodeName().equals(SchemaSymbols.ELT_PERIOD) || |
| child.getNodeName().equals(SchemaSymbols.ELT_DURATION) || |
| child.getNodeName().equals(SchemaSymbols.ELT_ENUMERATION) || |
| child.getNodeName().equals(SchemaSymbols.ELT_PATTERN) || |
| child.getNodeName().equals(SchemaSymbols.ELT_ANNOTATION)); |
| child = XUtil.getNextSiblingElement(child)) |
| { |
| if ( child.getNodeType() == Node.ELEMENT_NODE ) { |
| Element facetElt = (Element) child; |
| numFacets++; |
| if (facetElt.getNodeName().equals(SchemaSymbols.ELT_ENUMERATION)) { |
| numEnumerationLiterals++; |
| enumData.addElement(facetElt.getAttribute(SchemaSymbols.ATT_VALUE)); |
| //Enumerations can have annotations ? ( 0 | 1 ) |
| Element enumContent = XUtil.getFirstChildElement( facetElt ); |
| if( enumContent != null && enumContent.getNodeName().equals( SchemaSymbols.ELT_ANNOTATION ) ){ |
| traverseAnnotationDecl( child ); |
| } |
| // TO DO: if Jeff check in new changes to TraverseSimpleType, copy them over |
| } else { |
| facetData.put(facetElt.getNodeName(),facetElt.getAttribute( SchemaSymbols.ATT_VALUE )); |
| } |
| } |
| } |
| if (numEnumerationLiterals > 0) { |
| facetData.put(SchemaSymbols.ELT_ENUMERATION, enumData); |
| } |
| |
| //if (numFacets > 0) |
| // baseTypeValidator.setFacets(facetData, derivedBy ); |
| if (numFacets > 0) { |
| simpleTypeValidator = fDatatypeRegistry.createDatatypeValidator( typeName, baseTypeValidator, |
| facetData, false ); |
| } |
| else |
| simpleTypeValidator = baseTypeValidator; |
| |
| if (child != null) { |
| // REVISIT: Localize |
| reportGenericSchemaError("Invalid child '"+child.getNodeName()+"' in complexType : '" + typeName |
| + "', because it restricts another complexSimpleType"); |
| } |
| } |
| |
| // if content = textonly, base is a datatype |
| if (content.equals(SchemaSymbols.ATTVAL_TEXTONLY)) { |
| //TO DO |
| if (base.length() == 0) { |
| simpleTypeValidator = baseTypeValidator = getDatatypeValidator("", SchemaSymbols.ATTVAL_STRING); |
| } |
| else if ( baseTypeValidator == null |
| && baseTypeInfo != null && baseTypeInfo.datatypeValidator==null ) // must be datatype |
| reportSchemaError(SchemaMessageProvider.NotADatatype, |
| new Object [] { base }); //REVISIT check forward refs |
| //handle datatypes |
| contentSpecType = XMLElementDecl.TYPE_SIMPLE; |
| /**** |
| left = fSchemaGrammar.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_LEAF, |
| fStringPool.addSymbol(base), |
| -1, false); |
| /****/ |
| |
| } |
| else { |
| if (!baseIsComplexSimple) { |
| contentSpecType = XMLElementDecl.TYPE_CHILDREN; |
| } |
| csnType = XMLContentSpec.CONTENTSPECNODE_SEQ; |
| boolean mixedContent = false; |
| //REVISIT: is the default content " elementOnly" |
| boolean elementContent = true; |
| boolean textContent = false; |
| boolean emptyContent = false; |
| left = -2; |
| right = -2; |
| boolean hadContent = false; |
| |
| if (content.equals(SchemaSymbols.ATTVAL_EMPTY)) { |
| contentSpecType = XMLElementDecl.TYPE_EMPTY; |
| emptyContent = true; |
| elementContent = false; |
| left = -1; // no contentSpecNode needed |
| } else if (content.equals(SchemaSymbols.ATTVAL_MIXED) ) { |
| contentSpecType = XMLElementDecl.TYPE_MIXED; |
| mixedContent = true; |
| elementContent = false; |
| csnType = XMLContentSpec.CONTENTSPECNODE_CHOICE; |
| } else if (content.equals(SchemaSymbols.ATTVAL_ELEMENTONLY) || content.equals("")) { |
| elementContent = true; |
| } else if (content.equals(SchemaSymbols.ATTVAL_TEXTONLY)) { |
| textContent = true; |
| elementContent = false; |
| } |
| |
| if (mixedContent) { |
| // add #PCDATA leaf |
| |
| left = fSchemaGrammar.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_LEAF, |
| -1, // -1 means "#PCDATA" is name |
| -1, false); |
| csnType = XMLContentSpec.CONTENTSPECNODE_CHOICE; |
| } |
| |
| boolean seeParticle = false; |
| boolean seeOtherParticle = false; |
| boolean seeAll = false; |
| |
| for (child = XUtil.getFirstChildElement(complexTypeDecl); |
| child != null; |
| child = XUtil.getNextSiblingElement(child)) { |
| |
| int index = -2; // to save the particle's contentSpec handle |
| hadContent = true; |
| |
| seeParticle = false; |
| |
| String childName = child.getNodeName(); |
| |
| if (childName.equals(SchemaSymbols.ELT_ELEMENT)) { |
| if (mixedContent || elementContent) { |
| if ( DEBUGGING ) |
| System.out.println(" child element name " + child.getAttribute(SchemaSymbols.ATT_NAME)); |
| |
| QName eltQName = traverseElementDecl(child); |
| index = fSchemaGrammar.addContentSpecNode( XMLContentSpec.CONTENTSPECNODE_LEAF, |
| eltQName.localpart, |
| eltQName.uri, |
| false); |
| seeParticle = true; |
| seeOtherParticle = true; |
| |
| } |
| else { |
| reportSchemaError(SchemaMessageProvider.EltRefOnlyInMixedElemOnly, null); |
| } |
| |
| } |
| else if (childName.equals(SchemaSymbols.ELT_GROUP)) { |
| index = traverseGroupDecl(child); |
| seeParticle = true; |
| seeOtherParticle = true; |
| } |
| else if (childName.equals(SchemaSymbols.ELT_ALL)) { |
| index = traverseAll(child); |
| seeParticle = true; |
| seeAll = true; |
| |
| } |
| else if (childName.equals(SchemaSymbols.ELT_CHOICE)) { |
| index = traverseChoice(child); |
| seeParticle = true; |
| seeOtherParticle = true; |
| } |
| else if (childName.equals(SchemaSymbols.ELT_SEQUENCE)) { |
| index = traverseSequence(child); |
| seeParticle = true; |
| seeOtherParticle = true; |
| } |
| else if (childName.equals(SchemaSymbols.ELT_ATTRIBUTE) || |
| childName.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) { |
| break; // attr processing is done later on in this method |
| } |
| else if (childName.equals(SchemaSymbols.ELT_ANY)) { |
| |
| index = traverseAny(child); |
| seeParticle = true; |
| seeOtherParticle = true; |
| } |
| else if (childName.equals(SchemaSymbols.ELT_ANNOTATION)) { |
| //REVISIT, do nothing for annotation for now. |
| } |
| else if (childName.equals(SchemaSymbols.ELT_ANYATTRIBUTE)) { |
| break; |
| //REVISIT, do nothing for attribute wildcard for now. |
| } |
| else { // datatype qual |
| if (!baseIsComplexSimple ) |
| if (base.equals("")) |
| reportSchemaError(SchemaMessageProvider.GenericError, |
| new Object [] { "unrecognized child '"+childName+"' in complex type "+typeName }); |
| else |
| reportSchemaError(SchemaMessageProvider.GenericError, |
| new Object [] { "unrecognized child '"+childName+"' in complex type '"+typeName+"' with base "+base }); |
| } |
| |
| // if base is complextype with simpleType content, can't have any particle children at all. |
| if (baseIsComplexSimple && seeParticle) { |
| // REVISIT: Localize |
| reportGenericSchemaError("In complexType "+typeName+", base type is complexType with simpleType content, can't have any particle children at all"); |
| hadContent = false; |
| left = index = -2; |
| contentSpecType = XMLElementDecl.TYPE_SIMPLE; |
| break; |
| } |
| |
| |
| if (seeAll && seeOtherParticle) { |
| // REVISIT: Localize |
| reportGenericSchemaError ( " 'All' group needs to be the only child in Complextype : " + typeName); |
| } |
| |
| if (seeAll) { |
| //TO DO: REVISIT |
| //check the minOccurs = 1 and maxOccurs = 1 |
| } |
| |
| // check the minOccurs and maxOccurs of the particle, and fix the |
| // contentspec accordingly |
| if (seeParticle) { |
| index = expandContentModel(index, child); |
| if (index == -2 ) { |
| continue; |
| } |
| } //end of if (seeParticle) |
| |
| if (left == -2) { |
| left = index; |
| } else if (right == -2) { |
| right = index; |
| } else { |
| left = fSchemaGrammar.addContentSpecNode(csnType, left, right, false); |
| right = index; |
| } |
| } //end looping through the children |
| |
| if ( ! ( seeOtherParticle || seeAll ) && (elementContent || mixedContent) |
| && (base.length() == 0 || ( base.length() > 0 && derivedByRestriction && !baseIsComplexSimple)) ) { |
| contentSpecType = XMLElementDecl.TYPE_SIMPLE; |
| simpleTypeValidator = getDatatypeValidator("", SchemaSymbols.ATTVAL_STRING); |
| // REVISIT: Localize |
| reportGenericSchemaError ( " complexType '"+typeName+"' with a elementOnly or mixed content " |
| +"need to have at least one particle child"); |
| } |
| |
| if (hadContent && right != -2) |
| left = fSchemaGrammar.addContentSpecNode(csnType, left, right, false); |
| |
| if (mixedContent && hadContent) { |
| // set occurrence count |
| left = fSchemaGrammar.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE, |
| left, -1, false); |
| } |
| } |
| |
| // if derived by extension and base complextype has a content model, |
| // compose the final content model by concatenating the base and the |
| // current in sequence. |
| if (!derivedByRestriction && baseContentSpecHandle > -1 ) { |
| if (left == -2) { |
| left = baseContentSpecHandle; |
| } |
| else |
| left = fSchemaGrammar.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_SEQ, |
| baseContentSpecHandle, |
| left, |
| false); |
| } |
| |
| // REVISIT: this is when sees a topelevel <complexType name="abc">attrs*</complexType> |
| if (content.length() == 0 && base.length() == 0 && left == -2) { |
| contentSpecType = XMLElementDecl.TYPE_ANY; |
| } |
| |
| if (content.length() == 0 && simpleTypeValidator == null && left == -2 ) { |
| if (base.length() > 0 && baseTypeInfo != null |
| && baseTypeInfo.contentType == XMLElementDecl.TYPE_EMPTY) { |
| contentSpecType = XMLElementDecl.TYPE_EMPTY; |
| } |
| } |
| |
| if ( DEBUGGING ) |
| System.out.println("!!!!!>>>>>" + typeName+", "+ baseTypeInfo + ", " |
| + baseContentSpecHandle +", " + left +", "+scopeDefined); |
| |
| ComplexTypeInfo typeInfo = new ComplexTypeInfo(); |
| typeInfo.baseComplexTypeInfo = baseTypeInfo; |
| typeInfo.baseDataTypeValidator = baseTypeValidator; |
| int derivedByInt = -1; |
| if (derivedBy.length() > 0) { |
| derivedByInt = parseComplexDerivedBy(derivedBy); |
| } |
| typeInfo.derivedBy = derivedByInt; |
| typeInfo.scopeDefined = scopeDefined; |
| typeInfo.contentSpecHandle = left; |
| typeInfo.contentType = contentSpecType; |
| typeInfo.datatypeValidator = simpleTypeValidator; |
| typeInfo.blockSet = parseBlockSet(complexTypeDecl.getAttribute(SchemaSymbols.ATT_BLOCK)); |
| typeInfo.finalSet = parseFinalSet(complexTypeDecl.getAttribute(SchemaSymbols.ATT_FINAL)); |
| typeInfo.isAbstract = isAbstract.equals(SchemaSymbols.ATTVAL_TRUE) ? true:false ; |
| |
| //add a template element to the grammar element decl pool. |
| int typeNameIndex = fStringPool.addSymbol(typeName); |
| int templateElementNameIndex = fStringPool.addSymbol("$"+typeName); |
| |
| typeInfo.templateElementIndex = |
| fSchemaGrammar.addElementDecl(new QName(-1, templateElementNameIndex,typeNameIndex,fTargetNSURI), |
| (fTargetNSURI==-1) ? -1 : fCurrentScope, scopeDefined, |
| contentSpecType, left, |
| -1, simpleTypeValidator); |
| typeInfo.attlistHead = fSchemaGrammar.getFirstAttributeDeclIndex(typeInfo.templateElementIndex); |
| |
| |
| // (attribute | attrGroupRef)* |
| XMLAttributeDecl attWildcard = null; |
| Vector anyAttDecls = new Vector(); |
| |
| for (child = XUtil.getFirstChildElement(complexTypeDecl); |
| child != null; |
| child = XUtil.getNextSiblingElement(child)) { |
| |
| String childName = child.getNodeName(); |
| |
| if (childName.equals(SchemaSymbols.ELT_ATTRIBUTE)) { |
| if ((baseIsComplexSimple||baseIsSimpleSimple) && derivedByRestriction) { |
| // REVISIT: Localize |
| reportGenericSchemaError("In complexType "+typeName+ |
| ", base type has simpleType "+ |
| "content and derivation method is"+ |
| " 'restriction', can't have any "+ |
| "attribute children at all"); |
| break; |
| } |
| traverseAttributeDecl(child, typeInfo); |
| } |
| else if ( childName.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP) ) { |
| if ((baseIsComplexSimple||baseIsSimpleSimple) && derivedByRestriction) { |
| // REVISIT: Localize |
| reportGenericSchemaError("In complexType "+typeName+", base "+ |
| "type has simpleType content and "+ |
| "derivation method is 'restriction',"+ |
| " can't have any attribute children at all"); |
| break; |
| } |
| traverseAttributeGroupDecl(child,typeInfo,anyAttDecls); |
| } |
| else if ( childName.equals(SchemaSymbols.ELT_ANYATTRIBUTE) ) { |
| attWildcard = traverseAnyAttribute(child); |
| } |
| } |
| |
| if (attWildcard != null) { |
| XMLAttributeDecl fromGroup = null; |
| final int count = anyAttDecls.size(); |
| if ( count > 0) { |
| fromGroup = (XMLAttributeDecl) anyAttDecls.elementAt(0); |
| for (int i=1; i<count; i++) { |
| fromGroup = mergeTwoAnyAttribute(fromGroup,(XMLAttributeDecl)anyAttDecls.elementAt(i)); |
| } |
| } |
| if (fromGroup != null) { |
| int saveProcessContents = attWildcard.defaultType; |
| attWildcard = mergeTwoAnyAttribute(attWildcard, fromGroup); |
| attWildcard.defaultType = saveProcessContents; |
| } |
| } |
| else { |
| //REVISIT: unclear in the Scheme Structures 4.3.3 what to do in this case |
| } |
| |
| // merge in base type's attribute decls |
| XMLAttributeDecl baseAttWildcard = null; |
| if (baseTypeInfo != null && baseTypeInfo.attlistHead > -1 ) { |
| int attDefIndex = baseTypeInfo.attlistHead; |
| SchemaGrammar aGrammar = fSchemaGrammar; |
| if (baseFromAnotherSchema) { |
| aGrammar = (SchemaGrammar) fGrammarResolver.getGrammar(baseTypeSchemaURI); |
| } |
| if (aGrammar == null) { |
| reportGenericSchemaError("In complexType "+typeName+", can NOT find the grammar "+ |
| "with targetNamespace" + baseTypeSchemaURI+ |
| "for the base type"); |
| } |
| else |
| while ( attDefIndex > -1 ) { |
| fTempAttributeDecl.clear(); |
| aGrammar.getAttributeDecl(attDefIndex, fTempAttributeDecl); |
| if (fTempAttributeDecl.type == XMLAttributeDecl.TYPE_ANY_ANY |
| ||fTempAttributeDecl.type == XMLAttributeDecl.TYPE_ANY_LIST |
| ||fTempAttributeDecl.type == XMLAttributeDecl.TYPE_ANY_LOCAL |
| ||fTempAttributeDecl.type == XMLAttributeDecl.TYPE_ANY_OTHER ) { |
| if (attWildcard == null) { |
| baseAttWildcard = fTempAttributeDecl; |
| } |
| attDefIndex = aGrammar.getNextAttributeDeclIndex(attDefIndex); |
| continue; |
| } |
| // if found a duplicate, if it is derived by restriction. then skip the one from the base type |
| /**/ |
| int temp = fSchemaGrammar.getAttributeDeclIndex(typeInfo.templateElementIndex, fTempAttributeDecl.name); |
| if ( temp > -1) { |
| if (derivedByRestriction) { |
| attDefIndex = fSchemaGrammar.getNextAttributeDeclIndex(attDefIndex); |
| continue; |
| } |
| } |
| |
| /**/ |
| fSchemaGrammar.addAttDef( typeInfo.templateElementIndex, |
| fTempAttributeDecl.name, fTempAttributeDecl.type, |
| fTempAttributeDecl.enumeration, fTempAttributeDecl.defaultType, |
| fTempAttributeDecl.defaultValue, |
| fTempAttributeDecl.datatypeValidator, |
| fTempAttributeDecl.list); |
| attDefIndex = aGrammar.getNextAttributeDeclIndex(attDefIndex); |
| } |
| } |
| // att wildcard will inserted after all attributes were processed |
| if (attWildcard != null) { |
| if (attWildcard.type != -1) { |
| fSchemaGrammar.addAttDef( typeInfo.templateElementIndex, |
| attWildcard.name, attWildcard.type, |
| attWildcard.enumeration, attWildcard.defaultType, |
| attWildcard.defaultValue, |
| attWildcard.datatypeValidator, |
| attWildcard.list); |
| } |
| else { |
| //REVISIT: unclear in Schema spec if should report error here. |
| } |
| } |
| else if (baseAttWildcard != null) { |
| fSchemaGrammar.addAttDef( typeInfo.templateElementIndex, |
| baseAttWildcard.name, baseAttWildcard.type, |
| baseAttWildcard.enumeration, baseAttWildcard.defaultType, |
| baseAttWildcard.defaultValue, |
| baseAttWildcard.datatypeValidator, |
| baseAttWildcard.list); |
| } |
| |
| typeInfo.attlistHead = fSchemaGrammar.getFirstAttributeDeclIndex(typeInfo.templateElementIndex); |
| |
| if (!typeName.startsWith("#")) { |
| typeName = fTargetNSURIString + "," + typeName; |
| } |
| typeInfo.typeName = new String(typeName); |
| if ( DEBUGGING ) |
| System.out.println("add complex Type to Registry: " + typeName +","+content+"."); |
| fComplexTypeRegistry.put(typeName,typeInfo); |
| |
| // before exit the complex type definition, restore the scope, mainly for nested Anonymous Types |
| fCurrentScope = previousScope; |
| if (isNamedType) { |
| fCurrentTypeNameStack.pop(); |
| checkRecursingComplexType(); |
| } |
| |
| //set template element's typeInfo |
| fSchemaGrammar.setElementComplexTypeInfo(typeInfo.templateElementIndex, typeInfo); |
| |
| typeNameIndex = fStringPool.addSymbol(typeName); |
| return typeNameIndex; |
| |
| |
| } // end of method: traverseComplexTypeDecl |
| |
| private void checkRecursingComplexType() throws Exception { |
| if ( fCurrentTypeNameStack.empty() ) { |
| if (! fElementRecurseComplex.isEmpty() ) { |
| Enumeration e = fElementRecurseComplex.keys(); |
| while( e.hasMoreElements() ) { |
| QName nameThenScope = (QName) e.nextElement(); |
| String typeName = (String) fElementRecurseComplex.get(nameThenScope); |
| |
| int eltUriIndex = nameThenScope.uri; |
| int eltNameIndex = nameThenScope.localpart; |
| int enclosingScope = nameThenScope.prefix; |
| ComplexTypeInfo typeInfo = |
| (ComplexTypeInfo) fComplexTypeRegistry.get(fTargetNSURIString+","+typeName); |
| if (typeInfo==null) { |
| throw new Exception ( "Internal Error in void checkRecursingComplexType(). " ); |
| } |
| else { |
| int elementIndex = fSchemaGrammar.addElementDecl(new QName(-1, eltNameIndex, eltNameIndex, eltUriIndex), |
| enclosingScope, typeInfo.scopeDefined, |
| typeInfo.contentType, |
| typeInfo.contentSpecHandle, |
| typeInfo.attlistHead, |
| typeInfo.datatypeValidator); |
| fSchemaGrammar.setElementComplexTypeInfo(elementIndex, typeInfo); |
| } |
| |
| } |
| fElementRecurseComplex.clear(); |
| } |
| } |
| } |
| |
| private void checkParticleDerivationOK(Element derivedTypeNode, Element baseTypeNode) { |
| //TO DO: !!! |
| } |
| |
| private int expandContentModel ( int index, Element particle) throws Exception { |
| |
| String minOccurs = particle.getAttribute(SchemaSymbols.ATT_MINOCCURS).trim(); |
| String maxOccurs = particle.getAttribute(SchemaSymbols.ATT_MAXOCCURS).trim(); |
| |
| int min=1, max=1; |
| |
| if(minOccurs.equals("0") && maxOccurs.equals("0")){ |
| return -2; |
| } |
| |
| if (minOccurs.equals("")) { |
| minOccurs = "1"; |
| } |
| if (maxOccurs.equals("") ){ |
| if ( minOccurs.equals("0")) { |
| maxOccurs = "1"; |
| } |
| else { |
| maxOccurs = minOccurs; |
| } |
| } |
| |
| |
| int leafIndex = index; |
| //REVISIT: !!! minoccurs, maxoccurs. |
| if (minOccurs.equals("1")&& maxOccurs.equals("1")) { |
| |
| } |
| else if (minOccurs.equals("0")&& maxOccurs.equals("1")) { |
| //zero or one |
| index = fSchemaGrammar.addContentSpecNode( XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE, |
| index, |
| -1, |
| false); |
| } |
| else if (minOccurs.equals("0")&& maxOccurs.equals("unbounded")) { |
| //zero or more |
| index = fSchemaGrammar.addContentSpecNode( XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE, |
| index, |
| -1, |
| false); |
| } |
| else if (minOccurs.equals("1")&& maxOccurs.equals("unbounded")) { |
| //one or more |
| index = fSchemaGrammar.addContentSpecNode( XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE, |
| index, |
| -1, |
| false); |
| } |
| else if (maxOccurs.equals("unbounded") ) { |
| // >=2 or more |
| try { |
| min = Integer.parseInt(minOccurs); |
| } |
| catch (Exception e) { |
| reportSchemaError(SchemaMessageProvider.GenericError, |
| new Object [] { "illegal value for minOccurs : '" +e.getMessage()+ "' " }); |
| } |
| if (min<2) { |
| //REVISIT: report Error here |
| } |
| |
| // => a,a,..,a+ |
| index = fSchemaGrammar.addContentSpecNode( XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE, |
| index, |
| -1, |
| false); |
| |
| for (int i=0; i < (min-1); i++) { |
| index = fSchemaGrammar.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_SEQ, |
| leafIndex, |
| index, |
| false); |
| } |
| |
| } |
| else { |
| // {n,m} => a,a,a,...(a),(a),... |
| try { |
| min = Integer.parseInt(minOccurs); |
| max = Integer.parseInt(maxOccurs); |
| } |
| catch (Exception e){ |
| reportSchemaError(SchemaMessageProvider.GenericError, |
| new Object [] { "illegal value for minOccurs or maxOccurs : '" +e.getMessage()+ "' "}); |
| } |
| if (min==0) { |
| int optional = fSchemaGrammar.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE, |
| leafIndex, |
| -1, |
| false); |
| index = optional; |
| for (int i=0; i < (max-min-1); i++) { |
| index = fSchemaGrammar.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_SEQ, |
| index, |
| optional, |
| false); |
| } |
| } |
| else { |
| for (int i=0; i<(min-1); i++) { |
| index = fSchemaGrammar.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_SEQ, |
| index, |
| leafIndex, |
| false); |
| } |
| |
| int optional = fSchemaGrammar.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE, |
| leafIndex, |
| -1, |
| false); |
| for (int i=0; i < (max-min); i++) { |
| index = fSchemaGrammar.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_SEQ, |
| index, |
| optional, |
| false); |
| } |
| } |
| } |
| |
| return index; |
| } |
| |
| /** |
| * Traverses Schema attribute declaration. |
| * |
| * <attribute |
| * form = qualified | unqualified |
| * id = ID |
| * name = NCName |
| * ref = QName |
| * type = QName |
| * use = default | fixed | optional | prohibited | required |
| * value = string> |
| * Content: (annotation? , simpleType?) |
| * <attribute/> |
| * |
| * @param attributeDecl |
| * @return |
| * @exception Exception |
| */ |
| private int traverseAttributeDecl( Element attrDecl, ComplexTypeInfo typeInfo ) throws Exception { |
| String attNameStr = attrDecl.getAttribute(SchemaSymbols.ATT_NAME); |
| int attName = fStringPool.addSymbol(attNameStr);// attribute name |
| String isQName = attrDecl.getAttribute(SchemaSymbols.ATT_FORM);//form attribute |
| |
| DatatypeValidator dv = null; |
| // attribute type |
| int attType = -1; |
| boolean attIsList = false; |
| int dataTypeSymbol = -1; |
| |
| String ref = attrDecl.getAttribute(SchemaSymbols.ATT_REF); |
| String datatype = attrDecl.getAttribute(SchemaSymbols.ATT_TYPE); |
| String localpart = null; |
| |
| if (!ref.equals("")) { |
| if (XUtil.getFirstChildElement(attrDecl) != null) |
| reportSchemaError(SchemaMessageProvider.NoContentForRef, null); |
| String prefix = ""; |
| localpart = ref; |
| int colonptr = ref.indexOf(":"); |
| if ( colonptr > 0) { |
| prefix = ref.substring(0,colonptr); |
| localpart = ref.substring(colonptr+1); |
| } |
| String uriStr = resolvePrefixToURI(prefix); |
| |
| if (!uriStr.equals(fTargetNSURIString)) { |
| addAttributeDeclFromAnotherSchema(localpart, uriStr, typeInfo); |
| |
| return -1; |
| // TO DO |
| // REVISIT: different NS, not supported yet. |
| // REVISIT: Localize |
| //reportGenericSchemaError("Feature not supported: see an attribute from different NS"); |
| } |
| |
| Element referredAttribute = getTopLevelComponentByName(SchemaSymbols.ELT_ATTRIBUTE,localpart); |
| if (referredAttribute != null) { |
| traverseAttributeDecl(referredAttribute, typeInfo); |
| } |
| else { |
| // REVISIT: Localize |
| reportGenericSchemaError ( "Couldn't find top level attribute " + ref); |
| } |
| return -1; |
| } |
| |
| |
| if (datatype.equals("")) { |
| Element child = XUtil.getFirstChildElement(attrDecl); |
| |
| while (child != null && |
| !child.getNodeName().equals(SchemaSymbols.ELT_SIMPLETYPE)) |
| child = XUtil.getNextSiblingElement(child); |
| |
| |
| if (child != null && child.getNodeName().equals(SchemaSymbols.ELT_SIMPLETYPE)) { |
| attType = XMLAttributeDecl.TYPE_SIMPLE; |
| dataTypeSymbol = traverseSimpleTypeDecl(child); |
| localpart = fStringPool.toString(dataTypeSymbol); |
| } |
| else { |
| attType = XMLAttributeDecl.TYPE_SIMPLE; |
| localpart = "string"; |
| dataTypeSymbol = fStringPool.addSymbol(localpart); |
| } |
| localpart = fStringPool.toString(dataTypeSymbol); |
| |
| dv = fDatatypeRegistry.getDatatypeValidator(localpart); |
| |
| } else { |
| |
| String prefix = ""; |
| localpart = datatype; |
| dataTypeSymbol = fStringPool.addSymbol(localpart); |
| |
| int colonptr = datatype.indexOf(":"); |
| if ( colonptr > 0) { |
| prefix = datatype.substring(0,colonptr); |
| localpart = datatype.substring(colonptr+1); |
| } |
| String typeURI = resolvePrefixToURI(prefix); |
| |
| if ( typeURI.equals(SchemaSymbols.URI_SCHEMAFORSCHEMA) |
| || typeURI.length()==0) { |
| |
| dv = getDatatypeValidator("", localpart); |
| |
| if (localpart.equals("ID")) { |
| attType = XMLAttributeDecl.TYPE_ID; |
| } else if (localpart.equals("IDREF")) { |
| attType = XMLAttributeDecl.TYPE_IDREF; |
| } else if (localpart.equals("IDREFS")) { |
| attType = XMLAttributeDecl.TYPE_IDREF; |
| attIsList = true; |
| } else if (localpart.equals("ENTITY")) { |
| attType = XMLAttributeDecl.TYPE_ENTITY; |
| } else if (localpart.equals("ENTITIES")) { |
| attType = XMLAttributeDecl.TYPE_ENTITY; |
| attIsList = true; |
| } else if (localpart.equals("NMTOKEN")) { |
| attType = XMLAttributeDecl.TYPE_NMTOKEN; |
| } else if (localpart.equals("NMTOKENS")) { |
| attType = XMLAttributeDecl.TYPE_NMTOKEN; |
| attIsList = true; |
| } else if (localpart.equals(SchemaSymbols.ELT_NOTATION)) { |
| attType = XMLAttributeDecl.TYPE_NOTATION; |
| } |
| else { |
| attType = XMLAttributeDecl.TYPE_SIMPLE; |
| if (dv == null && typeURI.length() == 0) { |
| Element topleveltype = getTopLevelComponentByName(SchemaSymbols.ELT_SIMPLETYPE, localpart); |
| if (topleveltype != null) { |
| traverseSimpleTypeDecl( topleveltype ); |
| dv = getDatatypeValidator(typeURI, localpart); |
| }else { |
| // REVISIT: Localize |
| reportGenericSchemaError("simpleType not found : " + localpart); |
| } |
| } |
| } |
| } else { |
| |
| // check if the type is from the same Schema |
| |
| dv = getDatatypeValidator(typeURI, localpart); |
| if (dv == null && typeURI.equals(fTargetNSURIString) ) { |
| Element topleveltype = getTopLevelComponentByName(SchemaSymbols.ELT_SIMPLETYPE, localpart); |
| if (topleveltype != null) { |
| traverseSimpleTypeDecl( topleveltype ); |
| dv = getDatatypeValidator(typeURI, localpart); |
| }else { |
| // REVISIT: Localize |
| reportGenericSchemaError("simpleType not found : " + localpart); |
| } |
| } |
| |
| attType = XMLAttributeDecl.TYPE_SIMPLE; |
| } |
| |
| } |
| |
| |
| // attribute default type |
| int attDefaultType = -1; |
| int attDefaultValue = -1; |
| |
| String use = attrDecl.getAttribute(SchemaSymbols.ATT_USE); |
| boolean required = use.equals(SchemaSymbols.ATTVAL_REQUIRED); |
| |
| |
| if (dv == null) { |
| // REVISIT: Localize |
| reportGenericSchemaError("could not resolve the type or get a null validator for datatype : " |
| + fStringPool.toString(dataTypeSymbol)); |
| } |
| |
| if (required) { |
| attDefaultType = XMLAttributeDecl.DEFAULT_TYPE_REQUIRED; |
| } else { |
| if (use.equals(SchemaSymbols.ATTVAL_FIXED)) { |
| String fixed = attrDecl.getAttribute(SchemaSymbols.ATT_VALUE); |
| if (!fixed.equals("")) { |
| attDefaultType = XMLAttributeDecl.DEFAULT_TYPE_FIXED; |
| attDefaultValue = fStringPool.addString(fixed); |
| } |
| } |
| else if (use.equals(SchemaSymbols.ATTVAL_DEFAULT)) { |
| // attribute default value |
| String defaultValue = attrDecl.getAttribute(SchemaSymbols.ATT_VALUE); |
| if (!defaultValue.equals("")) { |
| attDefaultType = XMLAttributeDecl.DEFAULT_TYPE_DEFAULT; |
| attDefaultValue = fStringPool.addString(defaultValue); |
| } |
| } |
| else if (use.equals(SchemaSymbols.ATTVAL_PROHIBITED)) { |
| |
| //REVISIT, TO DO. !!! |
| attDefaultType = XMLAttributeDecl.DEFAULT_TYPE_IMPLIED; |
| //attDefaultValue = fStringPool.addString(""); |
| } |
| else { |
| attDefaultType = XMLAttributeDecl.DEFAULT_TYPE_IMPLIED; |
| } // check default value is valid for the datatype. |
| |
| if (attType == XMLAttributeDecl.TYPE_SIMPLE && attDefaultValue != -1) { |
| try { |
| if (dv != null) |
| //REVISIT |
| dv.validate(fStringPool.toString(attDefaultValue), null); |
| else |
| reportSchemaError(SchemaMessageProvider.NoValidatorFor, |
| new Object [] { datatype }); |
| } catch (InvalidDatatypeValueException idve) { |
| reportSchemaError(SchemaMessageProvider.IncorrectDefaultType, |
| new Object [] { attrDecl.getAttribute(SchemaSymbols.ATT_NAME), idve.getMessage() }); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| System.out.println("Internal error in attribute datatype validation"); |
| } |
| } |
| } |
| |
| int uriIndex = -1; |
| if ( isQName.equals(SchemaSymbols.ATTVAL_QUALIFIED)|| |
| fAttributeDefaultQualified || isTopLevel(attrDecl) ) { |
| uriIndex = fTargetNSURI; |
| } |
| |
| QName attQName = new QName(-1,attName,attName,uriIndex); |
| if ( DEBUGGING ) |
| System.out.println(" the dataType Validator for " + fStringPool.toString(attName) + " is " + dv); |
| |
| //put the top-levels in the attribute decl registry. |
| if (isTopLevel(attrDecl)) { |
| fTempAttributeDecl.datatypeValidator = dv; |
| fTempAttributeDecl.name.setValues(attQName); |
| fTempAttributeDecl.type = attType; |
| fTempAttributeDecl.defaultType = attDefaultType; |
| fTempAttributeDecl.list = attIsList; |
| if (attDefaultValue != -1 ) { |
| fTempAttributeDecl.defaultValue = new String(fStringPool.toString(attDefaultValue)); |
| } |
| fAttributeDeclRegistry.put(attNameStr, new XMLAttributeDecl(fTempAttributeDecl)); |
| } |
| |
| // add attribute to attr decl pool in fSchemaGrammar, |
| if (typeInfo != null) { |
| fSchemaGrammar.addAttDef( typeInfo.templateElementIndex, |
| attQName, attType, |
| dataTypeSymbol, attDefaultType, |
| fStringPool.toString( attDefaultValue), dv, attIsList); |
| } |
| return -1; |
| } // end of method traverseAttribute |
| |
| private int addAttributeDeclFromAnotherSchema( String name, String uriStr, ComplexTypeInfo typeInfo) throws Exception { |
| SchemaGrammar aGrammar = (SchemaGrammar) fGrammarResolver.getGrammar(uriStr); |
| if (uriStr == null || ! (aGrammar instanceof SchemaGrammar) ) { |
| // REVISIT: Localize |
| reportGenericSchemaError("!!Schema not found in #addAttributeDeclFromAnotherSchema, schema uri : " + uriStr); |
| return -1; |
| } |
| |
| Hashtable attrRegistry = aGrammar.getAttirubteDeclRegistry(); |
| if (attrRegistry == null) { |
| // REVISIT: Localize |
| reportGenericSchemaError("no attribute was defined in schema : " + uriStr); |
| return -1; |
| } |
| |
| XMLAttributeDecl tempAttrDecl = (XMLAttributeDecl) attrRegistry.get(name); |
| |
| if (tempAttrDecl == null) { |
| // REVISIT: Localize |
| reportGenericSchemaError( "no attribute named \"" + name |
| + "\" was defined in schema : " + uriStr); |
| return -1; |
| } |
| |
| |
| if (typeInfo!= null) { |
| fSchemaGrammar.addAttDef( typeInfo.templateElementIndex, |
| tempAttrDecl.name, tempAttrDecl.type, |
| -1, tempAttrDecl.defaultType, |
| tempAttrDecl.defaultValue, |
| tempAttrDecl.datatypeValidator, |
| tempAttrDecl.list); |
| } |
| |
| |
| return 0; |
| } |
| |
| /* |
| * |
| * <attributeGroup |
| * id = ID |
| * name = NCName |
| * ref = QName> |
| * Content: (annotation?, (attribute|attributeGroup), anyAttribute?) |
| * </> |
| * |
| */ |
| private int traverseAttributeGroupDecl( Element attrGrpDecl, ComplexTypeInfo typeInfo, Vector anyAttDecls ) throws Exception { |
| // attribute name |
| int attGrpName = fStringPool.addSymbol(attrGrpDecl.getAttribute(SchemaSymbols.ATT_NAME)); |
| |
| String ref = attrGrpDecl.getAttribute(SchemaSymbols.ATT_REF); |
| |
| // attribute type |
| int attType = -1; |
| int enumeration = -1; |
| |
| if (!ref.equals("")) { |
| if (XUtil.getFirstChildElement(attrGrpDecl) != null) |
| reportSchemaError(SchemaMessageProvider.NoContentForRef, null); |
| String prefix = ""; |
| String localpart = ref; |
| int colonptr = ref.indexOf(":"); |
| if ( colonptr > 0) { |
| prefix = ref.substring(0,colonptr); |
| localpart = ref.substring(colonptr+1); |
| } |
| String uriStr = resolvePrefixToURI(prefix); |
| if (!uriStr.equals(fTargetNSURIString)) { |
| |
| traverseAttributeGroupDeclFromAnotherSchema(localpart, uriStr, typeInfo, anyAttDecls); |
| |
| return -1; |
| // TO DO |
| // REVISIST: different NS, not supported yet. |
| // REVISIT: Localize |
| //reportGenericSchemaError("Feature not supported: see an attribute from different NS"); |
| } |
| Element referredAttrGrp = getTopLevelComponentByName(SchemaSymbols.ELT_ATTRIBUTEGROUP,localpart); |
| if (referredAttrGrp != null) { |
| traverseAttributeGroupDecl(referredAttrGrp, typeInfo, anyAttDecls); |
| } |
| else { |
| // REVISIT: Localize |
| reportGenericSchemaError ( "Couldn't find top level attributegroup " + ref); |
| } |
| return -1; |
| } |
| |
| for ( Element child = XUtil.getFirstChildElement(attrGrpDecl); |
| child != null ; child = XUtil.getNextSiblingElement(child)) { |
| |
| if ( child.getNodeName().equals(SchemaSymbols.ELT_ATTRIBUTE) ){ |
| traverseAttributeDecl(child, typeInfo); |
| } |
| else if ( child.getNodeName().equals(SchemaSymbols.ELT_ATTRIBUTEGROUP) ) { |
| traverseAttributeGroupDecl(child, typeInfo,anyAttDecls); |
| } |
| else if ( child.getNodeName().equals(SchemaSymbols.ELT_ANYATTRIBUTE) ) { |
| anyAttDecls.addElement(traverseAnyAttribute(child)); |
| break; |
| } |
| else if (child.getNodeName().equals(SchemaSymbols.ELT_ANNOTATION) ) { |
| // REVISIT: what about appInfo |
| } |
| } |
| return -1; |
| } // end of method traverseAttributeGroup |
| |
| private int traverseAttributeGroupDeclFromAnotherSchema( String attGrpName , String uriStr, |
| ComplexTypeInfo typeInfo, |
| Vector anyAttDecls ) throws Exception { |
| |
| SchemaGrammar aGrammar = (SchemaGrammar) fGrammarResolver.getGrammar(uriStr); |
| if (uriStr == null || aGrammar == null || ! (aGrammar instanceof SchemaGrammar) ) { |
| // REVISIT: Localize |
| reportGenericSchemaError("!!Schema not found in #traverseAttributeGroupDeclFromAnotherSchema, schema uri : " + uriStr); |
| return -1; |
| } |
| // attribute name |
| Element attGrpDecl = (Element) aGrammar.topLevelAttrGrpDecls.get((Object)attGrpName); |
| if (attGrpDecl == null) { |
| // REVISIT: Localize |
| reportGenericSchemaError( "no attribute group named \"" + attGrpName |
| + "\" was defined in schema : " + uriStr); |
| return -1; |
| } |
| |
| NamespacesScope saveNSMapping = fNamespacesScope; |
| int saveTargetNSUri = fTargetNSURI; |
| fTargetNSURI = fStringPool.addSymbol(aGrammar.getTargetNamespaceURI()); |
| fNamespacesScope = aGrammar.getNamespacesScope(); |
| |
| // attribute type |
| int attType = -1; |
| int enumeration = -1; |
| |
| |
| for ( Element child = XUtil.getFirstChildElement(attGrpDecl); |
| child != null ; child = XUtil.getNextSiblingElement(child)) { |
| |
| //child attribute couldn't be a top-level attribute DEFINITION, |
| if ( child.getNodeName().equals(SchemaSymbols.ELT_ATTRIBUTE) ){ |
| String childAttName = child.getAttribute(SchemaSymbols.ATT_NAME); |
| if ( childAttName.length() > 0 ) { |
| Hashtable attDeclRegistry = aGrammar.getAttirubteDeclRegistry(); |
| if (attDeclRegistry != null) { |
| if (attDeclRegistry.get((Object)childAttName) != null ){ |
| addAttributeDeclFromAnotherSchema(childAttName, uriStr, typeInfo); |
| return -1; |
| } |
| } |
| } |
| else |
| traverseAttributeDecl(child, typeInfo); |
| } |
| else if ( child.getNodeName().equals(SchemaSymbols.ELT_ATTRIBUTEGROUP) ) { |
| traverseAttributeGroupDecl(child, typeInfo, anyAttDecls); |
| } |
| else if ( child.getNodeName().equals(SchemaSymbols.ELT_ANYATTRIBUTE) ) { |
| anyAttDecls.addElement(traverseAnyAttribute(child)); |
| break; |
| } |
| else if (child.getNodeName().equals(SchemaSymbols.ELT_ANNOTATION) ) { |
| // REVISIT: what about appInfo |
| } |
| } |
| |
| fNamespacesScope = saveNSMapping; |
| fTargetNSURI = saveTargetNSUri; |
| return -1; |
| } // end of method traverseAttributeGroupFromAnotherSchema |
| |
| |
| /** |
| * Traverse element declaration: |
| * <element |
| * abstract = boolean |
| * block = #all or (possibly empty) subset of {equivClass, extension, restriction} |
| * default = string |
| * equivClass = QName |
| * final = #all or (possibly empty) subset of {extension, restriction} |
| * fixed = string |
| * form = qualified | unqualified |
| * id = ID |
| * maxOccurs = string |
| * minOccurs = nonNegativeInteger |
| * name = NCName |
| * nullable = boolean |
| * ref = QName |
| * type = QName> |
| * Content: (annotation? , (simpleType | complexType)? , (unique | key | keyref)*) |
| * </element> |
| * |
| * |
| * The following are identity-constraint definitions |
| * <unique |
| * id = ID |
| * name = NCName> |
| * Content: (annotation? , (selector , field+)) |
| * </unique> |
| * |
| * <key |
| * id = ID |
| * name = NCName> |
| * Content: (annotation? , (selector , field+)) |
| * </key> |
| * |
| * <keyref |
| * id = ID |
| * name = NCName |
| * refer = QName> |
| * Content: (annotation? , (selector , field+)) |
| * </keyref> |
| * |
| * <selector> |
| * Content: XPathExprApprox : An XPath expression |
| * </selector> |
| * |
| * <field> |
| * Content: XPathExprApprox : An XPath expression |
| * </field> |
| * |
| * |
| * @param elementDecl |
| * @return |
| * @exception Exception |
| */ |
| private QName traverseElementDecl(Element elementDecl) throws Exception { |
| |
| int contentSpecType = -1; |
| int contentSpecNodeIndex = -1; |
| int typeNameIndex = -1; |
| int scopeDefined = -2; //signal a error if -2 gets gets through |
| //cause scope can never be -2. |
| DatatypeValidator dv = null; |
| |
| |
| |
| String name = elementDecl.getAttribute(SchemaSymbols.ATT_NAME); |
| |
| if ( DEBUGGING ) |
| System.out.println("traversing element decl : " + name ); |
| |
| String ref = elementDecl.getAttribute(SchemaSymbols.ATT_REF); |
| String type = elementDecl.getAttribute(SchemaSymbols.ATT_TYPE); |
| String minOccurs = elementDecl.getAttribute(SchemaSymbols.ATT_MINOCCURS); |
| String maxOccurs = elementDecl.getAttribute(SchemaSymbols.ATT_MAXOCCURS); |
| String dflt = elementDecl.getAttribute(SchemaSymbols.ATT_DEFAULT); |
| String fixed = elementDecl.getAttribute(SchemaSymbols.ATT_FIXED); |
| String equivClass = elementDecl.getAttribute(SchemaSymbols.ATT_EQUIVCLASS); |
| // form attribute |
| String isQName = elementDecl.getAttribute(SchemaSymbols.ATT_FORM); |
| |
| String fromAnotherSchema = null; |
| |
| if (isTopLevel(elementDecl)) { |
| |
| int nameIndex = fStringPool.addSymbol(name); |
| int eltKey = fSchemaGrammar.getElementDeclIndex(fTargetNSURI, nameIndex,TOP_LEVEL_SCOPE); |
| if (eltKey > -1 ) { |
| return new QName(-1,nameIndex,nameIndex,fTargetNSURI); |
| } |
| } |
| |
| // parse out 'block', 'final', 'nullable', 'abstract' |
| int blockSet = parseBlockSet(elementDecl.getAttribute(SchemaSymbols.ATT_BLOCK)); |
| int finalSet = parseFinalSet(elementDecl.getAttribute(SchemaSymbols.ATT_FINAL)); |
| boolean isNullable = elementDecl.getAttribute |
| (SchemaSymbols.ATT_NULLABLE).equals(SchemaSymbols.ATTVAL_TRUE)? true:false; |
| boolean isAbstract = elementDecl.getAttribute |
| (SchemaSymbols.ATT_ABSTRACT).equals(SchemaSymbols.ATTVAL_TRUE)? true:false; |
| int elementMiscFlags = 0; |
| if (isNullable) { |
| elementMiscFlags += SchemaSymbols.NULLABLE; |
| } |
| if (isAbstract) { |
| elementMiscFlags += SchemaSymbols.ABSTRACT; |
| } |
| |
| //if this is a reference to a global element |
| int attrCount = 0; |
| if (!ref.equals("")) attrCount++; |
| if (!type.equals("")) attrCount++; |
| //REVISIT top level check for ref & archref |
| if (attrCount > 1) |
| reportSchemaError(SchemaMessageProvider.OneOfTypeRefArchRef, null); |
| |
| if (!ref.equals("")) { |
| if (XUtil.getFirstChildElement(elementDecl) != null) |
| reportSchemaError(SchemaMessageProvider.NoContentForRef, null); |
| String prefix = ""; |
| String localpart = ref; |
| int colonptr = ref.indexOf(":"); |
| if ( colonptr > 0) { |
| prefix = ref.substring(0,colonptr); |
| localpart = ref.substring(colonptr+1); |
| } |
| int localpartIndex = fStringPool.addSymbol(localpart); |
| String uriString = resolvePrefixToURI(prefix); |
| QName eltName = new QName(prefix != null ? fStringPool.addSymbol(prefix) : -1, |
| localpartIndex, |
| fStringPool.addSymbol(ref), |
| uriString != null ? fStringPool.addSymbol(uriString) : -1); |
| |
| //if from another schema, just return the element QName |
| if (! uriString.equals(fTargetNSURIString) ) { |
| return eltName; |
| } |
| |
| int elementIndex = fSchemaGrammar.getElementDeclIndex(eltName, TOP_LEVEL_SCOPE); |
| //if not found, traverse the top level element that if referenced |
| |
| if (elementIndex == -1 ) { |
| Element targetElement = getTopLevelComponentByName(SchemaSymbols.ELT_ELEMENT,localpart); |
| if (targetElement == null ) { |
| // REVISIT: Localize |
| reportGenericSchemaError("Element " + localpart + " not found in the Schema"); |
| //REVISIT, for now, the QName anyway |
| return eltName; |
| //return new QName(-1,fStringPool.addSymbol(localpart), -1, fStringPool.addSymbol(uriString)); |
| } |
| else { |
| // do nothing here, other wise would cause infinite loop for |
| // <element name="recur"><complexType><element ref="recur"> ... |
| //eltName= traverseElementDecl(targetElement); |
| } |
| } |
| return eltName; |
| } |
| |
| // Handle the equivClass |
| Element equivClassElementDecl = null; |
| int equivClassElementDeclIndex = -1; |
| boolean noErrorSoFar = true; |
| String equivClassUri = null; |
| String equivClassLocalpart = null; |
| String equivClassFullName = null; |
| ComplexTypeInfo equivClassEltTypeInfo = null; |
| DatatypeValidator equivClassEltDV = null; |
| |
| if ( equivClass.length() > 0 ) { |
| equivClassUri = resolvePrefixToURI(getPrefix(equivClass)); |
| equivClassLocalpart = getLocalPart(equivClass); |
| equivClassFullName = equivClassUri+","+equivClassLocalpart; |
| |
| if ( !equivClassUri.equals(fTargetNSURIString) ) { |
| equivClassEltTypeInfo = getElementDeclTypeInfoFromNS(equivClassUri, equivClassLocalpart); |
| if (equivClassEltTypeInfo == null) { |
| equivClassEltDV = getElementDeclTypeValidatorFromNS(equivClassUri, equivClassLocalpart); |
| if (equivClassEltDV == null) { |
| //TO DO: report error here; |
| noErrorSoFar = false; |
| reportGenericSchemaError("Could not find type for element '" +equivClassLocalpart |
| + "' in schema '" + equivClassUri+"'"); |
| } |
| } |
| } |
| else { |
| equivClassElementDecl = getTopLevelComponentByName(SchemaSymbols.ELT_ELEMENT, equivClassLocalpart); |
| if (equivClassElementDecl == null) { |
| equivClassElementDeclIndex = |
| fSchemaGrammar.getElementDeclIndex(fTargetNSURI, getLocalPartIndex(equivClass),TOP_LEVEL_SCOPE); |
| if ( equivClassElementDeclIndex == -1) { |
| noErrorSoFar = false; |
| // REVISIT: Localize |
| reportGenericSchemaError("Equivclass affiliation element " |
| +equivClass |
| +" in element declaration " |
| +name); |
| } |
| } |
| else { |
| equivClassElementDeclIndex = |
| fSchemaGrammar.getElementDeclIndex(fTargetNSURI, getLocalPartIndex(equivClass),TOP_LEVEL_SCOPE); |
| |
| if ( equivClassElementDeclIndex == -1) { |
| traverseElementDecl(equivClassElementDecl); |
| equivClassElementDeclIndex = |
| fSchemaGrammar.getElementDeclIndex(fTargetNSURI, getLocalPartIndex(equivClass),TOP_LEVEL_SCOPE); |
| } |
| } |
| |
| if (equivClassElementDeclIndex != -1) { |
| equivClassEltTypeInfo = fSchemaGrammar.getElementComplexTypeInfo( equivClassElementDeclIndex ); |
| if (equivClassEltTypeInfo == null) { |
| fSchemaGrammar.getElementDecl(equivClassElementDeclIndex, fTempElementDecl); |
| equivClassEltDV = fTempElementDecl.datatypeValidator; |
| if (equivClassEltDV == null) { |
| //TO DO: report error here; |
| noErrorSoFar = false; |
| reportGenericSchemaError("Could not find type for element '" +equivClassLocalpart |
| + "' in schema '" + equivClassUri+"'"); |
| } |
| } |
| } |
| } |
| |
| } |
| |
| |
| // |
| // resolving the type for this element right here |
| // |
| |
| ComplexTypeInfo typeInfo = null; |
| |
| // element has a single child element, either a datatype or a type, null if primitive |
| Element child = XUtil.getFirstChildElement(elementDecl); |
| |
| while (child != null && child.getNodeName().equals(SchemaSymbols.ELT_ANNOTATION)) |
| child = XUtil.getNextSiblingElement(child); |
| |
| boolean haveAnonType = false; |
| |
| // Handle Anonymous type if there is one |
| if (child != null) { |
| |
| String childName = child.getNodeName(); |
| |
| if (childName.equals(SchemaSymbols.ELT_COMPLEXTYPE)) { |
| if (child.getAttribute(SchemaSymbols.ATT_NAME).length() > 0) { |
| noErrorSoFar = false; |
| // REVISIT: Localize |
| reportGenericSchemaError("anonymous complexType in element '" + name +"' has a name attribute"); |
| } |
| else |
| typeNameIndex = traverseComplexTypeDecl(child); |
| if (typeNameIndex != -1 ) { |
| typeInfo = (ComplexTypeInfo) |
| fComplexTypeRegistry.get(fStringPool.toString(typeNameIndex)); |
| } |
| else { |
| noErrorSoFar = false; |
| // REVISIT: Localize |
| reportGenericSchemaError("traverse complexType error in element '" + name +"'"); |
| } |
| haveAnonType = true; |
| } |
| else if (childName.equals(SchemaSymbols.ELT_SIMPLETYPE)) { |
| // TO DO: the Default and fixed attribute handling should be here. |
| if (child.getAttribute(SchemaSymbols.ATT_NAME).length() > 0) { |
| noErrorSoFar = false; |
| // REVISIT: Localize |
| reportGenericSchemaError("anonymous simpleType in element '" + name +"' has a name attribute"); |
| } |
| else |
| typeNameIndex = traverseSimpleTypeDecl(child); |
| if (typeNameIndex != -1) { |
| dv = fDatatypeRegistry.getDatatypeValidator(fStringPool.toString(typeNameIndex)); |
| } |
| else { |
| noErrorSoFar = false; |
| // REVISIT: Localize |
| reportGenericSchemaError("traverse simpleType error in element '" + name +"'"); |
| } |
| contentSpecType = XMLElementDecl.TYPE_SIMPLE; |
| haveAnonType = true; |
| } else if (type.equals("")) { // "ur-typed" leaf |
| contentSpecType = XMLElementDecl.TYPE_ANY; |
| //REVISIT: is this right? |
| //contentSpecType = fStringPool.addSymbol("UR_TYPE"); |
| // set occurrence count |
| contentSpecNodeIndex = -1; |
| } else { |
| System.out.println("unhandled case in TraverseElementDecl"); |
| } |
| } |
| |
| // handle type="" here |
| if (haveAnonType && (type.length()>0)) { |
| noErrorSoFar = false; |
| // REVISIT: Localize |
| reportGenericSchemaError( "Element '"+ name + |
| "' have both a type attribute and a annoymous type child" ); |
| } |
| // type specified as an attribute and no child is type decl. |
| else if (!type.equals("")) { |
| if (equivClassElementDecl != null) { |
| checkEquivClassOK(elementDecl, equivClassElementDecl); |
| } |
| String prefix = ""; |
| String localpart = type; |
| int colonptr = type.indexOf(":"); |
| if ( colonptr > 0) { |
| prefix = type.substring(0,colonptr); |
| localpart = type.substring(colonptr+1); |
| } |
| String typeURI = resolvePrefixToURI(prefix); |
| |
| // check if the type is from the same Schema |
| if ( !typeURI.equals(fTargetNSURIString) |
| && !typeURI.equals(SchemaSymbols.URI_SCHEMAFORSCHEMA) |
| && typeURI.length() != 0) { // REVISIT, only needed because of resolvePrifixToURI. |
| fromAnotherSchema = typeURI; |
| typeInfo = getTypeInfoFromNS(typeURI, localpart); |
| if (typeInfo == null) { |
| dv = getTypeValidatorFromNS(typeURI, localpart); |
| if (dv == null) { |
| //TO DO: report error here; |
| noErrorSoFar = false; |
| reportGenericSchemaError("Could not find type " +localpart |
| + " in schema " + typeURI); |
| } |
| } |
| } |
| else { |
| typeInfo = (ComplexTypeInfo) fComplexTypeRegistry.get(typeURI+","+localpart); |
| if (typeInfo == null) { |
| dv = getDatatypeValidator(typeURI, localpart); |
| if (dv == null ) |
| if (typeURI.equals(SchemaSymbols.URI_SCHEMAFORSCHEMA) |
| && !fTargetNSURIString.equals(SchemaSymbols.URI_SCHEMAFORSCHEMA)) |
| { |
| noErrorSoFar = false; |
| // REVISIT: Localize |
| reportGenericSchemaError("type not found : " + typeURI+":"+localpart); |
| } |
| else { |
| Element topleveltype = getTopLevelComponentByName(SchemaSymbols.ELT_COMPLEXTYPE,localpart); |
| if (topleveltype != null) { |
| if (fCurrentTypeNameStack.search((Object)localpart) > - 1) { |
| //then we found a recursive element using complexType. |
| // REVISIT: this will be broken when recursing happens between 2 schemas |
| int uriInd = -1; |
| if ( isQName.equals(SchemaSymbols.ATTVAL_QUALIFIED)|| |
| fElementDefaultQualified) { |
| uriInd = fTargetNSURI; |
| } |
| int nameIndex = fStringPool.addSymbol(name); |
| QName tempQName = new QName(fCurrentScope, nameIndex, nameIndex, uriInd); |
| fElementRecurseComplex.put(tempQName, localpart); |
| return new QName(-1, nameIndex, nameIndex, uriInd); |
| } |
| else { |
| typeNameIndex = traverseComplexTypeDecl( topleveltype ); |
| typeInfo = (ComplexTypeInfo) |
| fComplexTypeRegistry.get(fStringPool.toString(typeNameIndex)); |
| } |
| } |
| else { |
| topleveltype = getTopLevelComponentByName(SchemaSymbols.ELT_SIMPLETYPE, localpart); |
| if (topleveltype != null) { |
| typeNameIndex = traverseSimpleTypeDecl( topleveltype ); |
| dv = getDatatypeValidator(typeURI, localpart); |
| // TO DO: the Default and fixed attribute handling should be here. |
| } |
| else { |
| noErrorSoFar = false; |
| // REVISIT: Localize |
| reportGenericSchemaError("type not found : " + typeURI+":"+localpart); |
| } |
| |
| } |
| |
| } |
| } |
| } |
| |
| } |
| else if (haveAnonType){ |
| if (equivClassElementDecl != null ) { |
| checkEquivClassOK(elementDecl, equivClassElementDecl); |
| } |
| |
| } |
| // this element is ur-type, check its equivClass afficliation. |
| else { |
| // if there is equivClass affiliation and not type defintion found for this element, |
| // then grab equivClass affiliation's type and give it to this element |
| if ( typeInfo == null && dv == null ) typeInfo = equivClassEltTypeInfo; |
| if ( typeInfo == null && dv == null ) dv = equivClassEltDV; |
| } |
| |
| if (typeInfo == null && dv==null) { |
| if (noErrorSoFar) { |
| // Actually this Element's type definition is ur-type; |
| contentSpecType = XMLElementDecl.TYPE_ANY; |
| // REVISIT, need to wait till we have wildcards implementation. |
| // ADD attribute wildcards here |
| } |
| else { |
| noErrorSoFar = false; |
| // REVISIT: Localize |
| reportGenericSchemaError ("untyped element : " + name ); |
| } |
| } |
| // if element belongs to a compelx type |
| if (typeInfo!=null) { |
| contentSpecNodeIndex = typeInfo.contentSpecHandle; |
| contentSpecType = typeInfo.contentType; |
| scopeDefined = typeInfo.scopeDefined; |
| dv = typeInfo.datatypeValidator; |
| } |
| |
| // if element belongs to a simple type |
| if (dv!=null) { |
| contentSpecType = XMLElementDecl.TYPE_SIMPLE; |
| if (typeInfo == null) { |
| fromAnotherSchema = null; // not to switch schema in this case |
| } |
| } |
| |
| // |
| // key/keyref/unique processing\ |
| // |
| |
| child = XUtil.getFirstChildElement(elementDecl); |
| Vector idConstraints = null; |
| |
| while (child != null){ |
| String childName = child.getNodeName(); |
| /**** |
| if ( childName.equals(SchemaSymbols.ELT_KEY) ) { |
| traverseKey(child, idCnstrt); |
| } |
| else if ( childName.equals(SchemaSymbols.ELT_KEYREF) ) { |
| traverseKeyRef(child, idCnstrt); |
| } |
| else if ( childName.equals(SchemaSymbols.ELT_UNIQUE) ) { |
| traverseUnique(child, idCnstrt); |
| } |
| |
| if (idCnstrt!= null) { |
| if (idConstraints != null) { |
| idConstraints = new Vector(); |
| } |
| idConstraints.addElement(idCnstrt); |
| } |
| /****/ |
| child = XUtil.getNextSiblingElement(child); |
| } |
| |
| // |
| // Create element decl |
| // |
| |
| int elementNameIndex = fStringPool.addSymbol(name); |
| int localpartIndex = elementNameIndex; |
| int uriIndex = -1; |
| int enclosingScope = fCurrentScope; |
| |
| if ( isQName.equals(SchemaSymbols.ATTVAL_QUALIFIED)|| |
| fElementDefaultQualified ) { |
| uriIndex = fTargetNSURI; |
| } |
| |
| if ( isTopLevel(elementDecl)) { |
| uriIndex = fTargetNSURI; |
| enclosingScope = TOP_LEVEL_SCOPE; |
| } |
| |
| |
| //There can never be two elements with the same name and different type in the same scope. |
| int existSuchElementIndex = fSchemaGrammar.getElementDeclIndex(uriIndex, localpartIndex, enclosingScope); |
| if ( existSuchElementIndex > -1) { |
| fSchemaGrammar.getElementDecl(existSuchElementIndex, fTempElementDecl); |
| DatatypeValidator edv = fTempElementDecl.datatypeValidator; |
| ComplexTypeInfo eTypeInfo = fSchemaGrammar.getElementComplexTypeInfo(existSuchElementIndex); |
| if ( ((eTypeInfo != null)&&(eTypeInfo!=typeInfo)) |
| || ((edv != null)&&(edv != dv)) ) { |
| noErrorSoFar = false; |
| // REVISIT: Localize |
| reportGenericSchemaError("duplicate element decl in the same scope : " + |
| fStringPool.toString(localpartIndex)); |
| |
| } |
| } |
| |
| QName eltQName = new QName(-1,localpartIndex,elementNameIndex,uriIndex); |
| |
| // add element decl to pool |
| |
| int attrListHead = -1 ; |
| |
| // copy up attribute decls from type object |
| if (typeInfo != null) { |
| attrListHead = typeInfo.attlistHead; |
| } |
| int elementIndex = fSchemaGrammar.addElementDecl(eltQName, enclosingScope, scopeDefined, |
| contentSpecType, contentSpecNodeIndex, |
| attrListHead, dv); |
| if ( DEBUGGING ) { |
| /***/ |
| System.out.println("########elementIndex:"+elementIndex+" ("+fStringPool.toString(eltQName.uri)+"," |
| + fStringPool.toString(eltQName.localpart) + ")"+ |
| " eltType:"+type+" contentSpecType:"+contentSpecType+ |
| " SpecNodeIndex:"+ contentSpecNodeIndex +" enclosingScope: " +enclosingScope + |
| " scopeDefined: " +scopeDefined+"\n"); |
| /***/ |
| } |
| |
| if (typeInfo != null) { |
| fSchemaGrammar.setElementComplexTypeInfo(elementIndex, typeInfo); |
| } |
| else { |
| fSchemaGrammar.setElementComplexTypeInfo(elementIndex, typeInfo); |
| |
| // REVISIT: should we report error from here? |
| } |
| |
| // mark element if its type belongs to different Schema. |
| fSchemaGrammar.setElementFromAnotherSchemaURI(elementIndex, fromAnotherSchema); |
| |
| // set BlockSet, FinalSet, Nullable and Abstract for this element decl |
| fSchemaGrammar.setElementDeclBlockSet(elementIndex, blockSet); |
| fSchemaGrammar.setElementDeclFinalSet(elementIndex, finalSet); |
| fSchemaGrammar.setElementDeclMiscFlags(elementIndex, elementMiscFlags); |
| |
| // setEquivClassElementFullName |
| fSchemaGrammar.setElementDeclEquivClassElementFullName(elementIndex, equivClassFullName); |
| |
| return eltQName; |
| |
| }// end of method traverseElementDecl(Element) |
| |
| |
| int getLocalPartIndex(String fullName){ |
| int colonAt = fullName.indexOf(":"); |
| String localpart = fullName; |
| if ( colonAt > -1 ) { |
| localpart = fullName.substring(colonAt+1); |
| } |
| return fStringPool.addSymbol(localpart); |
| } |
| |
| String getLocalPart(String fullName){ |
| int colonAt = fullName.indexOf(":"); |
| String localpart = fullName; |
| if ( colonAt > -1 ) { |
| localpart = fullName.substring(colonAt+1); |
| } |
| return localpart; |
| } |
| |
| int getPrefixIndex(String fullName){ |
| int colonAt = fullName.indexOf(":"); |
| String prefix = ""; |
| if ( colonAt > -1 ) { |
| prefix = fullName.substring(0,colonAt); |
| } |
| return fStringPool.addSymbol(prefix); |
| } |
| |
| String getPrefix(String fullName){ |
| int colonAt = fullName.indexOf(":"); |
| String prefix = ""; |
| if ( colonAt > -1 ) { |
| prefix = fullName.substring(0,colonAt); |
| } |
| return prefix; |
| } |
| |
| private void checkEquivClassOK(Element elementDecl, Element equivClassElementDecl){ |
| //TO DO!! |
| } |
| |
| private Element getTopLevelComponentByName(String componentCategory, String name) throws Exception { |
| Element child = XUtil.getFirstChildElement(fSchemaRootElement); |
| |
| if (child == null) { |
| return null; |
| } |
| |
| while (child != null ){ |
| if ( child.getNodeName().equals(componentCategory)) { |
| if (child.getAttribute(SchemaSymbols.ATT_NAME).equals(name)) { |
| return child; |
| } |
| } |
| child = XUtil.getNextSiblingElement(child); |
| } |
| |
| return null; |
| } |
| |
| private boolean isTopLevel(Element component) { |
| //REVISIT, is this the right way to check ? |
| /**** |
| if (component.getParentNode() == fSchemaRootElement ) { |
| return true; |
| } |
| /****/ |
| if (component.getParentNode().getNodeName().endsWith(SchemaSymbols.ELT_SCHEMA) ) { |
| return true; |
| } |
| return false; |
| } |
| |
| DatatypeValidator getTypeValidatorFromNS(String newSchemaURI, String localpart) throws Exception { |
| // The following impl is for the case where every Schema Grammar has its own instance of DatatypeRegistry. |
| // Now that we have only one DataTypeRegistry used by all schemas. this is not needed. |
| /***** |
| Grammar grammar = fGrammarResolver.getGrammar(newSchemaURI); |
| if (grammar != null && grammar instanceof SchemaGrammar) { |
| SchemaGrammar sGrammar = (SchemaGrammar) grammar; |
| DatatypeValidator dv = (DatatypeValidator) fSchemaGrammar.getDatatypeRegistry().getDatatypeValidator(localpart); |
| return dv; |
| } |
| else { |
| reportGenericSchemaError("could not resolve URI : " + newSchemaURI + " to a SchemaGrammar in getTypeValidatorFromNS"); |
| } |
| return null; |
| /*****/ |
| return getDatatypeValidator(newSchemaURI, localpart); |
| } |
| |
| ComplexTypeInfo getTypeInfoFromNS(String newSchemaURI, String localpart) throws Exception { |
| Grammar grammar = fGrammarResolver.getGrammar(newSchemaURI); |
| if (grammar != null && grammar instanceof SchemaGrammar) { |
| SchemaGrammar sGrammar = (SchemaGrammar) grammar; |
| ComplexTypeInfo typeInfo = (ComplexTypeInfo) sGrammar.getComplexTypeRegistry().get(newSchemaURI+","+localpart); |
| return typeInfo; |
| } |
| else { |
| reportGenericSchemaError("could not resolve URI : " + newSchemaURI + " to a SchemaGrammar in getTypeInfoFromNS"); |
| } |
| return null; |
| } |
| |
| DatatypeValidator getElementDeclTypeValidatorFromNS(String newSchemaURI, String localpart) throws Exception { |
| Grammar grammar = fGrammarResolver.getGrammar(newSchemaURI); |
| if (grammar != null && grammar instanceof SchemaGrammar) { |
| SchemaGrammar sGrammar = (SchemaGrammar) grammar; |
| int eltIndex = sGrammar.getElementDeclIndex(fStringPool.addSymbol(newSchemaURI), |
| fStringPool.addSymbol(localpart), |
| TOP_LEVEL_SCOPE); |
| |
| DatatypeValidator dv = null; |
| if (eltIndex>-1) { |
| sGrammar.getElementDecl(eltIndex, fTempElementDecl); |
| dv = fTempElementDecl.datatypeValidator; |
| } |
| else { |
| reportGenericSchemaError("could not find global element : '" + localpart |
| + " in the SchemaGrammar "+newSchemaURI); |
| } |
| return dv; |
| } |
| else { |
| reportGenericSchemaError("could not resolve URI : " + newSchemaURI |
| + " to a SchemaGrammar in getELementDeclTypeValidatorFromNS"); |
| } |
| return null; |
| } |
| |
| ComplexTypeInfo getElementDeclTypeInfoFromNS(String newSchemaURI, String localpart) throws Exception { |
| Grammar grammar = fGrammarResolver.getGrammar(newSchemaURI); |
| if (grammar != null && grammar instanceof SchemaGrammar) { |
| SchemaGrammar sGrammar = (SchemaGrammar) grammar; |
| int eltIndex = sGrammar.getElementDeclIndex(fStringPool.addSymbol(newSchemaURI), |
| fStringPool.addSymbol(localpart), |
| TOP_LEVEL_SCOPE); |
| ComplexTypeInfo typeInfo = null; |
| if (eltIndex>-1) { |
| typeInfo = sGrammar.getElementComplexTypeInfo(eltIndex); |
| } |
| else { |
| reportGenericSchemaError("could not find global element : '" + localpart |
| + " in the SchemaGrammar "+newSchemaURI); |
| |
| } |
| return typeInfo; |
| } |
| else { |
| reportGenericSchemaError("could not resolve URI : " + newSchemaURI |
| + " to a SchemaGrammar in getElementDeclTypeInfoFromNS"); |
| } |
| return null; |
| } |
| |
| /** |
| * Traverse attributeGroup Declaration |
| * |
| * <attributeGroup |
| * id = ID |
| * ref = QName> |
| * Content: (annotation?) |
| * </> |
| * |
| * @param elementDecl |
| * @exception Exception |
| */ |
| /*private int traverseAttributeGroupDecl( Element attributeGroupDecl ) throws Exception { |
| int attributeGroupID = fStringPool.addSymbol( |
| attributeGroupDecl.getAttribute( SchemaSymbols.ATTVAL_ID )); |
| |
| int attributeGroupName = fStringPool.addSymbol( |
| attributeGroupDecl.getAttribute( SchemaSymbols.ATT_NAME )); |
| |
| return -1; |
| }*/ |
| |
| |
| /** |
| * Traverse Group Declaration. |
| * |
| * <group |
| * id = ID |
| * maxOccurs = string |
| * minOccurs = nonNegativeInteger |
| * name = NCName |
| * ref = QName> |
| * Content: (annotation? , (element | group | all | choice | sequence | any)*) |
| * <group/> |
| * |
| * @param elementDecl |
| * @return |
| * @exception Exception |
| */ |
| private int traverseGroupDecl( Element groupDecl ) throws Exception { |
| |
| String groupName = groupDecl.getAttribute(SchemaSymbols.ATT_NAME); |
| String ref = groupDecl.getAttribute(SchemaSymbols.ATT_REF); |
| |
| if (!ref.equals("")) { |
| if (XUtil.getFirstChildElement(groupDecl) != null) |
| reportSchemaError(SchemaMessageProvider.NoContentForRef, null); |
| String prefix = ""; |
| String localpart = ref; |
| int colonptr = ref.indexOf(":"); |
| if ( colonptr > 0) { |
| prefix = ref.substring(0,colonptr); |
| localpart = ref.substring(colonptr+1); |
| } |
| int localpartIndex = fStringPool.addSymbol(localpart); |
| |
| String uriStr = resolvePrefixToURI(prefix); |
| |
| if (!uriStr.equals(fTargetNSURIString)) { |
| return traverseGroupDeclFromAnotherSchema(localpart, uriStr); |
| } |
| |
| int contentSpecIndex = -1; |
| Element referredGroup = getTopLevelComponentByName(SchemaSymbols.ELT_GROUP,localpart); |
| if (referredGroup == null) { |
| // REVISIT: Localize |
| reportGenericSchemaError("Group " + localpart + " not found in the Schema"); |
| //REVISIT, this should be some custom Exception |
| throw new Exception("Group " + localpart + " not found in the Schema"); |
| } |
| else { |
| contentSpecIndex = traverseGroupDecl(referredGroup); |
| } |
| |
| return contentSpecIndex; |
| } |
| |
| boolean traverseElt = true; |
| if (fCurrentScope == TOP_LEVEL_SCOPE) { |
| traverseElt = false; |
| } |
| |
| Element child = XUtil.getFirstChildElement(groupDecl); |
| while (child != null && child.getNodeName().equals(SchemaSymbols.ELT_ANNOTATION)) |
| child = XUtil.getNextSiblingElement(child); |
| |
| int contentSpecType = 0; |
| int csnType = 0; |
| int allChildren[] = null; |
| int allChildCount = 0; |
| |
| csnType = XMLContentSpec.CONTENTSPECNODE_SEQ; |
| contentSpecType = XMLElementDecl.TYPE_CHILDREN; |
| |
| int left = -2; |
| int right = -2; |
| boolean hadContent = false; |
| boolean seeAll = false; |
| boolean seeParticle = false; |
| |
| for (; |
| child != null; |
| child = XUtil.getNextSiblingElement(child)) { |
| int index = -2; |
| hadContent = true; |
| |
| boolean illegalChild = false; |
| |
| String childName = child.getNodeName(); |
| if (childName.equals(SchemaSymbols.ELT_ELEMENT)) { |
| QName eltQName = traverseElementDecl(child); |
| index = fSchemaGrammar.addContentSpecNode( XMLContentSpec.CONTENTSPECNODE_LEAF, |
| eltQName.localpart, |
| eltQName.uri, |
| false); |
| seeParticle = true; |
| |
| } |
| else if (childName.equals(SchemaSymbols.ELT_GROUP)) { |
| index = traverseGroupDecl(child); |
| seeParticle = true; |
| |
| } |
| else if (childName.equals(SchemaSymbols.ELT_ALL)) { |
| index = traverseAll(child); |
| //seeParticle = true; |
| seeAll = true; |
| } |
| else if (childName.equals(SchemaSymbols.ELT_CHOICE)) { |
| index = traverseChoice(child); |
| seeParticle = true; |
| |
| } |
| else if (childName.equals(SchemaSymbols.ELT_SEQUENCE)) { |
| index = traverseSequence(child); |
| seeParticle = true; |
| |
| } |
| else if (childName.equals(SchemaSymbols.ELT_ANY)) { |
| index = traverseAny(child); |
| seeParticle = true; |
| } |
| else { |
| illegalChild = true; |
| reportSchemaError(SchemaMessageProvider.GroupContentRestricted, |
| new Object [] { "group", childName }); |
| } |
| |
| if ( ! illegalChild ) { |
| index = expandContentModel( index, child); |
| } |
| |
| if (seeParticle && seeAll) { |
| reportSchemaError( SchemaMessageProvider.GroupContentRestricted, |
| new Object [] { "'all' needs to be 'the' only Child", childName}); |
| } |
| |
| if (left == -2) { |
| left = index; |
| } else if (right == -2) { |
| right = index; |
| } else { |
| left = fSchemaGrammar.addContentSpecNode(csnType, left, right, false); |
| right = index; |
| } |
| } |
| if (hadContent && right != -2) |
| left = fSchemaGrammar.addContentSpecNode(csnType, left, right, false); |
| |
| |
| return left; |
| } |
| |
| private int traverseGroupDeclFromAnotherSchema( String groupName , String uriStr ) throws Exception { |
| |
| SchemaGrammar aGrammar = (SchemaGrammar) fGrammarResolver.getGrammar(uriStr); |
| if (uriStr == null || aGrammar==null ||! (aGrammar instanceof SchemaGrammar) ) { |
| // REVISIT: Localize |
| reportGenericSchemaError("!!Schema not found in #traverseGroupDeclFromAnotherSchema, "+ |
| "schema uri: " + uriStr |
| +", groupName: " + groupName); |
| return -1; |
| } |
| |
| |
| Element groupDecl = (Element) aGrammar.topLevelGroupDecls.get((Object)groupName); |
| if (groupDecl == null) { |
| // REVISIT: Localize |
| reportGenericSchemaError( "no group named \"" + groupName |
| + "\" was defined in schema : " + uriStr); |
| return -1; |
| } |
| |
| NamespacesScope saveNSMapping = fNamespacesScope; |
| int saveTargetNSUri = fTargetNSURI; |
| fTargetNSURI = fStringPool.addSymbol(aGrammar.getTargetNamespaceURI()); |
| fNamespacesScope = aGrammar.getNamespacesScope(); |
| |
| boolean traverseElt = true; |
| if (fCurrentScope == TOP_LEVEL_SCOPE) { |
| traverseElt = false; |
| } |
| |
| Element child = XUtil.getFirstChildElement(groupDecl); |
| while (child != null && child.getNodeName().equals(SchemaSymbols.ELT_ANNOTATION)) |
| child = XUtil.getNextSiblingElement(child); |
| |
| int contentSpecType = 0; |
| int csnType = 0; |
| int allChildren[] = null; |
| int allChildCount = 0; |
| |
| csnType = XMLContentSpec.CONTENTSPECNODE_SEQ; |
| contentSpecType = XMLElementDecl.TYPE_CHILDREN; |
| |
| int left = -2; |
| int right = -2; |
| boolean hadContent = false; |
| |
| for (; |
| child != null; |
| child = XUtil.getNextSiblingElement(child)) { |
| int index = -2; |
| hadContent = true; |
| |
| boolean seeParticle = false; |
| String childName = child.getNodeName(); |
| int childNameIndex = fStringPool.addSymbol(childName); |
| String formAttrVal = child.getAttribute(SchemaSymbols.ATT_FORM); |
| if (childName.equals(SchemaSymbols.ELT_ELEMENT)) { |
| QName eltQName = traverseElementDecl(child); |
| index = fSchemaGrammar.addContentSpecNode( XMLContentSpec.CONTENTSPECNODE_LEAF, |
| eltQName.localpart, |
| eltQName.uri, |
| false); |
| seeParticle = true; |
| |
| } |
| else if (childName.equals(SchemaSymbols.ELT_GROUP)) { |
| index = traverseGroupDecl(child); |
| seeParticle = true; |
| |
| } |
| else if (childName.equals(SchemaSymbols.ELT_ALL)) { |
| index = traverseAll(child); |
| seeParticle = true; |
| |
| } |
| else if (childName.equals(SchemaSymbols.ELT_CHOICE)) { |
| index = traverseChoice(child); |
| seeParticle = true; |
| |
| } |
| else if (childName.equals(SchemaSymbols.ELT_SEQUENCE)) { |
| index = traverseSequence(child); |
| seeParticle = true; |
| |
| } |
| else if (childName.equals(SchemaSymbols.ELT_ANY)) { |
| index = traverseAny(child); |
| seeParticle = true; |
| } |
| else { |
| reportSchemaError(SchemaMessageProvider.GroupContentRestricted, |
| new Object [] { "group", childName }); |
| } |
| |
| if (seeParticle) { |
| index = expandContentModel( index, child); |
| } |
| if (left == -2) { |
| left = index; |
| } else if (right == -2) { |
| right = index; |
| } else { |
| left = fSchemaGrammar.addContentSpecNode(csnType, left, right, false); |
| right = index; |
| } |
| } |
| if (hadContent && right != -2) |
| left = fSchemaGrammar.addContentSpecNode(csnType, left, right, false); |
| |
| fNamespacesScope = saveNSMapping; |
| fTargetNSURI = saveTargetNSUri; |
| return left; |
| |
| |
| } // end of method traverseGroupDeclFromAnotherSchema |
| |
| /** |
| * |
| * Traverse the Sequence declaration |
| * |
| * <sequence |
| * id = ID |
| * maxOccurs = string |
| * minOccurs = nonNegativeInteger> |
| * Content: (annotation? , (element | group | choice | sequence | any)*) |
| * </sequence> |
| * |
| **/ |
| int traverseSequence (Element sequenceDecl) throws Exception { |
| |
| Element child = XUtil.getFirstChildElement(sequenceDecl); |
| while (child != null && child.getNodeName().equals(SchemaSymbols.ELT_ANNOTATION)) |
| child = XUtil.getNextSiblingElement(child); |
| |
| int contentSpecType = 0; |
| int csnType = 0; |
| |
| csnType = XMLContentSpec.CONTENTSPECNODE_SEQ; |
| contentSpecType = XMLElementDecl.TYPE_CHILDREN; |
| |
| int left = -2; |
| int right = -2; |
| boolean hadContent = false; |
| |
| for (; |
| child != null; |
| child = XUtil.getNextSiblingElement(child)) { |
| int index = -2; |
| hadContent = true; |
| |
| boolean seeParticle = false; |
| String childName = child.getNodeName(); |
| if (childName.equals(SchemaSymbols.ELT_ELEMENT)) { |
| QName eltQName = traverseElementDecl(child); |
| index = fSchemaGrammar.addContentSpecNode( XMLContentSpec.CONTENTSPECNODE_LEAF, |
| eltQName.localpart, |
| eltQName.uri, |
| false); |
| seeParticle = true; |
| |
| } |
| else if (childName.equals(SchemaSymbols.ELT_GROUP)) { |
| index = traverseGroupDecl(child); |
| seeParticle = true; |
| |
| } |
| else if (childName.equals(SchemaSymbols.ELT_CHOICE)) { |
| index = traverseChoice(child); |
| seeParticle = true; |
| |
| } |
| else if (childName.equals(SchemaSymbols.ELT_SEQUENCE)) { |
| index = traverseSequence(child); |
| seeParticle = true; |
| |
| } |
| else if (childName.equals(SchemaSymbols.ELT_ANY)) { |
| index = traverseAny(child); |
| seeParticle = true; |
| } |
| else { |
| reportSchemaError(SchemaMessageProvider.GroupContentRestricted, |
| new Object [] { "group", childName }); |
| } |
| |
| if (seeParticle) { |
| index = expandContentModel( index, child); |
| } |
| if (left == -2) { |
| left = index; |
| } else if (right == -2) { |
| right = index; |
| } else { |
| left = fSchemaGrammar.addContentSpecNode(csnType, left, right, false); |
| right = index; |
| } |
| } |
| |
| if (hadContent && right != -2) |
| left = fSchemaGrammar.addContentSpecNode(csnType, left, right, false); |
| |
| return left; |
| } |
| |
| /** |
| * |
| * Traverse the Sequence declaration |
| * |
| * <choice |
| * id = ID |
| * maxOccurs = string |
| * minOccurs = nonNegativeInteger> |
| * Content: (annotation? , (element | group | choice | sequence | any)*) |
| * </choice> |
| * |
| **/ |
| int traverseChoice (Element choiceDecl) throws Exception { |
| |
| // REVISIT: traverseChoice, traverseSequence can be combined |
| Element child = XUtil.getFirstChildElement(choiceDecl); |
| while (child != null && child.getNodeName().equals(SchemaSymbols.ELT_ANNOTATION)) |
| child = XUtil.getNextSiblingElement(child); |
| |
| int contentSpecType = 0; |
| int csnType = 0; |
| |
| csnType = XMLContentSpec.CONTENTSPECNODE_CHOICE; |
| contentSpecType = XMLElementDecl.TYPE_CHILDREN; |
| |
| int left = -2; |
| int right = -2; |
| boolean hadContent = false; |
| |
| for (; |
| child != null; |
| child = XUtil.getNextSiblingElement(child)) { |
| int index = -2; |
| hadContent = true; |
| |
| boolean seeParticle = false; |
| String childName = child.getNodeName(); |
| if (childName.equals(SchemaSymbols.ELT_ELEMENT)) { |
| QName eltQName = traverseElementDecl(child); |
| index = fSchemaGrammar.addContentSpecNode( XMLContentSpec.CONTENTSPECNODE_LEAF, |
| eltQName.localpart, |
| eltQName.uri, |
| false); |
| seeParticle = true; |
| |
| } |
| else if (childName.equals(SchemaSymbols.ELT_GROUP)) { |
| index = traverseGroupDecl(child); |
| seeParticle = true; |
| |
| } |
| else if (childName.equals(SchemaSymbols.ELT_CHOICE)) { |
| index = traverseChoice(child); |
| seeParticle = true; |
| |
| } |
| else if (childName.equals(SchemaSymbols.ELT_SEQUENCE)) { |
| index = traverseSequence(child); |
| seeParticle = true; |
| |
| } |
| else if (childName.equals(SchemaSymbols.ELT_ANY)) { |
| index = traverseAny(child); |
| seeParticle = true; |
| } |
| else { |
| reportSchemaError(SchemaMessageProvider.GroupContentRestricted, |
| new Object [] { "group", childName }); |
| } |
| |
| if (seeParticle) { |
| index = expandContentModel( index, child); |
| } |
| if (left == -2) { |
| left = index; |
| } else if (right == -2) { |
| right = index; |
| } else { |
| left = fSchemaGrammar.addContentSpecNode(csnType, left, right, false); |
| right = index; |
| } |
| } |
| |
| if (hadContent && right != -2) |
| left = fSchemaGrammar.addContentSpecNode(csnType, left, right, false); |
| |
| return left; |
| } |
| |
| |
| /** |
| * |
| * Traverse the "All" declaration |
| * |
| * <all |
| * id = ID |
| * maxOccurs = string |
| * minOccurs = nonNegativeInteger> |
| * Content: (annotation? , (element | group | choice | sequence | any)*) |
| * </all> |
| * |
| **/ |
| |
| int traverseAll( Element allDecl) throws Exception { |
| |
| Element child = XUtil.getFirstChildElement(allDecl); |
| |
| while (child != null && child.getNodeName().equals(SchemaSymbols.ELT_ANNOTATION)) |
| child = XUtil.getNextSiblingElement(child); |
| |
| int allChildren[] = null; |
| int allChildCount = 0; |
| |
| int left = -2; |
| |
| for (; |
| child != null; |
| child = XUtil.getNextSiblingElement(child)) { |
| |
| int index = -2; |
| boolean seeParticle = false; |
| |
| String childName = child.getNodeName(); |
| |
| if (childName.equals(SchemaSymbols.ELT_ELEMENT)) { |
| QName eltQName = traverseElementDecl(child); |
| index = fSchemaGrammar.addContentSpecNode( XMLContentSpec.CONTENTSPECNODE_LEAF, |
| eltQName.localpart, |
| eltQName.uri, |
| false); |
| seeParticle = true; |
| |
| } |
| else if (childName.equals(SchemaSymbols.ELT_GROUP)) { |
| index = traverseGroupDecl(child); |
| seeParticle = true; |
| |
| } |
| else if (childName.equals(SchemaSymbols.ELT_CHOICE)) { |
| index = traverseChoice(child); |
| seeParticle = true; |
| |
| } |
| else if (childName.equals(SchemaSymbols.ELT_SEQUENCE)) { |
| index = traverseSequence(child); |
| seeParticle = true; |
| |
| } |
| else if (childName.equals(SchemaSymbols.ELT_ANY)) { |
| index = traverseAny(child); |
| seeParticle = true; |
| } |
| else { |
| reportSchemaError(SchemaMessageProvider.GroupContentRestricted, |
| new Object [] { "group", childName }); |
| } |
| |
| if (seeParticle) { |
| index = expandContentModel( index, child); |
| } |
| try { |
| allChildren[allChildCount] = index; |
| } |
| catch (NullPointerException ne) { |
| allChildren = new int[32]; |
| allChildren[allChildCount] = index; |
| } |
| catch (ArrayIndexOutOfBoundsException ae) { |
| int[] newArray = new int[allChildren.length*2]; |
| System.arraycopy(allChildren, 0, newArray, 0, allChildren.length); |
| allChildren[allChildCount] = index; |
| } |
| allChildCount++; |
| } |
| left = buildAllModel(allChildren,allChildCount); |
| |
| return left; |
| } |
| |
| /** builds the all content model */ |
| private int buildAllModel(int children[], int count) throws Exception { |
| |
| // build all model |
| if (count > 1) { |
| |
| // create and initialize singletons |
| XMLContentSpec choice = new XMLContentSpec(); |
| |
| choice.type = XMLContentSpec.CONTENTSPECNODE_CHOICE; |
| choice.value = -1; |
| choice.otherValue = -1; |
| |
| int[] exactChildren = new int[count]; |
| System.arraycopy(children,0,exactChildren,0,count); |
| // build all model |
| sort(exactChildren, 0, count); |
| int index = buildAllModel(exactChildren, 0, choice); |
| |
| return index; |
| } |
| |
| if (count > 0) { |
| return children[0]; |
| } |
| |
| return -1; |
| } |
| |
| /** Builds the all model. */ |
| private int buildAllModel(int src[], int offset, |
| XMLContentSpec choice) throws Exception { |
| |
| // swap last two places |
| if (src.length - offset == 2) { |
| int seqIndex = createSeq(src); |
| if (choice.value == -1) { |
| choice.value = seqIndex; |
| } |
| else { |
| if (choice.otherValue != -1) { |
| choice.value = fSchemaGrammar.addContentSpecNode(choice.type, choice.value, choice.otherValue, false); |
| } |
| choice.otherValue = seqIndex; |
| } |
| swap(src, offset, offset + 1); |
| seqIndex = createSeq(src); |
| if (choice.value == -1) { |
| choice.value = seqIndex; |
| } |
| else { |
| if (choice.otherValue != -1) { |
| choice.value = fSchemaGrammar.addContentSpecNode(choice.type, choice.value, choice.otherValue, false); |
| } |
| choice.otherValue = seqIndex; |
| } |
| return fSchemaGrammar.addContentSpecNode(choice.type, choice.value, choice.otherValue, false); |
| } |
| |
| // recurse |
| for (int i = offset; i < src.length - 1; i++) { |
| choice.value = buildAllModel(src, offset + 1, choice); |
| choice.otherValue = -1; |
| sort(src, offset, src.length - offset); |
| shift(src, offset, i + 1); |
| } |
| |
| int choiceIndex = buildAllModel(src, offset + 1, choice); |
| sort(src, offset, src.length - offset); |
| |
| return choiceIndex; |
| |
| } // buildAllModel(int[],int,ContentSpecNode,ContentSpecNode):int |
| |
| /** Creates a sequence. */ |
| private int createSeq(int src[]) throws Exception { |
| |
| int left = src[0]; |
| int right = src[1]; |
| |
| for (int i = 2; i < src.length; i++) { |
| left = fSchemaGrammar.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_SEQ, |
| left, right, false); |
| right = src[i]; |
| } |
| |
| return fSchemaGrammar.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_SEQ, |
| left, right, false); |
| |
| } // createSeq(int[]):int |
| |
| /** Shifts a value into position. */ |
| private void shift(int src[], int pos, int offset) { |
| |
| int temp = src[offset]; |
| for (int i = offset; i > pos; i--) { |
| src[i] = src[i - 1]; |
| } |
| src[pos] = temp; |
| |
| } // shift(int[],int,int) |
| |
| /** Simple sort. */ |
| private void sort(int src[], final int offset, final int length) { |
| |
| for (int i = offset; i < offset + length - 1; i++) { |
| int lowest = i; |
| for (int j = i + 1; j < offset + length; j++) { |
| if (src[j] < src[lowest]) { |
| lowest = j; |
| } |
| } |
| if (lowest != i) { |
| int temp = src[i]; |
| src[i] = src[lowest]; |
| src[lowest] = temp; |
| } |
| } |
| |
| } // sort(int[],int,int) |
| |
| /** Swaps two values. */ |
| private void swap(int src[], int i, int j) { |
| |
| int temp = src[i]; |
| src[i] = src[j]; |
| src[j] = temp; |
| |
| } // swap(int[],int,int) |
| |
| /** |
| * Traverse Wildcard declaration |
| * |
| * <any |
| * id = ID |
| * maxOccurs = string |
| * minOccurs = nonNegativeInteger |
| * namespace = ##any | ##other | ##local | list of {uri, ##targetNamespace} |
| * processContents = lax | skip | strict> |
| * Content: (annotation?) |
| * </any> |
| * @param elementDecl |
| * @return |
| * @exception Exception |
| */ |
| private int traverseWildcardDecl( Element wildcardDecl ) throws Exception { |
| int wildcardID = fStringPool.addSymbol( |
| wildcardDecl.getAttribute( SchemaSymbols.ATTVAL_ID )); |
| |
| int wildcardMaxOccurs = fStringPool.addSymbol( |
| wildcardDecl.getAttribute( SchemaSymbols.ATT_MAXOCCURS )); |
| |
| int wildcardMinOccurs = fStringPool.addSymbol( |
| wildcardDecl.getAttribute( SchemaSymbols.ATT_MINOCCURS )); |
| |
| int wildcardNamespace = fStringPool.addSymbol( |
| wildcardDecl.getAttribute( SchemaSymbols.ATT_NAMESPACE )); |
| |
| int wildcardProcessContents = fStringPool.addSymbol( |
| wildcardDecl.getAttribute( SchemaSymbols.ATT_PROCESSCONTENTS )); |
| |
| |
| int wildcardContent = fStringPool.addSymbol( |
| wildcardDecl.getAttribute( SchemaSymbols.ATT_CONTENT )); |
| |
| |
| return -1; |
| } |
| |
| |
| |
| // utilities from Tom Watson's SchemaParser class |
| // TO DO: Need to make this more conformant with Schema int type parsing |
| |
| private int parseInt (String intString) throws Exception |
| { |
| if ( intString.equals("*") ) { |
| return SchemaSymbols.INFINITY; |
| } else { |
| return Integer.parseInt (intString); |
| } |
| } |
| |
| private int parseSimpleDerivedBy (String derivedByString) throws Exception |
| { |
| if ( derivedByString.equals (SchemaSymbols.ATTVAL_LIST) ) { |
| return SchemaSymbols.LIST; |
| } |
| else if ( derivedByString.equals (SchemaSymbols.ATTVAL_RESTRICTION) ) { |
| return SchemaSymbols.RESTRICTION; |
| } |
| else { |
| // REVISIT: Localize |
| reportGenericSchemaError ("SimpleType: Invalid value for 'derivedBy'"); |
| return -1; |
| } |
| } |
| |
| private int parseComplexDerivedBy (String derivedByString) throws Exception |
| { |
| if ( derivedByString.equals (SchemaSymbols.ATTVAL_EXTENSION) ) { |
| return SchemaSymbols.EXTENSION; |
| } |
| else if ( derivedByString.equals (SchemaSymbols.ATTVAL_RESTRICTION) ) { |
| return SchemaSymbols.RESTRICTION; |
| } |
| else { |
| // REVISIT: Localize |
| reportGenericSchemaError ( "ComplexType: Invalid value for 'derivedBy'" ); |
| return -1; |
| } |
| } |
| |
| private int parseSimpleFinal (String finalString) throws Exception |
| { |
| if ( finalString.equals (SchemaSymbols.ATTVAL_POUNDALL) ) { |
| return SchemaSymbols.ENUMERATION+SchemaSymbols.RESTRICTION+SchemaSymbols.LIST+SchemaSymbols.REPRODUCTION; |
| } else { |
| int enumerate = 0; |
| int restrict = 0; |
| int list = 0; |
| int reproduce = 0; |
| |
| StringTokenizer t = new StringTokenizer (finalString, " "); |
| while (t.hasMoreTokens()) { |
| String token = t.nextToken (); |
| |
| if ( token.equals (SchemaSymbols.ATTVAL_RESTRICTION) ) { |
| if ( restrict == 0 ) { |
| restrict = SchemaSymbols.RESTRICTION; |
| } else { |
| // REVISIT: Localize |
| reportGenericSchemaError ("restriction in set twice"); |
| } |
| } else if ( token.equals (SchemaSymbols.ATTVAL_LIST) ) { |
| if ( list == 0 ) { |
| list = SchemaSymbols.LIST; |
| } else { |
| // REVISIT: Localize |
| reportGenericSchemaError ("list in set twice"); |
| } |
| } |
| else { |
| // REVISIT: Localize |
| reportGenericSchemaError ( "Invalid value (" + |
| finalString + |
| ")" ); |
| } |
| } |
| |
| return enumerate+restrict+list+reproduce; |
| } |
| } |
| |
| private int parseComplexContent (String contentString) throws Exception |
| { |
| if ( contentString.equals (SchemaSymbols.ATTVAL_EMPTY) ) { |
| return XMLElementDecl.TYPE_EMPTY; |
| } else if ( contentString.equals (SchemaSymbols.ATTVAL_ELEMENTONLY) ) { |
| return XMLElementDecl.TYPE_CHILDREN; |
| } else if ( contentString.equals (SchemaSymbols.ATTVAL_TEXTONLY) ) { |
| return XMLElementDecl.TYPE_SIMPLE; |
| } else if ( contentString.equals (SchemaSymbols.ATTVAL_MIXED) ) { |
| return XMLElementDecl.TYPE_MIXED; |
| } else { |
| // REVISIT: Localize |
| reportGenericSchemaError ( "Invalid value for content" ); |
| return -1; |
| } |
| } |
| |
| private int parseDerivationSet (String finalString) throws Exception |
| { |
| if ( finalString.equals ("#all") ) { |
| return SchemaSymbols.EXTENSION+SchemaSymbols.RESTRICTION+SchemaSymbols.REPRODUCTION; |
| } else { |
| int extend = 0; |
| int restrict = 0; |
| int reproduce = 0; |
| |
| StringTokenizer t = new StringTokenizer (finalString, " "); |
| while (t.hasMoreTokens()) { |
| String token = t.nextToken (); |
| |
| if ( token.equals (SchemaSymbols.ATTVAL_EXTENSION) ) { |
| if ( extend == 0 ) { |
| extend = SchemaSymbols.EXTENSION; |
| } else { |
| // REVISIT: Localize |
| reportGenericSchemaError ( "extension already in set" ); |
| } |
| } else if ( token.equals (SchemaSymbols.ATTVAL_RESTRICTION) ) { |
| if ( restrict == 0 ) { |
| restrict = SchemaSymbols.RESTRICTION; |
| } else { |
| // REVISIT: Localize |
| reportGenericSchemaError ( "restriction already in set" ); |
| } |
| } else { |
| // REVISIT: Localize |
| reportGenericSchemaError ( "Invalid final value (" + finalString + ")" ); |
| } |
| } |
| |
| return extend+restrict+reproduce; |
| } |
| } |
| |
| private int parseBlockSet (String finalString) throws Exception |
| { |
| if ( finalString.equals ("#all") ) { |
| return SchemaSymbols.EQUIVCLASS+SchemaSymbols.EXTENSION+SchemaSymbols.LIST+SchemaSymbols.RESTRICTION+SchemaSymbols.REPRODUCTION; |
| } else { |
| int extend = 0; |
| int restrict = 0; |
| int reproduce = 0; |
| |
| StringTokenizer t = new StringTokenizer (finalString, " "); |
| while (t.hasMoreTokens()) { |
| String token = t.nextToken (); |
| |
| if ( token.equals (SchemaSymbols.ATTVAL_EQUIVCLASS) ) { |
| if ( extend == 0 ) { |
| extend = SchemaSymbols.EQUIVCLASS; |
| } else { |
| // REVISIT: Localize |
| reportGenericSchemaError ( "'equivClass' already in set" ); |
| } |
| } else if ( token.equals (SchemaSymbols.ATTVAL_EXTENSION) ) { |
| if ( extend == 0 ) { |
| extend = SchemaSymbols.EXTENSION; |
| } else { |
| // REVISIT: Localize |
| reportGenericSchemaError ( "extension already in set" ); |
| } |
| } else if ( token.equals (SchemaSymbols.ATTVAL_LIST) ) { |
| if ( extend == 0 ) { |
| extend = SchemaSymbols.LIST; |
| } else { |
| // REVISIT: Localize |
| reportGenericSchemaError ( "'list' already in set" ); |
| } |
| } else if ( token.equals (SchemaSymbols.ATTVAL_RESTRICTION) ) { |
| if ( restrict == 0 ) { |
| restrict = SchemaSymbols.RESTRICTION; |
| } else { |
| // REVISIT: Localize |
| reportGenericSchemaError ( "restriction already in set" ); |
| } |
| } else { |
| // REVISIT: Localize |
| reportGenericSchemaError ( "Invalid final value (" + finalString + ")" ); |
| } |
| } |
| |
| return extend+restrict+reproduce; |
| } |
| } |
| |
| private int parseFinalSet (String finalString) throws Exception |
| { |
| if ( finalString.equals ("#all") ) { |
| return SchemaSymbols.EQUIVCLASS+SchemaSymbols.EXTENSION+SchemaSymbols.LIST+SchemaSymbols.RESTRICTION+SchemaSymbols.REPRODUCTION; |
| } else { |
| int extend = 0; |
| int restrict = 0; |
| int reproduce = 0; |
| |
| StringTokenizer t = new StringTokenizer (finalString, " "); |
| while (t.hasMoreTokens()) { |
| String token = t.nextToken (); |
| |
| if ( token.equals (SchemaSymbols.ATTVAL_EQUIVCLASS) ) { |
| if ( extend == 0 ) { |
| extend = SchemaSymbols.EQUIVCLASS; |
| } else { |
| // REVISIT: Localize |
| reportGenericSchemaError ( "'equivClass' already in set" ); |
| } |
| } else if ( token.equals (SchemaSymbols.ATTVAL_EXTENSION) ) { |
| if ( extend == 0 ) { |
| extend = SchemaSymbols.EXTENSION; |
| } else { |
| // REVISIT: Localize |
| reportGenericSchemaError ( "extension already in set" ); |
| } |
| } else if ( token.equals (SchemaSymbols.ATTVAL_LIST) ) { |
| if ( extend == 0 ) { |
| extend = SchemaSymbols.LIST; |
| } else { |
| // REVISIT: Localize |
| reportGenericSchemaError ( "'list' already in set" ); |
| } |
| } else if ( token.equals (SchemaSymbols.ATTVAL_RESTRICTION) ) { |
| if ( restrict == 0 ) { |
| restrict = SchemaSymbols.RESTRICTION; |
| } else { |
| // REVISIT: Localize |
| reportGenericSchemaError ( "restriction already in set" ); |
| } |
| } else { |
| // REVISIT: Localize |
| reportGenericSchemaError ( "Invalid final value (" + finalString + ")" ); |
| } |
| } |
| |
| return extend+restrict+reproduce; |
| } |
| } |
| |
| private void reportGenericSchemaError (String error) throws Exception { |
| if (fErrorReporter == null) { |
| System.err.println("__TraverseSchemaError__ : " + error); |
| } |
| else { |
| reportSchemaError (SchemaMessageProvider.GenericError, new Object[] { error }); |
| } |
| } |
| |
| |
| private void reportSchemaError(int major, Object args[]) throws Exception { |
| if (fErrorReporter == null) { |
| System.out.println("__TraverseSchemaError__ : " + SchemaMessageProvider.fgMessageKeys[major]); |
| for (int i=0; i< args.length ; i++) { |
| System.out.println((String)args[i]); |
| } |
| } |
| else { |
| fErrorReporter.reportError(fErrorReporter.getLocator(), |
| SchemaMessageProvider.SCHEMA_DOMAIN, |
| major, |
| SchemaMessageProvider.MSG_NONE, |
| args, |
| XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR); |
| } |
| } |
| |
| //Unit Test here |
| public static void main(String args[] ) { |
| |
| if( args.length != 1 ) { |
| System.out.println( "Error: Usage java TraverseSchema yourFile.xsd" ); |
| System.exit(0); |
| } |
| |
| DOMParser parser = new DOMParser() { |
| public void ignorableWhitespace(char ch[], int start, int length) {} |
| public void ignorableWhitespace(int dataIdx) {} |
| }; |
| parser.setEntityResolver( new Resolver() ); |
| parser.setErrorHandler( new ErrorHandler() ); |
| |
| try { |
| parser.setFeature("http://xml.org/sax/features/validation", false); |
| parser.setFeature("http://apache.org/xml/features/dom/defer-node-expansion", false); |
| }catch( org.xml.sax.SAXNotRecognizedException e ) { |
| e.printStackTrace(); |
| }catch( org.xml.sax.SAXNotSupportedException e ) { |
| e.printStackTrace(); |
| } |
| |
| try { |
| parser.parse( args[0]); |
| }catch( IOException e ) { |
| e.printStackTrace(); |
| }catch( SAXException e ) { |
| e.printStackTrace(); |
| } |
| |
| Document document = parser.getDocument(); //Our Grammar |
| |
| OutputFormat format = new OutputFormat( document ); |
| java.io.StringWriter outWriter = new java.io.StringWriter(); |
| XMLSerializer serial = new XMLSerializer( outWriter,format); |
| |
| TraverseSchema tst = null; |
| try { |
| Element root = document.getDocumentElement();// This is what we pass to TraverserSchema |
| //serial.serialize( root ); |
| //System.out.println(outWriter.toString()); |
| |
| tst = new TraverseSchema( root, new StringPool(), new SchemaGrammar(), (GrammarResolver) new GrammarResolverImpl() ); |
| } |
| catch (Exception e) { |
| e.printStackTrace(System.err); |
| } |
| |
| parser.getDocument(); |
| } |
| |
| static class Resolver implements EntityResolver { |
| private static final String SYSTEM[] = { |
| "http://www.w3.org/TR/2000/WD-xmlschema-1-20000407/structures.dtd", |
| "http://www.w3.org/TR/2000/WD-xmlschema-1-20000407/datatypes.dtd", |
| "http://www.w3.org/TR/2000/WD-xmlschema-1-20000407/versionInfo.ent", |
| }; |
| private static final String PATH[] = { |
| "structures.dtd", |
| "datatypes.dtd", |
| "versionInfo.ent", |
| }; |
| |
| public InputSource resolveEntity(String publicId, String systemId) |
| throws IOException { |
| |
| // looking for the schema DTDs? |
| for (int i = 0; i < SYSTEM.length; i++) { |
| if (systemId.equals(SYSTEM[i])) { |
| InputSource source = new InputSource(getClass().getResourceAsStream(PATH[i])); |
| source.setPublicId(publicId); |
| source.setSystemId(systemId); |
| return source; |
| } |
| } |
| |
| // use default resolution |
| return null; |
| |
| } // resolveEntity(String,String):InputSource |
| |
| } // class Resolver |
| |
| static class ErrorHandler implements org.xml.sax.ErrorHandler { |
| |
| /** Warning. */ |
| public void warning(SAXParseException ex) { |
| System.err.println("[Warning] "+ |
| getLocationString(ex)+": "+ |
| ex.getMessage()); |
| } |
| |
| /** Error. */ |
| public void error(SAXParseException ex) { |
| System.err.println("[Error] "+ |
| getLocationString(ex)+": "+ |
| ex.getMessage()); |
| } |
| |
| /** Fatal error. */ |
| public void fatalError(SAXParseException ex) throws SAXException { |
| System.err.println("[Fatal Error] "+ |
| getLocationString(ex)+": "+ |
| ex.getMessage()); |
| throw ex; |
| } |
| |
| // |
| // Private methods |
| // |
| |
| /** Returns a string of the location. */ |
| private String getLocationString(SAXParseException ex) { |
| StringBuffer str = new StringBuffer(); |
| |
| String systemId_ = ex.getSystemId(); |
| if (systemId_ != null) { |
| int index = systemId_.lastIndexOf('/'); |
| if (index != -1) |
| systemId_ = systemId_.substring(index + 1); |
| str.append(systemId_); |
| } |
| str.append(':'); |
| str.append(ex.getLineNumber()); |
| str.append(':'); |
| str.append(ex.getColumnNumber()); |
| |
| return str.toString(); |
| |
| } // getLocationString(SAXParseException):String |
| } |
| |
| |
| } |
| |
| |
| |
| |
| |