org.opengis.cite.iso19136.util.XMLSchemaModelUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ets-gml32 Show documentation
Show all versions of ets-gml32 Show documentation
Checks GML application schemas or data sets for conformance to ISO 19136:2007.
package org.opengis.cite.iso19136.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.xml.namespace.QName;
import org.apache.xerces.xs.StringList;
import org.apache.xerces.xs.XSComplexTypeDefinition;
import org.apache.xerces.xs.XSConstants;
import org.apache.xerces.xs.XSElementDeclaration;
import org.apache.xerces.xs.XSModel;
import org.apache.xerces.xs.XSModelGroup;
import org.apache.xerces.xs.XSNamedMap;
import org.apache.xerces.xs.XSObject;
import org.apache.xerces.xs.XSObjectList;
import org.apache.xerces.xs.XSParticle;
import org.apache.xerces.xs.XSTerm;
import org.apache.xerces.xs.XSTypeDefinition;
import org.opengis.cite.iso19136.SchemaComponentFilter;
import org.opengis.cite.iso19136.general.GML32;
/**
* Provides utility methods for accessing components of XML Schema models.
*/
public class XMLSchemaModelUtils {
/**
* Returns a collection of concrete feature element declarations in the
* application namespace(s). These elements may substitute for
* gml:AbstractFeature.
*
* @param model
* An XSModel object representing the application schema.
* @return A List containing all (global) element declarations belonging to
* the substitution group having gml:AbstractFeature as its head.
*
* @see "ISO 19136:2007, 21.3.3"
*/
public static List getFeatureDeclarations(
XSModel model) {
XSElementDeclaration gmlAbstractFeature = model.getElementDeclaration(
GML32.ABSTRACT_FEATURE, GML32.NS_NAME);
List featureElems = getElementsByAffiliation(
model, gmlAbstractFeature);
removeGmlElementsFromList(featureElems);
return featureElems;
}
/**
* Returns a collection of concrete geometry element declarations in the
* application namespace(s). These elements may substitute for
* gml:AbstractGeometry.
*
* @param model
* An XSModel object representing the application schema.
* @return A List containing all (global) element declarations belonging to
* the substitution group having gml:AbstractGeometry as its head.
*
* @see "ISO 19136:2007, 21.4.2.1"
*/
public static List getGeometryDeclarations(
XSModel model) {
XSElementDeclaration gmlAbstractGeometry = model.getElementDeclaration(
GML32.ABSTRACT_GEOMETRY, GML32.NS_NAME);
List geomElems = getElementsByAffiliation(model,
gmlAbstractGeometry);
removeGmlElementsFromList(geomElems);
return geomElems;
}
/**
* Returns a list of geometry properties explicitly declared in an
* application namespace. Such geometry properties are identified as
* indicated below.
*
*
*
* - Elements declared to have a type that derives by restriction from
* gml:GeometryPropertyType
*
* - Elements declared to have a type that derives by restriction from
* gml:GeometryArrayPropertyType
*
* - Elements declared to use a predefined GML geometry property type (see
* cl. 9.5, Table 4)
*
*
*
* @param model
* An XSModel object incorporating application schema components.
* @return A list of element declarations that correspond to explicit
* geometry properties. The list is empty if none are found.
*/
public static List getExplicitGeometryProperties(
XSModel model) {
List geomProps = new ArrayList();
Set nsNames = getApplicationNamespaces(model);
for (String nsName : nsNames) {
// Uses type derived by restriction from generic property types
XSNamedMap typeDefs = model.getComponentsByNamespace(
XSConstants.TYPE_DEFINITION, nsName);
for (int i = 0; i < typeDefs.getLength(); i++) {
XSTypeDefinition typeDef = (XSTypeDefinition) typeDefs.item(i);
if (typeDef.derivedFrom(GML32.NS_NAME, GML32.GEOM_PROP_TYPE,
XSConstants.DERIVATION_RESTRICTION)
|| typeDef.derivedFrom(GML32.NS_NAME,
GML32.GEOM_ARRAY_PROP_TYPE,
XSConstants.DERIVATION_RESTRICTION)) {
geomProps.addAll(getGlobalElementsByType(model, typeDef));
}
}
// Uses predefined GML geometry property type
for (String geomPropType : GML32.GEOM_PROP_TYPE_SET) {
XSTypeDefinition typeDef = model.getTypeDefinition(
geomPropType, GML32.NS_NAME);
geomProps.addAll(getGlobalElementsByType(model, typeDef));
geomProps.addAll(getLocalElementsByType(model, typeDef,
new FeatureTypeFilter()));
}
}
return geomProps;
}
/**
* Returns a list of implicitly defined GML properties whose expected value
* is substitutable for the specified head element. Such properties have a
* content model that is consistent with gml:AssociationRoleType but is not
* explicitly derived from any predefined GML property type.
*
* @param model
* An XSModel object incorporating application schema components.
* @param headElem
* The head of the substitution group to which the property value
* belongs.
* @return A list of element declarations that correspond to implicit GML
* properties having the specified value domain. The list is empty
* if none are found.
*/
public static List getImplicitProperties(
XSModel model, XSElementDeclaration headElem) {
List typeDefs = new ArrayList();
// find complex types with element-only content type
for (String nsName : getApplicationNamespaces(model)) {
XSNamedMap types = model.getComponentsByNamespace(
XSTypeDefinition.COMPLEX_TYPE, nsName);
for (int i = 0; i < types.getLength(); i++) {
XSComplexTypeDefinition type = (XSComplexTypeDefinition) types
.item(i);
if (type.getContentType() == XSComplexTypeDefinition.CONTENTTYPE_ELEMENT) {
typeDefs.add(type);
}
}
}
List props = new ArrayList();
for (XSComplexTypeDefinition typeDef : typeDefs) {
if (propertyHasValueDomain(typeDef, headElem)) {
props.addAll(getGlobalElementsByType(model, typeDef));
props.addAll(getLocalElementsByType(model, typeDef,
new GMLObjectTypeFilter()));
}
}
return props;
}
/**
* Determines whether or not a given complex property type has a specified
* value domain.
*
* @param typeDef
* A complex type definition that resembles a GML property type.
* @param headElem
* The head element indicating the type of the property value(s).
* @return true if the property value is substitutable for the head element;
* false otherwise.
*/
public static boolean propertyHasValueDomain(
XSComplexTypeDefinition typeDef, XSElementDeclaration headElem) {
boolean hasValueDomain = false;
XSTerm term = typeDef.getParticle().getTerm();
// expect sequence compositor here
if (term.getType() == XSConstants.MODEL_GROUP) {
XSModelGroup group = (XSModelGroup) term;
XSParticle particle = (XSParticle) group.getParticles().item(0);
if (particle.getTerm().getType() == XSConstants.ELEMENT_DECLARATION) {
XSElementDeclaration propValue = (XSElementDeclaration) particle
.getTerm();
Set headElems = new HashSet();
getHeadElements(headElems, propValue);
if (headElems.contains(headElem)) {
hasValueDomain = true;
}
}
}
return hasValueDomain;
}
/**
* Identifies the set of (head) elements for which the given element can
* substitute.
*
* @param headElems
* The set to be populated with head element declarations. The
* set will always contain the given element declaration, which
* could serve as a head element itself.
* @param propValue
* A global element declaration that is presumably affiliated
* with some substitution group.
*/
public static void getHeadElements(Set headElems,
XSElementDeclaration propValue) {
if (propValue.getScope() != XSConstants.SCOPE_GLOBAL) {
return;
}
headElems.add(propValue);
if (null != propValue.getSubstitutionGroupAffiliation()) {
getHeadElements(headElems,
propValue.getSubstitutionGroupAffiliation());
}
}
/**
* Returns a collection of topology element declarations in the application
* namespace(s). These elements may substitute for gml:AbstractTopology.
*
* @param model
* An XSModel object representing the application schema.
* @return A List containing all (global) element declarations belonging to
* the substitution group having gml:AbstractTopology as its head.
*
* @see "ISO 19136:2007, 21.5.2.1"
*/
public static List getTopologyDeclarations(
XSModel model) {
XSElementDeclaration gmlAbstractTopo = model.getElementDeclaration(
GML32.ABSTRACT_TOPO, GML32.NS_NAME);
List topoElems = getElementsByAffiliation(model,
gmlAbstractTopo);
removeGmlElementsFromList(topoElems);
return topoElems;
}
/**
* Returns a collection of temporal element declarations in the application
* namespace(s). These elements may substitute for gml:AbstractTimeObject.
*
* @param model
* An XSModel object representing the application schema.
* @return A List containing all (global) element declarations belonging to
* the substitution group having gml:AbstractTimeObject as its head.
*
* @see "ISO 19136:2007, 21.6.2.1"
*/
public static List getTimeObjectDeclarations(
XSModel model) {
XSElementDeclaration gmlAbstractTime = model.getElementDeclaration(
GML32.ABSTRACT_TIME, GML32.NS_NAME);
List timeElems = getElementsByAffiliation(model,
gmlAbstractTime);
removeGmlElementsFromList(timeElems);
return timeElems;
}
/**
* Returns a collection of CRS declarations in the application namespace(s).
* These elements (which may substitute for gml:AbstractCRS) are typically
* declared whenever a standard CRS type must be extended or restricted.
*
* @param model
* An XSModel object representing the application schema.
* @return A List containing all (global) element declarations belonging to
* the substitution group having gml:AbstractCRS as its head.
*
* @see "ISO 19136:2007, 21.6.2.1"
*/
public static List getCRSDeclarations(XSModel model) {
XSElementDeclaration gmlAbstractCRS = model.getElementDeclaration(
GML32.ABSTRACT_CRS, GML32.NS_NAME);
List crsElems = getElementsByAffiliation(model,
gmlAbstractCRS);
removeGmlElementsFromList(crsElems);
return crsElems;
}
/**
* Returns a collection of coverage elements in the application
* namespace(s). These elements may substitute for gml:AbstractCoverage.
*
* Note that in the latest GML schema gml:AbstractContinuousCoverage, unlike
* gml:AbstractDiscreteCoverage, cannot substitute for gml:AbstractCoverage.
*
* @param model
* An XSModel object representing the application schema.
* @return A List containing all (global) element declarations belonging to
* the substitution group having gml:AbstractCoverage as its head.
*
* @see "ISO 19136:2007, 21.8.3"
*/
public static List getCoverageDeclarations(
XSModel model) {
XSElementDeclaration gmlAbstractCoverage = model.getElementDeclaration(
GML32.ABSTRACT_COVERAGE, GML32.NS_NAME);
List coverageElems = getElementsByAffiliation(
model, gmlAbstractCoverage);
removeGmlElementsFromList(coverageElems);
return coverageElems;
}
/**
* Returns a collection of observation elements declared in the application
* namespace(s). These elements may substitute for gml:Observation.
*
* @param model
* An XSModel object representing the application schema.
* @return A List containing all (global) element declarations belonging to
* the substitution group having gml:Observation as its head.
*
* @see "ISO 19136:2007, 21.9.3"
*/
public static List getObservationDeclarations(
XSModel model) {
XSElementDeclaration gmlObservation = model.getElementDeclaration(
GML32.OBSERVATION, GML32.NS_NAME);
List observationElems = getElementsByAffiliation(
model, gmlObservation);
removeGmlElementsFromList(observationElems);
return observationElems;
}
/**
* Returns a collection of definition elements declared in the application
* namespace(s), including dictionaries. These elements may substitute for
* gml:Definition.
*
* @param model
* An XSModel object representing the application schema.
* @return A List containing all (global) element declarations belonging to
* the substitution group having gml:Definition as its head.
*
* @see "ISO 19136:2007, 21.10.3-4"
*/
public static List getDefinitionDeclarations(
XSModel model) {
XSElementDeclaration gmlDefinition = model.getElementDeclaration(
GML32.DEFINITION, GML32.NS_NAME);
List defnElems = getElementsByAffiliation(model,
gmlDefinition);
removeGmlElementsFromList(defnElems);
return defnElems;
}
/**
* Returns a collection of element declarations that may substitute
* (directly or indirectly) for the specified element.
*
* @param model
* An XSModel object incorporating application schema components.
* @param head
* The head of the substitution group.
* @return A List containing all element declarations having the designated
* substitution group affiliation. The list may be empty; it will
* certainly be empty if the head element is null.
*/
public static List getElementsByAffiliation(
XSModel model, XSElementDeclaration head) {
List elemDecls = new ArrayList();
if (null == head) {
return elemDecls;
}
XSObjectList subGroupMembers = model.getSubstitutionGroup(head);
for (Object xsObject : subGroupMembers) {
XSElementDeclaration subGroupMember = (XSElementDeclaration) xsObject;
elemDecls.add(subGroupMember);
}
return elemDecls;
}
/**
* Returns a list of globally-scoped (top-level) element declarations whose
* type definition either matches the given type or derives from it by
* extension.
*
* @param model
* An XSModel object incorporating application schema components.
* @param typeDef
* A simple or complex type defining the content model of the
* desired elements. It may be an ancestor type.
* @return A List containing globally-scoped element declarations in an
* application namespace. The list is empty if no matching
* declarations are found.
*/
public static List getGlobalElementsByType(
XSModel model, XSTypeDefinition typeDef) {
List elems = new ArrayList();
Set nsNames = getApplicationNamespaces(model);
for (String nsName : nsNames) {
// Globally scoped element declarations
XSNamedMap elemDecls = model.getComponentsByNamespace(
XSConstants.ELEMENT_DECLARATION, nsName);
for (int i = 0; i < elemDecls.getLength(); i++) {
XSElementDeclaration elemDecl = (XSElementDeclaration) elemDecls
.item(i);
if (elemDecl.getTypeDefinition().equals(typeDef)
|| elemDecl.getTypeDefinition().derivedFromType(
typeDef, XSConstants.DERIVATION_EXTENSION)) {
elems.add(elemDecl);
}
}
}
return elems;
}
/**
* Returns a list of locally-scoped element declarations whose type
* definition either matches the given type or derives from it by extension.
* The scope of these declarations is some complex type definition that may
* be accessed using the
* {@link XSElementDeclaration#getEnclosingCTDefinition()
* getEnclosingCTDefinition} method. The type definitions to be examined may
* be restricted using a component filter.
*
* @param model
* An XSModel object incorporating application schema components.
* @param typeDef
* A simple or complex type defining the content model of the
* desired elements. It may be an ancestor type.
* @param typeFilter
* A schema component filter that determines which type
* definitions will be examined; if {@code null}, all complex
* types defined in application namespaces will be inspected.
* @return A List containing locally-scoped element declarations in an
* application namespace. The list is empty if no matching
* declarations are found.
*/
@SuppressWarnings("unchecked")
public static List getLocalElementsByType(
XSModel model, XSTypeDefinition typeDef,
SchemaComponentFilter typeFilter) {
List elemsByType = new ArrayList();
Set nsNames = getApplicationNamespaces(model);
for (String nsName : nsNames) {
Map complexTypes = new HashMap();
complexTypes.putAll(model.getComponentsByNamespace(
XSTypeDefinition.COMPLEX_TYPE, nsName));
// Add anonymous complex types from global element declarations
XSNamedMap globalElemDecls = model.getComponentsByNamespace(
XSConstants.ELEMENT_DECLARATION, nsName);
for (int i = 0; i < globalElemDecls.getLength(); i++) {
XSElementDeclaration elemDecl = (XSElementDeclaration) globalElemDecls
.item(i);
if (elemDecl.getTypeDefinition().getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) {
continue;
}
if (elemDecl.getTypeDefinition().getAnonymous()) {
complexTypes.put(new QName(nsName, "anon-" + i),
elemDecl.getTypeDefinition());
}
}
if (null != typeFilter) {
complexTypes = typeFilter.doFilter(complexTypes);
}
for (XSObject xsObj : complexTypes.values()) {
XSComplexTypeDefinition type = (XSComplexTypeDefinition) xsObj;
List childElems = getAllElementsInParticle(type
.getParticle());
for (XSElementDeclaration elemDecl : childElems) {
if (elemDecl.getTypeDefinition().equals(typeDef)
|| elemDecl.getTypeDefinition().derivedFromType(
typeDef, XSConstants.DERIVATION_EXTENSION)) {
if (elemDecl.getScope() == XSConstants.SCOPE_GLOBAL) {
continue; // refers to global element declaration
}
elemsByType.add(elemDecl);
}
}
}
}
return elemsByType;
}
/**
* Returns all element declarations contained in the given particle schema
* component. The {term} property of a particle is one of a model group, a
* wildcard, or an element declaration. Note that a model group (denoted by
* the "all", "choice", or "sequence" compositor) can contain other model
* groups.
*
* @param particle
* An XSParticle representing a particle component.
* @return A List of element declarations contained directly or indirectly
* in the particle; the components are listed in document order.
*/
@SuppressWarnings("rawtypes")
public static List getAllElementsInParticle(
XSParticle particle) {
List elems = new ArrayList();
if (null != particle) { // mixed or element-only content model
switch (particle.getTerm().getType()) {
case XSConstants.ELEMENT_DECLARATION:
XSElementDeclaration elemDecl = (XSElementDeclaration) particle
.getTerm();
elems.add(elemDecl);
break;
case XSConstants.MODEL_GROUP:
XSModelGroup group = (XSModelGroup) particle.getTerm();
for (Iterator itr = group.getParticles().iterator(); itr
.hasNext();) {
XSParticle xsParticle = (XSParticle) itr.next();
elems.addAll(getAllElementsInParticle(xsParticle));
}
break;
default:
// ignore wildcard term
}
}
return elems;
}
/**
* Returns all constituent particles corresponding to element declarations.
* The {term} property of a particle is one of a model group, a wildcard, or
* an element declaration.
*
* @param particle
* A particle schema component to inspect.
* @return A List containing particles that have an element declaration as
* its term.
*/
@SuppressWarnings("unchecked")
public static List getAllElementParticles(XSParticle particle) {
List particles = new ArrayList();
XSTerm xsTerm = particle.getTerm();
switch (xsTerm.getType()) {
case XSConstants.ELEMENT_DECLARATION:
particles.add(particle);
break;
case XSConstants.MODEL_GROUP:
XSModelGroup group = (XSModelGroup) xsTerm;
for (Iterator itr = group.getParticles().iterator(); itr
.hasNext();) {
XSParticle xsParticle = itr.next();
particles.addAll(getAllElementParticles(xsParticle));
}
break;
default:
// ignore wildcard term
}
return particles;
}
/**
* Returns a collection of complex type definitions referenced by global
* elements declared in all application namespaces. The resulting set may
* include anonymous types.
*
* @param model
* An XSModel object.
* @return A Set containing XSComplexTypeDefinition components.
*/
public static Set getReferencedComplexTypeDefinitions(
XSModel model) {
Set typeDefs = new HashSet();
Set appNamespaces = getApplicationNamespaces(model);
for (String nsName : appNamespaces) {
XSNamedMap elemDecls = model.getComponentsByNamespace(
XSConstants.ELEMENT_DECLARATION, nsName);
for (int i = 0; i < elemDecls.getLength(); i++) {
XSElementDeclaration elemDecl = (XSElementDeclaration) elemDecls
.item(i);
XSTypeDefinition typeDef = elemDecl.getTypeDefinition();
if (typeDef.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
typeDefs.add((XSComplexTypeDefinition) typeDef);
}
}
}
return typeDefs;
}
/**
* Returns a collection of top-level complex types defined in all
* application namespaces.
*
* @param model
* An XSModel object.
* @return A Set containing XSComplexTypeDefinition components.
*/
@SuppressWarnings("unchecked")
public static Set getGlobalComplexTypeDefinitions(
XSModel model) {
Set typeDefs = new HashSet();
for (String nsName : getApplicationNamespaces(model)) {
XSNamedMap components = model.getComponentsByNamespace(
XSTypeDefinition.COMPLEX_TYPE, nsName);
Collection values = components.values();
typeDefs.addAll(values);
}
return typeDefs;
}
/**
* Returns a list of application-specific namespace names declared in a
* schema. These are absolute URIs with non-standard authority components or
* scheme names.
*
* @param model
* An XSModel object incorporating application schema components.
* @return A Set of Strings denoting the target namespace(s) used by the
* application schema.
*/
public static Set getApplicationNamespaces(XSModel model) {
StringList nsNames = model.getNamespaces();
Set appNamespaces = new HashSet();
for (int i = 0; i < nsNames.getLength(); i++) {
String nsName = nsNames.item(i);
if (nsName.startsWith("http://www.opengis.net/gml")
|| nsName.startsWith("http://www.w3.org/")
|| nsName.startsWith("http://www.isotc211.org/")) {
continue;
}
appNamespaces.add(nsName);
}
return appNamespaces;
}
/**
* Returns the set of type definitions that are derived from the given base
* type using the specified method.
*
* @param model
* An XSModel object containing schema components.
* @param baseType
* The base (ancestor) type.
* @param derivationMethod
* A bit combination representing a subset of {
* DERIVATION_RESTRICTION, DERIVATION_EXTENSION,
* DERIVATION_UNION, DERIVATION_LIST }.
* @return A Set containing zero or more simple or complex type definitions
* (XSTypeDefinition objects).
*/
public static Set getDerivedTypeDefinitions(
XSModel model, XSTypeDefinition baseType, short derivationMethod) {
Set typeDefs = new HashSet();
for (String nsName : getApplicationNamespaces(model)) {
XSNamedMap components = model.getComponentsByNamespace(
XSConstants.TYPE_DEFINITION, nsName);
for (int i = 0; i < components.getLength(); i++) {
XSTypeDefinition typeDef = (XSTypeDefinition) components
.item(i);
if (typeDef.derivedFromType(baseType, derivationMethod)) {
typeDefs.add(typeDef);
}
}
}
return typeDefs;
}
/**
* Returns a list of element declarations (globally and locally scoped)
* whose type definition either matches the given base type or derives from
* it by extension. For local element declarations the enclosing (complex)
* type is restricted to being a feature type.
*
* @param model
* An XSModel object incorporating application schema components
* from one or more namespaces.
* @param baseType
* A simple or complex type defining the content model of the
* desired elements. It may be an ancestor type.
* @return A list of element declarations. The list is empty if no matching
* element declarations are found.
*/
public static List getElementDeclarationsByType(
XSModel model, XSTypeDefinition baseType) {
List elemDecls = getGlobalElementsByType(model,
baseType);
elemDecls.addAll(getLocalElementsByType(model, baseType,
new FeatureTypeFilter()));
return elemDecls;
}
/**
* Gets the name of the given XML Schema component.
*
* @param xsObject
* An XSObject representing a schema component.
* @return A QName indicating the qualified name of the schema component. If
* it is anonymous its localName is an empty string.
*/
public static QName getQName(XSObject xsObject) {
String localName = (null != xsObject.getName()) ? xsObject.getName()
: new String();
return new QName(xsObject.getNamespace(), localName);
}
/**
* Removes elements declared in the standard GML namespace (
* {@value org.opengis.cite.iso19136.general.GML32#NS_NAME}), leaving only
* those residing in an application namespace.
*
* @param elemDecls
* A List of element declarations.
*/
static void removeGmlElementsFromList(List elemDecls) {
Iterator itr = elemDecls.iterator();
while (itr.hasNext()) {
XSElementDeclaration decl = itr.next();
if (decl.getNamespace().equals(GML32.NS_NAME)) {
itr.remove();
}
}
}
}