自定义Json解析

1 篇文章 0 订阅

因为功能需求需要能够解析出继承父类的类的数据,没有找到这一类的json解析数据于是就想着自己写一个,下面来记录一下自己的解析过程。这个解析json的类主要可以解决父类的数据赋值问题,例如下面给出的例子。

/*父类*/
 public abstract class TriggerDataParent : IListVoluation
    {
        /// <summary>
        /// 对应原始数据的唯一id
        /// </summary>
        public float origId;

        public string fullName;
}

/*继承TriggerDataParent 的类*/
public abstract class TriggerEventDataParent : TriggerDataParent
    {
        public TriggerEventDataParent(float origId) : base(origId) { }
        public TriggerEventDataParent() { }

    }

/*继承TriggerEventDataParent 类*/
 public class TriggerEventItemTypeBehavior : TriggerEventDataParent
    {
        public float item_type;

        public TriggerEventItemTypeBehavior() { }

        public TriggerEventItemTypeBehavior(float origId) : base(origId) { }
}

//从以上可以看出类TriggerEventItemTypeBehavior 的父类为TriggerEventDataParent ,
//TriggerDataParent 。可以看出TriggerDataParent 中有两个变量,
//当存储为json数据后TriggerEventItemTypeBehavior 中会出现这两个变量,
//但是当解析该json数据时会出错,因为在TriggerEventItemTypeBehavior 中找不到这两个变量,
//我们写这个解析的初衷是为了解决这个问题,当然这个解析还有一些其他缺憾,
//希望各位大佬能够给出指点呀

首先分析一下json数据的格式,下面给出一段json数据

{"listChuFaQi":[
{"fullName":"DataStruct.ExportTriggerDataStruct","triggerStructIndex":1.0,
"listEvent":[
{"item_type":10100.0,"origId":2608.0,"fullName":"DataStruct.TriggerEventItemTypeBehavior"}
],
"listCondition":[
{"item_type":10100.0,"item_id":10020.0,"calculator_id":1003.0,"item_num":32.0,"origId":1101.0,"fullName":"DataStruct.TriggerConditionIntegerItem"}
],
"listAction":[
{"origId":0.0,"fullName":"DataStruct.TriggerActionNormalData"},
{"achievement_id":12.0,"origId":1500.0,"fullName":"DataStruct.TriggerActionReachChengJiu"}
]},
{"fullName":"DataStruct.ExportTriggerDataStruct","triggerStructIndex":6.0,
"listEvent":[
{"GM_str":"addEquip","origId":1004.0,"fullName":"DataStruct.TriggerEventPlayerGMStr"}
],
"listCondition":[],
"listAction":[
{"player_GM":1201.0,"origId":1003.0,"fullName":"DataStruct.TriggerActionPlayerChatCommand"}]
}],
"fullName":"DataStruct.ExportData"}

  从上述数据中我们可以观察到"{"是一个类的开始“}”表示一个类的结束,"["表示一个List的开始"]"表示一个List的结束,等等还有其他的,于是我们一下定义:

    private const int MARK_CLASS_OPEN = 0;//类的开始
    private const int MARK_CALSS_CLOSE = 1;//类的结束
    private const int MARK_LIST_OPEN = 2;//list的开始
    private const int MARK_LIST_CLOSE = 3;//list的结束
    private const int MARK_STRING = 4;//字符串的标识
    /// <summary>
    /// ","
    /// </summary>
    private const int MARK_COMMA = 5;
    /// <summary>
    /// 数字
    /// </summary>
    private const int MARK_NUMBER = 6;
    private const int MARK_TRUE = 7;//bool值true的标识
    private const int MARK_FALSE = 8;//bool值false的标识
    private const int MARK_NULL = 9;//null数据的标识

定义了每一个标识我们可以根据传入的字符串(这里我们将字符串转化为char[]数组)来寻找下一个位置的标识是什么,代码如下:

