Excel导出XML和CS脚本

第一次写博客,好紧张啊,有没有潜规则,用不用脱啊,该怎么说啊,打多少字才显的有文采啊,我写的这么好会不会太招遥,写的这么深奥别人会不会看不懂啊,好激动啊,怎么才能装成是经常写博客的样子,好紧张啊 ╯△╰


第一篇博客就跟各位同学们分享下如何在unity中制作一个把Excel表格导出成XML和CS脚本的工具吧!
首先说下用到的第三方库:NPOI 具体我就不介绍了,大家自行百度吧!下面附上下载地址:

点击下载NPOI


好了,下面正式开始!
首先打开unity,新建一个工程,在Project窗口右键->Create->C# Script(貌似有点啰嗦了≥﹏≤) ,创建一个cs脚本,命名为ConvertExcelWindow继承EditorWindow放到Assets/Editor文件夹下。下面附上完整代码及注释:

using System;
using UnityEngine;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using UnityEditor;
using Debug = UnityEngine.Debug;

public class ConvertExcelWindow : EditorWindow
{
    //导出脚本路径
    public static string scriptPath = "Assets/Scripts/ExcelData";

    //导出XML路径
    public static string xmlPath = "Assets/Res/Config";

    //Excel表格路径(会递归查找所有子目录并导出)
    public static string excelRootPath;

    //是否导出脚本
    private static bool exportScript = true;

    //是否导出XML
    private static bool exportXml = true;

    //创建一个按钮用来打开我们自定义的窗口
    [MenuItem("Tools/Convert Excel", false, 1)]
    static void ConvertExcel()
    {
        Rect rect = new Rect(0f, 0f, 500f, 150f);
        EditorWindow win = EditorWindow.GetWindowWithRect<ConvertExcelWindow>(rect, true, "Convert Excel", true);
        win.Show();
    }

    //窗口布局写在这个方法里
    private void OnGUI()
    {
        //都是一些简单的控件,就不一行一行写注释了
        EditorGUIUtility.labelWidth = 80;

        EditorGUILayout.BeginVertical();

        GUILayout.Space(20);

        GUILayout.BeginHorizontal();
        exportScript = EditorGUILayout.ToggleLeft("导出脚本", exportScript);
        GUILayout.Space(-180);
        EditorGUILayout.SelectableLabel("脚本生成路径: " + scriptPath);
        if (GUILayout.Button("打开目录"))
        {
            //打开脚本文件夹
            System.Diagnostics.Process.Start(scriptPath.Replace('/', '\\'));
        }
        GUILayout.EndHorizontal();

        GUILayout.Space(5);

        GUILayout.BeginHorizontal();
        exportXml = EditorGUILayout.ToggleLeft("导出Xml", exportXml);
        GUILayout.Space(-180);
        EditorGUILayout.SelectableLabel("Xml生成路径: " + xmlPath);
        if (GUILayout.Button("打开目录"))
        {
            //打开XML文件夹
            System.Diagnostics.Process.Start(xmlPath.Replace('/', '\\'));
        }
        GUILayout.EndHorizontal();

        GUILayout.Space(5);

        GUILayout.BeginHorizontal();
        EditorGUILayout.PrefixLabel("Excel根目录");
        excelRootPath = EditorGUILayout.TextField(excelRootPath);
        GUILayout.EndHorizontal();

        GUILayout.Space(5);

        if (GUILayout.Button("导出"))
        {
            if (string.IsNullOrEmpty(excelRootPath))
            {
                EditorUtility.DisplayDialog("提示", "Excel路径不能为空", "确定");
                return;
            }
            //获取路径下所有以xls,xlsx结尾的表格绝对路径
            List<string> files = Directory.GetFiles(excelRootPath, "*.xls", SearchOption.AllDirectories).ToList();
            //遍历Excel并执行导出方法
            for (int i = 0; i < files.Count; i++)
            {
                //这里为啥要用Try呢?防止导出报错导致进度条清除不了
                try
                {
                    //这里显示导出进度条
                    EditorUtility.DisplayProgressBar("converting...", files[i], (float)i / files.Count);
                    //调用导出方法传入表格路径
                    ExportCSharpClass(files[i]);
                }
                catch (Exception e)
                {
                    EditorUtility.ClearProgressBar();
                    throw new Exception(e.Source + "\n" + e.Message + "\n" + e.StackTrace);
                }
            }
            EditorUtility.ClearProgressBar();
        }
        EditorGUILayout.EndVertical();
    }

