/// <summary> /// Decompose path string into the individual navigation members (propertyName[arrayindex]) /// Property names can be separated by periods ($.foo.bar) and can be enclosed in square brackets ($.['foo'].['bar']) /// </summary> /// <param name="path"></param> /// <returns></returns> private static JsonPathPart DecomposePath(string path) { const string jsonPathStarter = "$."; if (path == "$") return JsonPathPart.Root; if (!path.StartsWith(jsonPathStarter)) throw new ArgumentException( string.Format("Path \"{0}\" doesn't appear to conform to JSONpath syntax.", path), "path"); List<JsonPathPart> pathParts = new List<JsonPathPart> { JsonPathPart.Root }; StringBuilder reader = new StringBuilder(); JsonPathPart partBeingRead = new JsonPathPart(); PathParserState state = PathParserState.ReadingPropertyName; for (int i = jsonPathStarter.Length; i < path.Length; i++) { // Walk through all the characters of the string and build up the path parts. char thisChar = path[i]; if (thisChar == '.' && state != PathParserState.ReadingEscapedPropertyName) { // End of a part name, save it and start a new path part. if (reader.Length > 0) { if (state == PathParserState.ReadingPropertyName) { partBeingRead.PropertyName = reader.ToString(); reader.Clear(); } else { throw new InvalidOperationException("Unexpected state. Malformed JsonPath syntax?"); } } pathParts.Add(partBeingRead); partBeingRead = new JsonPathPart(); state = PathParserState.ReadingPropertyName; } else if (thisChar == '[' && state != PathParserState.ReadingEscapedPropertyName) { if (reader.Length > 0) { if (state == PathParserState.ReadingPropertyName) { partBeingRead.PropertyName = reader.ToString(); reader.Clear(); } else { throw new InvalidOperationException("Unexpected state. Malformed JsonPath syntax?"); } } state = PathParserState.ReadingIndexer; } else if (thisChar == ']' && state != PathParserState.ReadingEscapedPropertyName) { if (state != PathParserState.ReadingIndexer) { throw new InvalidOperationException("Unexpected state. Malformed JsonPath syntax?"); } if (reader.Length > 0) { partBeingRead.ArrayIndex = Int32.Parse(reader.ToString()); reader.Clear(); } state = PathParserState.PartComplete; } else if (thisChar == '\'') { if (state == PathParserState.ReadingIndexer && reader.Length == 0) { state = PathParserState.ReadingEscapedPropertyName; } else if (state == PathParserState.ReadingEscapedPropertyName && reader.Length > 0) { partBeingRead.PropertyName = reader.ToString(); reader.Clear(); state = PathParserState.ReadingIndexer; } else { throw new InvalidOperationException("Unexpected state. Malformed JsonPath syntax?"); } } else { reader.Append(thisChar); } } if (reader.Length > 0 && (state == PathParserState.ReadingPropertyName || state == PathParserState.PartComplete)) { partBeingRead.PropertyName = reader.ToString(); } else if (reader.Length > 0) { throw new InvalidOperationException("Unexpected content in reader buffer. Malformed JsonPath syntax?"); } // Add the final part, if it wasn't there already. if (!string.IsNullOrEmpty(partBeingRead.PropertyName)) { pathParts.Add(partBeingRead); } for (int i = 0; i < pathParts.Count; i++) { if (i < pathParts.Count - 1) pathParts[i].Child = pathParts[i + 1]; } return pathParts[0]; }
/// <summary> /// Decompose path string into the individual navigation members (propertyName[arrayindex]) /// Property names can be separated by periods ($.foo.bar) and can be enclosed in square brackets ($.['foo'].['bar']) /// </summary> /// <param name="path"></param> /// <returns></returns> private static JsonPathPart DecomposePath(string path) { const string jsonPathStarter = "$."; if (path == "$") { return(JsonPathPart.Root); } if (!path.StartsWith(jsonPathStarter)) { throw new ArgumentException( string.Format("Path \"{0}\" doesn't appear to conform to JSONpath syntax.", path), "path"); } List <JsonPathPart> pathParts = new List <JsonPathPart> { JsonPathPart.Root }; StringBuilder reader = new StringBuilder(); JsonPathPart partBeingRead = new JsonPathPart(); PathParserState state = PathParserState.ReadingPropertyName; for (int i = jsonPathStarter.Length; i < path.Length; i++) { // Walk through all the characters of the string and build up the path parts. char thisChar = path[i]; if (thisChar == '.' && state != PathParserState.ReadingEscapedPropertyName) { // End of a part name, save it and start a new path part. if (reader.Length > 0) { if (state == PathParserState.ReadingPropertyName) { partBeingRead.PropertyName = reader.ToString(); reader.Clear(); } else { throw new InvalidOperationException("Unexpected state. Malformed JsonPath syntax?"); } } pathParts.Add(partBeingRead); partBeingRead = new JsonPathPart(); state = PathParserState.ReadingPropertyName; } else if (thisChar == '[' && state != PathParserState.ReadingEscapedPropertyName) { if (reader.Length > 0) { if (state == PathParserState.ReadingPropertyName) { partBeingRead.PropertyName = reader.ToString(); reader.Clear(); } else { throw new InvalidOperationException("Unexpected state. Malformed JsonPath syntax?"); } } state = PathParserState.ReadingIndexer; } else if (thisChar == ']' && state != PathParserState.ReadingEscapedPropertyName) { if (state != PathParserState.ReadingIndexer) { throw new InvalidOperationException("Unexpected state. Malformed JsonPath syntax?"); } if (reader.Length > 0) { partBeingRead.ArrayIndex = Int32.Parse(reader.ToString()); reader.Clear(); } state = PathParserState.PartComplete; } else if (thisChar == '\'') { if (state == PathParserState.ReadingIndexer && reader.Length == 0) { state = PathParserState.ReadingEscapedPropertyName; } else if (state == PathParserState.ReadingEscapedPropertyName && reader.Length > 0) { partBeingRead.PropertyName = reader.ToString(); reader.Clear(); state = PathParserState.ReadingIndexer; } else { throw new InvalidOperationException("Unexpected state. Malformed JsonPath syntax?"); } } else { reader.Append(thisChar); } } if (reader.Length > 0 && (state == PathParserState.ReadingPropertyName || state == PathParserState.PartComplete)) { partBeingRead.PropertyName = reader.ToString(); } else if (reader.Length > 0) { throw new InvalidOperationException("Unexpected content in reader buffer. Malformed JsonPath syntax?"); } // Add the final part, if it wasn't there already. if (!string.IsNullOrEmpty(partBeingRead.PropertyName)) { pathParts.Add(partBeingRead); } for (int i = 0; i < pathParts.Count; i++) { if (i < pathParts.Count - 1) { pathParts[i].Child = pathParts[i + 1]; } } return(pathParts[0]); }