diff --git a/src/context/context.rs b/src/context/context.rs
index 607653c8816cc68faf7e46c6871ee79c854afebb..b594b60d63e39285925545c0f5fdbca6db00c465 100644
--- a/src/context/context.rs
+++ b/src/context/context.rs
@@ -133,31 +133,59 @@ impl Context {
                                    .iter().rposition(|&b| b == b'/' || b == b':')
                                    .map_or(cwd.len(), |i| i + 1)]
                    .to_vec()
-            } else if path.starts_with(b"./") {
-                let mut canon = cwd.clone();
-                if ! canon.ends_with(b"/") {
-                    canon.push(b'/');
-                }
-                canon.extend_from_slice(&path[2..]);
-                canon
-            } else if path.starts_with(b"../") {
-                let mut canon = cwd[..cwd[..cwd.len() - 1]
-                                   .iter().rposition(|&b| b == b'/' || b == b':')
-                                   .map_or(cwd.len(), |i| i + 1)]
-                   .to_vec();
-                canon.extend_from_slice(&path[3..]);
-                canon
-            } else if path.starts_with(b"/") {
-                let mut canon = cwd[..cwd.iter().position(|&b| b == b':').map_or(1, |i| i + 1)].to_vec();
-                canon.extend_from_slice(&path);
-                canon
             } else {
-                let mut canon = cwd.clone();
-                if ! canon.ends_with(b"/") {
-                    canon.push(b'/');
-                }
+                let mut canon = if !path.starts_with(b"/") {
+                    let mut c = cwd.clone();
+                    if ! c.ends_with(b"/") {
+                        c.push(b'/');
+                    }
+                    c
+                } else {
+                    cwd[..cwd.iter().position(|&b| b == b':').map_or(1, |i| i + 1)].to_vec()
+                };
+
                 canon.extend_from_slice(&path);
-                canon
+                // NOTE: assumes the scheme does not include anything like "../" or "./"
+                let mut result = {
+                    let parts = canon.split(|&c| c == b'/')
+                        .filter(|&part| part != b".")
+                        .rev()
+                        .scan(0, |nskip, part| {
+                            if part == b".." {
+                                *nskip += 1;
+                                Some(None)
+                            } else {
+                                if *nskip > 0 {
+                                    *nskip -= 1;
+                                    Some(None)
+                                } else {
+                                    Some(Some(part))
+                                }
+                            }
+                        })
+                        .filter_map(|x| x)
+                        .collect::<Vec<_>>();
+                    parts
+                        .iter()
+                        .rev()
+                        .fold(Vec::new(), |mut vec, &part| {
+                            vec.extend_from_slice(part);
+                            vec.push(b'/');
+                            vec
+                        })
+                };
+                result.pop(); // remove extra '/'
+
+                // replace with the root of the schema if it's empty
+                if result.len() == 0 {
+                    let pos = canon.iter()
+                                    .position(|&b| b == b':')
+                                    .map_or(canon.len(), |p| p + 1);
+                    canon.truncate(pos);
+                    canon
+                } else {
+                    result
+                }
             }
         } else {
             path.to_vec()