using System; using System.Linq; using System.Collections.Generic; namespace Kawa.Json { public static partial class Json5 { /// /// Returns an object of type T found in the specified path. /// /// The type of object to return. /// The JsonObj to look through. /// The path to follow. /// The object at the end of the path. /// /// If obj is a Starbound Versioned JSON object, if the first key is not found, /// Path will automatically try skipping into the __content object. /// public static T Path(this JsonObj obj, string path) { if (string.IsNullOrWhiteSpace(path)) throw new ArgumentException("Path is empty."); if (!path.StartsWith("/")) throw new ArgumentException("Path does not start with root."); if (path.EndsWith("/")) throw new ArgumentException("Path does not end with a key or index."); var parts = path.Substring(1).Split('/'); object root = obj; var here = root; var index = -1; foreach (var part in parts) { if (part == "-") throw new JsonException("Can't use - here; we're not patching anything."); bool isIndex = int.TryParse(part, out index); if (isIndex && here == root) throw new JsonException("Tried to start with an array index. That's extra special."); if (isIndex && here is object[]) { var list = (object[])here; if (index < 0 || index >= list.Length) throw new IndexOutOfRangeException(); here = list[index]; } else if (here is JsonObj) { var map = (JsonObj)here; if (here == root && map.ContainsKey("__content") && !map.ContainsKey(part)) { //Sneakily stealthily skip into this. map = (JsonObj)map["__content"]; } if (!map.ContainsKey(part)) { throw new KeyNotFoundException(); } here = map[part]; } else { throw new JsonException("Current node is not an array or object, but path isn't done yet."); } } if (!(here is T)) throw new JsonException(string.Format("Value at end of path is not of the requested type -- found {0} but expected {1}.", here.GetType(), typeof(T))); return (T)here; } /// /// Returns the JsonObj found in the specified path. /// /// The JsonObj to look through. /// The path to follow. /// The JsonObj at the end of the path. /// /// If obj is a Starbound Versioned JSON object, if the first key is not found, /// Path will automatically try skipping into the __content object. /// public static JsonObj Path(this JsonObj obj, string path) { return Path(obj, path); } } }