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:
                    var jsonString = new JsonString(currentJsonElement.Value.GetString());
                    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 = new JsonNull();
                    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
 public RecursionStackFrame(string propertyName, JsonNode propertyValue) : this(propertyName, propertyValue, propertyValue.ValueKind)
 {
 }
Ejemplo n.º 3
0
        /// <summary>
        ///   Parses a string representing JSON document into <see cref="JsonNode"/>.
        /// </summary>
        /// <param name="json">JSON to parse.</param>
        /// <param name="options">Options to control the parsing behavior.</param>
        /// <returns><see cref="JsonNode"/> representation of <paramref name="json"/>.</returns>
        public static JsonNode Parse(string json, JsonNodeOptions options = default)
        {
            Utf8JsonReader reader = new Utf8JsonReader(Encoding.UTF8.GetBytes(json), options.GetReaderOptions());

            var      currentNodes = new Stack <KeyValuePair <string, JsonNode> >(); // nodes currently being created
            JsonNode toReturn     = null;

            while (reader.Read())
            {
                JsonTokenType tokenType = reader.TokenType;
                currentNodes.TryPeek(out KeyValuePair <string, JsonNode> currentPair);

                void AddNewPair(JsonNode jsonNode, bool keepInCurrentNodes = false)
                {
                    KeyValuePair <string, JsonNode> newProperty;

                    if (currentPair.Value == null)
                    {
                        // If previous token was property name,
                        // it was added to stack with not null name and null value,
                        // otherwise, this is first JsonNode added
                        if (currentPair.Key != null)
                        {
                            // Create as property, keep name, replace null with new JsonNode:
                            currentNodes.Pop();
                            newProperty = new KeyValuePair <string, JsonNode>(currentPair.Key, jsonNode);
                        }
                        else
                        {
                            // Add first JsonNode:
                            newProperty = new KeyValuePair <string, JsonNode>(null, jsonNode);
                        }
                    }
                    else
                    {
                        // Create as value:
                        newProperty = new KeyValuePair <string, JsonNode>(null, jsonNode);
                    }

                    if (keepInCurrentNodes)
                    {
                        // If after adding property, it should be kept in currentNodes, it must be JsonObject or JsonArray
                        Debug.Assert(jsonNode.ValueKind == JsonValueKind.Object || jsonNode.ValueKind == JsonValueKind.Array);

                        currentNodes.Push(newProperty);
                    }
                    else
                    {
                        AddToParent(newProperty, ref currentNodes, ref toReturn, options.DuplicatePropertyNameHandling);
                    }
                }

                switch (tokenType)
                {
                case JsonTokenType.StartObject:
                    AddNewPair(new JsonObject(), true);
                    break;

                case JsonTokenType.EndObject:
                    Debug.Assert(currentPair.Value is JsonObject);

                    currentNodes.Pop();
                    AddToParent(currentPair, ref currentNodes, ref toReturn, options.DuplicatePropertyNameHandling);
                    break;

                case JsonTokenType.StartArray:
                    AddNewPair(new JsonArray(), true);
                    break;

                case JsonTokenType.EndArray:
                    Debug.Assert(currentPair.Value is JsonArray);

                    currentNodes.Pop();
                    AddToParent(currentPair, ref currentNodes, ref toReturn, options.DuplicatePropertyNameHandling);
                    break;

                case JsonTokenType.PropertyName:
                    currentNodes.Push(new KeyValuePair <string, JsonNode>(reader.GetString(), null));
                    break;

                case JsonTokenType.Number:
                    AddNewPair(new JsonNumber(JsonHelpers.Utf8GetString(reader.ValueSpan)));
                    break;

                case JsonTokenType.String:
                    AddNewPair(new JsonString(reader.GetString()));
                    break;

                case JsonTokenType.True:
                    AddNewPair(new JsonBoolean(true));
                    break;

                case JsonTokenType.False:
                    AddNewPair(new JsonBoolean(false));
                    break;

                case JsonTokenType.Null:
                    AddNewPair(new JsonNull());
                    break;
                }
            }

            Debug.Assert(toReturn != null);
            return(toReturn);
        }
Ejemplo n.º 4
0
            }                                            // to retrieve ValueKind when PropertyValue is null

            public RecursionStackFrame(string propertyName, JsonNode propertyValue, JsonValueKind valueKind)
            {
                PropertyName  = propertyName;
                PropertyValue = propertyValue;
                ValueKind     = valueKind;
            }