cdm/src/main/java/ucar/nc2/util/URLnaming.java
public static String resolve(String baseUri, String relativeUri) {
    if ((baseUri == null) || (relativeUri == null))
      return relativeUri;

    if (relativeUri.startsWith("file:"))
      return relativeUri;

    // deal with a base file URL
    if (baseUri.startsWith("file:")) {

      // the case where the reletiveURL is absolute.
      // unfortunately, we may get an Exception
      try {
        URI uriRelative = URI.create(relativeUri);
        if (uriRelative.isAbsolute())
          return relativeUri;
      } catch (Exception e) {
        // empty
      }

      if ((relativeUri.length() > 0) && (relativeUri.charAt(0) == '#'))
        return baseUri + relativeUri;

      if ((relativeUri.length() > 0) && (relativeUri.charAt(0) == '/'))
        return relativeUri;

      baseUri = StringUtil2.substitute(baseUri, "\\", "/"); // assumes forward slash
      int pos = baseUri.lastIndexOf('/');
      if (pos > 0) {
        String baseDir = baseUri.substring(0, pos + 1);
        if (relativeUri.equals(".")) {
          return baseDir;
        } else {
          return baseDir + relativeUri;
        }
      }
    }

    // non-file URLs

    //relativeUri = canonicalizeRead(relativeUri);
    try {
      URI relativeURI = URI.create(relativeUri);
      if (relativeURI.isAbsolute())
        return relativeUri;

      //otherwise let the URI class resolve it
      URI baseURI = URI.create(baseUri);
      URI resolvedURI = baseURI.resolve(relativeURI);
      return resolvedURI.toASCIIString();

    } catch (IllegalArgumentException e) {
      return  relativeUri;
    }
  }
public static String resolve(String baseUri, String relativeUri) {
    if ((baseUri == null) || (relativeUri == null))
      return relativeUri;

    if (relativeUri.startsWith("file:"))
      return relativeUri;

    // deal with a base file URL
    if (baseUri.startsWith("file:")) {

      // the case where the reletiveURL is absolute.
      // unfortunately, we may get an Exception
      try {
        URI uriRelative = URI.create(relativeUri);
        if (uriRelative.isAbsolute())
          return relativeUri;
      } catch (Exception e) {
        // empty
      }

      if ((relativeUri.length() > 0) && (relativeUri.charAt(0) == '#'))
        return baseUri + relativeUri;

      if ((relativeUri.length() > 0) && (relativeUri.charAt(0) == '/'))
        return relativeUri;

      baseUri = StringUtil2.substitute(baseUri, "\\", "/"); // assumes forward slash
      int pos = baseUri.lastIndexOf('/');
      if (pos > 0) {
        String baseDir = baseUri.substring(0, pos + 1);
        if (relativeUri.equals(".")) {
          return baseDir;
        } else {
          return baseDir + relativeUri;
        }
      }
    }

    // non-file URLs

    //relativeUri = canonicalizeRead(relativeUri);
    try {
      URI relativeURI = URI.create(relativeUri);
      if (relativeURI.isAbsolute())
        return relativeUri;

      //otherwise let the URI class resolve it
      URI baseURI = URI.create(baseUri);
      URI resolvedURI = baseURI.resolve(relativeURI);
      return resolvedURI.toASCIIString();

    } catch (IllegalArgumentException e) {
      return  relativeUri;
    }
  }
public static String resolve ( String baseUri , String relativeUri ) { if ( ( baseUri == null ) || ( relativeUri == null ) ) return relativeUri ; if ( relativeUri . startsWith ( "file:" ) ) return relativeUri ; // deal with a base file URL
 if ( baseUri . startsWith ( "file:" ) ) { // the case where the reletiveURL is absolute.
 // unfortunately, we may get an Exception
 try { URI uriRelative = URI . create ( relativeUri ) ; if ( uriRelative . isAbsolute ( ) ) return relativeUri ; } catch ( Exception e ) { // empty
 } if ( ( relativeUri . length ( ) > 0 ) && ( relativeUri . charAt ( 0 ) == ' ' ) ) return baseUri + relativeUri ; if ( ( relativeUri . length ( ) > 0 ) && ( relativeUri . charAt ( 0 ) == ' ' ) ) return relativeUri ; baseUri = StringUtil2 . substitute ( baseUri , "\\" , "/" ) ; // assumes forward slash
 int pos = baseUri . lastIndexOf ( ' ' ) ; if ( pos > 0 ) { String baseDir = baseUri . substring ( 0 , pos + 1 ) ; if ( relativeUri . equals ( "." ) ) { return baseDir ; } else { return baseDir + relativeUri ; } } } // non-file URLs
 //relativeUri = canonicalizeRead(relativeUri);
 try { URI relativeURI = URI . create ( relativeUri ) ; if ( relativeURI . isAbsolute ( ) ) return relativeUri ; //otherwise let the URI class resolve it
 URI baseURI = URI . create ( baseUri ) ; URI resolvedURI = baseURI . resolve ( relativeURI ) ; return resolvedURI . toASCIIString ( ) ; } catch ( IllegalArgumentException e ) { return relativeUri ; } }
This augments URI.resolve(), by also dealing with file: URIs.
If baseURi is not a file: scheme, then URI.resolve is called.
Otherwise the last "/" is found in the base, and the ref is appended to it.
<p> For file: baseURLS: only reletive URLS not starting with / are supported. This is
apparently different from the behavior of URI.resolve(), so may be trouble,
but it allows NcML absolute location to be specified without the file: prefix.
<p/>
Example : <pre>
base:     file://my/guide/collections/designfaq.ncml
ref:      sub/my.nc
resolved: file://my/guide/collections/sub/my.nc
</pre>

@param baseUri     base URI as a Strng
@param relativeUri reletive URI, as a String
@return the resolved URI as a String
This augments URI . resolve () by also dealing with file : URIs . If baseURi is not a file : scheme then URI . resolve is called . Otherwise the last / is found in the base and the ref is appended to it . <p > For file : baseURLS : only reletive URLS not starting with / are supported . This is apparently different from the behavior of URI . resolve () so may be trouble but it allows NcML absolute location to be specified without the file : prefix . <p / > Example : <pre > base : file : // my / guide / collections / designfaq . ncml ref : sub / my . nc resolved : file : // my / guide / collections / sub / my . nc < / pre >