Brad Robinson 11 rokov pred
rodič
commit
a4d75c81da
1 zmenil súbory, kde vykonal 123 pridanie a 35 odobranie
  1. 123 35
      readme.md

+ 123 - 35
readme.md

@@ -2,15 +2,15 @@
 
 PetaJson is a simple but flexible JSON library implemented in a single C# file.  Features include:
 
-* Standard JSON format parsing and generation
-* Supports strongly typed serialization through reflection, or custom code
+* Standard JSON parsing and generation
+* Supports strongly typed serialization through reflection or custom code
 * Supports weakly typed serialization
 * Supports standard C# collection classes - no JSON specific classes (ie: no "JArray", "JObject" etc...)
 * Support for dynamic Expando (read) and anonymous types (write)
 * Custom formatting and parsing of any type
 * Support for serialization of abstract/virtual types
 * Directly reads from TextReader and writes to TextWriter and any underlying stream
-* Simple set of custom attributes to control serialization of types
+* Simple set of custom attributes to control serialization
 * Optional non-strict parsing allows comments, non-quoted dictionary keys and trailing commas (great for config files)
 * Optional pretty formatting
 * No dependencies, one file - PetaJson.cs
@@ -86,32 +86,32 @@ From a file:
 
 	var person = Json.ParseFile<Person>("aboutme.json");
 
-Into an existing instance:
+String into an existing instance:
 
-	var person = new Person();
-	Json.ParseFileInto<Person>("aboutme.json", person);
+	Json.ParseInto<Person>(jsonFromPersonExampleAbove, person);
 
-String into existing instance:
+From file into an existing instance:
 
-	Json.ParseInto<Person>(jsonFromPersonExampleAbove, person);
+	var person = new Person();
+	Json.ParseFileInto<Person>("aboutme.json", person);
 
 
 ## Attributes
 
 PetaJson provides two attributes for decorating objects for serialization - [Json] and [JsonExclude].
 
-The Json attribute when applied to a class or struct marks all public properties and fields for serialization:
+The [Json] attribute when applied to a class or struct marks all public properties and fields for serialization:
 
 	[Json]
 	class Person
 	{
 		public string Name;				// Serialized as "name"
 		public string Address;			// Serialized as "address"
-		public string alsoSerialized;	// Serialized as "alsoSerialized"
+		public string AlsoSerialized;	// Serialized as "alsoSerialized"
 		private string NotSerialized;
 	}
 
-When applied to one or more field/properties but not applied to the class itself, only the decorated members
+When applied to one or more field or properties but not applied to the class itself, only the decorated members
 will be serialized:
 
 	class Person
@@ -120,15 +120,15 @@ will be serialized:
 		public string Address;		// Not serialized
 	}
 
-By default, members are serialized using the same name as the field or properties, but with the first letter
-lowercased.  To override the serialized name, include the name as a parameter to the Json attribute:
+By default members are serialized using the name as the field or property with the first letter
+lowercased.  To override the serialized name, include the name as a parameter to the [Json] attribute:
 
 	class Person
 	{
 		[Json("PersonName")] public string Name; 	// Serialized as "PersonName"
 	}
 
-Use the JsonExclude attribute to exclude public fields/properties from serialization
+Use the [JsonExclude] attribute to exclude public fields or properties from serialization
 
 	[Json]
 	class Person
@@ -143,7 +143,7 @@ Use the JsonExclude attribute to exclude public fields/properties from serializa
 		}
 	}
 
-Sometimes you'll want sub-objects to be serialized into the existing object instance.
+Sometimes you'll want sub-objects to be serialized into an existing object instance.
 
 eg: 
 
@@ -151,9 +151,8 @@ eg:
 	{
 		public MyApp()
 		{
-			// Settings object has an owner pointer back to this so during
-			// serialization we don't want to create a new instance of the settings
-			// object.
+			// Settings object has an owner reference that needs to be maintained
+			// across serialization
 			CurrentSettings = new Settings(this);
 		}
 
@@ -161,7 +160,7 @@ eg:
 		Settings CurrentSettings;
 	}
 
