/// <summary> /// Returns the <see cref="JsonPlusObjectMember"/> associated with the <see cref="JsonPlusPath"/> specified. /// </summary> /// <param name="path">The path to the member to return.</param> /// <param name="result">If the member is returned successfully, this parameter will contain the result <see cref="JsonPlusObjectMember"/>. This parameter should be passed uninitialized.</param> /// <returns>`true` if the <see cref="JsonPlusObject"/> contains the <see cref="JsonPlusObjectMember"/> associated with <paramref name="path"/>. Otherwise, `false`.</returns> public bool TryGetMember(JsonPlusPath path, out JsonPlusObjectMember result) { result = null; if (path == null || path.Count == 0) { return(false); } int pathIndex = 0; JsonPlusObject currentObject = this; while (true) { string key = path[pathIndex]; if (!currentObject.TryGetValue(key, out var field)) { return(false); } if (pathIndex >= path.Count - 1) { result = field; return(true); } if (field.Type != JsonPlusType.Object) { return(false); } currentObject = field.GetObject(); pathIndex = pathIndex + 1; } }
private JsonPlusValue ResolveSubstitution(JsonPlusSubstitution sub) { JsonPlusObjectMember subField = sub.ParentMember; // first case, this substitution is a direct self-reference if (sub.Path == sub.GetMemberPath()) { IJsonPlusNode parent = sub.Parent; while (parent is JsonPlusValue) { parent = parent.Parent; } // Fail case if (parent is JsonPlusArray) { throw new JsonPlusException(RS.SelfRefSubstitutionInArray); } // try to resolve substitution by looking backward in the field assignment stack return(subField.OlderValueThan(sub)); } // need to recursively get full path JsonPlusPath fieldPath = subField.GetMemberPath(); // second case, the substitution references a field child in the past if (sub.Path.IsChildPathOf(fieldPath)) { JsonPlusValue olderValue = subField.OlderValueThan(sub); if ((olderValue != null) && (olderValue.Type == JsonPlusType.Object)) { int difLength = sub.Path.Count - fieldPath.Count; JsonPlusPath deltaPath = sub.Path.SubPath(sub.Path.Count - difLength, difLength); JsonPlusObject olderObject = olderValue.GetObject(); if (olderObject.TryGetValue(deltaPath, out JsonPlusValue innerValue)) { return(innerValue.Type == JsonPlusType.Object ? innerValue : null); } } } // Detect invalid parent-referencing substitution if (fieldPath.IsChildPathOf(sub.Path)) { throw new JsonPlusException(RS.SubstitutionRefDirectParentError); } // Detect invalid cyclic reference loop if (IsValueCyclic(subField, sub)) { throw new JsonPlusException(RS.CyclicSubstitutionLoop); } // third case, regular substitution _root.GetObject().TryGetValue(sub.Path, out JsonPlusValue field); return(field); }
/// <summary> /// Returns the <see cref="JsonPlusObjectMember"/> associated with the <see cref="JsonPlusPath"/> specified. /// </summary> /// <param name="path">The path to the field to return.</param> /// <exception cref="ArgumentNullException">The <paramref name="path"/> specified is `null`.</exception> /// <exception cref="ArgumentException">The <paramref name="path"/> specified is empty.</exception> /// <exception cref="KeyNotFoundException">The key does not exist in the <see cref="JsonPlusObject"/> instance.</exception> /// <exception cref="JsonPlusException">The <paramref name="path"/> specified is invalid.</exception> /// <returns>The <see cref="JsonPlusObjectMember"/> associated with <paramref name="path"/>.</returns> public JsonPlusObjectMember GetMember(JsonPlusPath path) { if (path == null) { throw new ArgumentNullException(nameof(path)); } if (path.Count == 0) { throw new ArgumentException(RS.PathIsEmpty, nameof(path)); } int pathIndex = 0; JsonPlusObject currentObject = this; while (true) { string key = path[pathIndex]; if (!currentObject.TryGetValue(key, out JsonPlusObjectMember field)) { throw new KeyNotFoundException(string.Format(RS.ObjectMemberNotFoundByPath, key, new JsonPlusPath(path.GetRange(0, pathIndex + 1)).Value)); } if (pathIndex >= path.Count - 1) { return(field); } if (field.Type != JsonPlusType.Object) { throw new JsonPlusException(string.Format(RS.ObjectMemberInPathNotObject, new JsonPlusPath(path.GetRange(0, pathIndex + 1)).Value)); } currentObject = field.GetObject(); pathIndex = pathIndex + 1; } }