带有=而不是:分隔符的JsonConverter键值 [英] JsonConverter Keyvalues with = instead of : separator

查看:97
本文介绍了带有=而不是:分隔符的JsonConverter键值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

通常,我通过Newtonsoft JsonConvert.SerializeObject() 记录我的对象数据,该对象将对象的内容序列化为字符串.

Usually I log my objects data through Newtonsoft JsonConvert.SerializeObject() which serializes to a string the object's contents.

但是,不要让KeyValue对用:分隔,我希望它们用=分隔,由Splunk记录.

But instead of having KeyValue pairs separated by : I want them to be separated by = to be logged by Splunk.

所以不要喜欢

{ "Name": "John", Age : 18 } 

我想要

{ "Name" = "John", Age = 18 }

当然,我也在寻找适合对象内部对象的东西.从API看来,分隔符的格式与:相比有点僵硬,因为在一天结束时它不是JSON格式.

Of course I am also looking for something that should work for objects inside objects.. From the API seems a bit rigid to format the separator differently than : because it's not a JSON format at the end of the day.

有什么简单的方法可以代替重新发明轮子?

There is any easy way to do this instead of reinvent the wheel?

推荐答案

这对于Json.NET应该可行,但对于自定义JsonConverter则不可行. Newtonsoft保持了它的 serializer 和递归 writer 之间的区别,其中 serializer 递归遍历ac#对象图,该对象图发出抽象列表和包含键/值对的对象,而其 writer 则格式化并输出结果根据某些特定标准进行序列化的过程.您可以利用这种区别来创建自己的 JsonWriter 以Splunk所需的方式设置键和值的格式.

This should be doable with Json.NET, but not with with a custom JsonConverter. Newtonsoft maintains a distinction between its serializer, which recursively walks a c# object graph emitting abstract lists and objects containing key/value pairs, and its writer, which formats and outputs the results of serialization according to some particular standard. You can take advantage of this distinction to create your own custom subclass of JsonWriter that formats your keys and values in Splunk's desired manner.

话虽这么说,但您的问题有一个矛盾之处:您引用了"Name"属性名称,但没有引用Age属性名称.如果您想使用特殊的规则来引用某些属性名称,而没有引用某些属性名称,那么我看不到使用Json.NET做到这一点的简单方法.但是,在 记录最佳做法 中,Splunk写道:

That being said, there's an inconsistency in your question: you quote the "Name" property name, but not the Age property name. If you want to have special rules where certain property names are quoted but others are not, I can't see a straightforward way to do that with Json.NET. However, in Logging best practices Splunk writes:

Splunk软件最强大的功能之一就是它能够在您搜索时从事件中提取字段,从而利用非结构化数据创建结构.为确保字段提取按预期工作,请使用以下字符串语法(可以使用空格和逗号):

One of the most powerful features of Splunk software is its ability to extract fields from events when you search, creating structure out of unstructured data. To make sure field extraction works as intended, use the following string syntax (using spaces and commas is fine):

key1=value1, key2=value2, key3=value3 . . .

如果您的值包含空格,请将其用引号引起来(例如,username="bob smith").

If your values contain spaces, wrap them in quotes (for example, username="bob smith").

因此,似乎不需要选择引用属性名称.

Thus it would appear that selective quoting of property names is not needed.

假设是这种情况,那么在创建自定义JsonWriter时,您可以将以下编写器用作模型,两者都是由Newtonsoft的James Newton-King创建的:

Assuming that is the case, when creating a custom JsonWriter, you can use the following writers as models, both created by James Newton-King of Newtonsoft:

基于这两个类,我提出了SplunkLogTextWriter的部分实现,该实现以您所需的格式生成输出:

Based on these two classes I whipped up a partial implementation of SplunkLogTextWriter that generates output in your required format:

public class SplunkLogTextWriter : JsonWriter
{
    readonly TextWriter _writer;

    public bool QuotePropertyNames { get; set; }

    public SplunkLogTextWriter(TextWriter textWriter)
    {
        if (textWriter == null)
        {
            throw new ArgumentNullException();
        }

        _writer = textWriter;
    }

    public override void Flush()
    {
        _writer.Flush();
    }

    public override void Close()
    {
        base.Close();
        if (CloseOutput)
            _writer.Close();
    }

    public override void WriteComment(string text)
    {
        base.WriteComment(text);
        throw new NotImplementedException();
    }

    public override void WriteRaw(string json)
    {
        base.WriteRaw(json);

        _writer.Write(json);
    }

    public override void WriteStartArray()
    {
        base.WriteStartArray();
        _writer.Write("[ ");
    }

    public override void WriteStartObject()
    {
        base.WriteStartObject();
        _writer.Write("{ ");
    }

    public override void WriteStartConstructor(string name)
    {
        base.WriteStartConstructor(name);
        throw new NotImplementedException();
    }

    protected override void WriteEnd(JsonToken token)
    {
        base.WriteEnd(token);
        switch (token)
        {
            case JsonToken.EndObject:
                _writer.Write(" }");
                break;
            case JsonToken.EndArray:
                _writer.Write(" ]");
                break;
            case JsonToken.EndConstructor:
                _writer.Write(" )");
                break;
            default:
                throw new JsonWriterException("Invalid JsonToken: " + token);
        }
    }

    public override void WritePropertyName(string name)
    {
        base.WritePropertyName(name);

        WriteEscapedString(name, QuotePropertyNames);

        _writer.Write(" = ");
    }