-In this example the existing CurrentSettings object will be instantiated into. If KeepInstance
+In this example the existing CurrentSettings object will be serialized into. If KeepInstance
 was set to false, PetaJson would instantiate a new Settings object, load it and then assign
 it to the CurrentSettings property.
 
@@ -176,7 +175,14 @@ Custom formatting can be used for any type.  Say we have the following type:
         public int Y;
     }
 
-We can serialize these as a string in the format "x,y" by registering a formatter
+and we want to serialize points as a comma separated string like this:
+
+	{
+		"TopLeft": "10,20",
+		"BottomRight: "30,40",
+	}
+
+To do this, we need to register a formatter:
 
     // Register custom formatter
     Json.RegisterFormatter<Point>( (writer,point) => 
@@ -184,7 +190,7 @@ We can serialize these as a string in the format "x,y" by registering a formatte
         writer.WriteStringLiteral(string.Format("{0},{1}", point.X, point.Y));
     });
 
-We also need a custom parser:
+And a custom parser:
 
     Json.RegisterParser<Point>( literal => {
 
@@ -200,7 +206,7 @@ We also need a custom parser:
 
     });
 
-We can now format and parse Point structs:
+We can now format and parse Points:
 
 	// Format a Point
 	var json = Json.Format(new Point() { X= 10, Y=20 });		// "10,20"
@@ -210,8 +216,8 @@ We can now format and parse Point structs:
 
 Note that in this example we're formatting the point to a string literal containing both
 the X and Y components of the Point.  The reader and writer objects passed to the callbacks
-however have methods for reading and writing any arbitrary json format - I just happened to
-use a single string literal for this example.
+however have methods for reading and writing any arbitrary json format - this example just 
+happens to use a string literal.
 
 ## Custom factories
 
@@ -235,15 +241,16 @@ Suppose we have a class heirarchy something like this:
 and we'd like to serialize a list of Shapes to Json like this:
 
 	[
-		{ "kind": "Rectangle", /* omitted */ },
-		{ "kind": "Shape", /* omitted */ },
+		{ "kind": "Rectangle", /* other rectangle properties omitted */ },
+		{ "kind": "Shape", /* other ellipse properties omitted */ },
 		// etc...
 	]
 
-In otherwords a key value in the dictionary for each object determines the type of object that 
+In otherwords a value in the Json dictionary for each object determines the type of object that 
 needs to be instantiated for each element.
 
-We can do this by firstly writing the element kind when saving using the IJsonWriting interface
+We can write out the shape kind by implementing the IJsonWriting interface which gets called
+before the other properties of the object are written:
 
     abstract class Shape : IJsonWriting
     {
@@ -255,7 +262,7 @@ We can do this by firstly writing the element kind when saving using the IJsonWr
         }
     }
 
-For parsing, we need to register a callback function that creates the correct instances of Shape:
+For parsing, we need to register a callback function that creates the correct instances:
 
     // Register a type factory that can instantiate Shape objects
     Json.RegisterTypeFactory(typeof(Shape), (reader, key) =>
@@ -284,8 +291,8 @@ When attempting to deserialize Shape objects, the registered callback will be ca
 key in the dictionary until it returns an object instance.  In this case we're looking for a key
 named "kind" and we use it's value to create a new Rectangle or Ellipse instance.
 
-Note that the field used to hold the type (aka "kind") does not need to be the first field in the
- in the dictionary being parsed. After instantiating the object, the input stream is rewound to the
+Note that the field used to hold the type (ie: "kind") does not need to be the first field in the
+ in the dictionary being parsed. After instantiating the object, the input stream is re-wound to the
  start of the dictionary and then re-parsed directly into the instantiated object.  Note too that
  the underlying stream doesn't need to support seeking - the rewind mechanism is implemented in 
  PetaJson.
@@ -327,7 +334,7 @@ by implementing one or more of the following interfaces:
     }
 
 
-For example, it's often necessary to wire up ownership chains on loaded subobjects:
+For example, it's often necessary to wire up ownership references on loaded subobjects:
 
 	class Drawing : IJsonLoaded
 	{
@@ -344,21 +351,24 @@ For example, it's often necessary to wire up ownership chains on loaded subobjec
 		}
 	}
 
