c# - Custom JSON Derivative Format -


i have serialization format identical json, except key-values represented <key>="<value>" instead of "<key>":"<value>".

with newtonsoft made custom jsonconverter called tsonconverter works well, except can't "see" embedded dictionary. given following type:

public class traceydata {     [safe]     public string application { get; set; }      [safe]     public string sessionid { get; set; }     [safe]     public string traceid { get; set; }     [safe]     public string workflow { get; set; }      [safe]     public dictionary<string, string> tags {get; set; }      [safe]     public string[] stuff {get; set;}  } 

and following code:

tsonconverter weird = new tsonconverter(); jsonserializersettings settings = new jsonserializersettings(); settings.nullvaluehandling = nullvaluehandling.ignore; settings.converters.add(weird);  var tracey = new traceydata(); tracey.traceid = guid.newguid().tostring(); tracey.sessionid = "5"; tracey.tags["referrer"] = "http://www.sky.net/deals"; tracey.stuff = new string[] { "alpha", "bravo", "charlie" }; tracey.application = "responsive";  string  stuff = jsonconvert.serializeobject(tracey, settings); 

i this:

[application="responsive" sessionid="5" traceid="082ef853-92f8-4ce8-9f32-8e4f792fb022" tags={"referrer":"http://www.sky.net/deals"} stuff=["alpha","bravo","charlie"]]

obviously have overridden startobject/endobject notation, replacing { } [ ]. otherwise results not bad.

however, there still problem of internal dictionary. in order convert dictionary use <key>="<value>" format, looks must make deep dictionary converter.

i'm wondering if there easier way this.

perhaps newtonsoft tool has "property generator" , "key-value" generator property can set globally handles me?

any suggestions?

and while we're here, wonder if there startobject/endobject formatter property override can set, handle other customization i've shown above. nice "skip" making jsonconverter tools these kinds of simple alterations.

incidentally:

  • my custom jsonconverter choosing properties serialize based on [safe] attribute shown in sample. nice-to-have. wonderful if json settings expose "attribute handler" property lets me override usual json attributes in favor of own.
  • i have no need de-serialize format. intended one-way operation. if wishes explain how de-serialize custom format interesting bonus, not necessary answer question.

appendix

below traceconverter had made. references fieldmetadata class holds property info.

public class tsonconverter : jsonconverter {     public override bool canread     {                 {             return false;         }     }      public override bool canconvert(type objecttype)     {         return dataclassifier.testforusertype(objecttype);     }      public override void writejson(         jsonwriter writer, object value, jsonserializer serializer)     {         type objtype = value.gettype();         var props = objtype.getproperties(bindingflags.instance | bindingflags.public | bindingflags.nonpublic);         var propmap = p in props                         in p.getcustomattributes(typeof(profileattribute), false)                         select new fieldmetadata(p, (profileattribute)a);          //writer.writestartobject();         writer.writestartarray();         bool loopstarted = true;         foreach(var prop in propmap){             object rawvalue = prop.getvalue(value);             if (rawvalue != null || serializer.nullvaluehandling == nullvaluehandling.include)             {                 string jsonvalue = jsonconvert.serializeobject(prop.getvalue(value), this);                 if (loopstarted)                 {                     loopstarted = false;                     writer.writeraw(string.format("{0}={1}", prop.name, jsonvalue));                 }                 else                 {                     writer.writeraw(string.format(" {0}={1}", prop.name, jsonvalue));                 }             }             //writer.writeraw(string.format("{0}={1}", prop.name, prop.getvalue(value)));             //writer.writepropertyname(prop.name, false);             //writer.writevalue(prop.getvalue(value));         }         writer.writeendarray();     }      public override object readjson(         jsonreader reader, type objecttype,         object existingvalue, jsonserializer serializer)     {         throw new notimplementedexception();     }  } 

rather creating own converter, you're going need create own subclass of jsonwriter writes custom file format. (this how json.net implements bsonwriter.) in case, file format close enough json can inherit jsontextwriter:

public class tsontextwriter : jsontextwriter {     textwriter _writer;      public tsontextwriter(textwriter textwriter)         : base(textwriter)     {         if (textwriter == null)             throw new argumentnullexception("textwriter");          quotename = false;         _writer = textwriter;     }      public override void writestartobject()     {         setwritestate(jsontoken.startobject, null);          _writer.write('[');     }      protected override void writeend(jsontoken token)     {         switch (token)         {             case jsontoken.endobject:                 _writer.write(']');                 break;             default:                 base.writeend(token);                 break;         }     }      public override void writepropertyname(string name)     {         writepropertyname(name, true);     }      public override void writepropertyname(string name, bool escape)     {         setwritestate(jsontoken.propertyname, name);          var escaped = name;         if (escape)         {             escaped = jsonconvert.tostring(name, '"', stringescapehandling);             escaped = escaped.substring(1, escaped.length - 2);         }          // maybe escape space character if appears in name?         _writer.write(escaped.replace("=", @"\u003d"));// replace "=" unicode escape sequence.          _writer.write('=');     }      /// <summary>     /// writes json value delimiter.  (remove override if want retain comma separator.)     /// </summary>     protected override void writevaluedelimiter()     {         _writer.write(' ');     }      /// <summary>     /// writes indent space.     /// </summary>     protected override void writeindentspace()     {         // nothing.     } } 

having done this, classes serialized custom format when use writer, instance:

        var tracey = new traceydata();         tracey.traceid = guid.newguid().tostring();         tracey.sessionid = "5";         tracey.tags["referrer"] = "http://www.sky.net/deals";         tracey.stuff = new string[] { "alpha", "bravo", "charlie" };         tracey.application = "responsive";          jsonserializersettings settings = new jsonserializersettings();         settings.nullvaluehandling = nullvaluehandling.ignore;           using (var sw = new stringwriter())         {             using (var jsonwriter = new tsontextwriter(sw))             {                 jsonserializer.createdefault(settings).serialize(jsonwriter, tracey);             }             debug.writeline(sw.tostring());         } 

produces output

[application="responsive" sessionid="5" traceid="2437fe67-9788-47ba-91ce-2e5b670c2a34" tags=[referrer="http://www.sky.net/deals"] stuff=["alpha" "bravo" "charlie"]] 

as far deciding whether serialize properties based on presence of [safe] attribute, that's sort of second question. need create own contractresolver , override createproperty, instance shown here: using json.net, how prevent serializing properties of derived class, when used in base class context?

update

if want retain comma separator arrays not objects, modify writevaluedelimiter follows:

    /// <summary>     /// writes json value delimiter.  (remove override if want retain comma separator.)     /// </summary>     protected override void writevaluedelimiter()     {         if (writestate == writestate.array)             _writer.write(',');         else             _writer.write(' ');     } 

Comments