最近项目用的配置表是xml文件,每次要手动添加两个cs代码文件,很浪费时间,所以写了一个代码生成工具,以下是代码
XmlGenTool.py
# -*- coding: utf-8 -*-
import wx
import xml.etree.ElementTree as et
import os
config_name = 'AssetsPath.txt'
assetsTextPath = os.getcwd() + "/" + config_name
class App(wx.App):
def OnInit(self):
frame = wx.Frame(parent=None, title='Xml代码生成器2.0', pos=(1000, 200), size=(650, 130))
xmlNameTitle = wx.StaticText(frame, label="表名称", pos=(5,8), size=(100, 24))
xmlNameInput = wx.TextCtrl(frame, pos=(105, 5), size=(400, 24))
assetsPathTitle = wx.StaticText(frame, label="Assets文件目录", pos=(5, 40), size=(150, 30))
assetsInput = wx.TextCtrl(frame, pos=(105, 40), size=(400, 24))
checkButton = wx.Button(frame, label="生成代码", pos=(505, 5), size=(100, 24))
#读取配置的Assets路径
file = open(assetsTextPath, encoding='utf-8')
if file:
fileLineArr = file.readlines()
for line in fileLineArr:
strArr = line.replace('\n', '').split(',')
if strArr[0] == "AssetsPath":
assetsInput.SetValue(strArr[1])
def onClickCheckButton(event):
xmlName = xmlNameInput.GetValue()
assetsPath = assetsInput.GetValue()
pathStr = assetsPath + '/Resources/XML/' + xmlName + ".xml"
path = pathStr.replace('\\', '/')
tree = et.parse(path)
root = tree.getroot()
node = root.find('item')
numList = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
typeDict = {}
for k, v in node.items():
if v == "":
typeDict[k] = "string"
continue
char1 = v[0]
if char1 in numList:
typeDict[k] = "int" # int类型
if "." in v:
typeDict[k] = "float" # float类型
elif char1 == '-':
char2 = v[1]
if char2 in numList and "." in v:
typeDict[k] = "float" # float类型
if char2 in numList and ("." not in v):
typeDict[k] = "int" # int类型
elif char1 == '[':
char2 = v[1]
if char2 in numList:
typeDict[k] = "numList"
elif char2 == "'":
typeDict[k] = "strList"
else:
typeDict[k] = "string"
elif char1 == '{' and v[1] == "'":
isNum = False
for i in range(len(v)):
if v[i] == ':':
if i + 1 < len(v):
isNum = v[i + 1] in numList
typeDict[k] = "numDict" if isNum else "strDict"
else:
typeDict[k] = "string"
# print(typeDict)
xFileDataPath = assetsPath + '/Scripts/Data/xml/'
#写入x表文件
file = open(xFileDataPath + 'X' + xmlName + ".cs", 'w+')
writeStr = "using System.Collections;\nusing System.Collections.Generic;\nusing UnityEngine;\n\n"
# Init val
writeStr += "public class X" + xmlName + " : XSuper\n{\n\tpublic override string _id { get; protected set; }\n"
writeStr += "\tpublic int id { get; private set; }\n"
for k, v in typeDict.items():
if k == '_id':
continue
if v == "int":
writeStr += "\tpublic int " + k + " { get; private set; }\n"
elif v == "float":
writeStr += "\tpublic float " + k + " { get; private set; }\n"
elif v == "string":
writeStr += "\tpublic string " + k + " { get; private set; }\n"
elif v == "numList":
writeStr += "\n\tpublic string " + k + " = string.Empty;\n"
writeStr += "\tpublic List<int> " + k + "List { get; private set; }\n"
elif v == "strList":
writeStr += "\n\tpublic string " + k + " = string.Empty;\n"
writeStr += "\tpublic List<string> " + k + "List { get; private set; }\n"
elif v == "numDict":
writeStr += "\n\tpublic string " + k + " { get; private set; }\n"
writeStr += "\tpublic Dictionary<string, int> " + k + "Dict { get; private set; }\n"
elif v == "strDict":
writeStr += "\n\tpublic string " + k + " { get; private set; }\n"
writeStr += "\tpublic Dictionary<string, string> " + k + "Dict { get; private set; }\n"
# Init From Xml
writeStr += '\n\tpublic override void InitFromXml(XmlReadTool tool, int iCount)\n\t{\n\t\t_id = tool.GetAttribute("_id", "", iCount);\n'
for k, v in typeDict.items():
if k == '_id':
continue
if v == "int":
writeStr += "\t\t" + k + ' = tool.GetAttribute("' + k + '", 0, iCount);\n'
else:
writeStr += "\t\t" + k + ' = tool.GetAttribute("' + k + '", "", iCount);\n'
# Init Property
writeStr += "\t}\n\n\tpublic override void InitProperty()\n\t{\n"
for k, v in typeDict.items():
if k == '_id':
writeStr += "\t\tid = int.Parse(_id);\n"
if v == "numDict":
writeStr += "\t\t" + k + 'Dict = JReadTool.Instance.ParseJsonToObject<Dictionary<string, int>>(' + k + ');\n'
elif v == "strDict":
writeStr += "\t\t" + k + 'Dict = JReadTool.Instance.ParseJsonToObject<Dictionary<string, string>>(' + k + ');\n'
elif v == "numList":
writeStr += "\t\tif (!string.IsNullOrEmpty(" + k + "))\n\t\t{\n\t\t\t" + k + "List = JReadTool.Instance.ParseJsonToObject<List<int>>(" + k + ");\n\t\t}\n"
elif v == "strList":
writeStr += "\t\tif (!string.IsNullOrEmpty(" + k + "))\n\t\t{\n\t\t\t" + k + "List = JReadTool.Instance.ParseJsonToObject<List<string>>(" + k + ");\n\t\t}\n"
# Parse Asset Xml
writeStr += "\t}\n\n\tpublic void ParseAssetXml(AssetItem_X" + xmlName + " vAssetData)\n\t{\n"
for k, v in typeDict.items():
if v == "numDict" or v == "strDict":
writeStr += "\t\t" + k + "Dict = vAssetData.Deserialize_" + k + "Dict();\n"
elif v == "numList" or v == "strList":
writeStr += "\t\t" + k + "List = vAssetData." + k + "List;\n"
else:
writeStr += "\t\t" + k + " = vAssetData." + k + ";\n"
if k == "_id":
writeStr += "\t\t" + "id = vAssetData.id;\n"
writeStr += "\t}\n\n}"
file.write(writeStr)
file.close()
assetsRootDataPath = assetsPath + '/Scripts/Data/xml/XMLSObjct/'
#写入AssetsRoot文件
file = open(assetsRootDataPath + 'AssetRoot_X' + xmlName + ".cs", 'w+')
writeStr = "using UnityEngine;\nusing System.Collections;\nusing System;\nusing System.Collections.Generic;\n\n"
writeStr += "public class AssetRoot_X" + xmlName + " : IAssetRoot_Base\n{\n\t[HideInInspector]\n"
writeStr += "\tpublic List<AssetItem_X" + xmlName + "> Itemlist = new List<AssetItem_X" + xmlName + ">();\n}\n\n"
writeStr += "[Serializable]\npublic class AssetItem_X" + xmlName + '\n{\n\t[XObject("_id")]\n\tpublic string _id;\n\tpublic int id;\n\n'
# Init Val
for k, v in typeDict.items():
if k == '_id':
continue
if v == "int":
writeStr += '\t[XObject("' + k + '")]\n\tpublic int ' + k + ';\n\n'
elif v == "float":
writeStr += '\t[XObject("' + k + '")]\n\tpublic float ' + k + ';\n\n'
elif v == "string":
writeStr += '\t[XObject("' + k + '")]\n\tpublic string ' + k + ';\n\n'
else:
writeStr += '\t[XObject("' + k + '")]\n\tpublic string ' + k + ';\n'
if v == "numList":
writeStr += "\tpublic List<int> " + k + "List = null;\n\n"
elif v == "strList":
writeStr += "\tpublic List<string> " + k + "List = null;\n\n"
elif v == "numDict":
writeStr += "\tpublic List<string> " + k + "Dict_Key = null;\n\tpublic List<int> " + k + "Dict_Value = null;\n\n"
elif v == "strDict":
writeStr += "\tpublic List<string> " + k + "Dict_Key = null;\n\tpublic List<string> " + k + "Dict_Value = null;\n\n"
# Serializable Dict && Deserialize Dict
for k, v in typeDict.items():
dictType = ""
if v == "numDict":
dictType = "int"
elif v == "strDict":
dictType = "string"
if dictType != "":
# Serializable
writeStr += "\tprivate void Serializable_" + k + "Dict(Dictionary<string, " + dictType + "> vDict)\n\t{\n\t\tif (vDict == null) return;\n"
writeStr += "\t\tif (" + k + "Dict_Key == null) " + k + "Dict_Key = new List<string>(vDict.Keys);\n"
writeStr += "\t\tif (" + k + "Dict_Value == null) " + k + "Dict_Value = new List<" + dictType + ">(vDict.Values);\n\t}\n\n"
# Deserialize
writeStr += "\tpublic Dictionary<string, " + dictType + "> Deserialize_" + k + "Dict()\n\t{\n"
writeStr += "\t\tif (" + k + "Dict_Key == null) return null;\n\t\tif (" + k + "Dict_Key.Count <= 0) return new Dictionary<string, " + dictType + ">();\n"
writeStr += "\t\tDictionary<string, " + dictType + "> vReData = new Dictionary<string, " + dictType + ">();\n"
writeStr += "\t\tfor (int iCount = 0; iCount < " + k + "Dict_Key.Count; iCount++)\n\t\t{\n"
writeStr += "\t\t\tvReData.Add(" + k + "Dict_Key[iCount], " + k + "Dict_Value[iCount]);\n\t\t}\n\t\treturn vReData;\n\t}\n\n"
# Run Parse
writeStr += "\tpublic void RunParse()\n\t{\n\t\tid = int.Parse(_id);\n\n"
for k, v in typeDict.items():
dictType = ""
listType = ""
if v == "numDict":
dictType = "int"
elif v == "strDict":
dictType = "string"
elif v == "numList":
listType = "int"
elif v == "strList":
listType = "string"
if dictType != "":
writeStr += "\t\tif (!string.IsNullOrEmpty(" + k + "))\n\t\t{\n\t\t\t"
writeStr += "Serializable_" + k + "Dict" + "(JReadTool.Instance.ParseJsonToObject<Dictionary<string, " + dictType + ">>(" + k + "));\n"
writeStr += "\t\t\t" + k + " = string.Empty;\n\t\t}\n\n"
elif listType != "":
writeStr += "\t\tif (!string.IsNullOrEmpty(" + k + "))\n\t\t{\n\t\t\t"
writeStr += k + "List = JReadTool.Instance.ParseJsonToObject<List<" + listType + ">>(" + k + ");\n"
writeStr += "\t\t\t" + k + " = string.Empty;\n\t\t}\n\n"
writeStr += "\t}\n\n}"
file.write(writeStr)
file.close()
#写入XmlDataManager
xmlDataManagerPath = assetsPath + '/Scripts/Manager/XmlDataManager.cs'
file = open(xmlDataManagerPath, encoding='utf-8')
fileArr = file.readlines()
lineIndex = 0
flag1 = 200
flag2 = -1
flag3 = -1
writeStr = ""
for line in fileArr:
lineIndex += 1
writeStr += line
#插入一行
if lineIndex == flag1:
writeStr += "\tprivate List<X" + xmlName + ">m" + xmlName + "List = null;\n"
#插入第二行
if "private void InitPath()" in line:
if flag2 == -1:
flag2 = lineIndex + 50
if lineIndex == flag2:
writeStr += "\t\tpathDic.Add(typeof(X" + xmlName + '), @"XML/' + xmlName + '.xml");\n'
#开始写方法
if lineIndex > 15000 and "endregion" in line:
if flag3 == -1:
flag3 = lineIndex + 1
if lineIndex == flag3:
#Init方法
writeStr += "#region " + xmlName + "\n\n\tpublic void Init" + xmlName + "()\n\t{\n\t\t"
writeStr += "if (m" + xmlName + "List == null)\n\t\t{\n\t\t\tDictionary<string, X" + xmlName
writeStr += "> vDict = new Dictionary<string, X" + xmlName + ">();\n\t\t\tInitDataFromXml(ref m"
writeStr += xmlName + "List, ref vDict);\n\t\t\tvDict.Clear();\n\t\t}\n\t}\n\n"
#GetId方法
writeStr += "\tpublic X" + xmlName + " Get" + xmlName + "(int vId)\n\t{\n#if !UsingAssetXml\n\t\t"
writeStr += "Init" + xmlName + "();\n\t\tif (m" + xmlName + "List == null) return null;\n\t\t"
writeStr += "if (m" + xmlName + "List.Count <= 0) return null;\n\t\t"
writeStr += "int len = m" + xmlName + "List.Count;\n\t\tfor (int i = 0; i < len; i++)\n\t\t{\n\t\t\t"
writeStr += "if (vId == m" + xmlName + "List[i].id)\n\t\t\t{\n\t\t\t\treturn m" + xmlName + "List[i];\n"
writeStr += "\t\t\t}\n\t\t}\n\t\treturn null;\n#else\n\t\t"
writeStr += "var vData = ConfigDataLoader.instance.Get" + xmlName + "(vId);\n\t\t"
writeStr += "if (vData == null) return null;\n\t\tX" + xmlName + " reData = new X" + xmlName + "();\n\t\t"
writeStr += "reData.ParseAssetXml(vData);\n\t\treturn reData;\n#endif\n\t}\n\n"
#GetAll方法
writeStr += "\tpublic List<X" + xmlName + "> Get" + xmlName + "All()\n\t{\n#if !UsingAssetXml\n\t\t"
writeStr += "Init" + xmlName + "();\n\t\tif (m" + xmlName + "List == null) return null;\n\t\t"
writeStr += "if (m" + xmlName + "List.Count <= 0) return m" + xmlName + "List;\n\t\t"
writeStr += "return m" + xmlName + "List;\n#else\n\t\tvar vData = ConfigDataLoader.instance.Get"
writeStr += xmlName + "All();\n\t\tif (vData == null) return null;\n\t\tList<X" + xmlName;
writeStr += "> reDataList = new List<X" + xmlName + ">();\n\t\tfor (int i = 0; i < vData.Count; i++)"
writeStr += "\n\t\t{\n\t\t\tX" + xmlName + " reData = new X" + xmlName + "();\n\t\t\t"
writeStr += "reData.ParseAssetXml(vData[i]);\n\t\t\treDataList.Add(reData);\n\t\t}\n\t\t"
writeStr += "return reDataList;\n#endif\n\t}\n\n#endregion\n\n"
#print(writeStr)
file = open(xmlDataManagerPath, "w+")
file.write(writeStr)
file.close()
# 写入ConfigDataLoader
configDataLoaderPath = assetsPath + '/Scripts/DataLoader/Loader/ConfigDataLoader.cs'
file = open(configDataLoaderPath, encoding='utf-8')
fileArr = file.readlines()
lineIndex = 0
flag1 = 101
flag2 = -1
flag3 = -1
flag4 = -1
flag5 = -1
writeStr = ""
for line in fileArr:
lineIndex += 1
writeStr += line
# 插入一行
if lineIndex == flag1:
writeStr += "\tprivate const string mXmlName_" + xmlName + ' = "' + xmlName+ '";\n'
#Init
if "public IEnumerator YieldInit()" in line:
if flag2 == -1:
flag2 = lineIndex + 100
if lineIndex == flag2:
writeStr += "\t\tInitConfigData(mXmlName_" + xmlName + ");\n"
#Parse
if "public IEnumerator YieldParseConfigData()" in line:
if flag3 == -1:
flag3 = lineIndex + 100
if lineIndex == flag3:
writeStr += "\t\tParseConfigData(mXmlName_" + xmlName + ");\n"
#Release
if "private IEnumerator ReleaseAll()" in line:
if flag4 == -1:
flag4 = lineIndex + 100
if lineIndex == flag4:
writeStr += "\t\tReleaseConfigData(mXmlName_" + xmlName + ");\n"
#开始写方法
if lineIndex > 5000 and "endregion" in line:
if flag5 == -1:
flag5 = lineIndex + 1
if lineIndex == flag5:
#GetId方法
writeStr += "#region " + xmlName + "\n\n\tpublic AssetItem_X" + xmlName + " Get" + xmlName + "(int vId)\n\t{\n\t\t"
writeStr += "Object vDataObj = DataLoaderCtrl.Instance.GetAssetData(mXmlName_" + xmlName + ");\n\t\t"
writeStr += "if (vDataObj == null) return null;\n\t\tvar vAssetData = (AssetRoot_X" + xmlName + ")vDataObj;\n\t\t"
writeStr += "if (vAssetData == null) return null;\n\t\tif (vAssetData.Itemlist == null) return null;\n\t\t"
writeStr += "if (vAssetData.Itemlist.Count <= 0) return new AssetItem_X" + xmlName + "();\n\t\t"
writeStr += "for (int i = 0; i < vAssetData.Itemlist.Count; i++)\n\t\t{\n\t\t\t"
writeStr += "if (vAssetData.Itemlist[i].id == vId)\n\t\t\t\treturn vAssetData.Itemlist[i];\n\t\t"
writeStr += "}\n\t\treturn null;\n\t}\n\n"
#GetAll方法
writeStr += "\tpublic List<AssetItem_X" + xmlName + "> Get" + xmlName + "All()\n\t{\n\t\t"
writeStr += "Object vDataObj = DataLoaderCtrl.Instance.GetAssetData(mXmlName_" + xmlName + ");\n\t\t"
writeStr += "if (vDataObj == null) return null;\n\t\tvar vAssetData = (AssetRoot_X" + xmlName + ")vDataObj;\n\t\t"
writeStr += "if (vAssetData == null) return null;\n\t\tif (vAssetData.Itemlist == null) return null;\n\t\t"
writeStr += "return vAssetData.Itemlist;\n\t}\n\n#endregion\n\n"
# print(writeStr)
file = open(configDataLoaderPath, "w+")
file.write(writeStr)
file.close()
msgWindow = wx.MessageDialog(None, "代码生成完毕!", "提示", wx.YES_DEFAULT | wx.ICON_QUESTION)
if msgWindow.ShowModal() == wx.ID_YES: # 如果点击了提示框的确定按钮
msgWindow.Destroy() # 则关闭提示框
checkButton.Bind(wx.EVT_BUTTON, onClickCheckButton)
frame.Show()
return True
app = App()
app.MainLoop()
需要配合一个配置文件使用
AssetsPath.txt
AssetsPath,E:\Work\Trunk\Assets
# 注意:XmlDataManager和ConfigDataLoader编码格式需要为utf-8,不然会解析错误