//当前index将会指向实际位置
private int nextMark(char[] json, ref int index)
    {
        if (index == json.Length)//检查当前位置是否超出字符串长度
        {
            return WillJsonParse.MARK_NONE;
        }

        char c = json[index];
        index++;
        switch (c)
        {
            case '{':
                return WillJsonParse.MARK_CLASS_OPEN;
            case '}':
                return WillJsonParse.MARK_CALSS_CLOSE;
            case '[':
                return WillJsonParse.MARK_LIST_OPEN;
            case ']':
                return WillJsonParse.MARK_LIST_CLOSE;
            case '"':
                return WillJsonParse.MARK_STRING;
            case ',':
                return WillJsonParse.MARK_COMMA;
            case ':':
                return WillJsonParse.MARK_COLON;
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
            case '.':
                return WillJsonParse.MARK_NUMBER;
        }
        index--;

        int remainLength = json.Length - index;

        if (remainLength >= 5)
        {
            if (json[index] == 'f' &&
                json[index + 1] == 'a' &&
                json[index + 2] == 'l' &&
                json[index + 3] == 's' &&
                json[index + 4] == 'e')
            {
                index += 5;
                return WillJsonParse.MARK_FALSE;
            }
        }

        if (remainLength >= 4)
        {
            if (json[index] == 't' &&
                json[index + 1] == 'r' &&
                json[index + 2] == 'u' &&
                json[index + 3] == 'e')
            {
                index += 4;
                return WillJsonParse.MARK_TRUE;
            }
        }
        if (remainLength >= 4)
        {
            if (json[index] == 'n' &&
                json[index + 1] == 'u' &&
                json[index + 2] == 'l' &&
                json[index + 3] == 'l')
            {
                index += 4;
                return WillJsonParse.MARK_NULL;
            }
        }

        return WillJsonParse.MARK_NONE;
    }


//当前index不变
private int GetAhead(char[] json, int index)
    {
        int saveIndex = index;
        return nextMark(json, ref saveIndex);
    }

有了当前的标识我们可以根据标识来解析各个数据,下面给出一个方法用于解析数据的中转:

 private object ParseValue(char[] json, ref int index, ref bool success)
    {
        switch (GetAhead(json, index))
        {
            case WillJsonParse.MARK_STRING:
                return parseString(json, ref index);
            case WillJsonParse.MARK_CLASS_OPEN:
                return parseClass(json, ref index);
            case WillJsonParse.MARK_LIST_OPEN:
                return parseList(json, ref index);
            case WillJsonParse.MARK_NUMBER:
                return parseNumber(json, ref index);
            case WillJsonParse.MARK_TRUE:
                nextMark(json, ref index);
                return Boolean.Parse("TRUE");
            case WillJsonParse.MARK_FALSE:
                nextMark(json, ref index);
                return Boolean.Parse("FALSE");
            case WillJsonParse.MARK_NULL:
                nextMark(json, ref index);
                return null;
            case WillJsonParse.MARK_NONE:
                break;
        }

        success = false;
        return null;
    }

下面就上面涉及到的方法逐一解释,首先看解析字符串

 private string parseString(char[] json, ref int index)
    {
        string s = "";
        char c;
        //"--将第一个"去掉
        c = json[index++];
        bool complete = false;
        while (!complete)
        {
            //已经到最后一个字符
            if (index == json.Length)
            {
                complete = true;
                break;
            }
            c = json[index++];
            if (c == '"')
            {
                complete = true;
                break;
            }
            else /*if ()*/
            {
                s += c;
            }
        }
        return s;
    }

再来看解析List数据,代码如下:

 private List<object> parseList(char[] json, ref int index)
    {
        List<object> list = new List<object>();
        nextMark(json, ref index);//去掉“[”
        bool done = false;
        while (!done)
        {
            int mark = GetAhead(json, index);//获取下一个标识
            if (mark == WillJsonParse.MARK_NONE)
            {
                return null;
            }
            else if (mark == WillJsonParse.MARK_COMMA)//list中的一个元素结束
            {
                nextMark(json, ref index);
            }
            else if (mark == WillJsonParse.MARK_LIST_CLOSE)//list结束符
            {
                nextMark(json, ref index);
                done = true;
                break;
            }
            else
            {
                bool success = true;
                object value = ParseValue(json, ref index, ref success);
                if (!success)
                {
                    return null;
                }

                list.Add(value);//添加value

            }
        }

        return list;
    }

