5

I have these two URIs:

http://www.google.de/blank.gif

http://www.google.de/sub/

I want the relative path from http://www.google.de/sub/ to http://www.google.de/blank.gif so that the result is ../blank.gif

URI.relativize() does not work here :/

Thanks!

Eng.Fouad
  • 115,165
  • 71
  • 313
  • 417
Heiko
  • 394
  • 1
  • 4
  • 14
  • 2
    This is [known bug](http://bugs.sun.com/view_bug.do?bug_id=6226081). I think you need to find different library or write it yourself. – Piotr Praszmo May 29 '12 at 14:57

2 Answers2

6

The Apache URIUtils should work. If you don't want to pull in an external library, here's a simple implementation of a method that should correctly resolve relative URIs for the case that java.net.URI can't handle (i.e. where the base URI path is not a prefix of the child URI path).

public static URI relativize(URI base, URI child) {
  // Normalize paths to remove . and .. segments
  base = base.normalize();
  child = child.normalize();

  // Split paths into segments
  String[] bParts = base.getPath().split("\\/");
  String[] cParts = child.getPath().split("\\/");

  // Discard trailing segment of base path
  if (bParts.length > 0 && !base.getPath().endsWith("/")) {
    bParts = Arrays.copyOf(bParts, bParts.length - 1);
  }

  // Remove common prefix segments
  int i = 0;
  while (i < bParts.length && i < cParts.length && bParts[i].equals(cParts[i])) {
    i++;
  }

  // Construct the relative path
  StringBuilder sb = new StringBuilder();
  for (int j = 0; j < (bParts.length - i); j++) {
    sb.append("../");
  }
  for (int j = i; j < cParts.length; j++) {
    if (j != i) {
      sb.append("/");
    }
    sb.append(cParts[j]);
  }

  return URI.create(sb.toString());
}

Note that this doesn't enforce that the base and child have the same scheme and authority -- you'll have to add that if you want it to handle the general case. This might not work against all boundary cases, but it works against you example.

Alex
  • 13,811
  • 1
  • 37
  • 50
  • Thanks, but you have to compare both host names `if (!base.getHost().equalsIgnoreCase(child.getHost())) { return child; }` – Heiko Jun 01 '12 at 12:23
4

I think you can use Apache URIUtils

http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/client/utils/URIUtils.html#resolve%28java.net.URI,%20java.net.URI%29

resolve

public static URI resolve(URI baseURI, URI reference)

Resolves a URI reference against a base URI. Work-around for bugs in java.net.URI (e.g. )

Parameters:
    baseURI - the base URI
    reference - the URI reference 
Returns:
    the resulting URI

Example:

http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/client/utils/TestURIUtils.java

Rodrigo Camargo
  • 180
  • 1
  • 6