Reputation: 57
Please see the following java code:
URL u = new URL("http://www.site1.com/aaa/");
URL u2 = new URL("http://www.site1.com/aaa/ccc/aaa/");
URI r = u2.toURI().relativize(u.toURI());
System.out.println(r); // print: http://www.site1.com/aaa/
However, how to return the REALLY relative path: ../../ ?
Upvotes: 0
Views: 2935
Reputation: 57
the code, hope it's useful :)
/**
* split path
* the String.split() is a little ambiguous because it might return empty string in the returned array that is unexpected.
* in this function, the only case that returned array is empty is when path is /
* @param path
* @return
*/
public static String[] splitPath(String path) {
ArrayList<String> ret = new ArrayList<String>();
Pattern p = Pattern.compile("/+");
Matcher m = p.matcher(path);
int s0 = 0;
int s1,e1;
while(m.find()) {
s1 = m.start();
e1 = m.end();
if(s1-s0>0) {
ret.add(path.substring(s0,s1));
}
s0 = e1;
}
if(s0<path.length()) {
ret.add(path.substring(s0));
}
String[] a = ret.toArray(new String[0]);
return a;
}
/**
* get the relative path against the base dir.
* @param base - the base path, must be a directory.
* @param path - the path to visit, can be directory or file.
* @return - the relative path from base to the path.
*/
public static String relativize(String baseDir, String path) {
if(!baseDir.endsWith("/")) {
baseDir = baseDir + "/"; // assume the baseDir is always a directory.
}
String[] bases = splitPath(baseDir);
String[] paths = splitPath(path);
int p = 0, q = 0;
while(p<bases.length && q<paths.length && bases[p].equals(paths[q])) {
p++;
q++;
}
StringBuilder sb = new StringBuilder(255);
int i;
for(i=bases.length-1;i>=p;i--) {
sb.append("../");
}
for(i=q;i<paths.length;i++) {
sb.append(paths[i]);
if(i!=paths.length-1) {
sb.append("/");
}
}
if(path.endsWith("/")) {
// ensure the last char of sb is not /
i = sb.length();
if(i>0 && sb.charAt(i-1)!='/') {
sb.append("/");
}
}
return sb.toString();
}
static void testRelativize() {
String r;
r = relativize("/", "/acdde");
if(!"acdde".equals(r)) {
throw new RuntimeException("1");
}
r = relativize("/a", "/b/c");
if(!"../b/c".equals(r)) {
throw new RuntimeException("2");
}
r = relativize("/c", "/c/a/");
if(!"a/".equals(r)) {
throw new RuntimeException("3");
}
r = relativize("/c/d", "/c/a/a.txt");
if(!"../a/a.txt".equals(r)) {
throw new RuntimeException("4");
}
r = relativize("/c/b/d/", "/c/");
if(!"../../".equals(r)) {
throw new RuntimeException("5");
}
r = relativize("/c/d", "/c/d/a.txt");
if(!"a.txt".equals(r)) {
throw new RuntimeException("6");
}
}
Upvotes: 2
Reputation: 4815
You probably want to switch u2
with u
, since u
is the prefix of u2
, like this:
URI r = u.toURI().relativize(u2.toURI());
System.out.println(r); // print: ccc/aaa/
According to URI.relativize() javadoc:
The relativization of the given URI against this URI is computed as follows:
If either this URI or the given URI are opaque, or if the scheme and authority components of the two URIs are not identical, or if the path of this URI is not a prefix of the path of the given URI, then the given URI is returned.
Otherwise a new relative hierarchical URI is constructed with query and fragment components taken from the given URI and with a path component computed by removing this URI's path from the beginning of the given URI's path.
Upvotes: 1