JSON.NET:无需重新解析即可压缩/格式化内容

10
使用Newtonsoft JSON.NET库,是否可以对JSON字符串进行压缩/格式化,而无需强制系统重新解析代码?这是我的方法:
public async Task<string> Minify(string json)
{
    // TODO: Some way to do this without a re-parse?
    var jsonObj = await JsonOpener.GetJsonFromString(json);
    return jsonObj.ToString(Formatting.None);
}

public async Task<string> Beautify(string json)
{
    // TODO: Some way to do this without a re-parse?
    var jsonObj = await JsonOpener.GetJsonFromString(json);
    return FormatJson(jsonObj);
}

private string FormatJson(JToken input)
{
    // We could just do input.ToString(Formatting.Indented), but this allows us
    // to take advantage of JsonTextWriter's formatting options.
    using (var stringWriter = new StringWriter(new StringBuilder()))
    {
        using (var jsonWriter = new JsonTextWriter(stringWriter))
        {
            // Configures indentation character and indentation width
            // (e.g., "indent each level using 2 spaces", or "use tabs")
            ConfigureWriter(jsonWriter);
            var serializer = new JsonSerializer();
            serializer.Serialize(jsonWriter, input);

            return stringWriter.ToString();
        }
    }
}

这段代码在小的JSON块中可以良好运行,但是处理大块内容时会变得非常缓慢。如果我能够在不经过解析器的情况下剥离所有东西,想必速度会更快。
如果我必须自己重新发明轮子并剥离所有空格或其他内容,我将这样做,但我不知道是否存在任何需要考虑的问题。
此外,是否有另一个更适合此类工作的库?
编辑:对不起,JSON本身不支持注释。

1
如果你想要最快的方式来完成它,那么 Json.NET 不是一个好选择,但是可以使用 https://github.com/EgorBo/SimdJsonSharp。虽然它仍处于 beta 版本,但其中包含了在测试中展示的 Minify 选项。这是 https://github.com/lemire/simdjson 的一个移植版本,由加拿大教授 Daniel Lemire 创建。即使你不能切换到这些库,它们也是一次有趣的阅读体验。 - Alois Kraus
1个回答

10

是的,您可以使用Json.Net完成此操作。只需直接将JsonTextReader连接到JsonTextWriter即可。这样,您可以重用读取器的令牌化逻辑和编写器的格式化逻辑,但跳过将标记转换为中间对象表示形式并返回的步骤(这是耗时的部分)。

以下是我如何将其拆分为辅助方法,使其易于使用和灵活:

public static string Minify(string json)
{
    return ReformatJson(json, Formatting.None);
}

public static string Beautify(string json)
{
    return ReformatJson(json, Formatting.Indented);
}

public static string ReformatJson(string json, Formatting formatting)
{
    using (StringReader stringReader = new StringReader(json))
    using (StringWriter stringWriter = new StringWriter())
    {
        ReformatJson(stringReader, stringWriter, formatting);
        return stringWriter.ToString();
    }
}

public static void ReformatJson(TextReader textReader, TextWriter textWriter, Formatting formatting)
{
    using (JsonReader jsonReader = new JsonTextReader(textReader))
    using (JsonWriter jsonWriter = new JsonTextWriter(textWriter))
    {
        jsonWriter.Formatting = formatting;
        jsonWriter.WriteToken(jsonReader);
    }
}

这是一个简短的演示:https://dotnetfiddle.net/RevZNU 有了这个设置,如果需要,你可以轻松地添加对流的额外重载。例如:
public static void Minify(Stream inputStream, Stream outputStream, Encoding encoding = null)
{
    ReformatJson(inputStream, outputStream, Formatting.None, encoding);
}

public static void Beautify(Stream inputStream, Stream outputStream, Encoding encoding = null)
{
    ReformatJson(inputStream, outputStream, Formatting.Indented, encoding);
}

public static void ReformatJson(Stream inputStream, Stream outputStream, Formatting formatting, Encoding encoding = null)
{
    if (encoding == null)
        encoding = new UTF8Encoding(false);

    const int bufferSize = 1024;
    using (StreamReader streamReader = new StreamReader(inputStream, encoding, true, bufferSize, true))
    using (StreamWriter streamWriter = new StreamWriter(outputStream, encoding, bufferSize, true))
    {
        ReformatJson(streamReader, streamWriter, formatting);
    }
}

很酷。但是为什么你要将ReformatJson()拆分成两个方法? - Chayim Friedman
@ChayimFriedman 我将它分成两部分,这样如果需要添加流支持就更容易了。为了实现这一点,您需要使用 StreamReaderStreamWriter 而不是 StringReaderStringWriter。最后一个方法被拆分出来,以便您可以在不重复代码的情况下调用它。我已经编辑了我的帖子以展示我的意思。 - Brian Rogers
1
使用新的 System.Text.Json API,这会是什么样子? - Muhammad Rehan Saeed
@MuhammadRehanSaeed 请查看此答案。正如我在对同一问题的回答中所详述的那样,Brian在这个答案中的代码是我能找到的最高效的。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接