Example #1
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);
        }
Example #2
0
        internal JsonPlusValue OlderValueThan(IJsonPlusNode marker)
        {
            List <JsonPlusObject> objectList = new List <JsonPlusObject>();
            int index = 0;

            while (index < _internalValues.Count)
            {
                JsonPlusValue value = _internalValues[index];
                if (value.Any(v => ReferenceEquals(v, marker)))
                {
                    break;
                }

                switch (value.Type)
                {
                case JsonPlusType.Object:
                    objectList.Add(value.GetObject());
                    break;

                case JsonPlusType.Literal:
                case JsonPlusType.Array:
                    objectList.Clear();
                    break;
                }

                index++;
            }

            if (objectList.Count == 0)
            {
                return(index == 0
                    ? null
                    : _internalValues[index - 1]);
            }

            JsonPlusValue  result = new JsonPlusValue(null);
            JsonPlusObject o      = new JsonPlusObject(result);

            result.Add(o);

            foreach (JsonPlusObject obj in objectList)
            {
                o.Merge(obj);
            }

            return(result);
        }