Unity Json解析
2015-10-10 10:18
811 查看
Unity Json解析
JSONObject
http://wiki.unity3d.com/index.php?title=JSONObjectISerializable.cs
using System; namespace testJson.Json { public interface ISerializable { string ToJson(); ISerializable FromObject(object obj); } }
JsonParser.cs
using System; using System.Collections; using System.Collections.Generic; using System.Text; namespace testJson.Json { public class JsonParser { private readonly string json; private readonly StringBuilder sb = new StringBuilder(); private int index = 0; private int jsonLength = -1; private int nextBackslash = -1; private JsonTokens lookAheadToken = JsonTokens.None; private bool internStrings = false; // This is effectively a constant, so we do not reset this static on game reload. private static readonly JsonTokens[] jsonTokenMap = new JsonTokens[256]; // Minimize dictionary creation, use a pool for empty dictionaries. #if SERVER // The battle server requires thread-safety. private readonly List<Dictionary<string, object>> pool = new List<Dictionary<string, object>>(); #else // The client is single-threaded and saves on many thousands of empty dictionary // instance creations if we make this static. private static List<Dictionary<string, object>> pool = new List<Dictionary<string, object>>(); // Per team coding conventions, we must reset all statics on game reload. public static void StaticReset() { pool.Clear(); } #endif static JsonParser() { for (int i = 0; i < 256; i++) { jsonTokenMap[i] = JsonTokens.None; } jsonTokenMap['{'] = JsonTokens.ObjectOpen; jsonTokenMap['}'] = JsonTokens.ObjectClose; jsonTokenMap['['] = JsonTokens.ArrayOpen; jsonTokenMap[']'] = JsonTokens.ArrayClose; jsonTokenMap[','] = JsonTokens.Comma; jsonTokenMap['"'] = JsonTokens.String; jsonTokenMap['0'] = JsonTokens.Number; jsonTokenMap['1'] = JsonTokens.Number; jsonTokenMap['2'] = JsonTokens.Number; jsonTokenMap['3'] = JsonTokens.Number; jsonTokenMap['4'] = JsonTokens.Number; jsonTokenMap['5'] = JsonTokens.Number; jsonTokenMap['6'] = JsonTokens.Number; jsonTokenMap['7'] = JsonTokens.Number; jsonTokenMap['8'] = JsonTokens.Number; jsonTokenMap['9'] = JsonTokens.Number; jsonTokenMap['-'] = JsonTokens.Number; jsonTokenMap['+'] = JsonTokens.Number; jsonTokenMap['.'] = JsonTokens.Number; jsonTokenMap[':'] = JsonTokens.Colon; jsonTokenMap['f'] = JsonTokens.False; jsonTokenMap['t'] = JsonTokens.True; jsonTokenMap['n'] = JsonTokens.Null; } public JsonParser(string json) : this(json, 0, false) { } public JsonParser(string json, int startFrom) : this(json, startFrom, false) { } public JsonParser(string json, int startFrom, bool internStrings) { this.json = json; jsonLength = json == null ? 0 : json.Length; index = startFrom; this.internStrings = internStrings; nextBackslash = 0; // Init to non-negative, so that the first find works. FindNextBackslash(); } public object Parse() { return jsonLength == 0 ? null : ParseValue(); } private Dictionary<string, object> ParseObject() { Dictionary<string, object> result; if (pool.Count == 0) { result = new Dictionary<string, object>(); } else { int i = pool.Count - 1; result = pool[i]; pool.RemoveAt(i); } lookAheadToken = JsonTokens.None; for (;;) { JsonTokens token = LookAhead(); if (token == JsonTokens.Comma) { lookAheadToken = JsonTokens.None; } else if (token == JsonTokens.ObjectClose) { lookAheadToken = JsonTokens.None; break; } else { string name = ParseString(); JsonTokens nextToken = (lookAheadToken != JsonTokens.None) ? lookAheadToken : NextTokenCore(); lookAheadToken = JsonTokens.None; if (nextToken != JsonTokens.Colon) { result.Clear(); break; } object value = ParseValue(); // NOTE: There is no need to check result.ContainsKey() because // any collisions imply invalid JSON data and we'd want a throw // in that case anyway. result[name] = value; } } // Null is the same as "empty dictionary". All user code must handle this. // Before this change, over 65% of our 50,000 dictionary instances in the // game were empty, and that's very wasteful of memory. if (result.Count == 0) { pool.Add(result); result = null; } return result; } private List<object> ParseArray() { var array = new List<object>(); lookAheadToken = JsonTokens.None; while (true) { JsonTokens token = LookAhead(); if (token == JsonTokens.Comma) { lookAheadToken = JsonTokens.None; } else if (token == JsonTokens.ArrayClose) { lookAheadToken = JsonTokens.None; array.Capacity = array.Count; return array; } else { array.Add(ParseValue()); } } } private object ParseValue() { switch (LookAhead()) { case JsonTokens.Number: return ParseNumber(); case JsonTokens.String: return ParseString(); case JsonTokens.ObjectOpen: return ParseObject(); case JsonTokens.ArrayOpen: return ParseArray(); case JsonTokens.True: lookAheadToken = JsonTokens.None; return true; case JsonTokens.False: lookAheadToken = JsonTokens.None; return false; case JsonTokens.Null: lookAheadToken = JsonTokens.None; return null; } return null; } private void FindNextBackslash() { // Only find the next backslash if we didn't already find out that there are no // more backslashes to find. if (nextBackslash >= 0) { nextBackslash = json.IndexOf('\\', index); } } private String NewString(String s) { return internStrings ? String.Intern(s) : s; } private String ParseString() { lookAheadToken = JsonTokens.None; // Optimization: Common case, no escape sequences in the current string. int endQuoteIndex = json.IndexOf('"', index); if (endQuoteIndex < 0) { return null; } if (nextBackslash < 0 || nextBackslash > endQuoteIndex) { String s = json.Substring(index, endQuoteIndex - index); index = endQuoteIndex + 1; return NewString(s); } // If there's an escape sequence in this string, step through each character. sb.Length = 0; int runIndex = -1; while (index < jsonLength) { var c = json[index++]; if (c == '"') { if (runIndex != -1) { if (sb.Length == 0) { FindNextBackslash(); return NewString(json.Substring(runIndex, index - runIndex - 1)); } sb.Append(json.Substring(runIndex, index - runIndex - 1)); } FindNextBackslash(); return NewString(sb.ToString()); } if (c != '\\') { if (runIndex == -1) { runIndex = index - 1; } continue; } if (index == jsonLength) { break; } if (runIndex != -1) { sb.Append(json.Substring(runIndex, index - runIndex - 1)); runIndex = -1; } switch (json[index++]) { case '"': sb.Append('"'); break; case '\\': sb.Append('\\'); break; case '/': sb.Append('/'); break; case 'b': sb.Append('\b'); break; case 'f': sb.Append('\f'); break; case 'n': sb.Append('\n'); break; case 'r': sb.Append('\r'); break; case 't': sb.Append('\t'); break; case 'u': if (jsonLength - index < 4) { break; } // parse 32 bit hex uint codePoint = ParseUnicode ( json[index], json[index + 1], json[index + 2], json[index + 3] ); sb.Append((char)codePoint); // skip 4 chars index += 4; break; } } FindNextBackslash(); return null; } private uint ParseSingleChar(char c1, uint multipliyer) { uint p1 = 0; if (c1 >= '0' && c1 <= '9') { p1 = (uint)(c1 - '0') * multipliyer; } else if (c1 >= 'A' && c1 <= 'F') { p1 = (uint)((c1 - 'A') + 10) * multipliyer; } else if (c1 >= 'a' && c1 <= 'f') { p1 = (uint)((c1 - 'a') + 10) * multipliyer; } return p1; } private uint ParseUnicode(char c1, char c2, char c3, char c4) { uint p1 = ParseSingleChar(c1, 0x1000); uint p2 = ParseSingleChar(c2, 0x100); uint p3 = ParseSingleChar(c3, 0x10); uint p4 = ParseSingleChar(c4, 1); return p1 + p2 + p3 + p4; } private String ParseNumber() { lookAheadToken = JsonTokens.None; var startIndex = index - 1; for (var c = json[index]; (c>='0' && c<='9') || c=='.' || c=='-' || c=='+' || c=='e' || c=='E'; c = json[index]) { if (++index == jsonLength) { return null; } } return NewString(json.Substring(startIndex, index - startIndex)); } private JsonTokens LookAhead() { if (lookAheadToken != JsonTokens.None) { return lookAheadToken; } return lookAheadToken = NextTokenCore(); } private JsonTokens NextTokenCore() { // Skip whitespace. // Optimization: Anything before space in ASCII we can consider whitespace. char c; for (c = json[index]; c <= ' '; c = json[index]) { if (++index == jsonLength) { return JsonTokens.None; } } index++; if (c >= 256) { return JsonTokens.None; } JsonTokens token = jsonTokenMap[c]; if (token >= JsonTokens.WordFirst) { // Find the end of the word. do { // Optimization: Very lenient. Any word that starts with f means false, // t -> true, n -> null. So, foobar -> false, totallyNotTrue -> true, and // nope -> null. c = json[index]; } while (c >= 'a' && c <= 'z' && ++index < jsonLength); } return token; } } }
JsonPropertyAttribute.cs
using System; namespace testJson.Json { [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, Inherited = false)] public class JsonPropertyAttribute : Attribute { public JsonPropertyAttribute(string name) { this.Name = name; } public string Name { get; set; } } }
JsonSerializableAttribute.cs
using System; namespace testJson.Json { public enum MappingType { Fields, Properties } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false)] public class JsonSerializableAttribute : Attribute { public JsonSerializableAttribute(MappingType type) { this.Type = type; } public JsonSerializableAttribute() : this(MappingType.Properties) { } public MappingType Type { get; set; } } }
JsonTokens.cs
namespace testJson.Json { /// <summary> /// Things like True, False and Null are special in that they represent "words" /// in the json. We keep them in their own range for an optimzation. /// </summary> public enum JsonTokens { None, ObjectOpen, ObjectClose, ArrayOpen, ArrayClose, Colon, Comma, String, Number, WordFirst = 100, True = WordFirst, False, Null, } }
Serializer.cs
using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; namespace testJson.Json { public class Serializer { private StringBuilder sb; private bool first; const string KEY_VALUE_QUOTED = "\"{0}\":\"{1}\""; const string KEY_VALUE_UNQUOTED = "\"{0}\":{1}"; const string KEY_ONLY = "\"{0}\":"; const string OBJECT_START = "{"; const string OBJECT_END = "}"; const string ARRAY_START = "["; const string ARRAY_END = "]"; const string COMMA = ","; private static Dictionary<string, string> ESCAPE_MAPPING = new Dictionary<string, string>() { {"\"", "\\\""}, {"\\", @"\\"}, {"\a", @"\a"}, {"\b", @"\b"}, {"\f", @"\f"}, {"\n", @"\n"}, {"\r", @"\r"}, {"\t", @"\t"}, {"\v", @"\v"}, }; private static Regex ESCAPE_REGEX = new Regex(string.Join("|", ESCAPE_MAPPING.Keys.ToArray())); private static string Escape(string s) { if (s != null) { return ESCAPE_REGEX.Replace(s, EscapeMatchEval); } return s; } private static string EscapeMatchEval(Match m) { return ESCAPE_MAPPING[m.Value]; } public Serializer() { sb = new StringBuilder(); sb.Append(OBJECT_START); first = true; } public static Serializer Start() { Serializer serializer = new Serializer(); return serializer; } public Serializer End() { sb.Append(OBJECT_END); return this; } override public string ToString() { return sb.ToString(); } public Serializer AddString(string key, string val) { return AddInternal<string>(key, Escape(val), KEY_VALUE_QUOTED); } public Serializer AddBool(string key, bool val) { // C# returns True/False instead of true/false return Add<string>(key, val.ToString().ToLower()); } public Serializer Add<T>(string key, T val) { return AddInternal<T>(key, val, KEY_VALUE_UNQUOTED); } private Serializer AddInternal<T>(string key, T val, string format) { AppendComma(first); sb.AppendFormat(format, Escape(key), val); first = false; return this; } public Serializer AddObject<T>(string key, T val) where T : ISerializable { return Add(key, val.ToJson()); } public Serializer AddArray<T>(string key, List<T> values) where T : ISerializable { AppendComma(first); sb.AppendFormat(KEY_ONLY, Escape(key)); sb.Append(ARRAY_START); bool arrayFirst = true; foreach (T serializable in values) { AppendComma(arrayFirst); Add(serializable); arrayFirst = false; } sb.Append(ARRAY_END); first = false; return this; } public Serializer AddDictionary<T>(string key, Dictionary<string, T> values) { AppendComma(first); sb.AppendFormat(KEY_ONLY, Escape(key)); sb.Append(OBJECT_START); bool isString = typeof(T) == typeof(string); // Reset first for this particular object first = true; foreach (KeyValuePair<string, T> pair in values) { if (isString) { if (pair.Value != null) { AddString(pair.Key, pair.Value.ToString()); } else { AddString(pair.Key, null); } } else { Add<T>(pair.Key, pair.Value); } } // Set it to false again first = false; sb.Append(OBJECT_END); return this; } public Serializer AddArrayOfPrimitives<T>(string key, List<T> values) { AppendComma(first); sb.AppendFormat(KEY_ONLY, Escape(key)); sb.Append(ARRAY_START); bool arrayFirst = true; bool isString = typeof(T) == typeof(string); foreach (T serializable in values) { AppendComma(arrayFirst); if (isString) { AddQuoted(serializable.ToString()); } else { Add(serializable.ToString()); } arrayFirst = false; } sb.Append(ARRAY_END); first = false; return this; } private void Add(ISerializable val) { Add(val.ToJson()); } private void Add(string val) { sb.Append(val); } private void AddQuoted(string val) { sb.Append('"'); sb.Append(Escape(val)); sb.Append('"'); } private void AppendComma(bool first) { if (!first) { sb.Append(COMMA); } } } }
Program.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO; using testJson.Json; //using UnityEngine; namespace testJson { public class Player { public string name; public int age; } class Program { static void Main(string[] args) { string json = "{\"Players\":[{ \"name\": \"guodong1\", \"age\": 23},{ \"name\": \"guodong2\", \"age\": 24}]}"; object obj = new JsonParser(json).Parse(); Dictionary<string, object> dict = obj as Dictionary<string, object>; if (dict.ContainsKey("Players")) { List<object> players = dict["Players"] as List<object>; foreach (var p in players) { Player player = new Player(); Dictionary<string, object> playerDict = p as Dictionary<string, object>; if (playerDict.ContainsKey("name")) { player.name = playerDict["name"].ToString(); Console.WriteLine("player name = " + player.name); } if (playerDict.ContainsKey("age")) { player.age = int.Parse(playerDict["age"].ToString()); Console.WriteLine("player age = " + player.age); } } } } } }
运行结果:
相关文章推荐
- Unity3D手机游戏开发-金玺曾读书摘要(2015-4-27 19:01、2016-4-11 10:39)
- unity游戏返回游戏黑屏
- Unity3D游戏开发-宣雨松读书摘要(2015-4-17 18:36)
- unity3D引擎打造,3d科幻机甲手游《机甲风暴》
- Unity报错:Collection was modified; enumeration operation may not execute
- Unity3d 框选
- Unity3D开发者快速上手Unreal Engine 4指南
- Unity3D占用内存太大的解决方法
- Cardboard Unity SDK Reference
- Unity3d渲染层级关系小结
- unity与java相互调用
- unity csharp socket 异步通信 客户端
- Unity3D学习笔记——NGUI之UIToggle
- Unity 使用MiniJson解析本地数据
- Unity 4.x Asset Bundle 重名
- Unity添加自定义拓展方法ExternMethod
- 在Unity3D中加载外部图片的两种方法
- Unity 使用JsonFx解析本地json数据
- Unity协同程序(Coroutine)的解析
- Unity3d优化之从Draw Calls到GC