Files
AgileConfig/AgileConfig.Server.Common/JsonConfigurationFileParser.cs
T
2020-09-21 14:33:20 +08:00

107 lines
3.3 KiB
C#

using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using System.Linq;
namespace AgileConfig.Server.Common
{
/// <summary>
/// 这个类抄的是微软的实现
/// </summary>
public class JsonConfigurationFileParser
{
private JsonConfigurationFileParser() { }
private readonly IDictionary<string, string> _data = new SortedDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
private readonly Stack<string> _context = new Stack<string>();
private string _currentPath;
public static IDictionary<string, string> Parse(Stream input)
=> new JsonConfigurationFileParser().ParseStream(input);
private IDictionary<string, string> 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());
}
}
}