下面看关于数字的解析,代码如下:

 private float parseNumber(char[] json, ref int index)
    {
        int lastIndex = getLastIndexOfNumber(json, index);
        int charLength = (lastIndex - index) + 1;
        char[] numberCharArray = new char[charLength];
        Array.Copy(json, index, numberCharArray, 0, charLength);
        index = lastIndex + 1;
//可以看出这里统一转化为float类型,显然并不符合广泛应用
//这里需要改进能够用于得到int/double/long等类型
        float f_vlaue = float.Parse(new string(numberCharArray));
        return f_vlaue;
    }


 private int getLastIndexOfNumber(char[] json, int index)
    {
        int lastIndex;
        for (lastIndex = index; lastIndex < json.Length; lastIndex++)
        {
            if ("0123456789+-.eE".IndexOf(json[lastIndex]) == -1)
            {
                break;
            }
        }
        return lastIndex - 1;
    }

最后来解析一个类,代码如下:

 private Assembly assembly;

  private object parseClass(char[] json, ref int index)
    {
        Hashtable table = new Hashtable();
        int mark;
        object clazz = null;

        //{  去掉{
        nextMark(json, ref index);

        bool done = false;
        while (!done)
        {
            mark = GetAhead(json, index);

            if (mark == WillJsonParse.MARK_NONE)
            {
                //数据格式不符合,返回null值
                return null;
            }
            else if (mark == WillJsonParse.MARK_COMMA)
            {//遇到“,”跳过该符号读取下一元素
                nextMark(json, ref index);
            }
            else if (mark == WillJsonParse.MARK_CALSS_CLOSE)
            {//遇到类结束符“}”该类结束返回该类
                nextMark(json, ref index);//去掉“}”
                clazz = creatClazz(table);
                return clazz;
            }
            else
            {
                string name = parseString(json, ref index);
                if (string.IsNullOrEmpty(name))
                {//没有变量名数据出错
                    return null;
                }

                mark = nextMark(json, ref index);
                if (mark != WillJsonParse.MARK_COLON)
                {若不是冒号,数据出错
                    return null;
                }

                //值
                bool success = true;
                object value = ParseValue(json, ref index, ref success);
                if (!success)
                {//没有值,不符合标准,该类出错返回null
                    return null;
                }
                table[name] = value;
            }
        }
        clazz = creatClazz(table);
        return clazz;
    }


//创建类的方法
 private object creatClazz(Hashtable table)
    {
        if (assembly == null)
        {
            assembly = Assembly.GetExecutingAssembly();
        }

//为了定位到每一个准确的类给每一个类定义了一个fullName变量,该变量赋值的内容为该类的完全限定名
//这里显然是一个并符合广泛的应用,还有需要改进的地方,小W想到的是自己写一个json的序列化额外定义
//每一个类的标识,当然这个序列化小W并没有写 @_@
        if (table.ContainsKey("fullName"))
        {
            string fullName = table["fullName"].ToString();
            object clazz = null;

            Type type = assembly.GetType(fullName);
            clazz = Activator.CreateInstance(type);

            foreach (string tb in table.Keys)
            {
                object obj = table[tb];
                if (obj is List<object>)
                {
                    List<object> list = (List<object>)obj;
//这里关于List的类型的转化小编并没有写,只是给出了一个接口用来实现一个方法listVoluation
//用来自己将object类型转化为自己需要的类型
//显然这里也需要改进,小W这里是针对自己写的一个编辑器来写的解析,所以也就没有改变这个
                    MethodInfo method = clazz.GetType().GetMethod("listVoluation");
                    method.Invoke(clazz, new object[] { list });
                }
                else
                {
                    try
                    {
                        clazz.GetType().GetField(tb).SetValue(clazz, obj);
                    }
                    catch (Exception e)
                    {
                        Debug.LogError("对字段设置出错提示:tb=" + tb + ",obj=" + obj.ToString() + "。" + e.Message);
                    }
                }
            }
            return clazz;
        }
        return null;
    }

最后我们在给出一个public方法用于外部调用反序列化,代码如下:

public object JsonDeserialize(string json)
    {
        object obj = null;
        char[] charJson = json.ToCharArray();

        int index = 0;
        bool success = true;

        obj = ParseValue(charJson, ref index, ref success);

        return obj;
    }

至此该解析已完成,从上述叙述中可以看出有三个已知的不足之处,以后若有需要小W会改进哒。

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值