/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2002-2008, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.xml; import org.eclipse.xsd.XSDSchema; import org.eclipse.xsd.util.XSDSchemaLocationResolver; import java.io.File; import java.net.URI; import java.net.URL; import java.util.List; /** * Resolves a physical schema location from a namespace uri. * <p> * This class works from a {@link org.geotools.xml.XSD} instance from which it * resolves location on disk relative to. * </p> * <p> * Example usage: * * <code> * <pre> * XSD xsd = ... * String namespaceURI = xsd.getNamesapceURI(); * * SchemaLocationResolver resolver = new SchemaLocationResolver( xsd ); * String schemaLocation = locator.resolveSchemaLocation( null, namespaceURI, "mySchema.xsd" ); * </pre> * </code> * * </p> * @author Justin Deoliveira, The Open Planning Project * * * @source $URL$ */ public class SchemaLocationResolver implements XSDSchemaLocationResolver { /** * the xsd instance */ protected XSD xsd; /** * A list of locations to use as prefixes when looking up schema files. * <p> * This value should be set in cases where an xml schema imports or includes * schema files from sub directories. * </p> */ protected String[] lookupDirectories; /** * Creates the new schema location resolver. * * @param xsd The xsd to resolve filenames relative to. */ public SchemaLocationResolver(XSD xsd) { this(xsd,new String[]{}); } /** * Creates the new schema location resolver specifying additional directories to locate * schema files in. * <p> * The <tt>lookupDirectories</tt> parameter should be used in cases where a main schema imports * or includes files from sub directories. Consider the following schema file structure: * <pre> * main.xsd * dir1/ * include1.xsd * dir2/ * include2.xsd * </pre> * * The constructor would be called with: * <pre> * new SchemaLocationResolver(this,"include1","include2"); * </pre> * * </p> * @param xsd The xsd to resolve files relative to. * @param lookupDirectories Additional lookup directories relative to the xsd to lookup files in. */ public SchemaLocationResolver(XSD xsd, String... lookupDirectories) { this.xsd = xsd; this.lookupDirectories = lookupDirectories; } /** * Determines if the locator can resolve the schema location for a particular * namespace uri and schema location. * * @return true if it can handle, otherwise false. */ public boolean canHandle( XSDSchema schema, String uri, String location ) { if ( xsd.getNamespaceURI().equals(uri) ) { //try resolving directly URL xsdLocation = resolveLocationToResource( location ); return xsdLocation != null; } return false; } private URL resolveLocationToResource( String location ) { //try to resolve it directly URL url = xsd.getClass().getResource( location ); if ( url == null ) { //strip off the filename and do a resource lookup String fileName = new File(location).getName(); url = xsd.getClass().getResource(fileName); } if ( url == null ) { //try resolving relative to lookupDirectories if ( lookupDirectories != null ) { for ( String lookup : lookupDirectories ) { if ( lookup.endsWith( "/" ) ) { lookup = lookup.substring(0,lookup.length()-1); } url = xsd.getClass().getResource( lookup + "/" + location ); } } } return url; } /** * Resolves <param>location<param> to a physical location. * <p> * Resolution is performed by stripping the filename off of <param>location</param> * and looking up a resource located in the same package as the xsd. * </p> */ public String resolveSchemaLocation(XSDSchema schema, String uri, String location) { if (location == null) { return null; } //if no namespace given, assume default for the current schema if (((uri == null) || "".equals(uri)) && (schema != null)) { uri = schema.getTargetNamespace(); } //namespace match? if (canHandle(schema, uri, location)) { return resolveLocationToResource( location ).toString(); } return null; } public String toString() { return xsd.toString(); } }