示例#1
0
        /// <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;
            }
        }
示例#2
0
        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);
        }
示例#3
0
        /// <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;
            }
        }