 
 extension Node {
     public func extract<T : NodeInitializable>(
-        _ keyType: PathIndex...)
+        _ path: PathIndex...)
         throws -> T? {
-            return try self[keyType].flatMap { try T(node: $0) }
-    }
-
-    public func extract<T : NodeInitializable>(
-        _ keyType: PathIndex...)
+            return try extract(path: path)
+    }
+
+    public func extract<T : NodeInitializable>(
+        path: [PathIndex])
+        throws -> T? {
+            return try self[path].flatMap { try T(node: $0) }
+    }
+
+    public func extract<T : NodeInitializable>(
+        _ path: PathIndex...)
         throws -> [T]? {
-            return try self[keyType].flatMap { try [T](node: $0) }
-    }
-
-    public func extract<T : NodeInitializable>(
-        _ keyType: PathIndex...)
+            return try extract(path: path)
+    }
+
+    public func extract<T : NodeInitializable>(
+        path: [PathIndex])
+        throws -> [T]? {
+            return try self[path].flatMap { try [T](node: $0) }
+    }
+
+    public func extract<T : NodeInitializable>(
+        _ path: PathIndex...)
         throws -> [[T]]? {
-            guard let initial = self[keyType] else { return nil }
+            return try extract(path: path)
+    }
+
+    public func extract<T : NodeInitializable>(
+        path: [PathIndex])
+        throws -> [[T]]? {
+            guard let initial = self[path] else { return nil }
             let array = initial.nodeArray ?? [initial]
             return try array.map { try [T](node: $0) }
     }
 
     public func extract<T : NodeInitializable>(
-        _ keyType: PathIndex...)
+        _ path: PathIndex...)
         throws -> [String : T]? {
-            return try self[keyType]?
+            return try extract(path: path)
+    }
+
+    public func extract<T : NodeInitializable>(
+        path: [PathIndex])
+        throws -> [String : T]? {
+            return try self[path]?
                 .nodeObject?
                 .mapValues { return try T(node: $0) }
     }
 
     public func extract<T : NodeInitializable>(
-        _ keyType: PathIndex...)
+        _ path: PathIndex...)
         throws -> [String : [T]]? {
-            return try self[keyType]?
+            return try extract(path: path)
+    }
+
+    public func extract<T : NodeInitializable>(
+        path: [PathIndex])
+        throws -> [String : [T]]? {
+            return try self[path]?
                 .nodeObject?
                 .mapValues { return try [T](node: $0) }
     }
 
     public func extract<T : NodeInitializable>(
-        _ keyType: PathIndex...)
+        _ path: PathIndex...)
         throws -> Set<T>? {
-            return try self[keyType]
+            return try extract(path: path)
+    }
+
+    public func extract<T : NodeInitializable>(
+        path: [PathIndex])
+        throws -> Set<T>? {
+            return try self[path]
                 .flatMap { try [T](node: $0) }
                 .flatMap { Set($0) }
     }


extension Node {
    public func extract<T, InputType: NodeInitializable>(
        _ keyType: PathIndex...,
        transform: (InputType) throws -> T)
        throws -> T {
            let node = self[keyType] ?? .null
            let input = try InputType(node: node)
            return try transform(input)
    }

    public func extract<T, InputType: NodeInitializable>(
        _ keyType: PathIndex...,
        transform: (InputType?) throws -> T)
        throws -> T {
            let value = try self[keyType].flatMap { try InputType(node: $0) }
            return try transform(value)
    }
}


extension Node {
    public func extract<T : NodeInitializable>(
        _ path: PathIndex...)
        throws -> T {
            return try extract(path: path)
    }

    public func extract<T : NodeInitializable>(
        path: [PathIndex])
        throws -> T {
            let node = self[path] ?? .null
            return try T(node: node)
    }

    public func extract<T : NodeInitializable>(
        _ path: PathIndex...)
        throws -> [T] {
            return try extract(path: path)
    }

    public func extract<T : NodeInitializable>(
        path: [PathIndex])
        throws -> [T] {
            let node = self[path] ?? .null
            return try [T](node: node)
    }

    public func extract<T : NodeInitializable>(
        _ path: PathIndex...)
        throws -> [[T]] {
            return try extract(path: path)
    }

    public func extract<T : NodeInitializable>(
        path: [PathIndex])
        throws -> [[T]] {
            let initial = self[path] ?? .null
            let array = initial.nodeArray ?? [initial]
            return try array.map { try [T](node: $0) }
    }

    public func extract<T : NodeInitializable>(
        _ path: PathIndex...)
        throws -> [String : T] {
            return try extract(path: path)
    }

    public func extract<T : NodeInitializable>(
        path: [PathIndex])
        throws -> [String : T] {
            guard let object = self[path]?.nodeObject else {
                throw NodeError.unableToConvert(node: .null, expected: "\([String: T].self)")
            }

