| /** |
| * Copyright (c) 2002-2007 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM - Initial API and implementation |
| */ |
| package org.eclipse.xsd.util; |
| |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.resource.ResourceSet; |
| |
| import org.eclipse.xsd.XSDElementDeclaration; |
| import org.eclipse.xsd.XSDImport; |
| import org.eclipse.xsd.XSDInclude; |
| import org.eclipse.xsd.XSDRedefine; |
| import org.eclipse.xsd.XSDSchema; |
| import org.eclipse.xsd.XSDSchemaContent; |
| import org.eclipse.xsd.XSDSchemaDirective; |
| import org.eclipse.xsd.XSDTypeDefinition; |
| |
| |
| // Various Eclipse, etools and EMF dependencies |
| |
| // xsd:annotation elements are modeled in the DOM |
| |
| |
| |
| /** |
| * XSDSchemaQueryTools is a collection of worker methods for performing |
| * simple queries or searches of schemas. |
| * |
| * <p>These are suitable to show examples of how to build convenience |
| * methods to more easily find components in a schema. They also |
| * serve as useful examples of usage of the library's functions.</p> |
| * |
| * <p>Note that these methods are somewhat simplistic, especially |
| * in terms of support for namespaces. To simplify the calling |
| * signatures, and to account for the 80% case where you don't have |
| * multiple namespaces, most method simply take a localName that's |
| * assumed to be correct in the current context. However it should |
| * be simple to copy & paste these methods and add namespaceURI's to |
| * each method if desired.</p> |
| * |
| * @author Shane_Curcuru@us.ibm.com |
| */ |
| public abstract class XSDSchemaQueryTools |
| { |
| /** |
| * Find typeDefinitions that derive from a named type. |
| * |
| * <p>This shows one way to query the schema for typeDefinitions |
| * and then how to find specific kinds of typeDefinitions.</p> |
| * |
| * @param schema to search for typeDefs |
| * @param namespace for the type derived from |
| * @param localName for the type derived from |
| * @return List of any XSDTypeDefinitions found |
| */ |
| public static List<XSDTypeDefinition> findTypesDerivedFrom(XSDSchema schema, String namespace, String localName) |
| { |
| if ((null == schema) || (null == localName)) |
| { |
| throw new IllegalArgumentException("findTypesDerivedFrom called with null schema/localName"); |
| } |
| |
| ArrayList<XSDTypeDefinition> typesDerivedFrom = new ArrayList<XSDTypeDefinition>(); |
| |
| // A handy convenience method quickly gets all |
| // typeDefinitions within our schema; note that |
| // whether or not this returns types in included, |
| // imported, or redefined schemas is subject to change |
| List<XSDTypeDefinition> typedefs = schema.getTypeDefinitions(); |
| |
| for (XSDTypeDefinition typedef : typedefs) |
| { |
| // Walk the baseTypes from this typedef seeing if any |
| // of them match the requested one |
| if (isTypeDerivedFrom(typedef, namespace, localName)) |
| { |
| // We found it, return the original one and continue |
| typesDerivedFrom.add(typedef); |
| continue; |
| } |
| } |
| |
| return typesDerivedFrom; |
| } |
| |
| /** |
| * Recursive worker method to find typeDefinitions that derive |
| * from a named type. |
| * |
| * <p>This is not a terribly time-efficient algorithm, but |
| * it does show usage of library methods. This works for |
| * simpleTypes; complexType support needs to be added.</p> |
| * |
| * @see #findTypesDerivedFrom(XSDSchema, String, String) |
| * @param typedef to see if it's derived from |
| * @param namespace for the type derived from |
| * @param localName for the type derived from |
| * @return true if it is; false otherwise |
| * @deprecated Use {@link XSDConstants#isOrIsDerivedFrom(XSDTypeDefinition, String, String)} instead. |
| */ |
| @Deprecated |
| public static boolean isTypeDerivedFrom(XSDTypeDefinition typedef, String namespace, String localName) |
| { |
| return XSDConstants.isOrIsDerivedFrom(typedef, localName, namespace); |
| } |
| |
| /** |
| * Find elementDeclarations that use any types derived |
| * from a named type. |
| * |
| * <p>This shows one way to query the schema for elementDeclarations |
| * and then how to find specific kinds of typeDefinitions.</p> |
| * |
| * @param schema to search for elemDecls |
| * @param namespace for the type used |
| * @param localName for the type used |
| * @return List of any XSDElementDeclarations found |
| */ |
| public static List<XSDElementDeclaration> findElementsUsingType(XSDSchema schema, String namespace, String localName) |
| { |
| if ((null == schema) || (null == localName)) |
| { |
| throw new IllegalArgumentException("findElementsUsingType called with null schema/localName"); |
| } |
| |
| ArrayList<XSDElementDeclaration> elemsUsingType = new ArrayList<XSDElementDeclaration>(); |
| |
| // A handy convenience method quickly gets all |
| // elementDeclarations within our schema; note that |
| // whether or not this returns types in included, |
| // imported, or redefined schemas is subject to change |
| List<XSDElementDeclaration> elemDecls = schema.getElementDeclarations(); |
| |
| for (XSDElementDeclaration elem : elemDecls) |
| { |
| XSDTypeDefinition typedef = null; |
| if (elem.getAnonymousTypeDefinition() != null) |
| { |
| typedef = elem.getAnonymousTypeDefinition(); |
| } |
| else if (elem.getTypeDefinition() != null) |
| { |
| typedef = elem.getTypeDefinition(); |
| } |
| else |
| { |
| // Element is not complete, since it has no type, |
| // thus it's not using our type |
| continue; |
| } |
| |
| // Ask this type and walk the baseTypes from this |
| // typedef seeing if any of them match the requested one |
| if (typedef.hasNameAndTargetNamespace(localName, namespace) |
| || isTypeDerivedFrom(typedef, namespace, localName)) |
| { |
| // We found it, return the element and continue |
| elemsUsingType.add(elem); |
| continue; |
| } |
| } |
| |
| return elemsUsingType; |
| } |
| |
| /** |
| * Find any included, imported, or redefined schemas that |
| * this one references. |
| * |
| * <p>This method uses solely the Schema model API to look for |
| * XSDSchemaDirective objects. Each directive is the result |
| * of an include, import, or redefine in our schema. We then |
| * walk the tree of directives, finding their resolved schemas |
| * (if available), and produce a simple HashMap of them all.</p> |
| * <p>See also {@link #hasImpInclRedef2(XSDSchema)} |
| * which uses the underlying ResourceSet model to query the |
| * external resources that were loaded with this schema: it |
| * has the same effect, but using different code.</p> |
| * |
| * @see #hasImpInclRedef2(XSDSchema) |
| * @param schema object to search for imports/includes/redefines |
| * @return HashMap where keys are the URI's of any other schemas |
| * found, and values are one of 'import', 'include', 'redefine'; |
| * null if none found or an error occurred |
| */ |
| public static HashMap<String, String> hasImpInclRedef(XSDSchema schema) |
| { |
| if (null == schema) |
| { |
| throw new IllegalArgumentException("hasImpInclRedef called with null schema"); |
| } |
| HashMap<String, String> hash = new HashMap<String, String>(); |
| |
| // Recurse to map all imports/includes/redefines |
| mapImpInclRedef(schema, hash, 0); |
| |
| // If none were found, return null |
| if (hash.size() == 0) |
| { |
| return null; |
| } |
| return hash; |
| } |
| |
| /** |
| * Find any included, imported, or redefined schemas that |
| * this one references. |
| * |
| * <p>This method uses the underlying ResourceSet model to query the |
| * external resources that were loaded with this schema. |
| * Note that the ResourceSet implementation is subject to change.</p> |
| * |
| * @see #hasImpInclRedef(XSDSchema) |
| * @param schema object to search for imports/includes/redefines |
| * @return HashMap where keys are the URI's of any other schemas |
| * found, and values are one of 'import', 'include', 'redefine'; |
| * null if none found or an error occurred |
| */ |
| public static HashMap<String, String> hasImpInclRedef2(XSDSchema schema) |
| { |
| if (null == schema) |
| { |
| throw new IllegalArgumentException("hasImpInclRedef2 called with null schema"); |
| } |
| HashMap<String, String> hash = new HashMap<String, String>(); |
| |
| // Use the Resource framework to iterate through any |
| // other resources that were loaded along with this schema |
| // to find what they import/include/redefine |
| Resource currentResource = schema.eResource(); |
| |
| // Get the whole set of resources that were loaded together |
| ResourceSet resourceSet = currentResource.getResourceSet(); |
| |
| // Iterate over all the resources, i.e., the main resource |
| // and those that have been included, imported, or redefined. |
| for (Resource resource : resourceSet.getResources()) |
| { |
| // Check for schema resources. |
| if (resource instanceof XSDResourceImpl) |
| { |
| XSDResourceImpl xsdResource = (XSDResourceImpl)resource; |
| |
| // Iterate over each schema's content looking for directives. |
| XSDSchema otherSchema = xsdResource.getSchema(); |
| for (XSDSchemaContent content : otherSchema.getContents()) |
| { |
| if (content instanceof XSDSchemaDirective) |
| { |
| XSDSchemaDirective schemaDirective = (XSDSchemaDirective)content; |
| String type = null; |
| if (content instanceof XSDImport) |
| { |
| type = "XSDImport"; |
| } |
| else if (content instanceof XSDInclude) |
| { |
| type = "XSDInclude"; |
| } |
| else if (content instanceof XSDRedefine) |
| { |
| type = "XSDRedefine"; |
| } |
| else |
| { |
| type = "unknown"; |
| } |
| if (schemaDirective.getResolvedSchema() == null) |
| { |
| type += "-unresolved"; |
| } |
| // Store the item in our hash to return to caller |
| hash.put(schemaDirective.getSchemaLocation(), type); |
| |
| // Recurse down the tree into the next schema |
| // using the schema API's |
| XSDSchema nextSchema = schemaDirective.getResolvedSchema(); |
| if (null != nextSchema) |
| { |
| mapImpInclRedef(nextSchema, hash, 1); |
| } |
| } |
| } |
| } |
| } |
| // If none were found, return null |
| if (hash.size() == 0) |
| { |
| return null; |
| } |
| return hash; |
| } |
| |
| /** |
| * Recursive worker method implementing {@link #hasImpInclRedef(XSDSchema)} |
| * and {@link #hasImpInclRedef2(XSDSchema)}. |
| * |
| * <p>This uses only the schema model library API's to look for |
| * XSDSchemaDirective objects in it's content. It then checks |
| * which specific subclass of directive each is to report and |
| * then recurses to any other schemas found.</p> |
| * |
| * @param schema object to search for imports/includes/redefines |
| * @param hash where keys are the URI's of any other schemas |
| * found, and values are one of 'import', 'include', 'redefine'; |
| * this object is mutated by this method |
| * @param level of iteration we're on |
| */ |
| protected static void mapImpInclRedef(XSDSchema schema, HashMap<String, String> hash, int level) |
| { |
| // Iterate through this schema itself to see what |
| // other schemas it *directly* import/include/redefines |
| for (XSDSchemaContent schemaContent : schema.getContents()) |
| { |
| if (schemaContent instanceof XSDSchemaDirective) |
| { |
| XSDSchemaDirective schemaDirective = (XSDSchemaDirective)schemaContent; |
| String type = null; |
| if (schemaContent instanceof XSDImport) |
| { |
| type = "XSDImport-level" + level; |
| } |
| else if (schemaContent instanceof XSDInclude) |
| { |
| type = "XSDInclude-level" + level; |
| } |
| else if (schemaContent instanceof XSDRedefine) |
| { |
| type = "XSDRedefine-level" + level; |
| } |
| else |
| { |
| type = "unknown-level" + level; |
| } |
| if (schemaDirective.getResolvedSchema() == null) |
| { |
| type += "-unresolved"; |
| } |
| // Store the item in our caller's hashtable |
| hash.put(schemaDirective.getSchemaLocation(), type); |
| |
| // Recurse down the tree into the next schema |
| XSDSchema nextSchema = schemaDirective.getResolvedSchema(); |
| if (null != nextSchema) |
| { |
| mapImpInclRedef(nextSchema, hash, level + 1); |
| } |
| } |
| } |
| } |
| } |