Json解析类序列化自动生成方法 VR资源

jskymoon 2017-07-28 11:49:49
前言
很多项目喜欢使用Json或Xml配置数据,Unity从5.3推出了JsonUtility。
这样大多数情况就不用导入插件去解析Json了,可以使用它直接解析Json。如下面的Json:
 
1
2
3
4
{
     "Name" : "Yumo",
     "Level" : 7,
     "Stats" : [ 4,7 ]
}

你可以先声明一个对应的解析类:
 
1
2
3
4
5
6
[System.Serializable]
public class Creature
{
    public string Name;
    public int Level;
    public int[] stats;
}
然后,直接调用解析方法即可:
 
Creature Yumo = JsonUtility.FromJson<Creature>(jsonString);


很方便啊~但是如果我要解析的是下面的Json呢
 
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
{
    "glossary": {
        "title": "example glossary",
                "GlossDiv": {
            "title": "S",
                        "GlossList": {
                "GlossEntry": {
                    "ID": "SGML",
                                        "SortAs": "SGML",
                                        "GlossTerm": "Standard Generalized Markup Language",
                                        "Acronym": "SGML",
                                        "Abbrev": "ISO 8879:1986",
                                        "GlossDef": {
                        "para": "A meta-markup language, used to create markup languages such as DocBook.",
                                                "GlossSeeAlso": ["GML", "XML"]
                    },
                                        "GlossSee": "markup"
                }
            }
        }
    }
}

当然,你可以一层层的去对应写解析类,但是这样会比较浪费时间。而且当Json结构发生变化时你需要再去调整。


需求
因此我们接下来做的就是自动生成Json解析类,效果如下图:







分析


既然要自动生成Json解析类,那么需要先了解Json。
Json大致分为五种类型:object、array、string、number、bool


object 的结构如下:


array 的结构如下:


由上面的结构图可以发现,Json对象其实就是一个键值对的集合。因此一个最基本的思路就是:
先将Json解析成C#字典类型,即Dictionary<string, object>。然后根据此字典类型生成对应的C#解析类

那么如何取出Json中所有的键值对呢?
刚开始打算直接用一个正则就能取出Json里所有数据的,后来Google了下发现.Net不支持递归正则
因此,我们将采用C#递归+正则的方式取出数据。

代码流程
1.定义需要用到的正则,代码如下:

 
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
#region 正则表达式
//解析键值对
private const string regexPairOf = @"\s*" + regexString + @"\s*:\s*";//\s*"([^"]*)"\s*:\s*
 
private const string regexPairOfObject = regexPairOf + regexObject;
private const string regexPairOfArray = regexPairOf + regexArray;
private const string regexPairOfString = regexPairOf + regexString;
private const string regexPairOfNumber = regexPairOf + regexNumber;
private const string regexPairOfBool = regexPairOf + regexBool;
 
//对象
private const string regexObject = @"(?<!\[[\s\S]*)\{((?>\{(?<c>)|[^\{\}]+|\}(?<-c>))*(?(c)(?!)))\}";//前面不含[的{}
 
//数组
private const string regexArray = @"\[((?>\[(?<c>)|[^\[\]]+|\](?<-c>))*(?(c)(?!)))\]";
 
//基础类型
private const string regexString = "\"([^\"]*)\"";//"[^"]*"
private const string regexNumber = @"(-?(?=[1-9]|0(?!\d))\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)";
private const string regexBool = "(true|false|null)";
#endregion

2.将json传入函数ParseRoot()
 
1
2
3
4
5
6
7
8
9
private static Dictionary<string, object> ParseRoot(string json)
{
    Match match = Regex.Match(json, regexObject);
    if (match.Success)
    {
        string content = match.Groups[1].Value;
        return ParseObject(ref content);
    }
    return null;
}

3.使用ParseObject() 解析并返回一个ObjectDictionary
 
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
private static Dictionary<string, object> ParseObject(ref string content)
{
    //解析members
    Pair[] members = ParseMembers(ref content);
 
    //创建Object
    Dictionary<string, object> result = new Dictionary<string, object>();
    if (members != null)
    {
        for (int i = 0, l = members.Length; i < l; i++)
        {
            result.Add(members[i].key, members.value);
        }
    }
    return result;
}


