/// <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); }
/// <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();