Unity Json解析

Unity Json解析


JSONObject

http://wiki.unity3d.com/index.php?title=JSONObject



ISerializable.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);
                    }

                    
                    
                }
            }
            
        }
    }
}

运行结果:
Unity Json解析_第1张图片

你可能感兴趣的:(Unity Json解析)