4.解析对象中的键值对将其封装成数组
 
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
private static Pair[] ParseMembers(ref string content)
{
    List<Pair> membersList = new List<Pair>();
 
    string original = content.ToString();
 
    //判断Object类型
    Pair[] pairsOfObject = ParsePairs(ref content, regexPairOfObject);
    foreach (Pair pair in pairsOfObject)
    {
        pair.index = original.IndexOf(pair.content);
        pair.value = ParseObject(ref pair.content);
    }
    membersList.AddRange(pairsOfObject);
 
    //判断Array类型
    Pair[] pairsOfArray = ParsePairs(ref content, regexPairOfArray);
    foreach (Pair pair in pairsOfArray)
    {
        pair.index = original.IndexOf(pair.content);
        pair.value = ParseArray(ref pair.content);
    }
    membersList.AddRange(pairsOfArray);
 
    //判断String类型
    Pair[] pairsOfString = ParsePairs(ref content, regexPairOfString);
    foreach (Pair pair in pairsOfString)
    {
        pair.index = original.IndexOf(pair.content);
        pair.value = pair.content;
    }
    membersList.AddRange(pairsOfString);
 
    //判断Number类型
    Pair[] pairsOfNumber = ParsePairs(ref content, regexPairOfNumber);
    foreach (Pair pair in pairsOfNumber)
    {
        pair.index = original.IndexOf(pair.content);
        pair.value = ConfigTools.ConvertNumber(pair.content);
    }
    membersList.AddRange(pairsOfNumber);
 
    //判断Bool类型
    Pair[] pairsOfBool = ParsePairs(ref content, regexPairOfBool);
    foreach (Pair pair in pairsOfBool)
    {
        pair.index = original.IndexOf(pair.content);
        pair.value = ConfigTools.ConvertBool(pair.content);
    }
    membersList.AddRange(pairsOfBool);
 
    //排序
    membersList.Sort(Pair.Compare);
 
    return membersList.ToArray();
}


5.将键值对中的数组类型解析成object[]
 
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
private static object[] ParseArray(ref string content)
{
    List<object> array = new List<object>();
 
    //排序
    string original = content.ToString();
    List<Sort> sorts = new List<Sort>();
 
    //Object
    MatchCollection matchObjects = MatchesAndRemove(ref content, regexObject);
    foreach (Match match in matchObjects)
    {
        string s = match.Groups[1].Value;
        sorts.Add(new Sort(original.IndexOf(s),ParseObject(ref s)));
    }
 
    //数组
    MatchCollection matchArraies = MatchesAndRemove(ref content, regexArray);
    foreach (Match match in matchArraies)
    {
        string s = match.Groups[1].Value;
        sorts.Add(new Sort(original.IndexOf(s), ParseArray(ref s)));
    }
 
    //String
    MatchCollection matchStrings = MatchesAndRemove(ref content, regexString);
    foreach (Match match in matchStrings)
    {
        string s = match.Groups[1].Value;
        sorts.Add(new Sort(original.IndexOf(s), s));
    }
 
    //Number
    MatchCollection matchNumbers = MatchesAndRemove(ref content, regexNumber);
    foreach (Match match in matchNumbers)
    {
        string s = match.Groups[1].Value;
        sorts.Add(new Sort(original.IndexOf(s), ConfigTools.ConvertNumber(s)));
    }
 
    //Bool
    MatchCollection matchBools = MatchesAndRemove(ref content, regexBool);
    foreach (Match match in matchBools)
    {
        string s = match.Groups[1].Value;
        sorts.Add(new Sort(original.IndexOf(s), ConfigTools.ConvertBool(s)));
    }
 
    //进行排序
    sorts.Sort(Sort.Compare);
    foreach (Sort s in sorts)
    {
        array.Add(s.data);
    }
 
    return array.ToArray();
}


整个过程如下图:
 

此流程不断递归,直至所有对象和数组中没有子对象或子数组
99VR视界二维码
热门推荐
Hot Recommended
在线客服