+Note: although these methods could have been implemented using reflection rather than interfaces,
+the use of interfaces is more discoverable through Intellisense/Autocomplete.
+
 ## Options
 
-PetaJson has a couple of options that can be set as global defaults:
+PetaJson has a couple of formatting/parsing options. These can be set as global defaults:
 
 	Json.WriteWhitespaceDefault = true;		// Pretty formatting
 	Json.StrictParserDefault = true;		// Enable strict parsing
 
-or, overridden on a case by case basis:
+or, provided on a case by case basis:
 
 	Json.Format(person, JsonOption.DontWriteWhitespace);		// Force pretty formatting off
 	Json.Format(person, JsonOption.WriteWhitespace);			// Force pretty formatting on
 	Json.Parse<object>(jsonData, JsonOption.StrictParser);		// Force strict parsing
 	Json.Parse<object>(jsonData, JsonOption.NonStrictParser);	// Disable strict parsing
 
-Non-strict parsing allows the following:
+Non-strict mode relaxes the parser to allow:
 
 * Inline C /* */ or C++ // style comments
 * Trailing commas in arrays and dictionaries
@@ -374,3 +384,81 @@ eg: the non-strict parser will allow this:
 		"trailing commas": "allowed ->",	// <- see the comma, not normally allowed
 	}
 
+
+## IJsonReader and IJsonWriter
+
+These interfaces only need to be used when writing custom formatters and parsers.  They are the low
+level interfaces used to read and write the Json stream.
+
+The IJsonReader interface reads from the Json input stream.  
+
+    public interface IJsonReader
+    {
+        object ReadLiteral(Func<object, object> converter);
+        void ReadDictionary(Action<string> callback);
+        void ReadArray(Action callback);
+        object Parse(Type type);
+        T Parse<T>();
+    }
+
+*ReadLiteral* - reads a single literal value from the input stream.  Throws an exception if
+the next token isn't a literal value.  You should provide a callback that converts the raw
+literal to the required value, which will then be returned as the return value from ReadLiteral.
+
+Wherever possible, conversion should be done in the callback to ensure that errors in the conversion
+report the error location just before the bad literal, instead of after it.
+
+
+*ReadDictionary* - reads a Json dictionary, calling the callback for each key encountered.  The
+callback routine should read the key's value using the IJsonReader interface.  If nothing is read
+by the callback, PetaJson will skip the value and move onto the next key.
+
+*ReadArray* - reads a Json array, calling the callback at each element position. The callback 
+routine must read each value from the IJsonReader before returning.
+
+*Parse* - parses a typed value from the input stream.
+
+The IJsonWriter interface writes to the Json output stream:
+
+    public interface IJsonWriter
+    {
+        void WriteStringLiteral(string str);
+        void WriteRaw(string str);
+        void WriteArray(Action callback);
+        void WriteDictionary(Action callback);
+        void WriteValue(object value);
+        void WriteElement();
+        void WriteKey(string key);
+    }
+
+*WriteStringLiteral* - writes a string literal to the output stream, including the surrounding quotes and
+ escaping the content as required.
+*WriteRaw* - writes directly to the output stream.  Use for comments, or self genarated Json data.
+*WriteArray* - writes an array to the output stream.  The callback should write each element.
+*WriteDictionary* - writes a dictionary to the output stream.  The callback should write each element.
+*WriteValue* - formats and writes any object value.
+*WriteElement* - call from the callback of WriteArray to indicate that the next element is about to be 
+written.  Causes PetaJson to write separating commas and whitespace.
+*WriteKey* - call from the callback of WriteDictionary to write the key part of the next element.  Writes
+whitespace, separating commas, the key and it's quotes, the colon.
+
+eg: to write a dictionary:
+
+	writer.WriteDictionary(() =>
+	{
+		writer.WriteKey("apples");
+		writer.WriteValue("red");
+		writer.WriteKey("bananas");
+		writer.WriteValue("yellow");
+	});
+
+eg: to write an array:
+
+	writer.WriteArray(()=>
+	{
+		for (int i=0; i<10; i++)
+		{
+			writer.WriteElement();
+			writer.WriteValue(i);
+		}
+	});