    void WriteEscapedString(string s, bool quote)
    {
        s = s ?? string.Empty;
        quote = quote || s.Length == 0 || s.Any(c => Char.IsWhiteSpace(c) || c == '=' || c == ']' || c == '}');

        if (quote)
            _writer.Write('"');

        foreach (var c in s)
        {
            switch (c)
            {
                case '\t':
                    _writer.Write(@"\t");
                    break;
                case '\n':
                    _writer.Write(@"\n");
                    break;
                case '\r':
                    _writer.Write(@"\r");
                    break;
                case '\f':
                    _writer.Write(@"\f");
                    break;
                case '\b':
                    _writer.Write(@"\b");
                    break;
                case '\\':
                    _writer.Write(@"\\");
                    break;
                case '\u0085': // Next Line
                    _writer.Write(@"\u0085");
                    break;
                case '\u2028': // Line Separator
                    _writer.Write(@"\u2028");
                    break;
                case '\u2029': // Paragraph Separator
                    _writer.Write(@"\u2029");
                    break;
                default:
                    _writer.Write(c);
                    break;
            }
        }

        if (quote)
            _writer.Write('"');
    }

    #region WriteValue methods

    public override void WriteNull()
    {
        base.WriteNull();
        _writer.Write("null");
    }

    public override void WriteValue(bool value)
    {
        base.WriteValue(value);
        _writer.Write(value ? "true" : "false");
    }

    public override void WriteValue(byte value)
    {
        base.WriteValue(value);
        WriteIntegerValue((ulong)value);
    }

    public override void WriteValue(byte[] value)
    {
        base.WriteValue(value);
        if (value == null)
            _writer.Write("null");
        else
            WriteEscapedString(Convert.ToBase64String(value), false);
    }

    public override void WriteValue(sbyte value)
    {
        base.WriteValue(value);
        WriteIntegerValue(value);
    }

    public override void WriteValue(char value)
    {
        base.WriteValue(value);
        WriteEscapedString(value.ToString(), false);
    }

    public override void WriteValue(short value)
    {
        base.WriteValue(value);
        WriteIntegerValue(value);
    }

    public override void WriteValue(ushort value)
    {
        base.WriteValue(value);
        WriteIntegerValue((ulong)value);
    }

    public override void WriteValue(int value)
    {
        base.WriteValue(value);
        WriteIntegerValue(value);
    }

    public override void WriteValue(uint value)
    {
        base.WriteValue(value);
        WriteIntegerValue((ulong)value);
    }

    public override void WriteValue(long value)
    {
        base.WriteValue(value);
        WriteIntegerValue(value);
    }

    public override void WriteValue(ulong value)
    {
        base.WriteValue(value);
        WriteIntegerValue(value);
    }

    private void WriteIntegerValue(long value)
    {
        _writer.Write(value.ToString(Culture ?? CultureInfo.InvariantCulture));
    }

    private void WriteIntegerValue(ulong value)
    {
        _writer.Write(value.ToString(Culture ?? CultureInfo.InvariantCulture));
    }

    public override void WriteValue(DateTime value)
    {
        base.WriteValue(value);

        // Use Json.NET to format the date.  Consider replacing with something more performant.
        var s = JsonConvert.ToString(value, DateFormatHandling, DateTimeZoneHandling);
        WriteEscapedString(s.Substring(1, s.Length - 2), false);
    }

    public override void WriteValue(DateTimeOffset value)
    {
        base.WriteValue(value);

        // Use Json.NET to format the date.  Consider replacing with something more performant.
        var s = JsonConvert.ToString(value, DateFormatHandling);
        WriteEscapedString(s.Substring(1, s.Length - 2), false);
    }

    public override void WriteValue(decimal value)
    {
        base.WriteValue(value);
        _writer.Write(value.ToString(Culture ?? CultureInfo.InvariantCulture));
    }

    public override void WriteValue(double value)
    {
        base.WriteValue(value);
        // JsonConvert.ToString(value, FloatFormatHandling, QuoteChar, false) -- not public
        _writer.Write(JsonConvert.ToString(value));
    }

    public override void WriteValue(string value)
    {
        base.WriteValue(value);
        WriteEscapedString(value, false);
    }

    protected override void WriteValueDelimiter()
    {
        base.WriteValueDelimiter();
        _writer.Write(", ");
    }

    public override void WriteUndefined()
    {
        base.WriteUndefined();
        throw new NotImplementedException();
    }

    public override void WriteValue(Guid value)
    {
        base.WriteValue(value);
        throw new NotImplementedException();
    }

    #endregion

    // ToDo
    // WriteIndentSpace()
    // WriteIndent()
    // async methods
    // Others for which I threw a NotImplementedException()
}

然后按以下方式使用它:

Then if you use it as follows:

var root = new { Name = "John", Age = 18 };

var sb = new StringBuilder();
using (var sw = new StringWriter(sb))
using (var writer = new SplunkLogTextWriter(sw))
{
    JsonSerializer.CreateDefault().Serialize(writer, root);
}

Console.WriteLine(sb);

生成以下结果:

{ Name = John, Age = 18 }

请注意,编写器的某些部分尚未实现.查找ToDo注释和NotImplementedException引发.给定日志记录格式的正式定义,您还需要调整编写器,您的问题未提供该定义.

Note that some portions of the writer are not implemented yet. Look for ToDo comments and NotImplementedException throws. You will also need to tweak the writer given the formal definition of the logging format, which your question does not provide.

示例小提琴.

这篇关于带有=而不是:分隔符的JsonConverter键值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