    /// <summary>
    /// 导出Excel
    /// </summary>
    /// <param name="filePath">文件路径</param>
    public static void ExportCSharpClass(string filePath)
    {
        if (!exportScript && !exportXml) return;
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Reset();
        stopwatch.Start();
        FileInfo info = new FileInfo(filePath);
        //去掉文件只读属性
        info.Attributes &= ~FileAttributes.ReadOnly;
        XmlDocument doc = new XmlDocument();
        XmlNode root = doc.CreateElement("info");
        doc.AppendChild(root);
        StringBuilder code = new StringBuilder();
        //保存表格每列的名称,用于给cs脚本添加注释
        Dictionary<int, string> noteDict = new Dictionary<int, string>();
        //保存表格字段名称,用于创建脚本字段名称和XML标签名称
        Dictionary<int, string> fieldDict = new Dictionary<int, string>();
        using (FileStream fs = File.Open(filePath, FileMode.Open))
        {
            //支持两种Excel格式,这里只读取Excel的第一张表
            ISheet sheet = null;
            if (filePath.EndsWith(".xls"))
            {
                HSSFWorkbook book = new HSSFWorkbook(fs);
                sheet = book.GetSheetAt(0);
            }
            if (filePath.EndsWith(".xlsx"))
            {
                XSSFWorkbook book2 = new XSSFWorkbook(fs);
                sheet = book2.GetSheetAt(0);
            }
            if (sheet == null)
            {
                EditorUtility.DisplayDialog("提示", "解析错误!文件格式不支持!", "Fuck");
                return;
            }
            //通过两个循环给noteDict和fieldDict赋值
            for (int i = 0; i < 2; i++)
            {
                IRow row = sheet.GetRow(i);
                for (int j = 0; j < row.LastCellNum; j++)
                {
                    ICell cell = row.GetCell(j);
                    string str = cell == null ? "" : cell.ToString();
                    if (i == 0)
                    {
                        noteDict.Add(j, str);
                    }
                    else if (i == 1)
                    {
                        fieldDict.Add(j, str);
                    }
                }
            }
            string fileName = sheet.SheetName;
            if (exportXml)
            {
                XmlNode item = null;
                for (int i = 0; i <= sheet.LastRowNum; i++)
                {
                    IRow row = sheet.GetRow(i);
                    //表格前两行是汉字说明和字段名称
                    if (i > 1)
                    {
                        //单独读取ID字段
                        item = doc.CreateElement("item");
                        XmlAttribute a = doc.CreateAttribute(fieldDict[0]);
                        if (row.GetCell(0) == null)
                        {
                            Debug.LogError(string.Format("第{0}行的id为空", i + 1));
                            return;
                        }
                        if (string.IsNullOrEmpty(row.GetCell(0).ToString())) continue;
                        a.Value = row.GetCell(0).ToString();
                        item.Attributes.Append(a);
                        root.AppendChild(item);
                    }
                    for (int j = 0; j < fieldDict.Count; j++)
                    {
                        //其他字段解析
                        if (i > 1 && item != null)
                        {
                            XmlNode node = doc.CreateElement(fieldDict[j]);
                            string str = "";
                            //如果Cell不为空的话把Cell的值赋给str
                            if (row.GetCell(j) != null && !string.IsNullOrEmpty(row.GetCell(j).ToString()))
                            {
                                str = row.GetCell(j).ToString();
                            }
                            else
                            {
                                //如果Cell为空(每填数值) 并且Cell是整形数值就给默认数值0 其他类型默认空字符串
                                if (fieldDict[j].StartsWith("n32")) str = "0";
                            }
                            node.InnerText = str;
                            item.AppendChild(node);
                        }
                    }
                }
                //保存XML
                string savePath = xmlPath + "/" + fileName + ".xml";
                if (!Directory.Exists(xmlPath)) Directory.CreateDirectory(xmlPath);
                doc.Save(savePath);
            }
            //导出cs代码
            if (exportScript)
            {
                code.Append("using System;");
                code.Append("\n\npublic class " + fileName + " : IConfig\n{");
                code.Append("\n\n\tpublic int UniqueId { get{ return id; }}");
                //根据字段名称创建字段
                for (int i = 0; i < fieldDict.Count; i++)
                {
                    code.Append("\n\n\t/// <summary>\n\t/// " + noteDict[i] + "\n\t/// </summary>");
                    string fieldName = fieldDict[i];
                    string type = "";
                    //这里只区分了整形和字符串两种类型 有需要的话可以拓展
                    if (fieldName.StartsWith("sz")) type = "string";
                    else type = "int";
                    code.Append("\n\tpublic " + type + " " + fieldName + ";");
                }
                code.Append("\n\n}");
                string codePath = scriptPath + "/" + fileName + ".cs";
                if (!Directory.Exists(scriptPath)) Directory.CreateDirectory(scriptPath);
                //保存
                using (StreamWriter sw = new StreamWriter(codePath, false))
                {
                    sw.Write(code.ToString());
                    sw.Flush();
                }
            }
            AssetDatabase.Refresh();
        }
        stopwatch.Stop();
        Debug.Log("转换Excel!耗时:" + stopwatch.Elapsed.TotalMilliseconds + " 毫秒");
    }
}

上面的脚本编译完之后在unity的菜单栏会多出一个Tools选项,点击Tools选择Convert Excel会打开下面的窗口
这里写图片描述
输入Excel路径 单击导出!结束!!

PS:

  • 一定要放到Editor文件夹下(如果你要打包发布的话)
  • 如果导出的XML是公式而不是最终计算的结果,可以复制Excel的列表再选择粘贴数值
  • 有不好的地方欢迎各位大佬批评指正

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值