using Microsoft.Extensions.Configuration; using System; using System.Collections.Generic; using System.IO; using System.Text.Json; using System.Linq; namespace AgileConfig.Server.Common { /// /// 这个类抄的是微软的实现 /// public class JsonConfigurationFileParser { private JsonConfigurationFileParser() { } private readonly IDictionary _data = new SortedDictionary(StringComparer.OrdinalIgnoreCase); private readonly Stack _context = new Stack(); private string _currentPath; public static IDictionary Parse(Stream input) => new JsonConfigurationFileParser().ParseStream(input); private IDictionary ParseStream(Stream input) { _data.Clear(); var jsonDocumentOptions = new JsonDocumentOptions { CommentHandling = JsonCommentHandling.Skip, AllowTrailingCommas = true, }; using (var reader = new StreamReader(input)) using (JsonDocument doc = JsonDocument.Parse(reader.ReadToEnd(), jsonDocumentOptions)) { if (doc.RootElement.ValueKind != JsonValueKind.Object) { throw new FormatException("Error_UnsupportedJSONToken"); } VisitElement(doc.RootElement); } return _data; } private void VisitElement(JsonElement element) { foreach (JsonProperty property in element.EnumerateObject()) { EnterContext(property.Name); VisitValue(property.Value); ExitContext(); } } private void VisitValue(JsonElement value) { switch (value.ValueKind) { case JsonValueKind.Object: VisitElement(value); break; case JsonValueKind.Array: int index = 0; foreach (JsonElement arrayElement in value.EnumerateArray()) { EnterContext(index.ToString()); VisitValue(arrayElement); ExitContext(); index++; } break; case JsonValueKind.Number: case JsonValueKind.String: case JsonValueKind.True: case JsonValueKind.False: case JsonValueKind.Null: string key = _currentPath; if (_data.ContainsKey(key)) { throw new FormatException("Error_KeyIsDuplicated"); } _data[key] = value.ToString(); break; default: throw new FormatException("Error_UnsupportedJSONToken"); } } private void EnterContext(string context) { _context.Push(context); _currentPath = ConfigurationPath.Combine(_context.Reverse()); } private void ExitContext() { _context.Pop(); _currentPath = ConfigurationPath.Combine(_context.Reverse()); } } }