Ejemplo n.º 1
0
        /// <summary>
        ///   Performs a deep copy operation on <paramref name="jsonElement"/> returning corresponding modifiable tree structure of JSON nodes.
        ///   Operations performed on returned <see cref="JsonNode"/> does not modify <paramref name="jsonElement"/>.
        /// </summary>
        /// <param name="jsonElement"><see cref="JsonElement"/> to copy.</param>
        /// <returns><see cref="JsonNode"/>  representing <paramref name="jsonElement"/>.</returns>
        public static JsonNode DeepCopy(JsonElement jsonElement)
        {
            if (!jsonElement.IsImmutable)
            {
                return(GetNode(jsonElement).Clone());
            }

            // Iterative DFS:

            var      currentNodes   = new Stack <KeyValuePair <string?, JsonNode?> >();    // objects/arrays currently being created
            var      recursionStack = new Stack <KeyValuePair <string?, JsonElement?> >(); // null JsonElement represents end of current object/array
            JsonNode?toReturn       = null;

            recursionStack.Push(new KeyValuePair <string?, JsonElement?>(null, jsonElement));

            while (recursionStack.TryPop(out KeyValuePair <string?, JsonElement?> currentPair))
            {
                JsonElement?currentJsonElement = currentPair.Value;

                if (!currentJsonElement.HasValue)
                {
                    // Current object/array is finished and can be added to its parent:

                    KeyValuePair <string?, JsonNode?> nodePair = currentNodes.Pop();

                    Debug.Assert(nodePair.Value is JsonArray || nodePair.Value is JsonObject);

                    AddToParent(nodePair, ref currentNodes, ref toReturn);

                    continue;
                }

                switch (currentJsonElement.Value.ValueKind)
                {
                case JsonValueKind.Object:
                    var jsonObject = new JsonObject();

                    // Add jsonObject to current nodes:
                    currentNodes.Push(new KeyValuePair <string?, JsonNode?>(currentPair.Key, jsonObject));

                    // Add end of object marker:
                    recursionStack.Push(new KeyValuePair <string?, JsonElement?>(null, null));

                    // Add properties to recursion stack. Reverse enumerate to keep properties order:
                    foreach (JsonProperty property in currentJsonElement.Value.EnumerateObject().Reverse())
                    {
                        recursionStack.Push(new KeyValuePair <string?, JsonElement?>(property.Name, property.Value));
                    }
                    break;

                case JsonValueKind.Array:
                    var jsonArray = new JsonArray();

                    // Add jsonArray to current nodes:
                    currentNodes.Push(new KeyValuePair <string?, JsonNode?>(currentPair.Key, jsonArray));

                    // Add end of array marker:
                    recursionStack.Push(new KeyValuePair <string?, JsonElement?>(null, null));

                    // Add elements to recursion stack. Reverse enumerate to keep items order:
                    foreach (JsonElement element in currentJsonElement.Value.EnumerateArray().Reverse())
                    {
                        recursionStack.Push(new KeyValuePair <string?, JsonElement?>(null, element));
                    }
                    break;

                case JsonValueKind.Number:
                    var jsonNumber = new JsonNumber(currentJsonElement.Value.GetRawText());
                    AddToParent(new KeyValuePair <string?, JsonNode?>(currentPair.Key, jsonNumber), ref currentNodes, ref toReturn);
                    break;

                case JsonValueKind.String:
                    string?value = currentJsonElement.Value.GetString();
                    Debug.Assert(value != null);
                    var jsonString = new JsonString(value);
                    AddToParent(new KeyValuePair <string?, JsonNode?>(currentPair.Key, jsonString), ref currentNodes, ref toReturn);
                    break;

                case JsonValueKind.True:
                    var jsonBooleanTrue = new JsonBoolean(true);
                    AddToParent(new KeyValuePair <string?, JsonNode?>(currentPair.Key, jsonBooleanTrue), ref currentNodes, ref toReturn);
                    break;

                case JsonValueKind.False:
                    var jsonBooleanFalse = new JsonBoolean(false);
                    AddToParent(new KeyValuePair <string?, JsonNode?>(currentPair.Key, jsonBooleanFalse), ref currentNodes, ref toReturn);
                    break;

                case JsonValueKind.Null:
                    var jsonNull = JsonNull.Instance;
                    AddToParent(new KeyValuePair <string?, JsonNode?>(currentPair.Key, jsonNull), ref currentNodes, ref toReturn);
                    break;

                default:
                    Debug.Assert(jsonElement.ValueKind == JsonValueKind.Undefined, "No handler for JsonValueKind.{jsonElement.ValueKind}");
                    throw ThrowHelper.GetJsonElementWrongTypeException(JsonValueKind.Undefined, jsonElement.ValueKind);
                }
            }

            Debug.Assert(toReturn != null);

            return(toReturn);
        }
Ejemplo n.º 2
0
 /// <summary>
 ///   Initializes a new instance of the <see cref="JsonArrayEnumerator"/> class supporting an interation over provided JSON array.
 /// </summary>
 /// <param name="jsonArray">JSON array to iterate over.</param>
 public JsonArrayEnumerator(JsonArray jsonArray) => _enumerator = jsonArray._list.GetEnumerator();